From 07de50d9f9ed1fa5d6e0f17b6125e9e5bc748df8 Mon Sep 17 00:00:00 2001 From: "Michael C. Rael" Date: Sun, 12 Jun 2016 09:52:39 -0600 Subject: [PATCH 0001/1275] Added Greedy Set Cover algorithm (unweighted) as extension to Set. --- SetCover.swift | 33 +++++++++++++++++++ .../contents.xcworkspacedata | 7 ++++ 2 files changed, 40 insertions(+) create mode 100644 SetCover.swift diff --git a/SetCover.swift b/SetCover.swift new file mode 100644 index 000000000..3a61140a8 --- /dev/null +++ b/SetCover.swift @@ -0,0 +1,33 @@ +extension Set { + func cover(from array: Array>) -> Array>? { + var result: [Set]? = [Set]() + var remainingSet = self + + func largestIntersectingSet() -> Set? { + var largestIntersectionLength = 0 + var largestSet: Set? + + for set in array { + let intersectionLength = remainingSet.intersect(set).count + if intersectionLength > largestIntersectionLength { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while remainingSet.count != 0 { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtract(largestSet) + } + + if remainingSet.count != 0 || self.count == 0 { + result = nil + } + + return result + } +} \ No newline at end of file diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 1ec94e727..1fdf194f5 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1628,6 +1628,13 @@ + + + + From 9c0c08382dfd5da8cbe7f4a7abdb6a04db415fb6 Mon Sep 17 00:00:00 2001 From: "Michael C. Rael" Date: Sun, 12 Jun 2016 10:08:12 -0600 Subject: [PATCH 0002/1275] Added playground, separating algorthm source from playground source. --- SetCover.playground/Contents.swift | 31 +++++++++++++ .../Sources/RandomArrayOfSets.swift | 43 +++++++++++++++++++ SetCover.playground/Sources/SetCover.swift | 33 ++++++++++++++ SetCover.playground/contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 3 ++ 5 files changed, 114 insertions(+) create mode 100644 SetCover.playground/Contents.swift create mode 100644 SetCover.playground/Sources/RandomArrayOfSets.swift create mode 100644 SetCover.playground/Sources/SetCover.swift create mode 100644 SetCover.playground/contents.xcplayground diff --git a/SetCover.playground/Contents.swift b/SetCover.playground/Contents.swift new file mode 100644 index 000000000..3822f16e3 --- /dev/null +++ b/SetCover.playground/Contents.swift @@ -0,0 +1,31 @@ +let universe1 = Set(1...7) +let array1 = randomArrayOfSets(covering: universe1) +let cover1 = universe1.cover(from: array1) + +let universe2 = Set(1...10) +let array2: Array> = [[1,2,3,4,5,6,7], [8,9]] +let cover2 = universe2.cover(from: array2) + +let universe3 = Set(["tall", "heavy"]) +let array3: Array> = [["tall", "light"], ["short", "heavy"], ["tall", "heavy", "young"]] +let cover3 = universe3.cover(from: array3) + +let universe4 = Set(["tall", "heavy", "green"]) +let cover4 = universe4.cover(from: array3) + +let universe5: Set = [16, 32, 64] +let array5: Array> = [[16,17,18], [16,32,128], [1,2,3], [32,64,128]] +let cover5 = universe5.cover(from: array5) + +let universe6: Set = [24, 89, 132, 90, 22] +let array6 = randomArrayOfSets(covering: universe6) +let cover6 = universe6.cover(from: array6) + +let universe7: Set = ["fast", "cheap", "good"] +let array7 = randomArrayOfSets(covering: universe7, minArraySizeFactor: 20.0, maxSetSizeFactor: 0.7) +let cover7 = universe7.cover(from: array7) + +let emptySet = Set() +let coverTest1 = emptySet.cover(from: array1) +let coverTest2 = universe1.cover(from: Array>()) +let coverTest3 = emptySet.cover(from: Array>()) \ No newline at end of file diff --git a/SetCover.playground/Sources/RandomArrayOfSets.swift b/SetCover.playground/Sources/RandomArrayOfSets.swift new file mode 100644 index 000000000..301fbf5f2 --- /dev/null +++ b/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -0,0 +1,43 @@ +import Foundation + +public func randomArrayOfSets(covering universe: Set, + minArraySizeFactor: Double = 0.8, + maxSetSizeFactor: Double = 0.6) -> Array> { + var result = [Set]() + var ongoingUnion = Set() + + let minArraySize = Int(Double(universe.count) * minArraySizeFactor) + var maxSetSize = Int(Double(universe.count) * maxSetSizeFactor) + if maxSetSize > universe.count { + maxSetSize = universe.count + } + + while true { + var generatedSet = Set() + let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) + + while true { + let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) + for (setIndex, value) in universe.enumerate() { + if setIndex == randomUniverseIndex { + generatedSet.insert(value) + break + } + } + + if generatedSet.count == targetSetSize { + result.append(generatedSet) + ongoingUnion = ongoingUnion.union(generatedSet) + break + } + } + + if result.count >= minArraySize { + if ongoingUnion == universe { + break + } + } + } + + return result +} \ No newline at end of file diff --git a/SetCover.playground/Sources/SetCover.swift b/SetCover.playground/Sources/SetCover.swift new file mode 100644 index 000000000..7f4cec314 --- /dev/null +++ b/SetCover.playground/Sources/SetCover.swift @@ -0,0 +1,33 @@ +public extension Set { + func cover(from array: Array>) -> Array>? { + var result: [Set]? = [Set]() + var remainingSet = self + + func largestIntersectingSet() -> Set? { + var largestIntersectionLength = 0 + var largestSet: Set? + + for set in array { + let intersectionLength = remainingSet.intersect(set).count + if intersectionLength > largestIntersectionLength { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while remainingSet.count != 0 { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtract(largestSet) + } + + if remainingSet.count != 0 || self.count == 0 { + result = nil + } + + return result + } +} \ No newline at end of file diff --git a/SetCover.playground/contents.xcplayground b/SetCover.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/SetCover.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 1fdf194f5..e1f4380e7 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1634,6 +1634,9 @@ + + Date: Sun, 12 Jun 2016 10:21:44 -0600 Subject: [PATCH 0003/1275] Added directory for all files. --- Set Cover (Unweighted)/README.markdown | 0 .../SetCover.playground}/Contents.swift | 0 .../Sources/RandomArrayOfSets.swift | 43 +++++++++++++++++++ .../Sources/SetCover.swift | 33 ++++++++++++++ .../contents.xcplayground | 0 Set Cover (Unweighted)/SetCover.swift | 33 ++++++++++++++ .../Sources/RandomArrayOfSets.swift | 43 ------------------- SetCover.playground/Sources/SetCover.swift | 33 -------------- SetCover.swift | 33 -------------- .../contents.xcworkspacedata | 7 ++- 10 files changed, 114 insertions(+), 111 deletions(-) create mode 100644 Set Cover (Unweighted)/README.markdown rename {SetCover.playground => Set Cover (Unweighted)/SetCover.playground}/Contents.swift (100%) create mode 100644 Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift create mode 100644 Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift rename {SetCover.playground => Set Cover (Unweighted)/SetCover.playground}/contents.xcplayground (100%) create mode 100644 Set Cover (Unweighted)/SetCover.swift delete mode 100644 SetCover.playground/Sources/RandomArrayOfSets.swift delete mode 100644 SetCover.playground/Sources/SetCover.swift delete mode 100644 SetCover.swift diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown new file mode 100644 index 000000000..e69de29bb diff --git a/SetCover.playground/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift similarity index 100% rename from SetCover.playground/Contents.swift rename to Set Cover (Unweighted)/SetCover.playground/Contents.swift diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift new file mode 100644 index 000000000..64253014b --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -0,0 +1,43 @@ +import Foundation + +public func randomArrayOfSets(covering universe: Set, + minArraySizeFactor: Double = 0.8, + maxSetSizeFactor: Double = 0.6) -> Array> { + var result = [Set]() + var ongoingUnion = Set() + + let minArraySize = Int(Double(universe.count) * minArraySizeFactor) + var maxSetSize = Int(Double(universe.count) * maxSetSizeFactor) + if maxSetSize > universe.count { + maxSetSize = universe.count + } + + while true { + var generatedSet = Set() + let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) + + while true { + let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) + for (setIndex, value) in universe.enumerate() { + if setIndex == randomUniverseIndex { + generatedSet.insert(value) + break + } + } + + if generatedSet.count == targetSetSize { + result.append(generatedSet) + ongoingUnion = ongoingUnion.union(generatedSet) + break + } + } + + if result.count >= minArraySize { + if ongoingUnion == universe { + break + } + } + } + + return result +} \ No newline at end of file diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift new file mode 100644 index 000000000..8e608cb52 --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -0,0 +1,33 @@ +public extension Set { + func cover(from array: Array>) -> Array>? { + var result: [Set]? = [Set]() + var remainingSet = self + + func largestIntersectingSet() -> Set? { + var largestIntersectionLength = 0 + var largestSet: Set? + + for set in array { + let intersectionLength = remainingSet.intersect(set).count + if intersectionLength > largestIntersectionLength { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while remainingSet.count != 0 { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtract(largestSet) + } + + if remainingSet.count != 0 || self.count == 0 { + result = nil + } + + return result + } +} \ No newline at end of file diff --git a/SetCover.playground/contents.xcplayground b/Set Cover (Unweighted)/SetCover.playground/contents.xcplayground similarity index 100% rename from SetCover.playground/contents.xcplayground rename to Set Cover (Unweighted)/SetCover.playground/contents.xcplayground diff --git a/Set Cover (Unweighted)/SetCover.swift b/Set Cover (Unweighted)/SetCover.swift new file mode 100644 index 000000000..58ffade9d --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.swift @@ -0,0 +1,33 @@ +extension Set { + func cover(from array: Array>) -> Array>? { + var result: [Set]? = [Set]() + var remainingSet = self + + func largestIntersectingSet() -> Set? { + var largestIntersectionLength = 0 + var largestSet: Set? + + for set in array { + let intersectionLength = remainingSet.intersect(set).count + if intersectionLength > largestIntersectionLength { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while remainingSet.count != 0 { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtract(largestSet) + } + + if remainingSet.count != 0 || self.count == 0 { + result = nil + } + + return result + } +} \ No newline at end of file diff --git a/SetCover.playground/Sources/RandomArrayOfSets.swift b/SetCover.playground/Sources/RandomArrayOfSets.swift deleted file mode 100644 index 301fbf5f2..000000000 --- a/SetCover.playground/Sources/RandomArrayOfSets.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation - -public func randomArrayOfSets(covering universe: Set, - minArraySizeFactor: Double = 0.8, - maxSetSizeFactor: Double = 0.6) -> Array> { - var result = [Set]() - var ongoingUnion = Set() - - let minArraySize = Int(Double(universe.count) * minArraySizeFactor) - var maxSetSize = Int(Double(universe.count) * maxSetSizeFactor) - if maxSetSize > universe.count { - maxSetSize = universe.count - } - - while true { - var generatedSet = Set() - let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) - - while true { - let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) - for (setIndex, value) in universe.enumerate() { - if setIndex == randomUniverseIndex { - generatedSet.insert(value) - break - } - } - - if generatedSet.count == targetSetSize { - result.append(generatedSet) - ongoingUnion = ongoingUnion.union(generatedSet) - break - } - } - - if result.count >= minArraySize { - if ongoingUnion == universe { - break - } - } - } - - return result -} \ No newline at end of file diff --git a/SetCover.playground/Sources/SetCover.swift b/SetCover.playground/Sources/SetCover.swift deleted file mode 100644 index 7f4cec314..000000000 --- a/SetCover.playground/Sources/SetCover.swift +++ /dev/null @@ -1,33 +0,0 @@ -public extension Set { - func cover(from array: Array>) -> Array>? { - var result: [Set]? = [Set]() - var remainingSet = self - - func largestIntersectingSet() -> Set? { - var largestIntersectionLength = 0 - var largestSet: Set? - - for set in array { - let intersectionLength = remainingSet.intersect(set).count - if intersectionLength > largestIntersectionLength { - largestIntersectionLength = intersectionLength - largestSet = set - } - } - - return largestSet - } - - while remainingSet.count != 0 { - guard let largestSet = largestIntersectingSet() else { break } - result!.append(largestSet) - remainingSet = remainingSet.subtract(largestSet) - } - - if remainingSet.count != 0 || self.count == 0 { - result = nil - } - - return result - } -} \ No newline at end of file diff --git a/SetCover.swift b/SetCover.swift deleted file mode 100644 index 3a61140a8..000000000 --- a/SetCover.swift +++ /dev/null @@ -1,33 +0,0 @@ -extension Set { - func cover(from array: Array>) -> Array>? { - var result: [Set]? = [Set]() - var remainingSet = self - - func largestIntersectingSet() -> Set? { - var largestIntersectionLength = 0 - var largestSet: Set? - - for set in array { - let intersectionLength = remainingSet.intersect(set).count - if intersectionLength > largestIntersectionLength { - largestIntersectionLength = intersectionLength - largestSet = set - } - } - - return largestSet - } - - while remainingSet.count != 0 { - guard let largestSet = largestIntersectingSet() else { break } - result!.append(largestSet) - remainingSet = remainingSet.subtract(largestSet) - } - - if remainingSet.count != 0 || self.count == 0 { - result = nil - } - - return result - } -} \ No newline at end of file diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index e1f4380e7..4e0f19dc2 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1632,10 +1632,13 @@ location = "container:" name = "Set Cover (Unweighted)"> + location = "group:Set Cover (Unweighted)/README.markdown"> + location = "group:Set Cover (Unweighted)/SetCover.playground"> + + Date: Sun, 12 Jun 2016 10:36:12 -0600 Subject: [PATCH 0004/1275] Started work on the README file. --- Set Cover (Unweighted)/README.markdown | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown index e69de29bb..68538cc60 100644 --- a/Set Cover (Unweighted)/README.markdown +++ b/Set Cover (Unweighted)/README.markdown @@ -0,0 +1,13 @@ +# Set Cover (Unweighted) + +A cover + +If you have a set (also called the universe in the mathematical descriptions of the problem) + +## The algorithm + +## See also + +[Set cover problem on Wikipedia](https://en.wikipedia.org/wiki/Set_cover_problem) + +*Written for Swift Algorithm Club by [Michael C. Rael](https://github.com/mrael2)* \ No newline at end of file From a573bb240c2d5e8acf90faf599c59f8def6d7461 Mon Sep 17 00:00:00 2001 From: "Michael C. Rael" Date: Sun, 12 Jun 2016 11:34:31 -0600 Subject: [PATCH 0005/1275] Work in progress on README. --- Set Cover (Unweighted)/README.markdown | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown index 68538cc60..48b5f3bfa 100644 --- a/Set Cover (Unweighted)/README.markdown +++ b/Set Cover (Unweighted)/README.markdown @@ -1,11 +1,25 @@ # Set Cover (Unweighted) -A cover +If you have a group of sets, this algorithm finds a subset of those sets within that group whose union will cover an initial set that you're trying to match. The initial set is also known as the universe. -If you have a set (also called the universe in the mathematical descriptions of the problem) +For example, suppose you have a universe of `{1, 5, 7}` and you want to find the sets which cover the universe within the following group of sets: + +> {8, 4, 2} +> {3, 1} +> {7, 6, 5, 4} +> {2} +> {1, 2, 3} + +You can see that the sets `{3, 1} {7, 6, 5, 4}` when unioned together will cover the universe of `{1, 5, 7}`. Yes, there may be additional elements in the sets returned by the algorithm, but every element in the universe is represented. + +If there is no cover within the group of sets, the function returns nil. For example, if your universe is `{7, 9}`, there is no combination of sets within the grouping above that will yield a cover. ## The algorithm +The Greedy Set Cover algorithm (unweighted) is provided here. It's known as greedy because it uses the largest intersecting set from the group of sets first before examining other sets in the group. + +The function (named `cover`) is provided as an extension of the Swift type `Set`. The function takes a single parameter, which is an array of sets. This array represents the group, and the set itself represents the universe. + ## See also [Set cover problem on Wikipedia](https://en.wikipedia.org/wiki/Set_cover_problem) From 5005c28b606b61fc26d73f03f350cd3c97e56b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Fri, 17 Jun 2016 10:39:54 +0200 Subject: [PATCH 0006/1275] Added B-Tree --- BTree/BTree.playground/Contents.swift | 10 + BTree/BTree.playground/Sources/BTree.swift | 473 ++++++++++++++++++ BTree/BTree.playground/contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + BTree/BTree.swift | 473 ++++++++++++++++++ BTree/Images/BTree20.png | Bin 0 -> 16592 bytes BTree/Images/InsertionSplit.png | Bin 0 -> 17998 bytes BTree/Images/MergingNodes.png | Bin 0 -> 8359 bytes BTree/Images/MovingKey.png | Bin 0 -> 12354 bytes BTree/Images/Node.png | Bin 0 -> 6255 bytes BTree/README.md | 172 +++++++ BTree/Tests/Tests.xcodeproj/project.pbxproj | 268 ++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 100 ++++ BTree/Tests/Tests/BTreeNodeTests.swift | 54 ++ BTree/Tests/Tests/BTreeTests.swift | 257 ++++++++++ BTree/Tests/Tests/Info.plist | 24 + 17 files changed, 1849 insertions(+) create mode 100644 BTree/BTree.playground/Contents.swift create mode 100644 BTree/BTree.playground/Sources/BTree.swift create mode 100644 BTree/BTree.playground/contents.xcplayground create mode 100644 BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 BTree/BTree.swift create mode 100644 BTree/Images/BTree20.png create mode 100644 BTree/Images/InsertionSplit.png create mode 100644 BTree/Images/MergingNodes.png create mode 100644 BTree/Images/MovingKey.png create mode 100644 BTree/Images/Node.png create mode 100644 BTree/README.md create mode 100644 BTree/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme create mode 100644 BTree/Tests/Tests/BTreeNodeTests.swift create mode 100644 BTree/Tests/Tests/BTreeTests.swift create mode 100644 BTree/Tests/Tests/Info.plist diff --git a/BTree/BTree.playground/Contents.swift b/BTree/BTree.playground/Contents.swift new file mode 100644 index 000000000..7d2973f77 --- /dev/null +++ b/BTree/BTree.playground/Contents.swift @@ -0,0 +1,10 @@ +//: Playground - noun: a place where people can play + +import Foundation + +let bTree = BTree(order: 1)! + +bTree.insertValue(1, forKey: 1) +bTree.insertValue(2, forKey: 2) +bTree.insertValue(3, forKey: 3) +bTree.insertValue(4, forKey: 4) diff --git a/BTree/BTree.playground/Sources/BTree.swift b/BTree/BTree.playground/Sources/BTree.swift new file mode 100644 index 000000000..16c4eabe4 --- /dev/null +++ b/BTree/BTree.playground/Sources/BTree.swift @@ -0,0 +1,473 @@ +// The MIT License (MIT) + +// Copyright (c) 2016 Viktor Szilárd Simkó (aqviktor[at]gmail.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. + +/* + B-Tree + + A B-Tree is a self-balancing search tree, in which nodes can have more than two children. + */ + +// MARK: - BTreeNode class + +class BTreeNode { + unowned var ownerTree: BTree + + private var keys = [Key]() + var values = [Value]() + var children: [BTreeNode]? + + var isLeaf: Bool { + return children == nil + } + + var numberOfKeys: Int { + return keys.count + } + + init(ownerTree: BTree) { + self.ownerTree = ownerTree + } + + convenience init(ownerTree: BTree, keys: [Key], + values: [Value], children: [BTreeNode]? = nil) { + self.init(ownerTree: ownerTree) + self.keys += keys + self.values += values + self.children = children + } +} + +// MARK: BTreeNode extesnion: Searching + +extension BTreeNode { + func valueForKey(key: Key) -> Value? { + var index = keys.startIndex + + while index.successor() < keys.endIndex && keys[index] < key { + index = index.successor() + } + + if key == keys[index] { + return values[index] + } else if key < keys[index] { + return children?[index].valueForKey(key) + } else { + return children?[index.successor()].valueForKey(key) + } + } +} + +// MARK: BTreeNode extension: Travelsals + +extension BTreeNode { + func traverseKeysInOrder(@noescape process: Key -> Void) { + for i in 0.. ownerTree.order * 2 { + splitChild(children![index], atIndex: index) + } + } + } + + private func splitChild(child: BTreeNode, atIndex index: Int) { + let middleIndex = child.numberOfKeys / 2 + keys.insert(child.keys[middleIndex], atIndex: index) + values.insert(child.values[middleIndex], atIndex: index) + child.keys.removeAtIndex(middleIndex) + child.values.removeAtIndex(middleIndex) + + let rightSibling = BTreeNode( + ownerTree: ownerTree, + keys: Array(child.keys[middleIndex..= 0 && + children![index.predecessor()].numberOfKeys > ownerTree.order { + + moveKeyAtIndex(index.predecessor(), toNode: child, + fromNode: children![index.predecessor()], atPosition: .Left) + + } else if index.successor() < children!.count && + children![index.successor()].numberOfKeys > ownerTree.order { + + moveKeyAtIndex(index, toNode: child, + fromNode: children![index.successor()], atPosition: .Right) + + } else if index.predecessor() >= 0 { + mergeChild(child, withIndex: index, toNodeAtPosition: .Left) + } else { + mergeChild(child, withIndex: index, toNodeAtPosition: .Right) + } + } + + private func moveKeyAtIndex(keyIndex: Int, toNode targetNode: BTreeNode, + fromNode: BTreeNode, atPosition position: BTreeNodePosition) { + switch position { + case .Left: + targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.startIndex) + targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.startIndex) + keys[keyIndex] = fromNode.keys.last! + values[keyIndex] = fromNode.values.last! + fromNode.keys.removeLast() + fromNode.values.removeLast() + if !targetNode.isLeaf { + targetNode.children!.insert(fromNode.children!.last!, + atIndex: targetNode.children!.startIndex) + fromNode.children!.removeLast() + } + + case .Right: + targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.endIndex) + targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.endIndex) + keys[keyIndex] = fromNode.keys.first! + values[keyIndex] = fromNode.values.first! + fromNode.keys.removeFirst() + fromNode.values.removeFirst() + if !targetNode.isLeaf { + targetNode.children!.insert(fromNode.children!.first!, + atIndex: targetNode.children!.endIndex) + fromNode.children!.removeFirst() + } + } + } + + private func mergeChild(child: BTreeNode, withIndex index: Int, toNodeAtPosition position: BTreeNodePosition) { + switch position { + case .Left: + // We can merge to the left sibling + + children![index.predecessor()].keys = children![index.predecessor()].keys + + [keys[index.predecessor()]] + child.keys + + children![index.predecessor()].values = children![index.predecessor()].values + + [values[index.predecessor()]] + child.values + + keys.removeAtIndex(index.predecessor()) + values.removeAtIndex(index.predecessor()) + + if !child.isLeaf { + children![index.predecessor()].children = + children![index.predecessor()].children! + child.children! + } + + case .Right: + // We should merge to the right sibling + + children![index.successor()].keys = child.keys + [keys[index]] + + children![index.successor()].keys + + children![index.successor()].values = child.values + [values[index]] + + children![index.successor()].values + + keys.removeAtIndex(index) + values.removeAtIndex(index) + + if !child.isLeaf { + children![index.successor()].children = + child.children! + children![index.successor()].children! + } + } + children!.removeAtIndex(index) + } +} + +// MARK: BTreeNode extension: Conversion + +extension BTreeNode { + func inorderArrayFromKeys() -> [Key] { + var array = [Key] () + + for i in 0.. { + + /** + The order of the B-Tree + + The number of keys in every node should be in the [order, 2*order] range, + except the root node which is allowed to contain less keys than the value of order. + */ + public let order: Int + + /// The root node of the tree + var rootNode: BTreeNode! + + private(set) public var numberOfKeys = 0 + + /** + Designated initializer for the tree + + - parameters: + - order: The order of the tree. + */ + public init?(order: Int) { + guard order > 0 else { + print("Order has to be greater than 0.") + return nil + } + self.order = order + rootNode = BTreeNode(ownerTree: self) + } +} + +// MARK: BTree extension: Travelsals + +extension BTree { + public func traverseKeysInOrder(@noescape process: Key -> Void) { + rootNode.traverseKeysInOrder(process) + } +} + +// MARK: BTree extension: Subscript + +extension BTree { + public subscript (key: Key) -> Value? { + return valueForKey(key) + } +} + +// MARK: BTree extension: Value for Key + +extension BTree { + public func valueForKey(key: Key) -> Value? { + guard rootNode.numberOfKeys > 0 else { + return nil + } + + return rootNode.valueForKey(key) + } +} + +// MARK: BTree extension: Insertion + +extension BTree { + public func insertValue(value: Value, forKey key: Key) { + rootNode.insertValue(value, forKey: key) + + if rootNode.numberOfKeys > order * 2 { + splitRoot() + } + } + + private func splitRoot() { + let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 + + let newRoot = BTreeNode( + ownerTree: self, + keys: [rootNode.keys[middleIndexOfOldRoot]], + values: [rootNode.values[middleIndexOfOldRoot]], + children: [rootNode] + ) + rootNode.keys.removeAtIndex(middleIndexOfOldRoot) + rootNode.values.removeAtIndex(middleIndexOfOldRoot) + + let newRightChild = BTreeNode( + ownerTree: self, + keys: Array(rootNode.keys[middleIndexOfOldRoot.. 0 else { + return + } + + rootNode.removeKey(key) + + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { + rootNode = rootNode.children!.first! + } + } +} + +// MARK: BTree extension: Conversion + +extension BTree { + public func inorderArrayFromKeys() -> [Key] { + return rootNode.inorderArrayFromKeys() + } +} + +// MARK: BTree extension: Decription + +extension BTree: CustomStringConvertible { + // Returns a String containing the preorder representation of the nodes + public var description: String { + return rootNode.description + } +} diff --git a/BTree/BTree.playground/contents.xcplayground b/BTree/BTree.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/BTree/BTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata b/BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/BTree/BTree.swift b/BTree/BTree.swift new file mode 100644 index 000000000..16c4eabe4 --- /dev/null +++ b/BTree/BTree.swift @@ -0,0 +1,473 @@ +// The MIT License (MIT) + +// Copyright (c) 2016 Viktor Szilárd Simkó (aqviktor[at]gmail.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. + +/* + B-Tree + + A B-Tree is a self-balancing search tree, in which nodes can have more than two children. + */ + +// MARK: - BTreeNode class + +class BTreeNode { + unowned var ownerTree: BTree + + private var keys = [Key]() + var values = [Value]() + var children: [BTreeNode]? + + var isLeaf: Bool { + return children == nil + } + + var numberOfKeys: Int { + return keys.count + } + + init(ownerTree: BTree) { + self.ownerTree = ownerTree + } + + convenience init(ownerTree: BTree, keys: [Key], + values: [Value], children: [BTreeNode]? = nil) { + self.init(ownerTree: ownerTree) + self.keys += keys + self.values += values + self.children = children + } +} + +// MARK: BTreeNode extesnion: Searching + +extension BTreeNode { + func valueForKey(key: Key) -> Value? { + var index = keys.startIndex + + while index.successor() < keys.endIndex && keys[index] < key { + index = index.successor() + } + + if key == keys[index] { + return values[index] + } else if key < keys[index] { + return children?[index].valueForKey(key) + } else { + return children?[index.successor()].valueForKey(key) + } + } +} + +// MARK: BTreeNode extension: Travelsals + +extension BTreeNode { + func traverseKeysInOrder(@noescape process: Key -> Void) { + for i in 0.. ownerTree.order * 2 { + splitChild(children![index], atIndex: index) + } + } + } + + private func splitChild(child: BTreeNode, atIndex index: Int) { + let middleIndex = child.numberOfKeys / 2 + keys.insert(child.keys[middleIndex], atIndex: index) + values.insert(child.values[middleIndex], atIndex: index) + child.keys.removeAtIndex(middleIndex) + child.values.removeAtIndex(middleIndex) + + let rightSibling = BTreeNode( + ownerTree: ownerTree, + keys: Array(child.keys[middleIndex..= 0 && + children![index.predecessor()].numberOfKeys > ownerTree.order { + + moveKeyAtIndex(index.predecessor(), toNode: child, + fromNode: children![index.predecessor()], atPosition: .Left) + + } else if index.successor() < children!.count && + children![index.successor()].numberOfKeys > ownerTree.order { + + moveKeyAtIndex(index, toNode: child, + fromNode: children![index.successor()], atPosition: .Right) + + } else if index.predecessor() >= 0 { + mergeChild(child, withIndex: index, toNodeAtPosition: .Left) + } else { + mergeChild(child, withIndex: index, toNodeAtPosition: .Right) + } + } + + private func moveKeyAtIndex(keyIndex: Int, toNode targetNode: BTreeNode, + fromNode: BTreeNode, atPosition position: BTreeNodePosition) { + switch position { + case .Left: + targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.startIndex) + targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.startIndex) + keys[keyIndex] = fromNode.keys.last! + values[keyIndex] = fromNode.values.last! + fromNode.keys.removeLast() + fromNode.values.removeLast() + if !targetNode.isLeaf { + targetNode.children!.insert(fromNode.children!.last!, + atIndex: targetNode.children!.startIndex) + fromNode.children!.removeLast() + } + + case .Right: + targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.endIndex) + targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.endIndex) + keys[keyIndex] = fromNode.keys.first! + values[keyIndex] = fromNode.values.first! + fromNode.keys.removeFirst() + fromNode.values.removeFirst() + if !targetNode.isLeaf { + targetNode.children!.insert(fromNode.children!.first!, + atIndex: targetNode.children!.endIndex) + fromNode.children!.removeFirst() + } + } + } + + private func mergeChild(child: BTreeNode, withIndex index: Int, toNodeAtPosition position: BTreeNodePosition) { + switch position { + case .Left: + // We can merge to the left sibling + + children![index.predecessor()].keys = children![index.predecessor()].keys + + [keys[index.predecessor()]] + child.keys + + children![index.predecessor()].values = children![index.predecessor()].values + + [values[index.predecessor()]] + child.values + + keys.removeAtIndex(index.predecessor()) + values.removeAtIndex(index.predecessor()) + + if !child.isLeaf { + children![index.predecessor()].children = + children![index.predecessor()].children! + child.children! + } + + case .Right: + // We should merge to the right sibling + + children![index.successor()].keys = child.keys + [keys[index]] + + children![index.successor()].keys + + children![index.successor()].values = child.values + [values[index]] + + children![index.successor()].values + + keys.removeAtIndex(index) + values.removeAtIndex(index) + + if !child.isLeaf { + children![index.successor()].children = + child.children! + children![index.successor()].children! + } + } + children!.removeAtIndex(index) + } +} + +// MARK: BTreeNode extension: Conversion + +extension BTreeNode { + func inorderArrayFromKeys() -> [Key] { + var array = [Key] () + + for i in 0.. { + + /** + The order of the B-Tree + + The number of keys in every node should be in the [order, 2*order] range, + except the root node which is allowed to contain less keys than the value of order. + */ + public let order: Int + + /// The root node of the tree + var rootNode: BTreeNode! + + private(set) public var numberOfKeys = 0 + + /** + Designated initializer for the tree + + - parameters: + - order: The order of the tree. + */ + public init?(order: Int) { + guard order > 0 else { + print("Order has to be greater than 0.") + return nil + } + self.order = order + rootNode = BTreeNode(ownerTree: self) + } +} + +// MARK: BTree extension: Travelsals + +extension BTree { + public func traverseKeysInOrder(@noescape process: Key -> Void) { + rootNode.traverseKeysInOrder(process) + } +} + +// MARK: BTree extension: Subscript + +extension BTree { + public subscript (key: Key) -> Value? { + return valueForKey(key) + } +} + +// MARK: BTree extension: Value for Key + +extension BTree { + public func valueForKey(key: Key) -> Value? { + guard rootNode.numberOfKeys > 0 else { + return nil + } + + return rootNode.valueForKey(key) + } +} + +// MARK: BTree extension: Insertion + +extension BTree { + public func insertValue(value: Value, forKey key: Key) { + rootNode.insertValue(value, forKey: key) + + if rootNode.numberOfKeys > order * 2 { + splitRoot() + } + } + + private func splitRoot() { + let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 + + let newRoot = BTreeNode( + ownerTree: self, + keys: [rootNode.keys[middleIndexOfOldRoot]], + values: [rootNode.values[middleIndexOfOldRoot]], + children: [rootNode] + ) + rootNode.keys.removeAtIndex(middleIndexOfOldRoot) + rootNode.values.removeAtIndex(middleIndexOfOldRoot) + + let newRightChild = BTreeNode( + ownerTree: self, + keys: Array(rootNode.keys[middleIndexOfOldRoot.. 0 else { + return + } + + rootNode.removeKey(key) + + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { + rootNode = rootNode.children!.first! + } + } +} + +// MARK: BTree extension: Conversion + +extension BTree { + public func inorderArrayFromKeys() -> [Key] { + return rootNode.inorderArrayFromKeys() + } +} + +// MARK: BTree extension: Decription + +extension BTree: CustomStringConvertible { + // Returns a String containing the preorder representation of the nodes + public var description: String { + return rootNode.description + } +} diff --git a/BTree/Images/BTree20.png b/BTree/Images/BTree20.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6a6a50e6b4a732da6f2f75b28ca896cda9a2d0 GIT binary patch literal 16592 zcmbV!bySpJ*EWnpgAA>L(%sS^A>BxibSRAo2qN7vl$0PTptLYZcZ-06bV&`J64K#& z=J!0$`+nd1{r9cKa^adY=RRkjeXf1&Yww$=Cz?t``1kNJFffQzl;w3WFd${%_j+7x z@Gr}~)?^F}It&&0$9i67yIBNN8a+3?tg`sUWC{#XKUJuhUy&ssk|UFKUa1c2PbR62 zgz+>ksIYVB@R+{kX%x%*_$#SsEP=`NQ`g_~L9wcvOTUHdy_SjZJ1w>o7lTL5Lwhui zKd#n}GK999Z2SeP=4zd1Yw=h}=`jE2=VfxcCwW<%ceqW0j5_WwujSbJv1j{>9rIJF zaw>sPWjYlo8$4;nc_IahFM|>6@$D@=7Mqw+0x}_3=$?R?282lla?T*rk6KMnOQO z-4IevAUnBxH2%9f1F9Sdbt3&>QKORdCIJI4nQpO>?$w->F#Esu8V*Ggy~V&=NekQ# z{^@b)w)4P73;i53*dlHz)r-6YrbS-NNvz!Mlk@F2Mw;l4PH>+fXRP}&!NemlBs1>% zj|^6up=|D#>91-W#^q;gofTs53B|mh{W3HKvjHmuKTkNo;)HL5?PQYjQG~*ZLa>QQ zyTXY$E!W42brm9R-;dc5sTnGIIj{cDco+f$%aKjJITETYlNwk|m&s=tEPDNCRN=Ex zO?NW8uKeyyP0y@L8@Hy!uAp{{x5q&rYfhx($&}pWBTI)I&yMB<^v0Fx1Tpa^einJr z1DoE)Bzs)%v28Hi;BL$R=I~ji@41_HoBwrtD8KdBNcSO0!$&7m)_GbvQsM=DKI%K8 zJjo)7;4m=oz&37UtT+i?_aZCC<-WB4BPDpgXxJorFM+neZ6)3B z{9wjhz)i!S_}%u`OweWC#P^_w%D!}v#9+Y)y2}jiLC^*mm@lw=ADkWu7->LW^XACr zU?oWl0XE*3Fh08@&IQxb!(0X{zZ;y9K7F4 z8$j+jS)OwFd9U?yPtg*iIDGaCFFB!^{6Eh8K_M_$pMcth0h1J0t=;4CMx&pl*pWEe zR*?e0Cq#WxJs2@@aR0f_Lzq+}Q1nM^qTr+8rahqsNY8cUn^M4umA9yH? z%Bn-#L8c7c&aeGhWrTS3O8(K$(R$%fxg004R?Ri{J%aEq!@h{uzQr7u7wtd$m${9e2*y(dObyF> z{d?Z(&&Kdzevx5C_Qq^oh23O%mgr*Ot<1VqY_!kGB!VTe^v#xW;;kfL$aCDh<2Giw zEp=vbzP^RK4gS;JpTfCn2^FyU{x+G;PaKFf-K?$u_TVs7jH|PBuqgv7_o%+}82mQm7zHb6o(FY}?4PexX1nloC zv_Lb9Lt$%Yy6Tg%!W|g^J+Vg~^dSrWm!BiORyRrs%yNmqI2GVT>4Nc9txOhC?cqe! z!NX%E`lYJ5h_;8%`{5iNKb%A_whGMcD8S^+zzSby+sf|a!CCoi2Qy`gPIjhs5o7sr z;{D!YQqR5(8`3t*Qv<9=$pi)q-8Or6Uzv^=n(ce2!mc-2Zc43wX;@(7u-Dml@MdsJFq9sm>kPt>Ae=6k*OOQy*4_q-|oxWQ*5F$d>I zKTsQvkFNWTfJaRMV>!e#yE9-`;64K2Y&BM-ZS^BvsG~Xn1c2reIhxoXf)|Jo0uxDY zuDDi=t0U{WO%d`SELgTcoG=GE_@Ur5uW1N`}R<0WT( z5Sx}&relGAjiqJ{;}E_y9K8Vn4xzFOk1c`%gQeW5008pxJvgy}`CMnFw_z9tXQlRk z!FaXYna{=|Zj3<;U|>J?V-TJt0B9^oDqoVRSgd`2?_6y6M=!a zIM}(O?N<5BqeA0GkmWR)?SeB3ayU+?#r63$BnKaFvT4FIK#j@7G zlMW1I{UyVwOqT#GM7HT^Fe3zUX+8+gJjoHX*MVisRNL!Le*Y-R1cNPZa8lm_S49d9 z7)ind3_;|O3=x;xin?`9)169nCkyU?&9{f+<_vsA6Mp1%(k%VawL| zU7qL^p;DuuC|NMb^?+&nF=P+y+oPANnrRKnqMk+<#sMvzNi2CW*T`QXRH_7#efcNl zGl-S#$>3nvAJ1z+?&A7h?$&kKIb?}@e0(CgT~_ri21=?1CXDis>)Qq;{5a#S<{hVH=yQ)&SGp(6yC%$Mv%gcnM;KWQF-MSW#WuA*`I zyZLC4es7H#jHU5=PK}1FSPU%AS!}#Jr0{AxZNA-w0u5?*J*`Iv@?9oxBmj&mnNMSb zlO_jVQHw?TlPM7Ghte+d%@%?b8P@{n>&3c%`MWK8bF?t}u7J%q>5rbfGgtv2gyvt% zzGnnsNB}H5%N2|0AgCSqZ?OH}bRkF8T<<}#^)m}`XQm)H+5yUb_4U7%F#zZPl;i+H z3PWYRo=?axw(gBXZ&1WVQxGirHaMx$Tbdv6nBH20kz&~2cdnU{9@`Ui!XC?CV}qW| zc}$vKeY@&PJRbR>|@R*W;J;=7a3}$`65JJPATeRI-~>!HE(B^B#9;RVP9LqNeQ94MS^ZUo^>leBjzm5@plTpCmH^ zo+-4+9eDiuU)S>BS1q+m^YG@q#j`PPnD0v&GRhaurdVS8 zEZNIzu|f+WNBZ*1$uiI8SynK$)SCeTW7FRofCoB05u8+kluNIZm)ZRI>hU*yJnr?S zd|>c6tIHdk((U{Au}W=;5NqNp?Z@kx!Q*Aq^?T-3GY2nn07P7@a1S|owB+Yo9G5*F zHetmBJJLm_3sFyAI~qvL?~(yq!@E4XJdEnc{5b~sEpnVeQU-Sw)|0zU3{_|CR=W@}^KYnkX^ z-sg7|AO{HG#!qS7zw_rk4#EB^=!7>BOD%#(HTQptrm|KM_dQ{kJ5});Q>M zv9)J+?{;LU&=FuJd0q@F(c)blgJ`W+^dwhag@B5OoVR&Dc*_5B7b{Nt#e8#v-DpAV z)o)~0DuULZ&6426PV#EM>v;eL%lkiamS-&>6R_Hz`25AiVXm>p?pM9* zovL6*^(*RPIx}_1Q(&eqQ7bWl_DZJ!ETV3%FQdUU^`WtKzucnhPi7n$Tj~+ER)={{ z-uMC1gL*4>o86LDejD&*h4B*on)CF-QJyrBL>VZgahIF{ALV|4>ap4!`DB%9>dCIN zRivFSpCjd`3U?b(VU1eP_R-v_9@We(8>1+j-U)F=@|$+zc!D%TZn|)m`1uzXkeXSw z2V$bioAw^=NqAgSmmGo&ivhrCEJk#yBBRC3aO?v~qd$9d#&Pi0KO<^Z6)h*ERklNv z05}uFx!_0{8n4Bm;TY8hqf>?4FK5S-<_c9dKUN4%Z!UjRt!KK&O;y_``S!J5Y?WF8 zYoKBT27lHLCI2fSV}M1@Xd0Hm=>d6T%J$x3KR`wEBDTg$Q(iEk&Td3k;EiLy8`It$6HGq@9_?zzr7*I_aHp0B3nfoOv| z=%q~!HWqom|4$MkqX*HRVb9(s(-eKIo+Bm6#*$^BPg|Nc_?4|pHOK#=*ly%w6k$Wq z6o4To1NVH~3FOH&m?F=9v>;C{l_xjM-9B7#Goo{*@ZuZ0Zh^7^N9O&%Z@0%Orv5#v(fZE(^F<#HMge0bLFVr&w6Bba8k1^A>}TfpIB` zrOrOUTYVdf3_hm^KItJKN6j#i%jl0Kn|l%;;FI#P!fLXB)7PPfr2mpj|GjdjQ;d#) zngEK4I+=B$0tB=H(0VfqrkmH-7su`_aP22|F2|HM!R=#*4YO zk(62P>i#2z$ljNTO)w{f#N3w<)>*ha-Zs585WtFQ3gD-4#mn3PA}k@!#nY|^VZ^?3 zzny%NHOE&+{+o?Z(G-@pIeE{KA@8`ZmZW~%$w!t@+&{ash9KoA_u|!MuKLOK*>e2DkC5nzIO!X&;aoYKgP(H5eV7nG>ASR=Us3XKMF_)cjNdlN7%H^01F}U=H)`elXgbeIHx! z-_c37uY2{%`5<~vZ2mE132&oz)G1hK9D>W;9kP5bi`$VY=KgF-BQ2SrqoiPh#MQ`6Y0GHs8oRKtJftrsKSGx`s+nq9aC>O+iDGL zwXMh^8A6w?PZy|q@4wD0GHvp-h(@%;l3JGnbU{VL+eF%OHF_@w;j9P;!YzMlBt zKCee1IA!_Az)HWrA;FUesrEfgO5Rw-_Ue4OUPRhYagQx>_B&0tXnglO5>QhkPs=a! zWXv42?wlGt6Cu1aobPcif!5luF9(|GH zSP}ia_cnLKW`pL#r9#~Yzv(gWqgRwOzF;8Nux9tqT!BJ2PbnJs`^A(4K)jGQQ1?u>pt` z#eoB?ki+u1l)(lg_tUid;)?8Kj z&+U(La$O04cbCzk5E6%8YHd ztIq%=M2VMQG_xN)y$ML$>&%X6Q~{BpUoF;JLAm{Tsws=e%2&@v%2Rvz#`_yAy8ex; zhf<`GvNCm9CF`~TQWQM#+HqMF~OUzt?AHVb1o}YjkA|wFXzCW?Lv*tGt*`G zC9!Cb7G`-Gkw_p*F{RFiPs21CZ-_FaD;U94Kn+Voc_iRXZEe7+5U~v;oCcLv3Jn~F zuhS)KNQI%L{lvVc-Q^5s6w%$UmJM`wt9p39EPLGo*JaULV*I`(Q3wVO-Qskwpl^fQ zswx+ZC@JEHf05T4B(ZA^tPV+BS$Yz4e1)#%P}Ym;@` z{J8I30g&>#Q4@Rv>UnGFXCVwn$`FvuFnKk|c)Yq+_)4V^bPqc^mg3(WZEfxUgQGRh z4{Ia6CqCGfCqYdD2HD|1(qp%8gi7!KK8XU+N^Ab`yTPP{IKIKqJ@OwOiGkZgVpye5 zt6b;WY-*P0q|mu}pKqdv4XdAamO1mRT7)`pAd`JPk6?!~4Xsho!q6WCr zN)(5>4V2EnlyV%shE}pC!Q-diKW}!RHwWOm0?D!; z_@7zw1FA8Mw3K_Zb^=6ba@63J`Qc905CTL}lbyD|H>fdPtsiZe^s3$b6{0H9jMVfN z2Z_P3jb9B_j}pgv;!84KG^)_NSxM-4%*Ydm45q$NrCHs|^DEI_Vw*y<+ea50`FXC( zUv=smXIv;(9$Vy!fh(Bq-rdKx7{!|XR+eHt(A;Y&3w1ad-ej&lAgC)5DZ7V|&{2=#{QoK{KzihDq$ zT>bW80FS1l3b4LJ+w;R!Q(+M#(Lo)o94O~_q1%9%tcUFijz|OAaC2U^NXctd%?2xJ z@jgzJ9ZyYT;iB;ZLGvU0vv$5>$5R`D4}eAG`JC=S+SHjAA!wyAx@t(uIQ;S#5X5-W z^h$`pbIH`+agj9b)@F=)axC*S?L0gfl=!VYyfs?ZPi5{)AI8~k>VspEqjVJ713StWgt=-u^drx0Bb>749;h%w2ZaJ7ZA2g!5N}Sm;&@1pY z7E=t(60DAM{$3TnXCwAicp0b$I{q`JsMuirb**GGUPY_w}5B zc~$@O{%4ErL2lkKu=gj*5D*u0?g-kwCD*wx;mP%pJ$C@)O)aZ9KtiaITUhQ48!gmI zrH2@rz4_E$_BP%gXf`^{R+!}o_hb9OE~Pcsy7$3Cdk-ecfNqfilm(EfE9Y*_PD+*B z0I@rAR8vAD4*BTjY&l&J|1~vbgeB`OaNIJvxF+74pHP4zq(+w_VLwy#+Wh^3vedv? zuSfR>6C3Eoh&36wN7cehi2`S*gM2L|TH@Sn|RNN3@vnQbCf=q*4Gvh8GHQ=6mn-zE^ZP zXsKTgrSZ!l^kRx8igkNujjZ)Zttc*`jrG#c;79@6LGrE$VyZ}58-^fX(sn(bZVt*T zOIsq^(IA`$Y_O3~(U&=+Ksw@h;I)X!ZZunMzwEC6ad+w#^%4Y}IbJ80$wFU;&jx=H z5KRa(?R2nWemyR-GNxeG^PATBRP7z`XIM$6?Bw@?xru8J1&bHH|LBg7&NobFQeR=?UD zp)H*S}cfsm4D zMG@VLN(Y3U2}#B1|6aMB5_9K6kOJatF?zdyXD~}bO*>?F7nKQWU=nvHjXoO*Z4TA< z`dYb|Mo#ubQ{gN@iX?Q=RTJ;Mg@EgAbDfV?<`P1?ZNN9*n3e9VnFHwt5N557`=vQto&CnePs(p!Rv&Jm)7_VTw>_8kwzb&%dG$Dq>y zYxHJn3zxA(1+jDvp0x6y6wWPe^ZiczBU>Ae6XR|JIoFxj!!fwOC+PQoxeuvSA`}p= zQ~9EVw?aoOc&CAUFY?^#?NSj zg~?B+PV}VUFT>caa8o~iqTn=89!4zNFIVe7g-bI?QFo#X7mqU?Njq0N4-XCin~P`( z-;`*6#+P1%(p_#Ol}e%p3M+FDho)4+W`N)l~C- zc9bZurg|?He-#zb$| z9V!Xm9xG-90sjk=fppOk(z5Frb)cQb2(C}bD2Yx%C?_S2Y`q(Osd+pWR;k=gXBRZL z@%m&|EjPWoz7$p7eiIBUy`vvyq2Um`->!xYKoS;?QR^euyv3Yq!T{8vbiTUo!}QXM zR-+fk$z$+abiAXXha1lQjKqZTfXLC<^+8#A_u%X+@Sgrodx! zgn4$g^5!+oKqCmpcr@1iOx*xCnH07GIb;L1>ufKkv>v_ua#41|{BqYv-26Oo1s2?I zS^395hn66;6ka|`f-U#Pr{)h#)#AIBs>`;%`g{F5fMDl#hdksHNqZy;L<$xv!~3s( zK90f>diD+0aBP~X6^Phc(Z~>18OG;1D=Ic=a2w;YdM$avV$fLw*o98L=k^4*=kcEw zS@Nclawkj) z7lX8$L)z&^ZDTFNg%YsnCK*CjU2Vu&{hQ-)!%udSD{ti@*8`w1@q>;0c>K%<#kD=1 zQd8<-XlBexYvDjGOA)jHD^ZE3SB(J2=RyT5gO$=a^QdkhyKa+-p58}CH&u&{U@X8^ zLwp~}ssGi&c+~p$#)sdk8`nxj4kI6NeR-Oim%@lpz-;+@bLlqb0hG+3mp!!z^)PgK zSngy>LQmr|KUc2E698-k^F@Y`qCQC-ekCA|rU9IZi~}U@;oRQ)05A|3*;J9^Xu>i~ zK&IwM0xD^B@D}eHkhn8ZYp_H4+(TfPgn7SSb`h=U#k2#J_D>~8G#lBD z^jmw;l-&5C4xlFS@yY7>*H0l|RoAqnuk{e)A73n_e7-B2yokgV+RfPYzVW%jvl#vk zOv)*T0T>bjaG)V z1y=wSYrfqrB(aqD0F~^=z7C+4%l!`4Rz|lGaCM->Zg9Ssy0^et(X8`U zN@#P?MH*R1dhWp4^(yxtbARl_S1%aBbDFKycwrni{(G@E`F*={-5d)tk)ln#k9mLG z(7Z2!FLG=+Ux}4U{#&~BF2;#FOX=J8(6>v>b@Se(wmGy%5LCVE>N(O_Jzy~i10l) zw7ztF%st8KkVqkUW!#HnQ3A(_BlngM$GO3*jgSavugyQCt70FOOZ`@%-mdc%5G_Ben zTIfwIKqcUDJw{zQ;Sld=3V9j5nANLWvL0V!?sim53*WK9*TRS%rZX7EGkZPfvE;In z0x>Qlyu&AR^N=|jBRd7HFIV>WWDNUC+mA3E0EPV9oi_y=|72_5ZoGlKV)Z?Z-zr}6 zBr;n?_P5NAU?}Ge9||EY)n*eL6f8s_o!JP@Mc`1bPcyQ$01&VlBl8j|sG>J;)niaZ zq~(#oE3Lv}Si5+2AL3ec`GjIvC_F^rHN1KAs?FMg+Q(jYUtp80J<1a9h%wxM%QVlm zTdG~PUiif?IQ}G%eua!!nvFohsWA$J#pe}VpUyb)isj7!(kgsc0}@FOs$ZZh;?87# zA54PXf`Y^UJxU8>w%PJoseY+}8wp|31I#~?Q_&Qx;{5MP+LeW7n4~aXz7p1b1%X|| zDyH&Hv+`;{I8+>B%YFR>Ss?1a+Ml9RWJN$;b{6tP63}b18NnSrpUzOcJf-*tZmPG{ z-~Yi&<~29llMga4I3xAi{FJ)#jl(mvej_g$Wjy?7jBxh$lGg;#Nmp~L&!~bJd+3e$ zWxWQt>$=-I#Y&dYy=q~ciZ>}Q(X1p+HCn5dyi7I{;DI4RkIN1mTBrj^Y*EXrkZ~x1 z0=nA34x(E3GewLH@8vM?P%l!Du1i2~V35FkgZJNYEz~$e=`CHHSR|l)1Gk2aa%Him zHN|9$hCD!)`?y{PR6IU;0lM+oKb*f!U^ti}KLA#O&P6D74wkA$QT(xQ7W_^@O7)FC zVyaJYseuOI{KIgz_T+@e(&$mzp|)ZUJ!F%iv(fGuvs8@R{2kwf$NwO)UV<*)6 z6ow}BQdj$O>;?^|nWn90NLd;_Y2=O@_p=viU&7%%4DSFrpcqMpzl$YtbXtsCR($UU z@V^X~qyKYNN@zO1cnYr~byLI1dQ@$zFcNY6=D9iw7 z7#%JiggD+6&r0{989uq2#i0C#zT7BYH)ctQ(3V)&cU6bUW?#Jmb&#_KEKkp|B zLW@UxeNpBtZFuP5@lVmLOxSVa`|o~HCrM9#`-N7?Q{KU(c)Ei9gg_XkQy2Q|G+%^x z_22~KQz?(!e6J)eGp>6i-P47Dzf618$;c4ixY$A#rFD-9G5Ck4h5$;3U zNjgkq5|uV65%&c(KY{vncuUyiQ>M4~AR+YzPRxDD z#tDs^;h8*z z=+3)|9}>~B3*a9T@}UH0tto}%Wg_!l`Bg9El|smhC(2DZk^QusQl|4U{-6{3E0^gB z&TTB2DJ(OHa=A2y_Vv=kOLQakRAE|gtltz)?{nJR+b%7~?=s)XO%V!TNv$U9$^-GL z(}1^PQo&DZ6gJj0Tu5?hw6cwe%1gBUK1L&q!}0HTw=~YN0rY9D1-J@uJp^` z+JeqA)!+J_ZB*#F&Cv!~guyHyGGc_+nqmBjc+dN?E>8Mq!&^VgsR-^ADSS1KBM)^r3TK#f8e11Pw~_d|&;oz|5CLRn=_mYzN*OA^iwlTERd4Z2Rjle|0~p*?w@ zzM>qE_Or@|*K?>nS6UUhRx%`9DSn)#-r*p77;rj6DOP(_^`wX4X?H^xy-(FdBC-ED zTUV%TW)88xOj>o!pVOHaLtu!hwG?e_RQl?Ak~ACqhcEZ<+PTM5gF~_u>~LqfvF}5L zgUp8J+rCnQ)Wp)r&t?34`R0c&W_PDO{cE=~s- z4zM%gI?TSQVZ%l8-FPe z9^r17(jP%;)$m!TQ(p9bmOn}g{E2u<@a4ylr@u`N=bJjMAsnnytlzUQ-l9#SfNwAh z6FNF7cF(n_sp74&(Pcjtp1qFVy>glqu^%G5wwwrdI;zUbdAiF6SA(4ae1hJ1pX{)6 z=oMLfpEQW5dbuQf&`H4iE#I_m_Jzc7^BebJ(42L?z|!X#Qk_M+6@C;3L=ogN4kW<+Rg`rmF!+lraS&juYz1oQ9gE-oiOp zG*wNY)4UQygvg1{#?hc7&~ZB1JBhuG4?8V6;j@cTjYEnT=-8qflp9?;}C8ue3fWmp$ zT~eg{jCE zJ0nHcOCIswF~2Ftov2&zH_kREtmJb=$+L$Wl$)@7|Jk4q6QUtzYwSzG&K|r0$#WFC zd)}L2X$*-DX>}!sQggSJC=jV6t~Z2*y-=y_gT{M)~v$AE*1 z-|7#3zJbF>iZH7X7ZU;NuY|6kS%g}0K>Pf8>8r7;&NFM!q=Rk&|Kb z2Y*D3Xy#uq#`qPht6xqPUEwbgN6LODT#|JAdwm-1J}9R2Vg8Pn7f9)Q&~H54warZU zA^7=JN%&uO?+wKxTM7RQ&Vm$Ff)c7^HY(8Xc@($&Gz3+t2NTyM25QqgTAv9F1k?W0 zZiBIsXrZ4)TOh-KQA%nCLzky`ahgAl#M*=&c;!-i*$a2_g0zMVxTeL+D1zYQco&CO4Mq;+nB<6(p*_8sS+nlE!b{ z-LRg`iEiR{J(;$Rus^Y{=)-D5VJWaPIxW2FV@{2{+-uT8mqv8hivIvna^NRR^G9BA z4WF3gU9ipJYP)uT!d^UrfT#Y0@_FNs8@azF2Mu!@-%Y#Fde-Y~!i7#c-0l+9l553c zAM$|EO5T*HSSexrHrcaV&#gWb0&y0V?pRI&8Y7J@ux+CE=?$+M`kvYHTqhWnzi8WT zl;%5J_@7r?4j1L9Jq)i!v4cl`uoWJuff>hjfT+|^b2HXxffWiEfx*@JdJYQIk#5W9 zax#{IcQa~eQUbRsK;zG%z%d2Pu%pDR)@#~QkZcr3Tl``~Jd2I!k?Dhyq^6@miPcEP zK_Nv#@=i+i?o5t>k6ru?BBrL})eLd1UDZz;*=zWC={;iEeU3Y|B$XcI&%kg&ElcPH zZSDCdYqFXcCqLa184jt$k{O3&DcN2nFDa5bM1owhz6lbTFdhZmFp=>n(o|t8X0M7S z#k}_9u27rPjm(=g&u+U1hnhrHK^FJ;t>iy8Djh4`xkLo~O#4%*eNNFydj{`n$AOZ{ z8tj``1me(=S;}F)xr>Xo>F4ogJl$!QcaaF>dSj8BT3taWSe67BBd5>r< ztH(a7By|I$@Jfq1|3Tk$e0;?rzSYPIYC|ZeQX$}OlojiMexOT*UPZL5u{ zF{rTW7|0uBI5aNW}jI&qfxanq&2o>!Ak0Vpu_U|MBVzGO0{dBL(UwPq`awAs#h*n%;p#67ce zcCh@p4FfSroU00)%>}O`-8<_Z(S+YS=SyXgHso)7F5h68&N2)e3>ZrwmF1LY$*lSF zsv!f~QUHtVPej_(kM(6&L47)Vo%VGjjloFf!OhdtlNr|saw7Vya8lfmHtYU<&;w7 z4&$w<1We~LuiiXkvAIFBln7!WTzxJkj_iH?xHvNrLG1JC72C^mw%xGIi@#K-Nf&jX zJiVrXEFnomF_x)Nlx-GlRMHVGnOYhaY)c8ehi3kenm7^2&oH+??y+O`ENkDxP(Jh8 zMt5ihSRK&nBtOYBIb%FN=i7blalTsGCMyQY*(nEmxaVB~);6T#*!=VG=(iQbJFkrJ zo5+hEt5ILuTVZkDdx&zOOMDA^9X&-o>YQz2zgU!%J|D`~&4Bf4Pq`rfp)eMw;yg$@ z{2GwV9s_g~v}CK>KTmK%HO%8^#B}1EtQDlJyq%cPdyJ(blp;iKY=Lb0?WmI1!6H^@ zj}-1`;E%>WmNwrOjE8t+_!B$ak0;ls75Vi0(kOs<5Mq)XE^5~N7Uwn%oB5b!;+}wR zx?k-jI-q$==}?)>d2fGy7^m-y6?OMLP-LHHlCZrfbPgaNTBu&|n4>M?rL?qCB=qxa zBwxK>vK+5&)bAOPuH134*Yq13MZ{<})eG~vm{u+qd^v_?1!H`t?4V85`gVMhUr~sk zIp&P=s!nsne$leOBN|WQ&LZ#5pVHD`eUC$PzvC1*cwKF!QzLe8@ZwS59?<>6J<{y(%fpow6qNby_gC!=WJU? z2^wnCds<|yaNRn1dnAW}TtsXg9%D5)A>=X0liqReSI%KswT&=eQ7ewWq7qebUMv>2 zP`yXM0gDK!FC5#nz3*zF`;(5>xK+=G(u$vKCUbL%yd;}tN5F$=YXQl|Zy!v-XamRm zZ1Ab@!G{mEt{vYJ({H{{u%?|w1|PQ(c=2yzNq@*u-DTX@j@~C!7YlbTY`kI9pqt*a zc0Lv>G2L2ARe_cGRYgZ6(+fgqVQJW3J4g6tkEc(RwvO!b7sgi&joLnBn6m^}VDjFc z@8Eh~@=klnQ@e93?~F0#-Iuu>7EN%MezLg=Pn)S0|1F=Ta~9cG7cO;HfvpD*&NC_4 zFZK)sJ?X*aFq1#i(VdmdO<*)x2Jb7z|MA!;vFK5?QO}}Skm?VW*b{nAJnywhzF=as zyG_M>(kFb0bb6Ijr_PH}1E=@MG0F4{+te)k7XL-1Eh?T39`?jvmR7sDty9&bdwJb~ z;*|q6p+H`$cgqXf(%Ee1HtEhsw4&cJb@#RyWsj-h6mfo8UA}4CQnZ#=micJM^D@l4 zwtgpid@hrQVWU;)$=n}&%JvW2JSh~TD0BG8!cncxTgoOAy&gg$DN4edHKLO|$V zKTAyLWRO)%5M8ck9d7D{ar@D}%=v!tE!I3IZ>L#W;i*#L2&xy!MC)C+!b!IDHTM_W zNRY&sm!Pu)>T_(B1CRN+%|dqWc`1a)ck7aaw+E7@9U?Re(br>`ta7mhn7_0EWpD1^$xd1KI72Ei4a-yX5I_~U# zmCYFojRS%TXn7I-GK7w^hIc<3!18y4L7Nai}CK$c4Hihs0g1u=QOVa z@s;d?OTDsKcgX^W(#C2%luc3;nm!FzFuR@anWbR@-{@fRo1e7w)QaB*e%i{>pd0H@ zo!y^DXyxR$EV=2mZCkjG&!<55XwAf@mBVx7aE=br#u|Kz5xN3!o;bd_OEuh~jSSIwMX`#RMD3B(!d zFaiB{5_SetM496A%{9vo5<=lK(%;#gUilKmz4=7V$|Y`?fI&mtBzty5m}|0Mofy|Qp7 zU#ZSS)qpH#|JoygQq#Vsq?7MIX>GW_2}{qOzaJm`y&e)g9(?L7qKtkl16HYXWcoSt z?&<)EWRa zc_@k^g7`}9)X^u=_#G-mkr*T)*0;=P&cmgh2$mdzooj19EBnzm!52g?Lw0@`Xa2CI z&yaaoH{pL9%&N zj-@pH)TG!j7B9^DOwzVmGF%M*KDZy#Qt*CF&uTZ(7*mp?-IWw}${55A+h{KuL%<<^);>G)Z8K9oe1XmcR~Cq;KZ5KFr6Ot4 z?&dFxoqNXqk;nqRgX_rjeabNBWabTK6|Tqq4`FTgX*wSmQb*&ov>We;rkl*LNeyNxocDBqe!vG2gXj{p=2?_}6eK>HfKl zH}9FG;r)Eb#>R&g3iefVwAh|o#omW7|L@Q3hKrjLjoFpsUqEOlts=?c={Y&Ae8?`D z!=HReG~#%Z&CRXx=#jr6YXk>w z#iH?0-PN_s^T>Rp)C!b^Z+s=QYdJ0Dr}0&Lb*SijqT;X4#JrzBl{%87u`u3cQHSyT zSK|3?ZHjL2>kwG}s@`kuNb>5PuVgHhj|888JL|?>wN|}sE5Dr}do)G0w&OGtB34aG z&BB7%MO$h&6EmQ&yS+kXC>y-`do>YNp$ znWe&Ym7MF^MW-Y3dik8jWIP^@6K{3J7|qk3#}#j7PMi>Mph`7y#z7;uu?#TD0W3a4 zFy3T&&ZuiWV4i4O!*9!v&aiTEah0b{(bsM^Gmr;-hl3CsTb%2Jtd}xfSP)fgnisVj zNuQoJwZoQo@FBT0GlxR`{~!)eqA_a~j=5&)9Rn}NnZgemn<+*$u&Ng5%Z~UA5NFn% z2@>UIHx*@$Hso;QW)pNU=`#}rv$nqeVp3A=v#+PYx=>D(1cSPx9vLKWJ6!w-{DB|u zV#aR8$#_?<>TSfiE)V7;C*NxcWdegc^*sO^>M!$FqbNHy^;@E1rYfqC7>S7x42-w& zwOLDORo@dQr{XtXlWBSNoiIT=!AuZD971bKl3}W+uOAl_6r^QfuteMX;kpor zH~wWz1ECD;4C5a2Oklx?*(ZQraw#^wCQbx#A*!o~_xAQif=xl5#T#rHlko{M-Xn>| z(=#(;o?(u@e1)VLy>cwxJK=_`a_=sxzkHb~C?pgW8*2%nzf@G`iL1sjA9lLcr-8_d z6S5cyC1pw0D*QT+LafoYF7{=O-Ksj?!-6)azMN?e0g*M*fM|f!v9hs&ohB?OM>WXdxJVm?WnP| z`T66^44hG+27A``Piji zEYggzt{O{~_?C(6{boVFjxke})>nq1fGq`d(o73Cq*OU^xq?+ z8tw<2I9KWnGGe}d&q{yM?71WToxQ8CxHZPddu&=8nZ8q-D9wMhk&?3Cty@bsj~*H? zuAYcsp9!HC{Cr#ygGF83xj$e-w_Nmwo{LZQk*aDD6B+ZD^xpf^vsnXP`14$Mi~8Q0 z815mB?PY&##fa^cASpHy@EvXN+It#7@TKc}u*it^nB}d&nFWS2C%cenf@l)hggDUNSL4J)c z%APZKGt2e59HP^Or7LPJEIeWN5fcu)Q%!yR!W{`Z?2N7JVR45b>InhtJp zm>m0KJf zW6%{$=P^HU8PhEfB*IMZJ8<#wX@eUg@x0YF@g9IB*o>Qw;m)(yLBYYh;MB1E^)oIW;#Rn|wPoA# zO?w}v5tu=7m-<5LSBJjVIi*jc$^ld?I;N(n=ct(TO^%mz%WqGSdwC?wM3ZNv>3JJ1 zc+Y21%f>);RT3pLz?dww3pDieplef8!8{6dj&4&sr_m`TLB1$Cs}nUmCmss=W&=^t0(S{Rl-E{Z{n6GF($lA+ zVq&nNZ(;Sr#{+cWeSs;snRnGHEJBxji9$V?)YLONcM2-!|v#PEWmfHP$FSnm!YFdgjVrP*ih;cDc3zZhM##e`Je0kglc{g-?+CnmKS3ThngI;>6X6ipg$g) zI8I#EyW1kvqBW!jV`9Hyk~w!!PB*mvXXP*6VOfCWJW?Tlpr>I*t2W#`JfJRJxHpc@|B4Z>iNj1aH9`W+9C7ubz2aH^Vb zwf<%t1l-uVk8Vgvh_$tKZ?<~c4p>G*p|kpR#fQNUiu~s6Su9{pNw?)gEnAUn^pY;w z#DJiRW%R~;-Q0?oz^o}#Z(sr3-OLgjB-CRs=;7^dP@j0t5G6!X5ajKpKe>= zy8QYxiNgq!dIw{=g55Se%`P}`dlpv&&_1`8@=!|qK0B1rC9)oyhvi^~`Sgn)BE`0$ zJtk<$Rl*kj!G^U=Uo8P%mxQjVB}mpLb@{5>ygoHdA7=^Czi5>|_)Cl`TZAx8WHvNTz$d*^;wnt(h#?w+W^iV1hks3rgjaCe+i>x0^-)rW$MmtIi;Xd6S?fl7j&PsgfJU!An6OvePBW{ z6O@pV;Sp#g@&OHP`H4ZvV>UxS`j-+c)!oIqCl=P_p-&XMI&}wnB$*0Ea#wa{|!WbaX{Z z?P{O%4K4ScGlq%6t?G*WsAMJ~w3&r{{B6<%qyp`Nd1ITCDBtv4uiE&YjM@*0{>9}_ z30GUg1rri4U*rk@1<|@@?HT&PE2~dU!%fDddcaH9%vR%i!d_TzZhkL8PP+}oa%Z=6 z!FT^ti=_{|`d51B>dtQSnStETkzAr8)~e?I=~LFy#q#D17^|^rS8l9!0eFb)rdVIB zTVltlmN~5Jgs^6ermzOLXsa+D)vlxAcxOvaM`eZhg(>j$5*fV>-Js zGZ$1+NJf9;)##As%m}NBLHaJ14r&b<(mfifv6k9QGBzGAH*_LUFRn!2o&G@Bv4G}w zn`vr7WFxO=97KC{T#M@-kbSG{w?5D(u?W9`ei|0SlHHMFOJV0@k|$Q`Jxk8#*}Zf) z^X{fyz_hAZ;^NW0z5s5U6D{}hU0Z>yrTXlIRNxNjrs-SXS=Xk;+!lm3NOh>wEl*N-iwJ6Na!d|jP>(;ZKT~RUd!@S&t zM8gY-`8)RxoyiiAY0|R(tUC29mm5NV$#urpKIITYw6;d+!;4_D@9BXLL1p5*gd z^xZPz&&t!O?g~$;YtE50m}eYo=xa?xO()%~;(BBDA{;RhpNL#3j4aJ4r+7rye3AaD+*n;JaZs zg4J@o3ud!Yp~JJ@M3H+~BK+(NMubO5dqCFvDXGY*kn18pG|Ka4g7DY0@cr%?D#`;F z))T82!o%Y?#JKDl=4{vB4@4LAPLl?g!R3!1g$d{E-SMB+w>aU2(kDqRrINj~8u7ET zYbe|Qy-Sqkfi4v|m-!spua4IlVk^)C#p|QFIBV8L!)l@7nnNwFsB1eR4w+AoIt`UN zEN=VozVR~r^TVuppUq=l)?hvqqEwlbfxOh^U`eID%12jEAm)k2J!pjoj@sOW1~mk` zQG4rYcAYX4bGAU=1rIxUKHGZP`XSximKgqlgp)cAI+?;!%b6fl_G1mjPR5Xu=t2fC z(IIBs;eq?R%zRd|D5KER*Hu)ElOmWD8$PRw@^x8#j_bO8%ZJI;aLkN@JRLGz<)LD) z^X{dS>aPz{jMyS-M}4;kC_fmnjbnfu^nrmrx{od^XZ=c5n1-%7k4Jor< z!`HV%qvmYmTjw-PYINmQyb5)oViTf|BapXc#aW_o>l9+kozR&V)A2to(YldAWFE)6 zaA^}ak7HMNX%wHa3BR{A3)#}C|HPGlJ%RoS*7_Fto94Sr-id7-FEH_1Ahz(hj^%?? ze<;9jN(nOq?J}oG>c9WpQzj?Pztn1?Uu5dP`UgqjYo4Vk9!E#Vq~qZU65_S~ocf>C z^k3facX0LpgJSL@p-d3rSCjW>u3mM)!vRq|N6DDIwdM4rmBfXu(~+?S_Q#|m9=DEO zMmHFrKYw1*bt&>31$}ySG_Ci+T#U7qRS^@_Ju(1|YXLeiKG~K%Nds(av3j|%FGn+L zRy;HbLGZx#kUV`0C9S{n>7V+zq7vPG zHr;`Y50zhJt%zDTRo-kXusYO)8^p_m z?*O!0bI5b)4^G$Na|I@%!w+OgjHU*08`+ABcASAD(Vq@Kvyo<7a5 zS+6&Yi;FX;e3i1QHwK&iaT!o@unsJb_BR1eju&%C0+8B4jr;u&0QO_Iph`+E!L!kZ z_C-v5x3Cosx&X~a^BImVn)jwd%gs(DJcHy1>79OoKfn-m#;jV{NB* zWF!}mHt_O2LpBn64uFa`HX0flsi~>AfFuAAxQA1h&*NGaZC%}(7L!cnPnn=B8H-mp zK*>U!G*1V>LLJR{u{K%-ICB5WaEV<@vHkY14nXE|^YdM@Vv5XK0K@~@O!5;JuMOYd z81+>aa=Eak6DHhs@STM)sUjdY?w)3NXLEB?_oU?>P>LoceU2&(iTu_r_{EQpH_Ouw zn!&g%)BgNUC7Tag004UzfX)~-Ztqcm2}f_`kaHvii5eg6)}9kBW*~TWq~R%S+TY`g6dbK41a$HG)9a0?HJ|1Tn^k1o#&~ zew2QNeIhwIxy#DXU4Wovyee1q7UVc-f&qR8k%-?}Bu3(Bl{2X0qBv|N7SLf14xVcl zt-rn@EjLS{O4fo8fAu39yG492B0-!$AnZ+Qd$|!NH#HY1{JPL#h`1K9B?q zS$|K#+0&;$zXM9k%d7j^=}f$)Xn*omjDqJh>ODCBz%!gMrOPYca3gn+CYt48vKX_NEt7F zTrz+8l3PefGcYi)JnhtFY>gWlO#ZspJcPJ?NH}K#WPeI=j^2xKFmE4D#PfVetV6>X zO!$VisQqX*h%B)1YWkjl=YCK$JC-}@&l8F59j%1dTO1kuyU7qG3CVjV43_c|h4FFv zOpI#Kd%IfMOUg=rb5mhw?;-^0X_gHZ!u1^n%Civ&t||26520%>;{UChNa;?<19tK8jIQHXxg2ICk(7y(((|KpBfrR79(5V z1o@1NZgM4mlM5*2l=!M5bK`V)A!654bg9gUBO^2qaTF5d0Kofb2Qob$Dc6RIv1Mba z^&K-|N|a2ohLXQn?A~L^TP?V&q<_HRvM(E8W8UG&B;}>3__9`hLdbSYitm%xA_l`} z%m!8L!Vb?oxW6)a&znrywJbM0J&=0fz(R05`{o%e!n5kQ^&X2>9ju6%Cp)}%OKWH6 zD%NrGloB@+tBQ|7M;7Yi6>5m`ewn$z;@qAeFTz9mniu;&yZ~~tJi{biITQK$Ef-ib zvR`%d(c40(qFLb$;05G zWq(+tVhp`@xpmIti;U%&dcVk6uC*`<&Z7VdZqD)HMzK zgT=Z})+?XnVY?EPF3c@vozyBt$ZK$X@u*QWwnL3KWL@kuyiXRX$Pr?&tLB+e+tngU}C zFuL?Pv$Rx;M<@R?)65lz+Rb;5!mx6roSh5`KI#jFk9bu%Vz#G)1(t{vO;1mk+F?bpj@`Zj>{0bv zoJ_j|n2@#QCxFo>G+a3W{VHW5-TIo|8zYvl#9NtAFP`|6Qg_-jIEy2y{wXI@5o7n| zJ}9R0$^?THBrK@M?E$-#@$Qjz!%uECAlsH~GviYoUH4d9xRqXma zY6|-Hh)#D}9<>Ygr!ecfThvII88QAfYQM+ARU<|1=Q9aBLth}%(?AxcL3SF^x4-Tb z?Nj#!8WI0PhnypN?ZlC_{a!j^54jk?tn!-abv-9lC z3}ps?O^3iw8tD67_VV8;)tcxBTi{fF?HNu$RvSc2PvQ?kSvlA|^TOwa61$d_YRBb1 zIgQRQ9`Q7BjUq6I^)_g^Dr$0Ot{{>66`=1JUxCs*`Q#UbIK+2}Hds(2o(mozW{4UO)bB zt6a6qS8eJMm93p;MEY#=4#&cp;HD((SEhu<7p}k;zQ*q`F(p+Yu-`CuUiPZFIOO&< zom(Al*`HU>_z7-79Nv#n*)7(^qaoO#zNmSQJeRCmv)dRuYm-5%&Ov)oSJfC)(V1Pp zK7zV-l=cWBTk&A~OlA_T^d-dhwGLHPOhSKAV*R*#vH?xBU{mJf)tvl~!cPn2_p)tg zBnu2HRLpB~2Y{UhU7Ll={WK~&P+w;#f{b(uK=Lx{N;q!dkm;r85e08UsV+Y0`z8$K z#&l9Kc=D;bl^3B9BR8PrKfC(tn5dF3ekvTcLTaU);GTPHImbiPP~sX9>|v3tiPurQ zcH;IcIgWN$IQV+;tHG>gOfPtSR*giG+*Jk8qc@=OCl9ON4PU$_)VZLFhz9grR0NP@ zuA5N~t(Xtt=Z%i#6nZB;cU@GfnSbzL%x1`}ojDEVK22bjDC}6gAG9-@M zs$Nu@CySTS(m%{9DJih<6i^c@FAA7Im>`9v4$3$FULGFM)-c{~!I zRyegC%zQn+HD^)7!^6cda9PWAeA3gov>{g!QbEhjQ)l<0)AL!TsLxNz`1fPtitSrY zQJ)&L56kCmHft~P8SDvZvy7z+Lwl|5hM2~TD0~J>-J;gqOYb2gljUP7y5()qI)7i&fUuY86F#`QVXwJ)QIdE=0)MA&kY>w)8Cm~j*p7VT|&tezKMU` z{DJ-jmm$WWi=dAb{yafJC*7MZ9o2)ni#{s)?Dcql4ACT)z=Dq455UfTI_epMhQ z{i^acnlWUimT9+GeH=g3;CR}=dvt19*%PxAu!>4LY{Hd%qcPH381Man`(Qz=r<2q#~7c5%1 zA85^*G5fPe+-9*_RB*M%uEto*VmU6PYz^a9fY-JAm>x;C+wl0Y#6#Bk+a{fzqb`M- zf%h8GILkoK&9wid(Ce?v`RHUNLj!}ADyr#PxIV7EnE&NkeTVO3S*v|LXRx@5oJRmp zgJwd0f)s}s#AS;7P`DkV>H33Cq04FO!nVNESdUHD8+8fmirAs8(e3r!*VJtt&Q8Cw zs!nt}2iF98l70m%=4ch#dYWa-uL^H@86%wIUQX{0uKsNJ{B_yANXs(A`N#AsTWw?G zvSl{6i{R-P{`n81$oD~5t$Itr@bw)6r5k)UI-R3Y}{)fQz84ei=KY<>DB-vkEk7r(JD&_1LI_ zkF1OJ4t!!gnfP+i#|o|}l)6ox%kq!|r^l<=!;!lB1m$0O=&`)p95T9j>7N`J(x9#3 z>$tGC!-aRBT<6mr1s#=NmNqo(4tTn3^yxHByz;YWfGoy4uwwhX{tLeTC?Gf+tfac_ zn9Tfll<*%n+{85vFGB4L_cIe=<6oUZKVV{54&VT3f_txcOJ0ogX%esh!+Y|-_)Y&E zF8fzosxLZUujm`>EQ#)yuIvCb@T&xB({Avy|0@&!{}^%qlL9A|o3&6^`$0~VKCTRW;DNMb}ZTo*B&u0#@!50~-FXx#@7-Vi-3_x;Z0WMn)t@j1vaFfg!f zIn#YAf?R4H7*#MQM_nfifT2_a->S<}KNq;u0|q`06DFa1uHh?i@!FkxMD~ZGzH&wK z`1)(HJ2_wIl04TWfcAgyPcKiGG%jK8AxSlGa8HQK7Tn1o8E*pL5{Y;}z(1K+zkH9? znq(k;cyV!YBnpMz-*?A4lDPO1-QM5V1pe8%|0WCzE0{=%c=-7{VQ=lH@Frgve^0*> z_j^gS%4wgtbQ0O;|JFSIyYiz9pMYoq(5290z3;c&MYj(~KsUu;QbG*{YOGf7vb!bm=kDnOC;9{LVIjq?yh^;u*=IBv zr`PiY`i{u9Sj{b!pBJ7+x{NrnlNhCHO**nH#~n}sXWHJNiRILgkEA{1%IkLU11s|` zsmxk(E;gG8A5qWG_2SNh-YY9K1SS#)u$K?Ed_wh{@u1OAEH9t6P(V&Yq&j`!Up&P# zuBlTGbJc_x+_iu2WHUmDOp4A_W%X89pIRf3pFOQ;RDORsM!EbW)ji$HU1=$9V?TMa z^!OR_v*}wwPr8nXd=&Y~fbYebR}x^v;(rQ`qTm&?5~bb7QhzH5J`Ru zwzHsKp#c0+zyUfJZD=bW`~z560p=|;Z>M#G#|c{jSoJzfoqHiXGn2hSLFRBps6wHh zu#3iqzI+OtLy$Uv?zpdA1TX8!FTMbcCCTMX#z#g*W&2)zWH;J~xIaZ!;}w+t*)H|{v#Lj#^w5zjqaY*9Y8)}sWFLtyC{TQpx8Dgwk^ z2Q;D=F!D*-*0<-WM{{O@>Quti;Y`>FkOeF>L~MM4R>{ljXyD}TC6EkJ39Cq%T&h1@D*>))U`S+f`}OmBg~HO((x0dq6s_<%h64^e zFgOUX^eRVBEs(ys%F@ z1DY9TWoPFaJUjW-4}@3jov$!qcP(@C3{Uvh8`29vGZJ=P0)yHu59%udfegZMaTj9( zR1d(h%gw%80IOFPkOr6_u%C&>@2FVpfh+uyVpA&c_klWtmcSikdC=kDlLjC!=u`)g531&w!JE@S z!S3$vNm}UdDe%4b1@!wSNV!Y&0Gb&HT}`klFnjN)gSfD9!tYqQ!2`p>+}5R=Ny{r~BNeHL z*vmfr;&s7?fQkd&uLW#;tCsf~ftzp{Og?1dAQVK_%gzKV2(8y^jjD4f1fj~1HA@u* z3!dG>I)Jo*_wgYNV%&_BHelhc?I0r~K>~^tccvoSpC?ja$|Fja&Gy6Z%kC$}!~Yd{ zvwr1xIl~6p;d$kcjt`%lM~E0q9M^CN-;T?h>v0nq zT4F7Sh04%(|H=EH^c{rIg5^tgje!qGV{Smzj~r!%C{FN(BN>`sRttwWYYY7Fedt0Y2zaPZwUQ={rl>o+)+wdfXZ6@xEWzzDG>-$DG zeYe+bG9VCDY&%BxRdT&wCa^av^fm@A9SL1`=>O=u+E6!2c#%w%Yh0rjM$@lg<-rYy z2MzFYP!f!hk)l&*2!$qnbf!OG0)>ezq6P|s6~t;9TUGN8cBnN>O|znk%U9UyMtwfc z2{k`Dg7@8Ecvs3MKIW3SeMXrjH~;w9^G{b7aBly5YkTo( z1?40upTXfQqqc%#D|DxX*K5x_0 zJSViX(AKW2&^ai1><;VtwnbQFh9Qjd&C${0jxjnF6;K0CRoUZt^LQyiq~s~n_ClmC zHVe0Y9avwl{LfFpkQYDGv?Q(ia|1>$uzgHHnh+jrvlrD|Sjg8w2LScpPwzZG(MLJW z*U;C2`#FGL)u&^&YhNYrbAN{u}Ae7d8WHp3=oi zR)1m7AU7Eo?;^BTn1B&iMt@!*zQvj$*`U<1Nmc7M7n?DDulc3UKhYj8jnl^Ga%0(qJ#l2TIJMB*dxmE3K*HdY4*WW8mX#R@{T zLRwA2orI-FU(f0=7@*R9GG}r@uMim9IhR;b##;^O(`}I z_FH6^GC$cD9~bPD#&Qv*x`|O4UsGRYAQl)9Ek)Oih-PU;MMc||%6zauB1&~RMtvy;ZM z2(sCVnVK}cy!Ui@Z9jIclW!j`zjjMRsT>uDcA#WU7({K=?p!NnnhPSPM)hT>E<2p; zIqbHZ5PD&ZT^p-+qx42DIe#GSQ3Ht!prgdhsgjzS>MbCE!10xe^3K10_JETd-NJ$x z1+CneTSMysnZb2b==`{P^p|cc^K^*IXBrpwu+Ko4>oP!7dnF26} zS)4WXiPvFW%*jg901sTm#t(;@CZgG+^!Ot~@omd*^?gt(k|TAV6@*0;0eW(PIa&P>b&I_j|YqADAmdfF)`SadKQfvm@E1 z%1ulFXnfNi*aX@;ugbTV1`;cd!6malN!rs^e$h24Ned716es+Zv7=|S3~&q2G1HPJmWvqRsd!fmS{@XXY=Uo0~s_+XXyb1;+mt9xKN zFu-VT4N*jI&JqO=j2^$YE^p$nD<8Nq2_pzzz$1bUy>hu>6yAKc3;5*41;PR|))#~O zpzPd57mMQlKkPe6c*ii}ME zWM2&hcQtVBuCZ+i{1JQCtQ59tkdc|0TU^`=OUV8#lk@rciUfP~&{r2HbD#Q`bEXj- zs)Mq?CT6p@GF+ba(0`z$f%A7Vz@To|N;NGpyJM~X(Eb>QIH_3WY|aO1o5b4 z6Q>POSROdX>Kz3xrXSYtm7zg*p}#Y1n_@{X&~gG3z{KG=&Q|_zTU+{rl!s*P1G2Fy zg<~MGB7JGey1=+@1a>uz7-czCRl^vI3fKN+kV_#@tye$(D+@)lE`m6kVIlUcOZEf= z_6%W@ilbwwT`<#)btA4tV04L^5x=TPHR{r*Oia?%HZ}&U-H{mS zl+04uWj2_R&?`m8JT&API5pn!Z$;G3rgQO8h57m=kBM?6NX~o#QG5tD2MG$MWbI=z zp^32ry}hZ#fd%XU3{VHiHQDuJ0k-B$l0cABxp@u+xek!P+Em*)04!IP}L%HnY-V~*Rnhdf9~C}qkp>=cky zZ1Ve^IN%JD3vi>#Vq@tb1hJt#d`8hhbac5c&og%ZC2`<){=g5qxZrL51{@v94cLFA zoBtI@D7pA-nQ4~k6#T*CGdRIx^Vms?aN((u<}PIcyy_uGWb)bFzKy_%-r4{Qn-{68 zFYcxn8GM?MN*>$~X0g;hDwxn}zB-67`?qS9K1yKS8ao{wR#xSnHhzLWCz2?gcawTu zcW`=`p0V|0`2RMC07Vz8-^r7BFQ#3b?-yoX0SHlsUM@NA3S1;4qzlB~3jjo^0YT+< z*q#_p3RN^_!WS~Yjjhz-iSF##Z^8Pk%zt_NM5aDPtlweqyYm(+6ev<7Cc0U2QJ=0V zhNsg@mrt^Z7*Je;$VeZ>v2xw!FadHDH?QqU*~<{c@^d0To$6!%o0Nhk{HQvvyeS0V zD*IEt3b+e$j?@yDD5EOuZgcBcds!wL!0B)FvP+?#+YGXW#6)W{_c$k6+(Mxq;^7Q! zSQ%-u2mW-@p9i23j2W|A=SS{t|5b=O*Is2L=YfUieRR(5!-z?6A#eXFM%C6QphZmF z%A2xywntc=xV14zN~u-kcVBP7fFFbq^$dEYcLhx!50r$N5U+x@{DW%o3Tn7C`J>)ItdH$^_)=Q*IfhO(X* zFQA7iR>?sbbsb$T437@7D3Ix2j+Dl*nBNXavaPn=p?%*G#399BNPyO>NL1zBn?-`_Y~ ze}a6+F_GD6W0@y>qxeLI+X7LR6w+Lh%26+_m)laJ3&W4R|I!iN+Zfw?2Jd>f0JwTD z)dL(CVb=aw*fYc0nmp3S^Ua>vybWXBm6Wp~@vl-uMd@6OQSxE*<5*v>87J)YzK>mp zI_A}8*h}W$lF?aNqX?iFjs91~=<5HmVl-A_^haf~)jIdsrll`1>Ub(+eeuVTD2VJM zWTcR5v}j4J=WO%CZ4S*x^O7`r1N)9;lqm5u!xkU8+aMjO66(jM+#5M;rO4=3vt=D> zGvTWlFNRD!cNwZMIGu&6+gZLXR4T>uh$hblE~|MF|Efh4s_~3KZ+9|0y@#gkD_O2s zwB3C*H_*Ru?7iD|trq>;861TT?twvVnl0QzxXy=E5 z^8TlCRk!KCW)8G8u|#~*@{E0OH`Du!xRgi#BdUvirDWKb4+iILgqGGek?BF+4Vs!+ z@+y`HtVeVFom>kxWsqm@;3Z^)EX6mK;VZvmKJ66_P+?`Ialz{rH}!1~j?(P7ht!fY z+I8IwI(KWn!KsB`||rgvjq?)|I8Lxf7N80)YqZe zofh$DzQ8KxSRwTEq6*ADDdJPql#Ig-n}{(l=F6MQmYnOa=G=lJq9W#JUk30$eU75V zVvHUkfkHD46dLT?e^qFLw;yF_aqE`X74>ez=sjf6h(2YZP53hGm&wqiYwaK0rM(g^ z6cx|j>-;Is=aMIW_>$2sal3*wby_s4>w;2kXy2ijL`vk780Q=%`Q?87j}0M^M4<5z4zyP60Qk-cAe}F83+WruB;^g z90Veu0p51kh=ETy{86O9jnqNO009D#17DES5P(uJ^dQh(kh1(!9XHI@l&{XPOFe#v zJC1dXWA)SE3n#0Q7UjOr6}MokD>107XM;67?wcg;ql6c@MB=U31CM|2L3cgH>VJPN*!n)+5n z^q%s1;to#t&V3H8LXXdVWZ2kdv}GoU+KsK{uj9?F`qu_@kDlW)Ej93DoWQ4ZNncv+XdSTwD4l}f%Zy{o7$HQ80e z(mZ~vlS4CjjcjbzWjFrInvBWTNN{9Y%=xXT=F<8y3}nZWrX}w@dOF)0weRf4>*`9P z?6mB0pOGu^fojLj^tk{Gl zAMr?&^3&qhT*5wK*1~F%@@q{iHsk!Qz|o`+F@t6kOGV!kzr;Mr>EQ^2T%e}snhd8J z`f>HW`Mm!FC0~H_l@vya3Cn<YTDn`0&|hlF&y~zAb!TKt_WdUPm6{7qt4u*)&!z=J|(I=Pn;-B*nCVv|yuQfiNzQzQ<^?y1QJHv%&| zW!s;dI+gZ4XKEx}8PL+BVO;3WIiuyucxpo3EW4yYfB&?9bPZGhtg#>!6+0~#n`uy^ zynLi)(%(A5YpJ-KAMxu6Pd@g@Us2T6z0IpvQ~?XYa0e?#zpVFybR|A$!XJiq+pP^` zS5#HeFfeo=dZnyRar*V_K$DK1p5;bzfluY-aoMWqpZsmrw|I3OHpd>Oq@>VGx(N~y z5mlQgspX=#`j&4{SZO;`LR`nna zcCXWN5%52LjP}1uGQW2$hTNpj*DcI6#??Dcdi8yLy125k_X~@EuB+Rcpa<`0ea~oz z<}{Wwq5cT>+EE~;1gm*_OR1}?OP=o!%FENkl{l0r7#~G`wHYl#tUxR6CKSEABqu8E z%3+BZ1rzF5y2bDxeHn6jg@xHgMJNo0iNF5Hbi#rtNGnUR)TD{{k?mMRjmt)opve_Z zPR`1%*tcYHAT53U_U*Z*ah$Kr@bGZ$b|X2(9g%jV0Ray`KWgUUpo*53_HuGggX)j9 zbagGU1=1Q3>;?w|sseLJY_gam8#pS|q$y;apJz2bA))kjKO0~kgHlr>8ZNaG*z@#H zf~B8wbFWoRs6T&B4YZ|VR~!S{Cd9{=xb2vRTxV>3cZ)YHBBC5-Cs9^bX657zuBj29u=veD76&i0=(;^WKR;IM zE(};>VF_)#{EoM%1g5K$^2qKEyclgg_}Q_I*)=*PMFoK<-zt+$Yiu@|sIp&4u_?;P z%?(rk@Tk;!kjvD}%nm)w-JK#Dah2pobbNes5Gjq4hQ`WRsaa(gnE@G1Xzflbqgs-n ze`BL8++&UNk^OXc(nB*_;3=u2*+3CdQ7RUe-dwFLx3itLwbfN%4DDJ;^tvx!s>sS- z5vbk10(g?`MCE(Oh1PL?RlkY~5foUe6RWj3Syv9Ymk%gI*l z9UXJ7xKrkZwx}vtqE~Pm*mH9zC$6cnv0~Gol`IaQS6hpjc#D0%)P;^qO;uM`CVf2V z5V%#gXsBQDn#u=f+y$o36ohEtYxiz+baa?oT9%o2P)~d9sZ-O?01me@w`oDSySHbD zrj4iNn$c2FAd)#9?`>~ypQXbc5m{JROnPh-0^WjO>$af$lAr%|^SgWBt&*96i}O=Q z?3Bpk#|t}dNg~#z4-x9IoQCDE}Ef!cMz=>Y*sMRal**$n$^-*s{9>7OSrV zgZ;=fb<0f>{Oj8ac!E)3P z)td;X@xTxE_1}6Qc;4JK8R+l-9;YGQ0l0+YHzOt~kN9U`_hzI4^*q>Z)*q25_1fMZ z@Pn+zGasA`A73|;dH2@IQRxmMsB>@s&~?TdOPKY`&5pN^M4Tq($=>d%Xr-!yd=x&J z;=r{r4sQf(Ku*;}{i5Zw;7*AW?SOOlnmu1A$?UT6*?<%0Os`?@nPJo^>v8ti?@Sy6 zpsa4kpnvT4049ZaMHoJ%Ewu{jeMk=#Uo^iQF;cDrDJ7$BXVB zLyFf0u0_?q^JQQ(L)Mn>zf5v7?&V^)y6QLyb~YK%!iI-uS!wx<9Gq>c4UFnVKVA{% zbqS}r5tk6F28GPlVA^i0wU(kk&h>m+%BoUwNA8VEiYHK3$+Qb*u^%kHPI5k~J)8UC zty2r@E;}pAU(950Ol2CVMI9rJwZ~925YR&nYofa<(3*azkr@!VyHf)k;Hik~o z`=1AbdH5ubiyRGnPb45obArc)gN~q!rJ`?>-p3$ujYrbPUf+ZJ^@O_TtP`?K1}g1E zwJnK`M~N#$W{DiKwaXE=U{WtA*4!Dzwht^8b%yu8``-?8sSKuFVdjS`IUS6j=OENH z5U7(BKNiQ)W?$3RC=3hU76pgOaO{xYKhV)M(0&Sk*VU21H270r^;W~z(E$V{zvXM^ z!>FetwjFw6Mrxh$wy(r(Mg%ra3|U;=x&?3|ZW665HgEh`oga;sl%G9#^vfqAbvkNQ zP`rnss$9&oo8t|~C}$+$Y+Pw+Nyc>l9Oh<1iQmD3_03zu3r~#f90~HVGtI;oef^gD zOs-+UJlgk2gpg+`v7DibRp(KCVGvNXz;$!7cX>hy^aqt_0#h~Ga6 z#(HHo3S+t>!o(LM)$`G31>8w!?JIt~E>e3mA^Km`)b7FESjLxbqU(cKxG29Lj;wL# zXK5J54WcTEr&lk|Ua3tM@>RQ2%(cmIROJR8QsRE3?g_lYr$8bd1vQ*gJF1qm#9SHn zgmxk0#@Wl8ckSyDIX7C|Lo4~sRgjQoixR2gjjL`}Jug!?A@7k~ba2_9Fl}p;bBxb~ zKJgVnRI*v|V!Cf~FC4jZLK0W)(R~+TmZo5`Yv)|sR@=YOfrrL4580-{CDVgq-o?x= zo7G8RH`=~1fuSB~%a4V%o)<5_Mv|h77g~=Q-7I_pj_1_j1gC+j)%bMo)KgEAHer0? zpVsLqUw<0o6y`lXvN-!icGs7#(bb>J9rucp-BUk{X0T#d^}c=l0!EXoboNTcX&W1B z*lw(#BHxw?A0vkOFT9O~M>*6ie`#d)x_wHOVL4VEb>prV@xpxO1_JBrDMKYi(gtTF zex~t9&8%pUd`$fk`#|sXChrm|qa(iAVqg`vG^t=i9F@%UM^#h+pFg+M8gZ1Ppj}<- z>A9DFsCgva5LNB@i0R`b_@0Yl67$`DfR++S2;!8cmV;EcbQE7jU8{YV$hFM%1_Oq$;}&DS#;G>5b?t zymk+xG-gQag(r5sDI&I(T63s&`$*kbk3m^X)<_Ha4!;*Y&9$%B6;fC4CfqrO-^_0@RTKC?I|@ zWK1Rpb-GT5bo#XGkssjjczivL-{FnN21U($&(LHp{_{y#TTOh`5X%;t~>n)j?@u@~PqURbIzV zP>k49RaJ62BL{*94;~zy`y>h&zr~6;MvK!pHv17=1rnT$3xI=}ZQi6(>uSwZK*}Px zN(^%7SD*vZHlH2`RNIOT1sPAxF)ZoUnW~p#kH$Db*g|H(P#9?_fT!(S2IRTh{!L! z>7P)^sx4~&ovuC4xBSNgPY9{@SITVct(K?a7#J>dp@OjsYYs*-`^^cD7S@F|%gWrh zh262Bn9mAYJ1+0|MrM&^P~;iL<=;SQ3#~e$S*xCMI-ATPyU1$g3k1e!W_r&HLBet) zRTh%IlRQk;LK_?|cHe7TLrEFBJiu7|t90tH9_^$m8ZPYIEe~}((U)tRtD~*Ec;DKlB?2U1kK~$vqq`D(aCgjk=U>*caU_ED)`)c$bFV@hWvFQ^y zEAMVTXq9DpM%KbKFpPwqBV1AFDYiWmQ7Iba`K{XY{a4J5QaU#}-roQBi@c!`LJjPYmn0+sWX zhTWwuh~qq=Dw_W*?41@rIwCWZ?XPN_dUq&!-*J3=+{kS%*cpioF^UEajgH18CwK4` z*P3GEqjLn;vi=!^0!6Kskx{p{hLi=+>a*aQnG*uRAm(saIz7s)4ORMP`2NXn^7Dml z1qFqQ%F5WZw6{RJY{515e+8Qj7FJd?0M5koXxpNxV`;fq-~L`7reGG2|M~Of`uh4M znaoE3$dV{(ZEgK2JNqGWQ-2~m2-AnRKg|UQ2`J08bD-HZH7TreYW$J(lUy2U-CU_=v#f6nVDifXJX}6y`QVA$B>Yx8iSa- zhwJ&p^GGa%jE^J$l17d#w<=Z1#1j${)RKjQLqdoL1_o@=G!;Y1gn17PD{s=#wJrbn zFkWfLD1bXF3t037N_!H39=p5MCb9`105ZXNy|=`u5#l;vLffAe;Q%&LF*4d<3!&`>Hvs0f;c(Q%7IDME&T7^k!ILg}FA3n&ogNANEE22X z9dI~eX#W)!i(%#A2?yBoSKT2Tm>OSjxCOvZ)l+X#%n~60p3OIh19(>a(DT4{eqq6& z`pV<0b zRCFV%t!XGv+YZe!qxJMDK}$=^=2&SHl7~PcC&W|v9~lpm1B^*AlKwkj_`HIG3K+CO z(`vpXkc1LgMF8o5X*u*t9gguUQvk@w!NoPu*Z0waqHk#*W&Qf~tUn3(6)?)BV8l=NEDF37^9)=HOC*dYBEK!@zH9y$uny!iK}4Bu-?lu_dq+@1_Aw_#v`1QF zMgoL8n%Q2)LBzXxvQ~bcpMDXha%^|elkFE^#mm^~4M;H6U3oM%L#lz)|8LmK(>`lc zG~Sy@J)LSOtb!bD5ab^FvWQDGRDJ4N!v(*(L4ABX;7naW6Uc*5ObP6%5}>c;3SX+M znSy^^tx;6p8MzAKPURz1(rYW9G$B@#l^*Va7Nqk==hnbiWNyAsuw)4^jrVGdm{yq_`SV?2bEVuiaj;rKX2r7 z9zeLEVo2U|7v3%?e=Cw_UuLesjespzJg(9^KUs*koo?68x`BLFCC75*evQW$`hmSi z4zpWb?Rj5T0BqXK`DiO_~2>e?NrA?~kgcmFY}$Gk5No_EQUWB6lAC zi6snrr1j+&P*GiCny14hbxqeSNP|#~CesLrQmU5$?Ayfe%S5`OT-p z$u~t~H>ee_YJVZtVYTz|^@ro}AfsbOAWuaNYMqk!PFC>|0a zT}2^JO$h|SY7ou3+LfM_^zowEGX)F-M6&qJr!7w zda{|r)keVt1d@@Os^~~+zqQS2T<`~%@A=-X@G+kOGzHuF=8r<|YWC~|>QT@ga<=d} zd8H8LKCs_)U6KpuU9!)GlS2HFB_#-ZgKX)1(F4d0ctvYC&30gqaO;UIT_I7*c5VcS zUQn=_zw>Aj&yrqG<7HJT7dHrN>@b$OS3%hzUh~m8mv18X{F*v9T|D@FA>x7F?)lJJ z;q?;SN9R5y7h5Y~pAKshkDB~YDFYx(1DYLh?H6ggJdF^ixs<8N{<@|tUw#2pLqS<4 z)c0o`8SkI68W%3pxNvc;mP3H5ksUo4p)`}#^AD2tzpF_9{s2VmJ}++= zJ|Caj49D2BT;YGMm;c{%{{LP$|NSuk^PaL)R8_-KD9f#%U!^LGVc5jg)z>O2Dts@v zpyYd}=ROk(O0UBsBR?7Ad;syiZ(yL26Ky2>>={XFYO1rd^BBJdQ)Z8Rq#+>vb3-wg zJVMT2?U$H%`^-nC3oTFuOA%8_4Hq+Q@FM_3!t@#zDysg4`XDd>5Z8dL1z-rMdNng* z+f6c&mpUg;n5qr42^~tqGn~qy|%WtxU@tC2EWBJIVN46 zPV|X9`}-q`e>Azg%!k0x;NWp4ILAH0E|=`}%hRm<)DGqEv9-o4=Aqf=*C;Y7S-#8u z#T);~B?OL-+O+;AB1e9O{cs&!&lYqQ_08S7D@4ua<8{k*I=!`d?A}CzH+SLmb0ZD$gG^EY{^PzW+TxLFUYxQOt9dIv)cqdIjXrvaq}c+jtmk^ zj7@pxuZzc5H8wA%tY!f5jh>}9?>u)r_Bi1bGsig*mV$xLN#6OF8Ww!Uf*f0e_k4Es5zHSpGAHusfi z-x=81GrOB!64P^qlTz%Aev93|bsjx>UT#I6=LmW+>1t0PollgOeksQB;_DHB7-v|> zB^b0Ql4CdX=5u#v6|D7eaKMkQAp!cM=Y_L+pQ%#sM1y~o0DI1tG|C$lPi!NHg>d2c zK-au0K!_aw_69oInnX`FGx_fCR5P~)~E!MW?&>|Tz^2fKc&FQ_wn5Aj=aKeu@XH)qlWcg zdUFjd#6AdSmnkOr`1o*)Gt;zc|Aue#Xi3yC1UA?kUtxX)TO~fodi%3l22=akj*X@9 z%XT9`YLD)th!ge#+e+;-ux0j$4fn5e%50D>FU5mkgCWPHa(pk4K0l@1-hX3&NL9jq z-LcI}!56vBd7GoN8!fH#!_-n5;Ag{G^htNl2@L&o0vVBSJE+hPI}E~K!BN0eX)_E+FV zcXiQ@kZY1u=^Gyz)DgNR^+JM!o9kqOn&!Mn7>d9e@%yUufCJ6ehf3%d*j<0R?QRf^ zIzQ57$|!IkAY~8CXL0{$P)U5|zvvKRG(4>Q%}Db(9Qwi?Vg(M*FD_nL80p=Lr@IRr z+kJ7dXJz074UX6Ok_#7;7cH=JpYNZTgLcye7W)_`3}<-F6?|@i&YP}!$KF&pNsQV) zJ@?v=VZq@}k)MLh{i@aOockd8>&B58x;$!EhWuq-ApcY(7`6se-A4X;kT0?=aHx`$ ztitr9L#U|QiCckH# z=RD6i_kGS^?>Mhxpkpl7Trs~f*Y%l~L2s30aWE+{ArJ_TyquH@1cCqsKaJ?9;E3hp zQAF?$hMk=DM+gLq=-~$el9)sefzU(brJk#~B<(M_>ym6NJ~;|`iyO^Ix|=bBNucaA zA+*4eV)>Hcl6;3MoywWrnrJu*mK|q>#@oD-89L~>D_(I69 z{N8pTeGxmPqefId;cGAac606d%;U@BCl|K5{UJ-@g1_}yqnYLD8OMH_S&~U!n;IFV z!!gQ@4AMTl$<>1pD61Np%Lb3T$!6Bzs;lko1g)Xr2OWpB1Z*QplovNRW;UZH-wy0+sjJm@+gMrFIssI+m$v65;sNU-tX=A zV$A3&Wx^5jxoXmvL*aAp77IOug?m&fFlKa@G7ZWnNg%A`d4F8i@K}8x@`qD+w|b#= z_+HisTsk{RJ^`=fNUg>7NmI}%DkNd@*AN!5BX7f*FEP_SH&rLP)BBLff!)-3J-uU2 z?>`e0b?*yX4O?2Y?Jqs1Am6&yiypbPvZTnp95DQC0TDQX@j-g?!b&~pTQM$f?&ID^skyh)ig-aV+45TWJ|!a~0bAD zT9p=2bEdsEz0oYSF2{_)!NDWhuc->PD`fVgw-NaFw#)Vw>dDr+!hDK~xc~h5gHJ{l zaQ}Bp;^^W+vtFoEOG|5cEkZ&@U!PV$KwzZISk`*JR(ZdC`;FZsk(&hz3yW5>r+9is z28@p!A0HoLU|>+yuQFKDd>6dDY)CC)2T_RQYMm)Fp5zHS_>xQ`UP=RnFIP?Lzq~kD zP}bKE|N519Z?-~qI}OPjmqv`9l@+z#`LL_{!>@;T`0%SbPmgrrb280>rl;pKa2o;| zny{u%H*HHxbQv;XD)n3$ao@fLfm;!ikid4vvh19lHS3u{5+AID@HR<0Itn>BI4mC? z;(2*_RoX7;@0Sa)aC75ek#e=1{hls!+)=@%eX6w|?b}tFA*QXZ9T*z(W~~=qP3KIG;6tcz+)K26S*b2vC}7f1G7} z7PPmw7abQ@CIFYF)TEbC1PU$Ci+)QE{~`w8(^?==mynPECmSxee71~d@ddBRARW}PJ0c?D!#k*|s#Ylwjm2^6;8RnFGQ9LR1X0}{ z`QbCivO{SrPSElh35^fdhFobqO9Acc}+0tt(uze$jIB7*;&|RzWUMGne_Yj?BLz}i}mXB z^=QR2ML%v%6crm88MT>anY5LTmzFeLW75*nZZ9=UFw3_^G08@L{pvfKAzPqF*=yMP z1tpR>sQ*>3FD!>&R8;hGOX5E0$%i?59v)ml^C2l1jN!$L7Y`X+)z5@7|Fcj{P3`L( z%X`9hB_?p1?~j)OM(aIMPW|kkt~TOb&L%Y{dBPGUZ%wm2@2<>wIM2|@;WB$Ush(|> z@5c>oY#uV#*Uygu3Z?qEHRKl-7B;sLg=uYVjZZ-lbl7}Pi-t!l70;trYT8cU1&^eHGPwCWt$H8X$W`6ow-cwF*Ll^8_4 z{{CbVMK|@?rwN`Aq1CNaudXjBSha-{pZNCF)b#cBFV4BCsHi|LEe{GWsnv6h@$qmv z*j3Y-|R0o*3X$nh1+T8b&e!M~?)zbLDI6>({nNGhBWb)hz%1jRk6b zePaU@2*=DU`||0|xRa(D8V)5gs00^RS5Uah3*{<4Xn0+qkNLgR2u@B8U0q#08dKnH z9ULsO5zPW!BJsJbOa@##56nJhO(Ajn0l%r4nbGFJx6<0=>9&MP~VEMMcGlVjoAvuYxRYSI(7I16G#t^aYxC$q?^k z8iIutuQy3*^~lmf1@}HvUP#k-W*he8XpN3ycnZIVe;wSf;Xug6F2rLwU7y~>d(A9w znO$6dlwz*ashKF2)Bvku9p}#G>nepv60kTPgo8^4N!E1^g$GKt3>^@}ni`sJ%Otoe z%A|c)jltpkUXE?8^^{R}g(&;H!V3r6HM!iy6`RH{~ET7d9-r~#HtBcG5(fR@rHy66Ir7%8^fHAmU3sfH2ODT9J*wS%kAtA z-s7%yyABt4jBA5GabsR>x(HIxF%`bpnbXrlIy8vIhaY7dot)t?qYooL(O^rxh{Q=s zFHO=oA@r7Q7S?@JEjcx0tcHrO!EZYm8`B_<@N7G!%ppA;zV=pc3oSo8@@_c{BS9K` z7|To*xQvXgn$k1MOuKdZkZIo1zy&-(*_9-wxzmoWC|{m=-TT!xtKUPfjr0)1_2Zly zpzL$Av2=P^C1sTNGd0l_JrKxCdZhzTx=Hao8bqeGNcS`%4Up6w?}PAjBzGZ~hD#}#j2%&m7$Xm75fX1s zj+3UBt3PzVY9M|{+3|}HsB3xA`@=M;D=ulMs|GT1*u1iEhv_-c)9Dxdz0|E-JbNgj z1v-g@h^bGce4dnCC4P-viU!ejUBnnMoYBTh2>2bJ4Vjw4(bt*{vMQ}+WqBu_w_L*X zP3z*geXG6zS{K}QSbEjZ#P-ac*h*6^RsSe?wRqk!khYyfw+R)Jm%wLj*#3HmDC+NP z=J~zYpr`U(rB?7?mDk@h*vSQ*n3`@H7rSz{zd7?o+>V+g% z(xqm?EgZk!tVGhx40|4`Lx1bWtoyYGN|96MN9I{{i@S7tNBmc&?nm>W6LW`6drfoB z3SH~;$nm%{zgBC*+9x<(A$btzOFkz!vE|Kp5GS18Augv}6$51k7x#tRoXgh~=x1I= zQbrC@x)uGBw5^?(BjsF$G}(!AEHl4=v{H400nAgWvl2bq%P`8&)?@=&j&yuyK6D+#!W+?0HTZq9b@_EuvD#P@zNy({9EyRlN5ph|{7ER{}|^IOL!Cs- z(pZZh>8Q!0;*L!F82nfjm+m+LlPwN%$J~Rx^=r$~hRud^?!3`z&R9(ZNb;|Dy<(fm zxA_tb&p3>bh9=w__GVDI@^)|s21D;(gjl?K z!@|JIgQ~hE_1I+*^TM`c&IH2OvO?h(ci-%)T3wR!VV@5I@l3jlFL%$(R&-Tg7! zT5F~ZiBn3r$rsmOazcGxK*}(CW{T}uj%aWo=DT|nYS3L9ZuTeKHGmZhDrm(Ckqpt8 zOXSr1se4HI^ZX#`%BK-8`W)mWOf@Po)%z&Tx9)W@ktV&E11Y(aOwSOJ&bSf3>nSqx z`Xgg$Ifn(-!$@wenjW2>Wu~|(D+dTOM%RzKSZO;KCv3}VHjfc*8_LY~3`Sn9_@PmH zEQe3U$86d^4Ky3bcOiJ7ZON_jAj!>yv7*>_WVa{iHcG8F_h-C8b{QMM=5x;t^nk zfzcSBVX{&$3}*Wn_H@<%_PXDKN`Y(F* z|A&X<$W&BRM(UibIyyRpT%H1rQ>0TPG8RO{WlbnObW($Z2% zd3lT!&+GT#3pFi2ACrWH#4=u%!`NK5j)0WZ|5uG|MrI~*c6K%!JNsv5d2}o+)p{WT zL?F5~-&I85BAe+ZjTZAss>rfpBtia_Ki{Z3Opdl~yn<D46VMGx>>!JQ;W(cWAUt`xMB@1VK+Hq`H>8n{22h8a zWYEbY`llpzxbwkpo_lwQrngopyA0I_0m-~`f6kLsnK+L`;lPSXi^n{?Ew?0Wq=f zu*AJ?8UHExT7N&b*yvv7dFy8Vs~QIg9&~hc?}~~F%d_>(&9?S-Btf%*7NA~8sLcOf z9^2X5w>G$*5L3M@A%|yD{A<8rY1kD?(K9&MIg|_~p<)8!#MIO@FgRGn8e4o-C@yp{ zoCbO{XI1jU{o;U)msj@HE6nq~S!2iNXb=Jdf`n(E#6WK=1*%!P3mp$HAS48wu6 zDmdIkt?6F7!d0KEZmTb{^M6>-`nmI)`B*Q6tE-Xn=gt-kYn!GVTif?BjzJ91>FY=?1>H)J*5;>6t%8 zLO}3YztL@FBi_J2Ch2D?{?)TEgMFbnwr|@Qy!=FaH955bV zfB!a6k_8$?UrI`NUnwY*S&{ct_ml#`cN zuBxtA-c2SeE-n^vIii19z71G|L!8H6-s~2X-~)0O8j1~~v(^*E1d=CX&J+Ox-pr3e z&}=#AQA*3fLjB6}G6Z5VnNOnl`gNJdl|!ZFh4ZQUH@@WS_ zq?tjt*a4{;Rt;8Gd4OLcDh)uFd4IAw7@?EG3YchpJ{N6Y>w1!13EzL0_a^n3N{N1BCg37!b@pribEXUGN=o6U zV6I;QN~U6CQ#`jJ6qF2gegy$Ehg-qN*A2JUJd7 z9szapd2%>noyS%A>2Wum!a}`sJSr|V+lL2C9DS#@?<&e-(=_>oNj6*#5T!U!V83m` zQR$twM^?%%l2cN6sz8kE9CxCzV<~x4Dv0Djv-I%r*wrAv0&ilsJ;Km%wfWsL9{#4v zs%WU|~~5oS?@lDh?R$FLidJfIocX*gZWxE`^^c1bL9t z0G>-O&^fNLnl66mrc|~KKj7M49Kymi2duvW1JNBpW$j0+sR9}ekerFBDTBB;4QL)n z03F+{w4pq`T90|iNlYv(Q;OeLTdA_3WS)wPo6e^4!)A6S05E$XKoKMaMX=iLc**l<4ul{gPk=len#fYzqC14S(-*dE~X z<XfpytenykjIb*y_A8(4hi6HCZ~A@sbfQ)|#zj0lk+Y zhf_M;RL_x+KlZ123~(_U9DdOWj@$Uaa^$h=Z;WP?nfCUCg2!iW#=K_!E47Q6n|#{v zZ>U``PM*|^p7=L^?(gTThyx?kgQG)Pc>3pi5xCr@bgy(BoZ<2Lk#?Dcv4d2$0#?ST zhx*R5h8>P{a0&x|oaAOc^!d(g;_m* zatYUdng~z7$M==8M+a|?UI}w*cN4`8z%)HJDfJCh;1NYrY$79s@R1=ZBu5H3Nhif6 zd{{Y?Movmj4H1%7<@c>mT|6_`I6;fb@!P;YUS~hSNj6AZ+f*&Al?l4kDQw$c2g#B zKS$a3h>u`!3YL7~D_CBjjB4gv(Fk8d+uC^U${qwUupU!%T?qdyC+br3OsGwK# zE!;=eG1w*td#`wPksz0$mI!pe>K*MU>*>?`ODmi{k-ZOi)K-XN$LA=N-L+AmH};Z~ zvqy#%(r|=G$ul%T_`&KIy(V6!(VT(^yc#>5y576Mrk<5SeU7eao2PcSxi1ojL+L_9;5oo zSFW?zy{nvj$TZ-ql!Zm2LDRePAEmqEK2lokJS9IdLPLUZc=or|KtH}c|IKb4k@qZc zWzBt+Jt#Su%OtsLv27!G_mFkqu5pF+hExvMozP~#>SGh`h}F!bs_V;rOxk2Wr$)|V zQ;I-L5E4yhBnUQC%)x1j+c_W|hIj73?A|8jRiVDv9p#8}rVeC&j zhARbwuyc2kxT2r_1A^1bcf$1I$MUrn+iJB3?MgSnQMCfds^+pkswI+ZjnEj)T{)h_ zzUAT7M?3_PXz<5_Wg_vNpM4$sPrf zDDT^^B*e?p2Aqa#7LqqlH27+@5L{4)+G${qjh;01T+z7xG_~8Gkg4YPW7!g_rr_Jb z=})|!au=_(@)u?LJh2bS{ND0mUn&sJL8A1ZY|Enx_t~ef->MhohlUOeUGS%vk(j1R zI=;f5oK;u0R`AXti26yM{7UNUd)_s~b7O%Lw~umND=cehJMN~V7^#;zknn0;36CS8 z{P2k(Tma%?ymVajn$%I!X{Pt=tWW_D(lRuBzFOlJVbD7ha5*?hcYh%z=-N#j$J~3a z{>~AH|E3tWTgQt|h-K|Cmg)+t77`qKRV~|gcBiHt$Y(%bO zX|1z*q4!ac>&e#gKVo%&K=8I7yZ~)S#~AB$bN*h~gWVQOL%DqtLAFg|%C~6OP2rjb zm4wjDb;dOzcuNbZ-R<<_%uR!rTf!xeH(7^H{UOZD71ZY*09jQ#$UuE>(<^S&o<4}ziKskzqa|&buTqRHa+?i zSpjv+r>HKr{@i3ajntcBXm#Kbm4nLnSQ?+k`?dApVCx!j$*Q!w`$ zsm;B_0zzUX1ryTG1n>RA_qj>P(R#$3sJ&h2YR8L`2@5!$er{{yAl60TutnU5J`RYf z5@=3TO5sIIn@2m?ZmP%#c(es&yEDY7PdU%M-+W@)MUcR#@N~gn4=u)R_0eUoBEblt1__Yg=D)cyI!t8L|^hPI&t&suy40mk#mnh*kl z$0Yv%g?~w?{yWFYQ~-(=EJ8B=hiUYB0{r}=f6?fp8fIqykCf}bU*q4gu>Xf=Me%^| z#WbhiQ-MK2?~hy*6|o;=JWdIL=Kr}Qov>IH>`beT4a6_HyuZ6OLjB7CN0AMWgxVX5z z-CP7P0;;aAj*g8jWn#iSFfcH|6A%jM3_w-yx&A+xM2l=VLZ$&LD=XMyB^a@aS@BTYR_Q*Q51K?p-sl zcc{ibH)}E#;@Ni&a7Wf4xcGCM{}5SV;~W>dpU{O zs|8fE>cE_1KuJAx4sUOC`FNFxLQXx8bqqBHyb9Z=;)3)esP)|+^x$FI&N&kM9<*gD zSMpRe+(;+tl!|dQFzwnK+V}qVdn7ot?o%T&S(g7{kzrdTP$yQlf!-lGa5;7=zup<35FG>3pu~=GDL}y{nx0EH=Cippx2E}D* zT&bF$0)E}1^F~hf?sn*eT*R9GnbQ&v_BJG%XX-eQzdcCtSOas9uDMK*d z71xJbBgILXB0>fR2h?*zLuqo#GRdX0z06lv#$34s5L%YQ(rRvgtWM|`2Fe#N9#Dp3 zp>4HlG!ck~O=9@du*>8{vdz<>0IE;5pt&VxkCM)0-YVZ@MFb&-yS0{rd7&cg?72KZ z9#Tg%<9q2IKxc7yylJyL|rgf8nIM!{Nl5?x~bfiJ(=8rvVp4 zM|XFD9;!HFlg}4o0y?^gm`87nfXBx&p0S|JxI4YPobdSg*kZBa=iJ7~OT(F{!UvAA zwuU4qC}=%fF1_zS92FS}p`)V%h*hN+4+)?slZyA_tXkUIt;54_Y5;y(TwKg8 zEbIVMo8MtwPPZQZ`oRWtgoq+u4P5fL#wnEyFb z3iFxUAjffbcGd;{6p6b_CVjUZ7Gg580zJaX_Rpq8wujTo0d(kgz83^gIBYQSv1PpRsXrcFI5?9YcsKyG zVB_FWsb^k!(Epg2n0yu^^uT$r0t7qx6YB)v6zKz#aJ&*g_h75KT#tD(!6R#d4Xw+G zcy^8MgNoDkXQRK&a+0H}f3y%FvLB_T_|nqS4`vn5s|~U$1wulwEQx-)7Si`PmQIrJ zqBS2*=>(P?V22@lc6Vu9sNYE09)Q;!KVT zG<%AC+{6Zsqd-74nI1io1y&@Gnvj;>m`9@(=5KTx-AG(rUAKSLlmJ`M92%X6H*j%0 zSX=(tD4+(uK6J2Z9i5+dWxxJj3LH>X{RA>Vlmd(r2EacMnQOpjqEXMRXFP+!1*9;L z^a0HBJ$-#`C&LmYaQPSS8eI5S*VZ0ldViIAuUt>PU^Iha2^=^_Cnqmoyg&p-8!$O8 z!{Qgz0)m304Xz(WL`7G+>AckHnHOL)7_7j81Out>B;s}o_KbEA+m#>z zcywKY!%uyHvt{Mxuvr!ef8aZ#ZE-(r3;^)K==yZWWh>bkJlhE{APEDAJdg|}1N5V< z{;&yT@o8krr*my;Q3vD)w^DL4jf$!&2u}q#xeC}|fPst_Jhq7AHolnCZYEs*lpHu! zd;r=2VjO)u=Z$7P_3PEuWHBMrK4QQTRsiv{m@ZD9+lW*I+%pic)Yb7f64Jk_KRnd< zN_zk>u$Yxrj7I@45pWfuio2h80CyX?qu65rj{X8M4r100fItykG_iF^=@IMeMBgu8 z5J6tHc6G_@JIKMRtE*=!%<%x7K?6o0&_>!97WDSZL&2wLn1Z5WN6edNK_D9$L`A zNN;Rp!L?-ql9N$cn3-D!2C!{xY=Ef`%_kfJv28pfeE^R(3u6CRzQRZOAGWkU*bxy` z`Dfp}J!XM@y%c+_gm)um`mkxh7yJ?a?vUBi>*V)_$o9eMpTD~sBDAE?e`P*pB>bYR z8>X(NjjG{qmX*i;i;LjYxOGgMw0!kncb7jYg7ksGRTW_#kV z(rtgcPTE^#w&d)I(v{u&OkedW-Ma}PFJ2UtK&!zMEA(hgV)EyCYqh1k+r=fLyCt*b zbp08$0X)$9;8kpo`YpCGTxLdQ4g|=^T>5AU%^FZfMD=0P9FSTxn1K{M^}x{D_XsnX zr5Z;%YiO6jb+T`2jG5>C_@~T)3u(E1#*X9xSh3|}ye-`WSBSUsTV@ZpYAI9GLI1wp zp&_NlG0G9sng4LTC|kxKySy4=1X}U4$j_TkYHyJD@X09x=8=+183pOIf3kSTlr?B6ici;v$==ggnSYntDh9&*xvKF4l zC({(}kD7anLzeqalq7YV`cTB5{zf>lyB#BLnX79J+TH7Ttfe!KT)Kvd#^~lC-|vm~NtUCg=9&f@I8~f3j-+Qk z#au|rAN8LLm(Z^x@hOIOKA222WFt83?~r|S5QjeN90%oa_m%uTHkushuf9aCp8osi zaV;97Tfas}aRLsoB87f--*S$GF>|LpgF^M#Wmfy}6_aWF=I$I%-x&SrZkmJS%$?Or5x9~a55@zbNrxH1IQ|R;8Sio+{+bkEEnOK6=YljBe zq9>Lkg!5A7!+&_?pQ;fWts3z;DG@)IK8!-(~Gm8qHAT&C`urH7T@| zrm*tyzyC{;s8VPd##~Vs15Xq+4nQzAYaxLMw2xlRYVtigMeZ}(T+2c@jq8;RFec^JUzRr$sCNqu5K=hl zGzKB!<fxI{mE4fc-?$i2qJWK7R) h1Li>AqkDv}=KjR$U$@i1e+q!eODjngzcBprKLA*ZJLLcX literal 0 HcmV?d00001 diff --git a/BTree/Images/Node.png b/BTree/Images/Node.png new file mode 100644 index 0000000000000000000000000000000000000000..346f940bfaabea7e9ac859b643646f23bc6f736f GIT binary patch literal 6255 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 VQtBuS_#=TxU&mOx4t6*CKLEWg(=q@6 literal 0 HcmV?d00001 diff --git a/BTree/README.md b/BTree/README.md new file mode 100644 index 000000000..0a25c44c3 --- /dev/null +++ b/BTree/README.md @@ -0,0 +1,172 @@ +# B-Tree + +A B-Tree is a self-balancing search tree, in which nodes can have more than two children. + +### Properties + +A B-Tree of order *n* satisfies the following properties: + - Every node has at most *2n* keys. + - Every node (except root) has at least *n* keys. + - Eyery non-leaf node with *k* keys has *k+1* children. + - The keys in all nodes are sorted in increasing order. + - The subtree between two keys *k* and *l* of a non-leaf node contains all the keys between *k* and *l*. + - All leaves appear at the same level. + +A second order B-Tree with keys from 1 to 20 looks like this: + +![A B-Tree with 20 keys.](Images/BTree20.png) + +### The representation of a B-Tree node in code + +```swift +class BTreeNode { + unowned var ownerTree: BTree + + private var keys = [Key]() + var children: [BTreeNode]? + + ... +} +``` + +The main parts of a node are two arrays: + - An array containing the keys + - An array containing the children + +![Node.](Images/Node.png) + +Nodes also have a reference to the tree they belong to. +This is necessary because nodes have to know the order of the tree. + +*Note: The array containing the children is an Optional, because leaf nodes don't have children.* + +## Searching + +1. Searching for a key `k` begins at the root node. +2. We perform a linear search on the keys of the node, until we find a key `l` that is not less than `k`, + or reach the end of the array. +3. If `k == l` then we have found the key. +4. If `k < l`: + - If the node we are on is not a leaf, then we go to the left child of `l`, and perform the steps 3.-5. again. + - If we are on a leaf, then `k` is not in the tree. +5. If we have reached the end of the array: + - If we are on a non-leaf node, then we go to the last child of the node, and perform the steps 3.-5. again. + - If we are on a leaf, then `k` is not in the tree. + +### The code + +`valueForKey(_:)` method searches for the given key and if it's in the tree, +it returns the value associated with it, else it returns `nil`. + +## Insertion + +Keys can only be inserted to leaf nodes. + +1. Perform a search for the key `k` we want to insert. +2. If we haven't found it and we are on a leaf node, we can insert it. + - If after the search the key `l` which we are standing on is greater than `k`: + We insert `k` to the position before `l`. + - Else: + We insert `k` to the position after `l`. + +After insertion we should check if the number of keys in the node is in the correct range. +If there are more keys in the node than `order*2`, we need to split the node. + +####Splitting a node + +1. Move up the middle key of the node we want to split, to its parent (if it has one). +2. If it hasn't got a parent(it is the root), then create a new root and insert to it. + Also add the old root as the left child of the new root. +3. Split the node into two by moving the keys (and children, if it's a non-leaf) that were after the middle key + to a new node. +4. Add the new node as a right child for the key that we have moved up. + +After splitting a node it is possible that the parent node will also contain too many keys, so we need to split it also. +In the worst case the splitting goes up to the root (in this case the height of the tree increases). + +An insertion to a first order tree looks like this: + +![Splitting](Images/InsertionSplit.png) + +### The code + +The method `insertValue(_:forKey:)` does the insertion. +After it has inserted a key, as the recursion goes up every node checks the number of keys in its child. +if a node has too many keys, its parent calls the `splitChild(_:atIndex:)` method on it. + +The root node is checked by the tree itself. +If the root has too many nodes after the insertion the tree calls the `splitRoot()` method. + +## Removal + +Keys can only be removed from leaf nodes. + +1. Perform a search for the key `k` we want to remove. +2. If we have found it: + - If we are on a leaf node: + We can remove the key. + - Else: + We overwrite `k` with its inorder predecessor `p`, then we remove `p` from the leaf node. + +After a key have been removed from a node we should check that the node has enough keys. +If a node has fewer keys than the order of the tree, then we should move a key to it, +or merge it with one of its siblings. + +####Moving a key to the child + +If the problematic node has a nearest sibling that has more keys than the order of the tree, +we should perform this operation on the tree, else we should merge the node with one of its siblings. + +Let's say the child we want to fix `c1` is at index `i` in its parent node's children array. + +If the child `c2` at index `i-1` has more keys than the order of the tree: + +1. We move the key at index `i-1` from the parent node to the child `c1`'s keys array at index `0`. +2. We move the last key from `c2` to the parent's keys array at index `i-1`. +3. (If `c1` is non-leaf) We move the last children from `c1` to `c2`'s children array at index 0. + +Else: + +1. We move the key at index `i` from the parent node to the end of child `c1`'s keys array. +2. We move the first key from `c2` to the parent's keys array at index `i`. +3. (If `c1` isn't a leaf) We move the first children from `c2` to the end of `c1`'s children array. + +![Moving Key](Images/MovingKey.png) + +####Merging two nodes + +Let's say we want to merge the child `c1` at index `i` in its parent's children array. + +If `c1` has a left sibling `c2`: + +1. We move the key from the parent at index `i-1` to the end of `c2`'s keys array. +2. We move the keys and the children(if it's a non-leaf) from `c1` to the end of `c2`'s keys and children array. +3. We remove the children at index `i` from the parent node. + +Else if `c1` only has a right sibling `c2`: + +1. We move the key from the parent at index `i` to the beginning of `c2`'s keys array. +2. We move the keys and the children(if it's a non-leaf) from `c1` to the beginning of `c2`'s keys and children array. +3. We remove the children at index `i` from the parent node. + +After merging it is possible that now the parent node contains too few keys, +so in the worst case merging also can go up to the root, in which case the height of the tree decreases. + +![Merging Nodes](Images/MergingNodes.png) + +### The code + +- `removeKey(_:)` method removes the given key from the tree. After a key has been deleted, + every node checks the number of keys in its child. If a child has less nodes than the order of the tree, + it calls the `fixChildWithLessNodesThanOrder(_:atIndex:)` method. + +- `fixChildWithLessNodesThanOrder(_:atIndex:)` method decides which way to fix the child (by moving a key to it, + or by merging it), then calls `moveKeyAtIndex(keyIndex:toNode:fromNode:atPosition:)` or + `mergeChild(_:withIndex:toNodeAtPosition:)` method according to its choice. + +## See also + +[Wikipedia](https://en.wikipedia.org/wiki/B-tree) +[GeeksforGeeks](http://www.geeksforgeeks.org/b-tree-set-1-introduction-2/) + +*Written for Swift Algorithm Club by Viktor Szilárd Simkó* diff --git a/BTree/Tests/Tests.xcodeproj/project.pbxproj b/BTree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..0780f04c8 --- /dev/null +++ b/BTree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,268 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + C66702821D0EEE5F008CD769 /* BTreeNodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C66702801D0EEE5F008CD769 /* BTreeNodeTests.swift */; }; + C66702831D0EEE5F008CD769 /* BTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C66702811D0EEE5F008CD769 /* BTreeTests.swift */; }; + C66702851D0EEE99008CD769 /* BTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = C66702841D0EEE99008CD769 /* BTree.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C66702781D0EEE25008CD769 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C667027C1D0EEE25008CD769 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C66702801D0EEE5F008CD769 /* BTreeNodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BTreeNodeTests.swift; sourceTree = ""; }; + C66702811D0EEE5F008CD769 /* BTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BTreeTests.swift; sourceTree = ""; }; + C66702841D0EEE99008CD769 /* BTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BTree.swift; path = ../../BTree.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C66702751D0EEE25008CD769 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C66702611D0EEE0D008CD769 = { + isa = PBXGroup; + children = ( + C66702791D0EEE25008CD769 /* Tests */, + C667026B1D0EEE0D008CD769 /* Products */, + ); + sourceTree = ""; + }; + C667026B1D0EEE0D008CD769 /* Products */ = { + isa = PBXGroup; + children = ( + C66702781D0EEE25008CD769 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + C66702791D0EEE25008CD769 /* Tests */ = { + isa = PBXGroup; + children = ( + C66702841D0EEE99008CD769 /* BTree.swift */, + C66702801D0EEE5F008CD769 /* BTreeNodeTests.swift */, + C66702811D0EEE5F008CD769 /* BTreeTests.swift */, + C667027C1D0EEE25008CD769 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C66702771D0EEE25008CD769 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = C667027D1D0EEE25008CD769 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + C66702741D0EEE25008CD769 /* Sources */, + C66702751D0EEE25008CD769 /* Frameworks */, + C66702761D0EEE25008CD769 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = C66702781D0EEE25008CD769 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C66702621D0EEE0D008CD769 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Viktor Szilárd Simkó"; + TargetAttributes = { + C66702771D0EEE25008CD769 = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = C66702651D0EEE0D008CD769 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C66702611D0EEE0D008CD769; + productRefGroup = C667026B1D0EEE0D008CD769 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C66702771D0EEE25008CD769 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C66702761D0EEE25008CD769 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C66702741D0EEE25008CD769 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C66702831D0EEE5F008CD769 /* BTreeTests.swift in Sources */, + C66702821D0EEE5F008CD769 /* BTreeNodeTests.swift in Sources */, + C66702851D0EEE99008CD769 /* BTree.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C667026F1D0EEE0D008CD769 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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"; + }; + name = Debug; + }; + C66702701D0EEE0D008CD769 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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; + }; + name = Release; + }; + C667027E1D0EEE25008CD769 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C667027F1D0EEE25008CD769 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C66702651D0EEE0D008CD769 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C667026F1D0EEE0D008CD769 /* Debug */, + C66702701D0EEE0D008CD769 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C667027D1D0EEE25008CD769 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C667027E1D0EEE25008CD769 /* Debug */, + C667027F1D0EEE25008CD769 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C66702621D0EEE0D008CD769 /* Project object */; +} diff --git a/BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..d9200547d --- /dev/null +++ b/BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BTree/Tests/Tests/BTreeNodeTests.swift b/BTree/Tests/Tests/BTreeNodeTests.swift new file mode 100644 index 000000000..07457d937 --- /dev/null +++ b/BTree/Tests/Tests/BTreeNodeTests.swift @@ -0,0 +1,54 @@ +// +// BTreeNodeTests.swift +// BTree +// +// Created by Viktor Szilárd Simkó on 13/06/16. +// Copyright © 2016 Viktor Szilárd Simkó. All rights reserved. +// + +import XCTest + +class BTreeNodeTests: XCTestCase { + + let ownerTree = BTree(order: 2)! + var root: BTreeNode! + var leftChild: BTreeNode! + var rightChild: BTreeNode! + + override func setUp() { + super.setUp() + + root = BTreeNode(ownerTree: ownerTree) + leftChild = BTreeNode(ownerTree: ownerTree) + rightChild = BTreeNode(ownerTree: ownerTree) + + root.insertValue(1, forKey: 1) + root.children = [leftChild, rightChild] + } + + func testIsLeafRoot() { + XCTAssertFalse(root.isLeaf) + } + + func testIsLeafLeaf() { + XCTAssertTrue(leftChild.isLeaf) + XCTAssertTrue(rightChild.isLeaf) + } + + func testOwner() { + XCTAssert(root.ownerTree === ownerTree) + XCTAssert(leftChild.ownerTree === ownerTree) + XCTAssert(rightChild.ownerTree === ownerTree) + } + + func testNumberOfKeys() { + XCTAssertEqual(root.numberOfKeys, 1) + XCTAssertEqual(leftChild.numberOfKeys, 0) + XCTAssertEqual(rightChild.numberOfKeys, 0) + } + + func testChildren() { + XCTAssertEqual(root.children!.count, 2) + } +} + diff --git a/BTree/Tests/Tests/BTreeTests.swift b/BTree/Tests/Tests/BTreeTests.swift new file mode 100644 index 000000000..77337c5e4 --- /dev/null +++ b/BTree/Tests/Tests/BTreeTests.swift @@ -0,0 +1,257 @@ +// +// BTreeTests.swift +// BTreeTests +// +// Created by Viktor Szilárd Simkó on 09/06/16. +// Copyright © 2016 Viktor Szilárd Simkó. All rights reserved. +// + +import XCTest + +class BTreeTests: XCTestCase { + var bTree: BTree! + + override func setUp() { + super.setUp() + bTree = BTree(order: 3)! + } + + // MARK: - Tests on empty tree + + func testOrder() { + XCTAssertEqual(bTree.order, 3) + } + + func testRootNode() { + XCTAssertNotNil(bTree.rootNode) + } + + func testNumberOfNodesOnEmptyTree() { + XCTAssertEqual(bTree.numberOfKeys, 0) + } + + func testInorderTraversalOfEmptyTree() { + bTree.traverseKeysInOrder { i in + XCTFail("Inorder travelsal fail.") + } + } + + func testSubscriptOnEmptyTree() { + XCTAssertEqual(bTree[1], nil) + } + + func testSearchEmptyTree() { + XCTAssertEqual(bTree.valueForKey(1), nil) + } + + func testInsertToEmptyTree() { + bTree.insertValue(1, forKey: 1) + + XCTAssertEqual(bTree[1]!, 1) + } + + func testRemoveFromEmptyTree() { + bTree.removeKey(1) + XCTAssertEqual(bTree.description, "[]") + } + + func testInorderArrayFromEmptyTree() { + XCTAssertEqual(bTree.inorderArrayFromKeys(), [Int]()) + } + + func testDescriptionOfEmptyTree() { + XCTAssertEqual(bTree.description, "[]") + } + + // MARK: - Travelsal + + func testInorderTravelsal() { + for i in 1...20 { + bTree.insertValue(i, forKey: i) + } + + var j = 1 + + bTree.traverseKeysInOrder { i in + XCTAssertEqual(i, j) + j += 1 + } + } + + // MARK: - Searching + + func testSearchForMaximum() { + for i in 1...20 { + bTree.insertValue(i, forKey: i) + } + + XCTAssertEqual(bTree.valueForKey(20)!, 20) + } + + func testSearchForMinimum() { + for i in 1...20 { + bTree.insertValue(i, forKey: i) + } + + XCTAssertEqual(bTree.valueForKey(1)!, 1) + } + + // MARK: - Insertion + + func testInsertion() { + bTree.insertKeysUpTo(20) + + XCTAssertEqual(bTree.numberOfKeys, 20) + + for i in 1...20 { + XCTAssertNotNil(bTree[i]) + } + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + + XCTAssertEqual(bTree.description, + "[4, 8, 12, 16][1, 2, 3][5, 6, 7][9, 10, 11][13, 14, 15][17, 18, 19, 20]") + } + + // MARK: - Removal + + func testRemoveMaximum() { + for i in 1...20 { + bTree.insertValue(i, forKey: i) + } + + bTree.removeKey(20) + + XCTAssertNil(bTree[20]) + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + } + + func testRemoveMinimum() { + bTree.insertKeysUpTo(20) + + bTree.removeKey(1) + + XCTAssertNil(bTree[1]) + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + } + + func testRemoveSome() { + bTree.insertKeysUpTo(20) + + bTree.removeKey(6) + bTree.removeKey(9) + + XCTAssertNil(bTree[6]) + XCTAssertNil(bTree[9]) + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + + XCTAssertEqual(bTree.description, + "[7, 12, 16][1, 2, 3, 4, 5][8, 10, 11][13, 14, 15][17, 18, 19, 20]") + } + + func testRemoveSomeFrom2ndOrder() { + bTree = BTree(order: 2)! + bTree.insertKeysUpTo(20) + + bTree.removeKey(6) + bTree.removeKey(9) + + XCTAssertNil(bTree[6]) + XCTAssertNil(bTree[9]) + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + + XCTAssertEqual(bTree.description, + "[12][4, 8][1, 2, 3][5, 7][10, 11][15, 18][13, 14][16, 17][19, 20]") + } + + func testRemoveAll() { + bTree.insertKeysUpTo(20) + + XCTAssertEqual(bTree.numberOfKeys, 20) + + for i in (1...20).reverse() { + bTree.removeKey(i) + } + + do { + try bTree.checkBalanced() + } catch { + XCTFail("BTree is not balanced") + } + + XCTAssertEqual(bTree.numberOfKeys, 0) + } + + // MARK: - InorderArray + + func testInorderArray() { + bTree.insertKeysUpTo(20) + + let returnedArray = bTree.inorderArrayFromKeys() + let targetArray = Array(1...20) + + XCTAssertEqual(returnedArray, targetArray) + } +} + +enum BTreeError: ErrorType { + case TooManyNodes + case TooFewNodes +} + +extension BTreeNode { + func checkBalanced(isRoot root: Bool) throws { + if numberOfKeys > ownerTree.order * 2 { + throw BTreeError.TooManyNodes + } else if !root && numberOfKeys < ownerTree.order { + throw BTreeError.TooFewNodes + } + + if !isLeaf { + for child in children! { + try child.checkBalanced(isRoot: false) + } + } + } +} + +extension BTree where Key: SignedIntegerType, Value: SignedIntegerType { + func insertKeysUpTo(to: Int) { + var k: Key = 1 + var v: Value = 1 + + for _ in 1...to { + insertValue(v, forKey: k) + k = k + 1 + v = v + 1 + } + } + + func checkBalanced() throws { + try rootNode.checkBalanced(isRoot: true) + } +} diff --git a/BTree/Tests/Tests/Info.plist b/BTree/Tests/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/BTree/Tests/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 + + From 01248c5725728cfe8f56b06c7f44a55353c7d469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Fri, 17 Jun 2016 10:50:17 +0200 Subject: [PATCH 0007/1275] cleaned up tests --- BTree/Tests/Tests/BTreeTests.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/BTree/Tests/Tests/BTreeTests.swift b/BTree/Tests/Tests/BTreeTests.swift index 77337c5e4..947781478 100644 --- a/BTree/Tests/Tests/BTreeTests.swift +++ b/BTree/Tests/Tests/BTreeTests.swift @@ -112,9 +112,6 @@ class BTreeTests: XCTestCase { } catch { XCTFail("BTree is not balanced") } - - XCTAssertEqual(bTree.description, - "[4, 8, 12, 16][1, 2, 3][5, 6, 7][9, 10, 11][13, 14, 15][17, 18, 19, 20]") } // MARK: - Removal @@ -163,9 +160,6 @@ class BTreeTests: XCTestCase { } catch { XCTFail("BTree is not balanced") } - - XCTAssertEqual(bTree.description, - "[7, 12, 16][1, 2, 3, 4, 5][8, 10, 11][13, 14, 15][17, 18, 19, 20]") } func testRemoveSomeFrom2ndOrder() { @@ -183,9 +177,6 @@ class BTreeTests: XCTestCase { } catch { XCTFail("BTree is not balanced") } - - XCTAssertEqual(bTree.description, - "[12][4, 8][1, 2, 3][5, 7][10, 11][15, 18][13, 14][16, 17][19, 20]") } func testRemoveAll() { From c40de6e3685f70244b265dedb3a54a8f6384cdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Fri, 17 Jun 2016 10:56:05 +0200 Subject: [PATCH 0008/1275] added test in .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0b14e9a40..a7861ed76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ script: - xctool test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests +- xctool test -project ./BTree\ BTree/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Graph/Graph.xcodeproj -scheme GraphTests From 25e470ca002e3b7e104eb646a92843e9226980d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Fri, 17 Jun 2016 11:08:41 +0200 Subject: [PATCH 0009/1275] renamed folder --- .travis.yml | 2 +- {BTree => B-Tree}/BTree.playground/Contents.swift | 0 .../BTree.playground/Sources/BTree.swift | 0 .../BTree.playground/contents.xcplayground | 0 .../playground.xcworkspace/contents.xcworkspacedata | 0 {BTree => B-Tree}/BTree.swift | 0 {BTree => B-Tree}/Images/BTree20.png | Bin {BTree => B-Tree}/Images/InsertionSplit.png | Bin {BTree => B-Tree}/Images/MergingNodes.png | Bin {BTree => B-Tree}/Images/MovingKey.png | Bin {BTree => B-Tree}/Images/Node.png | Bin {BTree => B-Tree}/README.md | 0 .../Tests/Tests.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Tests.xcscheme | 0 {BTree => B-Tree}/Tests/Tests/BTreeNodeTests.swift | 0 {BTree => B-Tree}/Tests/Tests/BTreeTests.swift | 0 {BTree => B-Tree}/Tests/Tests/Info.plist | 0 18 files changed, 1 insertion(+), 1 deletion(-) rename {BTree => B-Tree}/BTree.playground/Contents.swift (100%) rename {BTree => B-Tree}/BTree.playground/Sources/BTree.swift (100%) rename {BTree => B-Tree}/BTree.playground/contents.xcplayground (100%) rename {BTree => B-Tree}/BTree.playground/playground.xcworkspace/contents.xcworkspacedata (100%) rename {BTree => B-Tree}/BTree.swift (100%) rename {BTree => B-Tree}/Images/BTree20.png (100%) rename {BTree => B-Tree}/Images/InsertionSplit.png (100%) rename {BTree => B-Tree}/Images/MergingNodes.png (100%) rename {BTree => B-Tree}/Images/MovingKey.png (100%) rename {BTree => B-Tree}/Images/Node.png (100%) rename {BTree => B-Tree}/README.md (100%) rename {BTree => B-Tree}/Tests/Tests.xcodeproj/project.pbxproj (100%) rename {BTree => B-Tree}/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {BTree => B-Tree}/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme (100%) rename {BTree => B-Tree}/Tests/Tests/BTreeNodeTests.swift (100%) rename {BTree => B-Tree}/Tests/Tests/BTreeTests.swift (100%) rename {BTree => B-Tree}/Tests/Tests/Info.plist (100%) diff --git a/.travis.yml b/.travis.yml index a7861ed76..019948716 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - xctool test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./BTree\ BTree/Tests/Tests.xcodeproj -scheme Tests +- xctool test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests - xctool test -project ./Graph/Graph.xcodeproj -scheme GraphTests diff --git a/BTree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift similarity index 100% rename from BTree/BTree.playground/Contents.swift rename to B-Tree/BTree.playground/Contents.swift diff --git a/BTree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift similarity index 100% rename from BTree/BTree.playground/Sources/BTree.swift rename to B-Tree/BTree.playground/Sources/BTree.swift diff --git a/BTree/BTree.playground/contents.xcplayground b/B-Tree/BTree.playground/contents.xcplayground similarity index 100% rename from BTree/BTree.playground/contents.xcplayground rename to B-Tree/BTree.playground/contents.xcplayground diff --git a/BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata b/B-Tree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata similarity index 100% rename from BTree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata rename to B-Tree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/BTree/BTree.swift b/B-Tree/BTree.swift similarity index 100% rename from BTree/BTree.swift rename to B-Tree/BTree.swift diff --git a/BTree/Images/BTree20.png b/B-Tree/Images/BTree20.png similarity index 100% rename from BTree/Images/BTree20.png rename to B-Tree/Images/BTree20.png diff --git a/BTree/Images/InsertionSplit.png b/B-Tree/Images/InsertionSplit.png similarity index 100% rename from BTree/Images/InsertionSplit.png rename to B-Tree/Images/InsertionSplit.png diff --git a/BTree/Images/MergingNodes.png b/B-Tree/Images/MergingNodes.png similarity index 100% rename from BTree/Images/MergingNodes.png rename to B-Tree/Images/MergingNodes.png diff --git a/BTree/Images/MovingKey.png b/B-Tree/Images/MovingKey.png similarity index 100% rename from BTree/Images/MovingKey.png rename to B-Tree/Images/MovingKey.png diff --git a/BTree/Images/Node.png b/B-Tree/Images/Node.png similarity index 100% rename from BTree/Images/Node.png rename to B-Tree/Images/Node.png diff --git a/BTree/README.md b/B-Tree/README.md similarity index 100% rename from BTree/README.md rename to B-Tree/README.md diff --git a/BTree/Tests/Tests.xcodeproj/project.pbxproj b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj similarity index 100% rename from BTree/Tests/Tests.xcodeproj/project.pbxproj rename to B-Tree/Tests/Tests.xcodeproj/project.pbxproj diff --git a/BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from BTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme similarity index 100% rename from BTree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme rename to B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/BTree/Tests/Tests/BTreeNodeTests.swift b/B-Tree/Tests/Tests/BTreeNodeTests.swift similarity index 100% rename from BTree/Tests/Tests/BTreeNodeTests.swift rename to B-Tree/Tests/Tests/BTreeNodeTests.swift diff --git a/BTree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift similarity index 100% rename from BTree/Tests/Tests/BTreeTests.swift rename to B-Tree/Tests/Tests/BTreeTests.swift diff --git a/BTree/Tests/Tests/Info.plist b/B-Tree/Tests/Tests/Info.plist similarity index 100% rename from BTree/Tests/Tests/Info.plist rename to B-Tree/Tests/Tests/Info.plist From 7dd0cb5cca1baa5115b5e111454d279cef42ad03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Fri, 17 Jun 2016 13:59:36 +0200 Subject: [PATCH 0010/1275] Added playground contents. --- B-Tree/BTree.playground/Contents.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift index 7d2973f77..186718bbd 100644 --- a/B-Tree/BTree.playground/Contents.swift +++ b/B-Tree/BTree.playground/Contents.swift @@ -8,3 +8,19 @@ bTree.insertValue(1, forKey: 1) bTree.insertValue(2, forKey: 2) bTree.insertValue(3, forKey: 3) bTree.insertValue(4, forKey: 4) + +bTree.valueForKey(3) +bTree[3] + +bTree.removeKey(2) + +bTree.traverseKeysInOrder { + key in + print(key) +} + +bTree.numberOfKeys + +bTree.order + +bTree.inorderArrayFromKeys() \ No newline at end of file From 396924baef1ec0bfad18d7105ec86419676f6d0c Mon Sep 17 00:00:00 2001 From: "Michael C. Rael" Date: Sat, 18 Jun 2016 09:38:31 -0600 Subject: [PATCH 0011/1275] Completed documentation. Also changed external parameter name in cover from 'from' to 'within'. --- Set Cover (Unweighted)/README.markdown | 12 ++++++++--- .../SetCover.playground/Contents.swift | 20 +++++++++---------- .../Sources/SetCover.swift | 2 +- Set Cover (Unweighted)/SetCover.swift | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown index 48b5f3bfa..fde032438 100644 --- a/Set Cover (Unweighted)/README.markdown +++ b/Set Cover (Unweighted)/README.markdown @@ -10,16 +10,22 @@ For example, suppose you have a universe of `{1, 5, 7}` and you want to find the > {2} > {1, 2, 3} -You can see that the sets `{3, 1} {7, 6, 5, 4}` when unioned together will cover the universe of `{1, 5, 7}`. Yes, there may be additional elements in the sets returned by the algorithm, but every element in the universe is represented. +You can see that the sets `{3, 1} {7, 6, 5, 4}` when unioned together will cover the universe of `{1, 5, 7}`. Yes, there may be additional elements in the sets returned by the algorithm, but every element in the universe is represented in the cover itself. -If there is no cover within the group of sets, the function returns nil. For example, if your universe is `{7, 9}`, there is no combination of sets within the grouping above that will yield a cover. +There may be cases where no cover exists. For example, if your universe is `{7, 9}`, there is no combination of sets within the group above that will yield a cover. ## The algorithm -The Greedy Set Cover algorithm (unweighted) is provided here. It's known as greedy because it uses the largest intersecting set from the group of sets first before examining other sets in the group. +The Greedy Set Cover algorithm (unweighted) is provided here. It's known as greedy because it uses the largest intersecting set from the group of sets first before examining other sets in the group. This is part of the reason why the cover may have additional elements which are not part of the universe. The function (named `cover`) is provided as an extension of the Swift type `Set`. The function takes a single parameter, which is an array of sets. This array represents the group, and the set itself represents the universe. +One of the first things done in `cover` is to make a copy of the universe in `remainingSet`. Then, the algorithm enters a `while` loop in which a call to `largestIntersectingSet` is made. The value returned from `largestIntersectingSet` is the set which has the most elements in common with the remaining universe identified by `remainingSet`. If all sets have nothing in common, `largestIntersectingSet` returns `nil`. + +If the result from `largestIntersectingSet` is not nil, that result is subtracted from `remainingSet` (reducing its size), and the loop continues until `remainingSet` has zero length (meaning a cover has been found) or until `largestIntersectingSet` returns `nil`. + +If there is no cover within the group of sets, `cover` returns `nil`. + ## See also [Set cover problem on Wikipedia](https://en.wikipedia.org/wiki/Set_cover_problem) diff --git a/Set Cover (Unweighted)/SetCover.playground/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift index 3822f16e3..6fac33e6d 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Contents.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Contents.swift @@ -1,31 +1,31 @@ let universe1 = Set(1...7) let array1 = randomArrayOfSets(covering: universe1) -let cover1 = universe1.cover(from: array1) +let cover1 = universe1.cover(within: array1) let universe2 = Set(1...10) let array2: Array> = [[1,2,3,4,5,6,7], [8,9]] -let cover2 = universe2.cover(from: array2) +let cover2 = universe2.cover(within: array2) let universe3 = Set(["tall", "heavy"]) let array3: Array> = [["tall", "light"], ["short", "heavy"], ["tall", "heavy", "young"]] -let cover3 = universe3.cover(from: array3) +let cover3 = universe3.cover(within: array3) let universe4 = Set(["tall", "heavy", "green"]) -let cover4 = universe4.cover(from: array3) +let cover4 = universe4.cover(within: array3) let universe5: Set = [16, 32, 64] let array5: Array> = [[16,17,18], [16,32,128], [1,2,3], [32,64,128]] -let cover5 = universe5.cover(from: array5) +let cover5 = universe5.cover(within: array5) let universe6: Set = [24, 89, 132, 90, 22] let array6 = randomArrayOfSets(covering: universe6) -let cover6 = universe6.cover(from: array6) +let cover6 = universe6.cover(within: array6) let universe7: Set = ["fast", "cheap", "good"] let array7 = randomArrayOfSets(covering: universe7, minArraySizeFactor: 20.0, maxSetSizeFactor: 0.7) -let cover7 = universe7.cover(from: array7) +let cover7 = universe7.cover(within: array7) let emptySet = Set() -let coverTest1 = emptySet.cover(from: array1) -let coverTest2 = universe1.cover(from: Array>()) -let coverTest3 = emptySet.cover(from: Array>()) \ No newline at end of file +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/SetCover.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift index 8e608cb52..c739a595a 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -1,5 +1,5 @@ public extension Set { - func cover(from array: Array>) -> Array>? { + func cover(within array: Array>) -> Array>? { var result: [Set]? = [Set]() var remainingSet = self diff --git a/Set Cover (Unweighted)/SetCover.swift b/Set Cover (Unweighted)/SetCover.swift index 58ffade9d..587da4d9d 100644 --- a/Set Cover (Unweighted)/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.swift @@ -1,5 +1,5 @@ extension Set { - func cover(from array: Array>) -> Array>? { + func cover(within array: Array>) -> Array>? { var result: [Set]? = [Set]() var remainingSet = self From f81304b29683e25e6b8947c5f96ab124ff1bbf97 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 26 Jun 2016 17:15:23 -0700 Subject: [PATCH 0012/1275] Fixed some typos --- B-Tree/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/B-Tree/README.md b/B-Tree/README.md index 0a25c44c3..28b617ca1 100644 --- a/B-Tree/README.md +++ b/B-Tree/README.md @@ -7,7 +7,7 @@ A B-Tree is a self-balancing search tree, in which nodes can have more than two A B-Tree of order *n* satisfies the following properties: - Every node has at most *2n* keys. - Every node (except root) has at least *n* keys. - - Eyery non-leaf node with *k* keys has *k+1* children. + - Every non-leaf node with *k* keys has *k+1* children. - The keys in all nodes are sorted in increasing order. - The subtree between two keys *k* and *l* of a non-leaf node contains all the keys between *k* and *l*. - All leaves appear at the same level. @@ -47,10 +47,10 @@ This is necessary because nodes have to know the order of the tree. or reach the end of the array. 3. If `k == l` then we have found the key. 4. If `k < l`: - - If the node we are on is not a leaf, then we go to the left child of `l`, and perform the steps 3.-5. again. + - If the node we are on is not a leaf, then we go to the left child of `l`, and perform the steps 3 - 5 again. - If we are on a leaf, then `k` is not in the tree. 5. If we have reached the end of the array: - - If we are on a non-leaf node, then we go to the last child of the node, and perform the steps 3.-5. again. + - If we are on a non-leaf node, then we go to the last child of the node, and perform the steps 3 - 5 again. - If we are on a leaf, then `k` is not in the tree. ### The code From d680e0648f07e5ddf8912d5fa2bc845ba25ec18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Viktor?= Date: Mon, 27 Jun 2016 09:35:56 +0200 Subject: [PATCH 0013/1275] Fixed link to B-Tree in README.md --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index d36aec465..c125742fc 100644 --- a/README.markdown +++ b/README.markdown @@ -152,7 +152,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. - Fibonacci Heap - Trie -- B-Tree +- [B-Tree](B-Tree/). A self-balancing search tree, in which nodes can have more than two children. ### Hashing From 1da67165b48b33ff421fd8dfd2ac9883e5bdb83e Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 27 Jun 2016 21:17:12 -0700 Subject: [PATCH 0014/1275] Altered the tree diagram so that one of the leafs is actually labeled as a leaf rather than a node --- Tree/Images/Tree.png | Bin 19207 -> 21989 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Tree/Images/Tree.png b/Tree/Images/Tree.png index 751dac2e33741afc1489102e8dcd1642f018360b..59ef800cbac28467b3ebcd9d5e51e0b2eec4f09f 100644 GIT binary patch literal 21989 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 Date: Tue, 28 Jun 2016 16:09:53 +0200 Subject: [PATCH 0015/1275] Removing swiftlint warnings from Set Cover (Unweighted) --- .../SetCover.playground/Contents.swift | 4 ++-- .../Sources/RandomArrayOfSets.swift | 14 +++++++------- .../SetCover.playground/Sources/SetCover.swift | 14 +++++++------- Set Cover (Unweighted)/SetCover.swift | 14 +++++++------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Set Cover (Unweighted)/SetCover.playground/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift index 6fac33e6d..dcf998a66 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Contents.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Contents.swift @@ -3,7 +3,7 @@ let array1 = randomArrayOfSets(covering: universe1) let cover1 = universe1.cover(within: array1) let universe2 = Set(1...10) -let array2: Array> = [[1,2,3,4,5,6,7], [8,9]] +let array2: Array> = [[1, 2, 3, 4, 5, 6, 7], [8, 9]] let cover2 = universe2.cover(within: array2) let universe3 = Set(["tall", "heavy"]) @@ -14,7 +14,7 @@ let universe4 = Set(["tall", "heavy", "green"]) let cover4 = universe4.cover(within: array3) let universe5: Set = [16, 32, 64] -let array5: Array> = [[16,17,18], [16,32,128], [1,2,3], [32,64,128]] +let array5: Array> = [[16, 17, 18], [16, 32, 128], [1, 2, 3], [32, 64, 128]] let cover5 = universe5.cover(within: array5) let universe6: Set = [24, 89, 132, 90, 22] diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift index 64253014b..b64d8d70e 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -5,17 +5,17 @@ public func randomArrayOfSets(covering universe: Set, maxSetSizeFactor: Double = 0.6) -> Array> { var result = [Set]() var ongoingUnion = Set() - + let minArraySize = Int(Double(universe.count) * minArraySizeFactor) var maxSetSize = Int(Double(universe.count) * maxSetSizeFactor) if maxSetSize > universe.count { maxSetSize = universe.count } - + while true { var generatedSet = Set() let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) - + while true { let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) for (setIndex, value) in universe.enumerate() { @@ -24,20 +24,20 @@ public func randomArrayOfSets(covering universe: Set, break } } - + if generatedSet.count == targetSetSize { result.append(generatedSet) ongoingUnion = ongoingUnion.union(generatedSet) break } } - + if result.count >= minArraySize { if ongoingUnion == universe { break } } } - + return result -} \ No newline at end of file +} diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift index c739a595a..0e93caf0b 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -2,11 +2,11 @@ public extension Set { func cover(within array: Array>) -> Array>? { var result: [Set]? = [Set]() var remainingSet = self - + func largestIntersectingSet() -> Set? { var largestIntersectionLength = 0 var largestSet: Set? - + for set in array { let intersectionLength = remainingSet.intersect(set).count if intersectionLength > largestIntersectionLength { @@ -14,20 +14,20 @@ public extension Set { largestSet = set } } - + return largestSet } - + while remainingSet.count != 0 { guard let largestSet = largestIntersectingSet() else { break } result!.append(largestSet) remainingSet = remainingSet.subtract(largestSet) } - + if remainingSet.count != 0 || self.count == 0 { result = nil } - + return result } -} \ No newline at end of file +} diff --git a/Set Cover (Unweighted)/SetCover.swift b/Set Cover (Unweighted)/SetCover.swift index 587da4d9d..86be6729b 100644 --- a/Set Cover (Unweighted)/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.swift @@ -2,11 +2,11 @@ extension Set { func cover(within array: Array>) -> Array>? { var result: [Set]? = [Set]() var remainingSet = self - + func largestIntersectingSet() -> Set? { var largestIntersectionLength = 0 var largestSet: Set? - + for set in array { let intersectionLength = remainingSet.intersect(set).count if intersectionLength > largestIntersectionLength { @@ -14,20 +14,20 @@ extension Set { largestSet = set } } - + return largestSet } - + while remainingSet.count != 0 { guard let largestSet = largestIntersectingSet() else { break } result!.append(largestSet) remainingSet = remainingSet.subtract(largestSet) } - + if remainingSet.count != 0 || self.count == 0 { result = nil } - + return result } -} \ No newline at end of file +} From 31935d9ac62b7ad4d3a8464d855211cf29ece79e Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 28 Jun 2016 17:07:39 +0200 Subject: [PATCH 0016/1275] Set cover (unweighted) - replacing count = 0 conditions with isEmpty --- .../SetCover.playground/Sources/SetCover.swift | 4 ++-- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ Set Cover (Unweighted)/SetCover.swift | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 Set Cover (Unweighted)/SetCover.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift index 0e93caf0b..8d40e1fda 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -18,13 +18,13 @@ public extension Set { return largestSet } - while remainingSet.count != 0 { + while !remainingSet.isEmpty { guard let largestSet = largestIntersectingSet() else { break } result!.append(largestSet) remainingSet = remainingSet.subtract(largestSet) } - if remainingSet.count != 0 || self.count == 0 { + if !remainingSet.isEmpty || isEmpty { result = nil } diff --git a/Set Cover (Unweighted)/SetCover.playground/playground.xcworkspace/contents.xcworkspacedata b/Set Cover (Unweighted)/SetCover.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Set Cover (Unweighted)/SetCover.swift b/Set Cover (Unweighted)/SetCover.swift index 86be6729b..d67dfbfa9 100644 --- a/Set Cover (Unweighted)/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.swift @@ -18,13 +18,13 @@ extension Set { return largestSet } - while remainingSet.count != 0 { + while !remainingSet.isEmpty { guard let largestSet = largestIntersectingSet() else { break } result!.append(largestSet) remainingSet = remainingSet.subtract(largestSet) } - if remainingSet.count != 0 || self.count == 0 { + if !remainingSet.isEmpty || isEmpty { result = nil } From dfec36d031bfaa1e861da559498a4ebd6b367364 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 28 Jun 2016 17:09:33 +0200 Subject: [PATCH 0017/1275] Set cover (unweighted) - adding link on under construction page --- Under Construction.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/Under Construction.markdown b/Under Construction.markdown index 95ead4218..555d778e6 100644 --- a/Under Construction.markdown +++ b/Under Construction.markdown @@ -28,3 +28,4 @@ Special-purpose sorts: - [Minimum Edit Distance](Minimum Edit Distance/). Measure the similarity of two strings by counting the number of operations required to transform one string into the other. - [Treap](Treap/) +- [Set Cover (Unweighted)][Set Cover (Unweighted)/] From 824d06c19cddd5855e36e7ee3239ddd5c09d93b6 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 28 Jun 2016 17:10:50 +0200 Subject: [PATCH 0018/1275] Set cover (unweighted) - adding link on under construction page --- Under Construction.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Under Construction.markdown b/Under Construction.markdown index 555d778e6..0c59d90c1 100644 --- a/Under Construction.markdown +++ b/Under Construction.markdown @@ -28,4 +28,4 @@ Special-purpose sorts: - [Minimum Edit Distance](Minimum Edit Distance/). Measure the similarity of two strings by counting the number of operations required to transform one string into the other. - [Treap](Treap/) -- [Set Cover (Unweighted)][Set Cover (Unweighted)/] +- [Set Cover (Unweighted)](Set Cover (Unweighted)/) From 912c21d455aa7cda0579d9ffc68bdb211b5cfdee Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 30 Jun 2016 10:50:21 -0700 Subject: [PATCH 0019/1275] Fixed a typo in the main readme markdown file --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index c125742fc..b1947a6c8 100644 --- a/README.markdown +++ b/README.markdown @@ -214,7 +214,7 @@ The Swift Algorithm Club was originally created by [Matthijs Hollemans](https:// It is now maintained by [Chris Pilcher](https://github.com/chris-pilcher) and [Kelvin Lau](https://github.com/kelvinlauKL). -The Swift Algorithm Club is a 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](How to Contribute.markdown)? :] +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](How to Contribute.markdown)? :] ## License From c77a74803bc87a59cfac94f9bda8a5291b68ba68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81s=20Pesate?= Date: Fri, 1 Jul 2016 15:30:58 +0200 Subject: [PATCH 0020/1275] Added preconditions to subscript to avoid unwanted changes or crashes. --- Array2D/Array2D.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Array2D/Array2D.swift b/Array2D/Array2D.swift index ca84275f3..6177974d7 100644 --- a/Array2D/Array2D.swift +++ b/Array2D/Array2D.swift @@ -19,6 +19,9 @@ public struct Array2D { return array[row*columns + column] } set { + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + array[row*columns + column] = newValue } } From 358ea45332f92c6d2a29d64c7c786a0acf1784da Mon Sep 17 00:00:00 2001 From: Stephen Rutstein Date: Wed, 13 Jul 2016 23:20:12 -0500 Subject: [PATCH 0021/1275] Palindromes swift file, playground, and README file added --- .../Palindromes.playground/Contents.swift | 36 +++++++++++ .../contents.xcplayground | 4 ++ Palindromes/Palindromes.swift | 21 ++++++ Palindromes/README.markdown | 64 +++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 Palindromes/Palindromes.playground/Contents.swift create mode 100644 Palindromes/Palindromes.playground/contents.xcplayground create mode 100644 Palindromes/Palindromes.swift create mode 100644 Palindromes/README.markdown diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift new file mode 100644 index 000000000..c89231d09 --- /dev/null +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -0,0 +1,36 @@ +import Cocoa + +public func palindromeCheck (text: String?) -> Bool { + if let text = text { + let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let length: Int = mutableText.characters.count + + if length < 1 { + return false + } + + if length == 1 { + return true + } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { + let range = Range(mutableText.startIndex.successor().. + + + \ No newline at end of file diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift new file mode 100644 index 000000000..96269fe23 --- /dev/null +++ b/Palindromes/Palindromes.swift @@ -0,0 +1,21 @@ +import Cocoa + +public func palindromeCheck (text: String?) -> Bool { + if let text = text { + let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let length: Int = mutableText.characters.count + + if length < 1 { + return false + } + + if length == 1 { + return true + } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { + let range = Range(mutableText.startIndex.successor().. Bool { + if let text = text { + let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let length: Int = mutableText.characters.count + + if length < 1 { + return false + } + + if length == 1 { + return true + } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { + let range = Range(mutableText.startIndex.successor().. Date: Wed, 13 Jul 2016 23:24:07 -0500 Subject: [PATCH 0022/1275] Updated README --- Palindromes/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index d27605ed4..a595408ca 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -25,7 +25,7 @@ original String. Here is a recursive implementation of this in Swift: -``swift +```swift func palindromeCheck (text: String?) -> Bool { if let text = text { let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString @@ -45,7 +45,7 @@ func palindromeCheck (text: String?) -> Bool { return false } -`` +``` This code can be tested in a playground using the following: From 58c0128fb7d1235ae39ad23782db76543fe65fe8 Mon Sep 17 00:00:00 2001 From: srutstein21 Date: Wed, 13 Jul 2016 23:25:13 -0500 Subject: [PATCH 0023/1275] Updating markdown format for README --- Palindromes/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index a595408ca..a0696ff93 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -50,9 +50,9 @@ func palindromeCheck (text: String?) -> Bool { This code can be tested in a playground using the following: -``swift +```swift palindromeCheck("Race car") -`` +``` Since the phrase "Race car" is a palindrome, this will return true. From d67c81f1f82bec733a60e8819539c7b4781b32e2 Mon Sep 17 00:00:00 2001 From: lionel0806 Date: Thu, 14 Jul 2016 23:27:11 +0800 Subject: [PATCH 0024/1275] Processing index out of bounds --- Heap/Heap.swift | 4 ++++ Heap/Tests/HeapTests.swift | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index 64bd90cd8..bf7031abe 100644 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -112,6 +112,8 @@ public struct Heap { * larger than the old one; in a min-heap it should be smaller. */ public mutating func replace(index i: Int, value: T) { + guard i < elements.count else { return } + assert(isOrderedBefore(value, elements[i])) elements[i] = value shiftUp(index: i) @@ -141,6 +143,8 @@ public struct Heap { * to know the node's index, which may actually take O(n) steps to find. */ public mutating func removeAtIndex(i: Int) -> T? { + guard i < elements.count else { return nil } + let size = elements.count - 1 if i != size { swap(&elements[i], &elements[size]) diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index ec17560a5..6178a8094 100644 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -196,6 +196,12 @@ class HeapTests: XCTestCase { XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) + //test index out of bounds + let v = h.removeAtIndex(10) + XCTAssertEqual(v, nil) + XCTAssertTrue(verifyMaxHeap(h)) + XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) + let v1 = h.removeAtIndex(5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) @@ -308,5 +314,10 @@ class HeapTests: XCTestCase { 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]) } } From 5524ef40ca461c445e40952011560fee391f414f Mon Sep 17 00:00:00 2001 From: Lukas Schramm Date: Sat, 16 Jul 2016 17:41:37 +0200 Subject: [PATCH 0025/1275] Added SlowSort --- Slow Sort/README.markdown | 50 +++++++++++++++++++ Slow Sort/SlowSort.swift | 28 +++++++++++ .../contents.xcworkspacedata | 7 +++ 3 files changed, 85 insertions(+) create mode 100644 Slow Sort/README.markdown create mode 100644 Slow Sort/SlowSort.swift diff --git a/Slow Sort/README.markdown b/Slow Sort/README.markdown new file mode 100644 index 000000000..f8cc743cc --- /dev/null +++ b/Slow Sort/README.markdown @@ -0,0 +1,50 @@ +# Slow Sort + +Goal: Sort an array of numbers from low to high (or high to low). + +You are given an array of numbers and need to put them in the right order. The insertion sort algorithm works as follows: + +We can decompose the problem of sorting n numbers in ascending order into + +1. find the maximum of the numbers + 1. find the maximum of the first n/2 elements + 2. find the maximum of the remaining n/2 elements + 3. find the largest of those two maxima +2. sorting the remaining ones + +## The code + +Here is an implementation of slow sort in Swift: + +```swift +public func slowsort(_ i: Int, _ j: Int) { + if i>=j { + return + } + let m = (i+j)/2 + slowsort(i,m) + slowsort(m+1,j) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowsort(i,j-1) +} +``` + +## Performance + +| Case | Performance | +|:-------------: |:---------------:| +| Worst | slow | +| Best | O(n^(log(n)/(2+e)))) | +| Average | O(n^(log(n)/2)) | + +## See also + +[Slow Sort explanation in the Internet](http://c2.com/cgi/wiki?SlowSort) + +*Written for Swift Algorithm Club by Lukas Schramm* + +(used the Insertion Sort Readme as template) \ No newline at end of file diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift new file mode 100644 index 000000000..c21a77fd8 --- /dev/null +++ b/Slow Sort/SlowSort.swift @@ -0,0 +1,28 @@ +// +// SlowSort.swift +// +// +// Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. +// +// + +var numberList = [1,12,9,17,13,12] + +public func slowsort(_ i: Int, _ j: Int) { + if i>=j { + return + } + let m = (i+j)/2 + slowsort(i,m) + slowsort(m+1,j) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowsort(i,j-1) +} + + +slowsort(0,numberList.count-1) +print(numberList) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4e0f19dc2..3feeaa5c2 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1019,6 +1019,13 @@ + + + + From 185e7caab77acdb6ae830f17ed1ab9ce6774d78b Mon Sep 17 00:00:00 2001 From: Stephen Rutstein Date: Sun, 17 Jul 2016 00:59:48 -0500 Subject: [PATCH 0026/1275] Added files for Comb Sort --- Comb Sort/Comb Sort.playground/Contents.swift | 50 ++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 ++ Comb Sort/Comb Sort.swift | 36 +++++++++ Comb Sort/README.markdown | 78 +++++++++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 Comb Sort/Comb Sort.playground/Contents.swift create mode 100644 Comb Sort/Comb Sort.playground/contents.xcplayground create mode 100644 Comb Sort/Comb Sort.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Comb Sort/Comb Sort.swift create mode 100644 Comb Sort/README.markdown diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift new file mode 100644 index 000000000..3bc03546a --- /dev/null +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -0,0 +1,50 @@ +// Comb Sort Function +// Created by Stephen Rutstein +// 7-16-2016 + +import Cocoa + +func combSort (input: [Int]) -> [Int] { + var copy: [Int] = input + var gap = copy.count + let shrink = 1.3 + + while gap > 1 { + gap = (Int)(Double(gap) / shrink) + if gap < 1 { + gap = 1 + } + + var index = 0 + while !(index + gap >= copy.count) { + if copy[index] > copy[index + gap] { + swap(©[index], ©[index + gap]) + } + index += 1 + } + } + return copy +} + +// A function to swap two integer values +// Used for swapping within the array of values. +func swap (inout a: Int, inout b: Int) { + let temp = a + a = b + b = temp +} + +// Test Comb Sort with small array of ten values +let array: [Int] = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] +combSort(array) + +// Test Comb Sort with large array of 1000 random values +var bigArray = [Int](count: 1000, repeatedValue: 0) +var i = 0 +while i < 1000 { + bigArray[i] = Int(arc4random_uniform(1000) + 1) + i += 1 +} +combSort(bigArray) + + diff --git a/Comb Sort/Comb Sort.playground/contents.xcplayground b/Comb Sort/Comb Sort.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Comb Sort/Comb Sort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Comb Sort/Comb Sort.playground/playground.xcworkspace/contents.xcworkspacedata b/Comb Sort/Comb Sort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Comb Sort/Comb Sort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Comb Sort/Comb Sort.swift b/Comb Sort/Comb Sort.swift new file mode 100644 index 000000000..7abba8c7f --- /dev/null +++ b/Comb Sort/Comb Sort.swift @@ -0,0 +1,36 @@ +// Comb Sort.swift +// Comb Sort +// +// Created by Stephen.Rutstein on 7/16/16. +// Copyright © 2016 Stephen.Rutstein. All rights reserved. +// + +import Foundation + +func combSort (input: [Int]) -> [Int] { + var copy: [Int] = input + var gap = copy.count + let shrink = 1.3 + + while gap > 1 { + gap = (Int)(Double(gap) / shrink) + if gap < 1 { + gap = 1 + } + + var index = 0 + while !(index + gap >= copy.count) { + if copy[index] > copy[index + gap] { + swap(©[index], ©[index + gap]) + } + index += 1 + } + } + return copy +} + +func swap (inout a: Int, inout b: Int) { + let temp = a + a = b + b = temp +} diff --git a/Comb Sort/README.markdown b/Comb Sort/README.markdown new file mode 100644 index 000000000..fedbc5705 --- /dev/null +++ b/Comb Sort/README.markdown @@ -0,0 +1,78 @@ +# Comb Sort + +A common issue for Bubble Sort is when small values are located near the end of an array. +This problem severely slows down Bubble Sort, as it must move the small value -- or _turtle_ -- +through nearly the entire array. Bubble Sort works by checking the current index of an array +against the next index, and when those two values are unsorted, they are swapped into place. +As a result, the values bubble into their rightful place within the array. + +Comb Sort improves upon Bubble Sort by dealing with these turtles near the end of the array. +The value of the current index of the array is compared against one a set distance away. This +removes a worst-case scenario of Bubble Sort, and greatly improves on the time complexity of Bubble Sort. + +## Example + +A step-by-step example of how Comb Sort works, and differs from Bubble Sort, can be seen [here](http://www.exforsys.com/tutorials/c-algorithms/comb-sort.html). + +Here is a visual to see Comb Sort in effect: +![](https://upload.wikimedia.org/wikipedia/commons/4/46/Comb_sort_demo.gif) + +## Algorithm + +Similar to Bubble Sort, two values within an array are compared. When the lower index value +is larger than the higher index value, and thus out of place within the array, they are +swapped. Unlike Bubble Sort, the value being compared against is a set distance away. This +value -- the _gap_ -- is slowly decreased through iterations. + +## The Code + +Here is a Swift implementation of Comb Sort: + +```swift +func combSort (input: [Int]) -> [Int] { + var copy: [Int] = input + var gap = copy.count + let shrink = 1.3 + + while gap > 1 { + gap = (Int)(Double(gap) / shrink) + if gap < 1 { + gap = 1 + } + + var index = 0 + while !(index + gap >= copy.count) { + if copy[index] > copy[index + gap] { + swap(©[index], ©[index + gap]) + } + index += 1 + } + } + return copy +} +``` + +This code can be tested in a playground by calling this method with a paramaterized array to sort: + +```swift +combSort(example_array_of_values) +``` + +This will sort the values of the array into ascending order -- increasing in value. + +## 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. + +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. + + +## Additional Resources + +[Comb Sort Wikipedia](https://en.wikipedia.org/wiki/Comb_sort) + + +*Written for the _Swift Algorithm Club_ by [Stephen Rutstein](https://github.com/srutstein21)* From 0951ea332ec1ec7b8e700321d1558fd1ea4b35bc Mon Sep 17 00:00:00 2001 From: Stephen Rutstein Date: Sun, 17 Jul 2016 01:03:35 -0500 Subject: [PATCH 0027/1275] Quick change to the read me file to fix spacing --- Comb Sort/README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/Comb Sort/README.markdown b/Comb Sort/README.markdown index fedbc5705..d30d429b3 100644 --- a/Comb Sort/README.markdown +++ b/Comb Sort/README.markdown @@ -15,6 +15,7 @@ removes a worst-case scenario of Bubble Sort, and greatly improves on the time c A step-by-step example of how Comb Sort works, and differs from Bubble Sort, can be seen [here](http://www.exforsys.com/tutorials/c-algorithms/comb-sort.html). Here is a visual to see Comb Sort in effect: + ![](https://upload.wikimedia.org/wikipedia/commons/4/46/Comb_sort_demo.gif) ## Algorithm From ab2d1a2c7c4017c0c3a37011abe82883ba9a565f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 17 Jul 2016 08:49:31 -0700 Subject: [PATCH 0028/1275] Tweaks to palindrome article. Linked up Palindrome alg on front page --- Palindromes/Palindromes.playground/Contents.swift | 4 ++-- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ Palindromes/Palindromes.swift | 4 ++-- Palindromes/README.markdown | 4 ++-- README.markdown | 1 + 5 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 Palindromes/Palindromes.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index c89231d09..b548182af 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -2,10 +2,10 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString let length: Int = mutableText.characters.count - if length < 1 { + guard length >= 1 else { return false } diff --git a/Palindromes/Palindromes.playground/playground.xcworkspace/contents.xcworkspacedata b/Palindromes/Palindromes.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Palindromes/Palindromes.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index 96269fe23..61e7740ab 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -2,10 +2,10 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString let length: Int = mutableText.characters.count - if length < 1 { + guard length >= 1 else { return false } diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index a0696ff93..3df775e31 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -28,10 +28,10 @@ Here is a recursive implementation of this in Swift: ```swift func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).lowercaseString + let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString let length: Int = mutableText.characters.count - if length < 1 { + guard length >= 1 { return false } diff --git a/README.markdown b/README.markdown index b1947a6c8..3d011a178 100644 --- a/README.markdown +++ b/README.markdown @@ -183,6 +183,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Two-Sum Problem](Two-Sum Problem/) - [Fizz Buzz](Fizz Buzz/) - [Monty Hall Problem](Monty Hall Problem/) +- [Finding Palindromes](Palindromes/) ## Learn more! From 790533767da1213c2886ae3f7790b950b14b702d Mon Sep 17 00:00:00 2001 From: jamesharrop Date: Sun, 17 Jul 2016 21:15:17 +0100 Subject: [PATCH 0029/1275] First draft of Linear Regression First draft --- .../Contents.swift | 23 +++++++++++++++++++ .../contents.xcplayground | 4 ++++ .../contents.xcworkspacedata | 7 ++++++ Linear Regression/README.markdown | 19 +++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 Linear Regression/LinearRegression.playground/Contents.swift create mode 100644 Linear Regression/LinearRegression.playground/contents.xcplayground create mode 100644 Linear Regression/LinearRegression.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Linear Regression/README.markdown diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift new file mode 100644 index 000000000..2b111ce68 --- /dev/null +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -0,0 +1,23 @@ +// Linear Regression + +import Foundation + +let carAge: [Double] = [10, 8, 3, 3, 2, 1] +let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] +var intercept = 10000.0 +var slope = -1000.0 +let alpha = 0.0001 +let numberOfCarAdvertsWeSaw = carPrice.count + +func h(carAge: Double) -> Double { + return intercept + slope * carAge +} + +for n in 1...10000 { + for i in 1...numberOfCarAdvertsWeSaw { + intercept += alpha * (carPrice[i-1] - h(carAge[i-1])) * 1 + slope += alpha * (carPrice[i-1] - h(carAge[i-1])) * carAge[i-1] + } +} + +print("A car age 4 years is predicted to be worth £\(Int(h(4)))") diff --git a/Linear Regression/LinearRegression.playground/contents.xcplayground b/Linear Regression/LinearRegression.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Linear Regression/LinearRegression.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Linear Regression/LinearRegression.playground/playground.xcworkspace/contents.xcworkspacedata b/Linear Regression/LinearRegression.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Linear Regression/LinearRegression.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown new file mode 100644 index 000000000..1aa03fbe8 --- /dev/null +++ b/Linear Regression/README.markdown @@ -0,0 +1,19 @@ +# Linear Regression +## First draft version of this document + +Linear regression is a technique for creating a model of the relationship between two (or more) variable quantities. + +For example, let's say we are planning to sell a car. We are not sure how much money to ask for. So we look at recent advertisments for the asking prices of other cars. There are a lot of variables we could look at - for example: make, model, engine size. To simplify our task, we collect data on just the age of the car and the price: + +Age (in years)| Price (in £) +--------------|------------- +10 | 500 +8 | 400 +3 | 7,000 +3 | 8,500 +2 | 11,000 +1 | 10,500 + +Our car is 4 years old. How can we set a price for our car based on the data in this table? + +*Written for Swift Algorithm Club by James Harrop* \ No newline at end of file From 9f96077964cbf5d300888034ccf89bfe3ce44612 Mon Sep 17 00:00:00 2001 From: John Pham Date: Mon, 18 Jul 2016 16:23:19 +0700 Subject: [PATCH 0030/1275] Remove comma at end of array --- Merge Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index 023e18b32..a24c71f2f 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -19,7 +19,7 @@ Assume you're given an array of *n* numbers and you need to put them in the righ Let's say the numbers to sort are `[2, 1, 5, 4, 9]`. This is your unsorted pile. The goal is to keep splitting the pile until you can't split anymore. -First, split the array into two halves: `[2, 1,]` and `[5, 4, 9]`. Can you keep splitting them? Yes you can! +First, split the array into two halves: `[2, 1]` and `[5, 4, 9]`. Can you keep splitting them? Yes you can! Focus on the left pile. `[2, 1]` will split into `[2]` and `[1]`. Can you keep splitting them? No. Time to check the other pile. From 236c4e4b632f45e0d487eae168291ca836ed570f Mon Sep 17 00:00:00 2001 From: jamesharrop Date: Fri, 22 Jul 2016 22:03:23 +0100 Subject: [PATCH 0031/1275] Playground and readme file completed --- Linear Regression/Images/graph1.png | Bin 0 -> 22918 bytes Linear Regression/Images/graph2.png | Bin 0 -> 43570 bytes Linear Regression/Images/graph3.png | Bin 0 -> 31467 bytes .../Contents.swift | 47 ++++-- Linear Regression/README.markdown | 149 +++++++++++++++++- 5 files changed, 185 insertions(+), 11 deletions(-) create mode 100644 Linear Regression/Images/graph1.png create mode 100644 Linear Regression/Images/graph2.png create mode 100644 Linear Regression/Images/graph3.png diff --git a/Linear Regression/Images/graph1.png b/Linear Regression/Images/graph1.png new file mode 100644 index 0000000000000000000000000000000000000000..bffe838ef01e2d68a8b00963276fa0dc141e40ea GIT binary patch literal 22918 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 al{H3Ro0f`B&#>T{D19Bn<3(C_fBiR81dewA literal 0 HcmV?d00001 diff --git a/Linear Regression/Images/graph2.png b/Linear Regression/Images/graph2.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb45b1a8ed6355b52ecc1007880860251a9c195 GIT binary patch literal 43570 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 z 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 Double { +func predictedCarPrice(carAge: Double) -> Double { return intercept + slope * carAge } -for n in 1...10000 { - for i in 1...numberOfCarAdvertsWeSaw { - intercept += alpha * (carPrice[i-1] - h(carAge[i-1])) * 1 - slope += alpha * (carPrice[i-1] - h(carAge[i-1])) * carAge[i-1] +// An iterative approach + +let numberOfCarAdvertsWeSaw = carPrice.count - 1 +let numberOfIterations = 100 +let alpha = 0.0001 + +for n in 1...numberOfIterations { + for i in 0...numberOfCarAdvertsWeSaw { + let difference = carPrice[i] - predictedCarPrice(carAge[i]) + intercept += alpha * difference + slope += alpha * difference * carAge[i] } } -print("A car age 4 years is predicted to be worth £\(Int(h(4)))") +print("A car age of 4 years is predicted to be worth £\(Int(predictedCarPrice(4)))") + +// A closed form solution + +func average(input: [Double]) -> Double { + return input.reduce(0, combine: +) / Double(input.count) +} + +func multiply(input1: [Double], _ input2: [Double]) -> [Double] { + return input1.enumerate().map({ (index, element) in return element*input2[index] }) +} + +func linearRegression(xVariable: [Double], _ yVariable: [Double]) -> (Double -> Double) { + let sum1 = average(multiply(xVariable, yVariable)) - average(xVariable) * average(yVariable) + let sum2 = average(multiply(xVariable, xVariable)) - pow(average(xVariable), 2) + let slope = sum1 / sum2 + let intercept = average(yVariable) - slope * average(xVariable) + return { intercept + slope * $0 } +} + +let result = linearRegression(carAge, carPrice)(4) + +print("A car of age 4 years is predicted to be worth £\(Int(result))") diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 1aa03fbe8..e78514df5 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -1,5 +1,4 @@ # Linear Regression -## First draft version of this document Linear regression is a technique for creating a model of the relationship between two (or more) variable quantities. @@ -16,4 +15,152 @@ Age (in years)| Price (in £) Our car is 4 years old. How can we set a price for our car based on the data in this table? +Let's start by looking at the data plotted out: + +![graph1](Images/graph1.png) + +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. + +We can describe the straight line in terms of two variables: + +1. The point at which it crosses the y-axis i.e. the predicted price of a brand new car. This is the *intercept*. +2. The *slope* of the line - i.e. for every year of age, how much does the price change. + +This is the equation for our line: + +$$ +carPrice = slope \times carAge + intercept +$$ + +How can we find the best values for the intercept and the slope? Let's look at two different ways to do this. + +## An iterative approach +One approach is to start with some arbitrary values for the intercept and the slope. We work out what small changes we make to these values to move our line closer to the data points. Then we repeat this multiple times. Eventually our line will approach the optimum position. + +First let's set up our data structures. We will use two Swift arrays for the car age and the car price: + +```swift +let carAge: [Double] = [10, 8, 3, 3, 2, 1] +let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] +``` + +This is how we can represent our straight line: + +```swift +var intercept = 0.0 +var slope = 0.0 +func predictedCarPrice(carAge: Double) -> Double { + return intercept + slope * carAge +} +``` +Now for the code which will perform the iterations: + +```swift +let numberOfCarAdvertsWeSaw = carPrice.count - 1 +let iterations = 2000 +let alpha = 0.0001 + +for n in 1...iterations { + for i in 0...numberOfCarAdvertsWeSaw { + let difference = carPrice[i] - predictedCarPrice(carAge[i]) + intercept += alpha * difference + slope += alpha * difference * carAge[i] + } +} +``` + +```alpha``` is a factor that determines how much closer we move to the correct solution with each iteration. If this factor is too large then our program will not converge on the correct solution. + +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 minimse the square of the distance between the line and the points. Let's define a function J which represents this distance - for simplicity we consider only one point here: + +$$ +J \propto ((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: + +$$ +\frac{\partial J}{\partial (slope)} \propto (slope.carAge+intercept) - carPrice).carAge +$$ + +And similarly for the intercept: + +$$ +\frac{\partial J}{\partial (intercept)} \propto +(slope.carAge+intercept) - carPrice) +$$ + +We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. + +Looking at the code, it intuitively makes sense - the larger the difference between the current predicted car Price and the actual car price, and the larger the value of ```alpha```, the greater the adjustments to the intercept and the slope. + +It can take a lot of iterations to approach the ideal values. Let's look at how the intercept and slope change as we increase the number of iterations: + +Iterations | Intercept | Slope | Predicted value of a 4 year old car +:---------:|:---------:|:-----:|:------------------------: +0 | 0 | 0 | 0 +2000 | 4112 | -113 | 3659 +6000 | 8564 | -764 | 5507 +10000 | 10517 | -1049 | 6318 +14000 | 11374 | -1175 | 6673 +18000 | 11750 | -1230 | 6829 + +Here is the same data shown as a graph. Each of the blue lines on the graph represents a row in the table above. + +![graph2](Images/graph2.png) + +After 18,000 iterations it looks as if the line is getting closer to what we would expect (just by looking) to be the correct line of best fit. Also, each additional 2,000 iterations has less and less effect on the final result - the values of the intercept and the slope are converging on the correct values. + +##A closed form solution + +There is another way we can calculate the line of best fit, without having to do multiple iterations. We can solve the equations describing the least squares minimisation and just work out the intercept and slope directly. + +First we need some helper functions. This one calculates the average (the mean) of an array of Doubles: + +```swift +func average(input: [Double]) -> Double { + return input.reduce(0, combine: +) / Double(input.count) +} +``` +We are using the ```reduce``` Swift function to sum up all the elements of the array, and then divide that by the number of elements. This gives us the mean value. + +We also need to be able to multiply each element in an array by the corresponding element in another array, to create a new array. Here is a function which will do this: + +```swift +func multiply(input1: [Double], _ input2: [Double]) -> [Double] { + return input1.enumerate().map({ (index, element) in return element*input2[index] }) +} +``` + +We are using the ```map``` function to multiply each element. + +Finally, the function which fits the line to the data: + +```swift +func linearRegression(xVariable: [Double], _ yVariable: [Double]) -> (Double -> Double) { + let sum1 = average(multiply(xVariable, yVariable)) - average(xVariable) * average(yVariable) + let sum2 = average(multiply(xVariable, xVariable)) - pow(average(xVariable), 2) + let slope = sum1 / sum2 + let intercept = average(yVariable) - slope * average(xVariable) + return { intercept + slope * $0 } +} +``` +This function takes as arguments two arrays of Doubles, and returns a function which is the line of best fit. The formulas to calculate the slope and the intercept can be derived from our definition of the function J. Let's see how the output from this line fits our data: + +![graph3](Images/graph3.png) + +Using this line, we would predict a price for our 4 year old car of £6952. + + +##Summary +We've seen two different ways to implement a simple linear regression in Swift. An obvious question is: why bother with the iterative approach at all? + +Well, the line we've found doesn't fit the data perfectly. For one thing, the graph includes some negative values at high car ages! Possibly we would have to pay someone to tow away a very old car... but really these negative values just show that we have not modelled the real life situation very accurately. The relationship between the car age and the car price is not linear but instead is some other function. We also know that a car's price is not just related to its age but also other factors such as the make, model and engine size of the car. We would need to use additional variables to describe these other factors. + +It turns out that in some of these more complicated models, the iterative approach is the only viable or efficient approach. This can also occur when the arrays of data are very large and may be sparsely populated with data values. + *Written for Swift Algorithm Club by James Harrop* \ No newline at end of file From 0abfd03de68af02f62d1b41298e364d634362e15 Mon Sep 17 00:00:00 2001 From: jamesharrop Date: Fri, 22 Jul 2016 22:11:22 +0100 Subject: [PATCH 0032/1275] Removed LaTex equations --- Linear Regression/README.markdown | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index e78514df5..3fc16ff31 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -30,9 +30,8 @@ We can describe the straight line in terms of two variables: This is the equation for our line: -$$ -carPrice = slope \times carAge + intercept -$$ +carPrice = slope * carAge + intercept + How can we find the best values for the intercept and the slope? Let's look at two different ways to do this. @@ -75,26 +74,9 @@ for n in 1...iterations { 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 minimse the square of the distance between the line and the points. Let's define a function J which represents this distance - for simplicity we consider only one point here: - -$$ -J \propto ((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: - -$$ -\frac{\partial J}{\partial (slope)} \propto (slope.carAge+intercept) - carPrice).carAge -$$ - -And similarly for the intercept: - -$$ -\frac{\partial J}{\partial (intercept)} \propto -(slope.carAge+intercept) - carPrice) -$$ +We want to minimse 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 proprotional to ((slope.carAge+intercept) - carPrice))^2 -We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. +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. Looking at the code, it intuitively makes sense - the larger the difference between the current predicted car Price and the actual car price, and the larger the value of ```alpha```, the greater the adjustments to the intercept and the slope. From a9aa744dd0a389bb6f2efa8b9c9e9a65ace0a8d9 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 28 Jul 2016 07:03:07 -0700 Subject: [PATCH 0033/1275] Indexed the Linear Regression article in the main read.me file. Also made a code style change. --- Linear Regression/LinearRegression.playground/Contents.swift | 4 ++-- README.markdown | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 07ebe6a5d..585471487 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -13,12 +13,12 @@ func predictedCarPrice(carAge: Double) -> Double { // An iterative approach -let numberOfCarAdvertsWeSaw = carPrice.count - 1 +let numberOfCarAdvertsWeSaw = carPrice.count let numberOfIterations = 100 let alpha = 0.0001 for n in 1...numberOfIterations { - for i in 0...numberOfCarAdvertsWeSaw { + for i in 0.. Date: Thu, 28 Jul 2016 07:03:49 -0700 Subject: [PATCH 0034/1275] Minor code style change in read.me file of Linear Regression --- 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 3fc16ff31..c04e3b3dc 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -57,12 +57,12 @@ func predictedCarPrice(carAge: Double) -> Double { Now for the code which will perform the iterations: ```swift -let numberOfCarAdvertsWeSaw = carPrice.count - 1 +let numberOfCarAdvertsWeSaw = carPrice.count let iterations = 2000 let alpha = 0.0001 for n in 1...iterations { - for i in 0...numberOfCarAdvertsWeSaw { + for i in 0.. Date: Sun, 31 Jul 2016 09:56:27 +0900 Subject: [PATCH 0035/1275] Add public access in Tree --- Tree/Tree.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tree/Tree.swift b/Tree/Tree.swift index 89f1a39da..39d1f3df5 100644 --- a/Tree/Tree.swift +++ b/Tree/Tree.swift @@ -25,7 +25,7 @@ extension TreeNode: CustomStringConvertible { } extension TreeNode where T: Equatable { - func search(value: T) -> TreeNode? { + public func search(value: T) -> TreeNode? { if value == self.value { return self } From c95bec277b89eda7992abfe4716281d3bf136301 Mon Sep 17 00:00:00 2001 From: Tim Camber Date: Mon, 1 Aug 2016 12:59:24 -0400 Subject: [PATCH 0036/1275] Adds Knuth-Morris-Pratt to Substring Searches --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 35dad0aff..418cb1fa8 100644 --- a/README.markdown +++ b/README.markdown @@ -55,6 +55,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [Brute-Force String Search](Brute-Force String Search/). A naive method. - [Boyer-Moore](Boyer-Moore/). A fast method to search for substrings. It skips ahead based on a look-up table, to avoid looking at every character in the text. +- Knuth-Morris-Pratt - Rabin-Karp - [Longest Common Subsequence](Longest Common Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. From 9c5aad72a5bf760088377ce0dc4ee0113337de9d Mon Sep 17 00:00:00 2001 From: Ian Alexander Rahman Date: Mon, 1 Aug 2016 22:02:35 -0400 Subject: [PATCH 0037/1275] Minor grammatical fixes --- K-Means/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/K-Means/README.markdown b/K-Means/README.markdown index bebcf225b..774cc18d2 100644 --- a/K-Means/README.markdown +++ b/K-Means/README.markdown @@ -45,11 +45,11 @@ The selection of initial centroids was fortuitous! We found the lower left clust #### Bad clustering -The next two examples highlight the unpredictability of k-Means and how it not always finds the best clustering. +The next two examples highlight the unpredictability of k-Means and how it does not always find the best clustering. ![Bad Clustering 1](Images/k_means_bad1.png) -As you can see in this one, the initial centroids were all a little too close to one another, and the blue one didn't quite get to a good place. By adjusting the convergence distance we should be able to get it better. +As you can see in this example, the initial centroids were all a little too close to one another, and the blue one didn't quite get to a good place. By adjusting the convergence distance we should be able to improve the fit of our centroids to the data. ![Bad Clustering 1](Images/k_means_bad2.png) From 4d56039855507bdbe090f8ecb1b7dc52b9ab6329 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 3 Aug 2016 22:41:05 -0700 Subject: [PATCH 0038/1275] Minor styling fixes to comb sort --- Comb Sort/Comb Sort.playground/Contents.swift | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift index 3bc03546a..2d6155b50 100644 --- a/Comb Sort/Comb Sort.playground/Contents.swift +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -5,45 +5,37 @@ import Cocoa func combSort (input: [Int]) -> [Int] { - var copy: [Int] = input - var gap = copy.count - let shrink = 1.3 - - while gap > 1 { - gap = (Int)(Double(gap) / shrink) - if gap < 1 { - gap = 1 - } - - var index = 0 - while !(index + gap >= copy.count) { - if copy[index] > copy[index + gap] { - swap(©[index], ©[index + gap]) - } - index += 1 - } + var copy = input + var gap = copy.count + let shrink = 1.3 + + while gap > 1 { + gap = Int(Double(gap) / shrink) + if gap < 1 { + gap = 1 } - return copy -} -// A function to swap two integer values -// Used for swapping within the array of values. -func swap (inout a: Int, inout b: Int) { - let temp = a - a = b - b = temp + var index = 0 + while index + gap < copy.count { + if copy[index] > copy[index + gap] { + swap(©[index], ©[index + gap]) + } + index += 1 + } + } + return copy } // Test Comb Sort with small array of ten values -let array: [Int] = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] +let array = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] combSort(array) // Test Comb Sort with large array of 1000 random values var bigArray = [Int](count: 1000, repeatedValue: 0) var i = 0 while i < 1000 { - bigArray[i] = Int(arc4random_uniform(1000) + 1) - i += 1 + bigArray[i] = Int(arc4random_uniform(1000) + 1) + i += 1 } combSort(bigArray) From 5046c1f6fd1496528ac7a072100aa625a31be03c Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 3 Aug 2016 22:43:42 -0700 Subject: [PATCH 0039/1275] Added Comb Sort to main readme file --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 35dad0aff..233bd94f3 100644 --- a/README.markdown +++ b/README.markdown @@ -92,6 +92,7 @@ Bad sorting algorithms (don't use these!): ### Miscellaneous - [Shuffle](Shuffle/). Randomly rearranges the contents of an array. +- [Comb Sort](Comb Sort/). An improve upon the Bubble Sort algorithm. ### Mathematics From bbee485a20d3f8ce77243d110506abce87fd0042 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 17 Aug 2016 19:36:23 +0200 Subject: [PATCH 0040/1275] Create README.md --- Skip-List/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Skip-List/README.md diff --git a/Skip-List/README.md b/Skip-List/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Skip-List/README.md @@ -0,0 +1 @@ + From 559c0b1c7039a87c769c10545f5731fad0da39e0 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Thu, 18 Aug 2016 22:43:03 +1200 Subject: [PATCH 0041/1275] Xcode auto migration to Swift 3 --- AVL Tree/AVLTree.swift | 62 +++++++++---------- AVL Tree/Tests/AVLTreeTests.swift | 24 +++---- .../Tests/Tests.xcodeproj/project.pbxproj | 3 + 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/AVL Tree/AVLTree.swift b/AVL Tree/AVLTree.swift index 580a51e8e..427d3da11 100644 --- a/AVL Tree/AVLTree.swift +++ b/AVL Tree/AVLTree.swift @@ -20,16 +20,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -public class TreeNode { +open class TreeNode { public typealias Node = TreeNode - public var payload: Payload? + open var payload: Payload? - private var key: Key + fileprivate var key: Key internal var leftChild: Node? internal var rightChild: Node? - private var height: Int - weak private var parent: Node? + fileprivate var height: Int + weak fileprivate var parent: Node? public init(key: Key, payload: Payload?, leftChild: Node?, rightChild: Node?, parent: Node?, height: Int) { self.key = key @@ -51,46 +51,46 @@ public class TreeNode { self.init(key: key, payload: nil) } - public var isRoot: Bool { + open var isRoot: Bool { return parent == nil } - public var isLeaf: Bool { + open var isLeaf: Bool { return rightChild == nil && leftChild == nil } - public var isLeftChild: Bool { + open var isLeftChild: Bool { return parent?.leftChild === self } - public var isRightChild: Bool { + open var isRightChild: Bool { return parent?.rightChild === self } - public var hasLeftChild: Bool { + open var hasLeftChild: Bool { return leftChild != nil } - public var hasRightChild: Bool { + open var hasRightChild: Bool { return rightChild != nil } - public var hasAnyChild: Bool { + open var hasAnyChild: Bool { return leftChild != nil || rightChild != nil } - public var hasBothChildren: Bool { + open var hasBothChildren: Bool { return leftChild != nil && rightChild != nil } } // MARK: - The AVL tree -public class AVLTree { +open class AVLTree { public typealias Node = TreeNode - private(set) public var root: Node? - private(set) public var size = 0 + fileprivate(set) open var root: Node? + fileprivate(set) open var size = 0 public init() { } } @@ -119,7 +119,7 @@ extension AVLTree { set { insert(key, newValue) } } - public func search(input: Key) -> Payload? { + public func search(_ input: Key) -> Payload? { if let result = search(input, root) { return result.payload } else { @@ -127,7 +127,7 @@ extension AVLTree { } } - private func search(key: Key, _ node: Node?) -> Node? { + fileprivate func search(_ key: Key, _ node: Node?) -> Node? { if let node = node { if key == node.key { return node @@ -144,7 +144,7 @@ extension AVLTree { // MARK: - Inserting new items extension AVLTree { - public func insert(key: Key, _ payload: Payload? = nil) { + public func insert(_ key: Key, _ payload: Payload? = nil) { if let root = root { insert(key, payload, root) } else { @@ -153,7 +153,7 @@ extension AVLTree { size += 1 } - private func insert(input: Key, _ payload: Payload?, _ node: Node) { + fileprivate func insert(_ input: Key, _ payload: Payload?, _ node: Node) { if input < node.key { if let child = node.leftChild { insert(input, payload, child) @@ -177,7 +177,7 @@ extension AVLTree { // MARK: - Balancing tree extension AVLTree { - private func updateHeightUpwards(node: Node?) { + fileprivate func updateHeightUpwards(_ node: Node?) { if let node = node { let lHeight = node.leftChild?.height ?? 0 let rHeight = node.rightChild?.height ?? 0 @@ -186,13 +186,13 @@ extension AVLTree { } } - private func lrDifference(node: Node?) -> Int { + fileprivate func lrDifference(_ node: Node?) -> Int { let lHeight = node?.leftChild?.height ?? 0 let rHeight = node?.rightChild?.height ?? 0 return lHeight - rHeight } - private func balance(node: Node?) { + fileprivate func balance(_ node: Node?) { guard let node = node else { return } @@ -200,8 +200,8 @@ extension AVLTree { updateHeightUpwards(node.leftChild) updateHeightUpwards(node.rightChild) - var nodes = [Node?](count: 3, repeatedValue: nil) - var subtrees = [Node?](count: 4, repeatedValue: nil) + var nodes = [Node?](repeating: nil, count: 3) + var subtrees = [Node?](repeating: nil, count: 4) let nodeParent = node.parent let lrFactor = lrDifference(node) @@ -295,7 +295,7 @@ extension AVLTree { // MARK: - Displaying tree extension AVLTree { - private func display(node: Node?, level: Int) { + fileprivate func display(_ node: Node?, level: Int) { if let node = node { display(node.rightChild, level: level + 1) print("") @@ -310,7 +310,7 @@ extension AVLTree { } } - public func display(node: Node) { + public func display(_ node: Node) { display(node, level: 0) print("") } @@ -319,7 +319,7 @@ extension AVLTree { // MARK: - Delete node extension AVLTree { - public func delete(key: Key) { + public func delete(_ key: Key) { if size == 1 { root = nil size -= 1 @@ -329,7 +329,7 @@ extension AVLTree { } } - private func delete(node: Node) { + fileprivate func delete(_ node: Node) { if node.isLeaf { // Just remove and balance up if let parent = node.parent { @@ -351,11 +351,11 @@ extension AVLTree { } } else { // Handle stem cases - if let replacement = node.leftChild?.maximum() where replacement !== node { + if let replacement = node.leftChild?.maximum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload delete(replacement) - } else if let replacement = node.rightChild?.minimum() where replacement !== node { + } else if let replacement = node.rightChild?.minimum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload delete(replacement) diff --git a/AVL Tree/Tests/AVLTreeTests.swift b/AVL Tree/Tests/AVLTreeTests.swift index 065367bb6..637f499e9 100644 --- a/AVL Tree/Tests/AVLTreeTests.swift +++ b/AVL Tree/Tests/AVLTreeTests.swift @@ -67,25 +67,25 @@ class AVLTreeTests: XCTestCase { } func testSingleInsertionPerformance() { - self.measureBlock { + self.measure { self.tree?.insert(5, "E") } } func testMultipleInsertionsPerformance() { - self.measureBlock { + self.measure { self.tree?.autopopulateWithNodes(50) } } func testSearchExistentOnSmallTreePerformance() { - self.measureBlock { + self.measure { self.tree?.search(2) } } func testSearchExistentElementOnLargeTreePerformance() { - self.measureBlock { + self.measure { self.tree?.autopopulateWithNodes(500) self.tree?.search(400) } @@ -150,8 +150,8 @@ class AVLTreeTests: XCTestCase { } } -extension AVLTree where Key : SignedIntegerType { - func autopopulateWithNodes(count: Int) { +extension AVLTree where Key : SignedInteger { + func autopopulateWithNodes(_ count: Int) { var k: Key = 1 for _ in 0...count { self.insert(k) @@ -160,12 +160,12 @@ extension AVLTree where Key : SignedIntegerType { } } -enum AVLTreeError: ErrorType { - case NotBalanced +enum AVLTreeError: Error { + case notBalanced } -extension AVLTree where Key : SignedIntegerType { - func height(node: Node?) -> Int { +extension AVLTree where Key : SignedInteger { + func height(_ node: Node?) -> Int { if let node = node { let lHeight = height(node.leftChild) let rHeight = height(node.rightChild) @@ -175,10 +175,10 @@ extension AVLTree where Key : SignedIntegerType { return 0 } - func inOrderCheckBalanced(node: Node?) throws { + func inOrderCheckBalanced(_ node: Node?) throws { if let node = node { guard abs(height(node.leftChild) - height(node.rightChild)) <= 1 else { - throw AVLTreeError.NotBalanced + throw AVLTreeError.notBalanced } try inOrderCheckBalanced(node.leftChild) try inOrderCheckBalanced(node.rightChild) diff --git a/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj index dfaf44e8d..079f0010b 100644 --- a/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj +++ b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -224,6 +225,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; }; name = Debug; }; @@ -235,6 +237,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; }; name = Release; }; From 4683bb9bf30ce68aa005111dfd3fd7b852a9091b Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Thu, 18 Aug 2016 22:49:37 +1200 Subject: [PATCH 0042/1275] Updating project to recommended settings --- AVL Tree/Tests/Tests.xcodeproj/project.pbxproj | 7 ++++++- .../Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj index 079f0010b..64c244747 100644 --- a/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj +++ b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -86,7 +86,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -150,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -194,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -214,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; diff --git a/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 18 Aug 2016 23:44:10 +1200 Subject: [PATCH 0043/1275] Removing "open" access level that was automatically included in auto migration to swift 3. Removing underscore labels. --- AVL Tree/AVLTree.swift | 102 +++++++++++++++--------------- AVL Tree/Tests/AVLTreeTests.swift | 34 +++++----- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/AVL Tree/AVLTree.swift b/AVL Tree/AVLTree.swift index 427d3da11..b4b97f0d6 100644 --- a/AVL Tree/AVLTree.swift +++ b/AVL Tree/AVLTree.swift @@ -20,10 +20,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -open class TreeNode { +public class TreeNode { public typealias Node = TreeNode - open var payload: Payload? + var payload: Payload? fileprivate var key: Key internal var leftChild: Node? @@ -51,35 +51,35 @@ open class TreeNode { self.init(key: key, payload: nil) } - open var isRoot: Bool { + var isRoot: Bool { return parent == nil } - open var isLeaf: Bool { + var isLeaf: Bool { return rightChild == nil && leftChild == nil } - open var isLeftChild: Bool { + var isLeftChild: Bool { return parent?.leftChild === self } - open var isRightChild: Bool { + var isRightChild: Bool { return parent?.rightChild === self } - open var hasLeftChild: Bool { + var hasLeftChild: Bool { return leftChild != nil } - open var hasRightChild: Bool { + var hasRightChild: Bool { return rightChild != nil } - open var hasAnyChild: Bool { + var hasAnyChild: Bool { return leftChild != nil || rightChild != nil } - open var hasBothChildren: Bool { + var hasBothChildren: Bool { return leftChild != nil && rightChild != nil } } @@ -89,8 +89,8 @@ open class TreeNode { open class AVLTree { public typealias Node = TreeNode - fileprivate(set) open var root: Node? - fileprivate(set) open var size = 0 + fileprivate(set) var root: Node? + fileprivate(set) var size = 0 public init() { } } @@ -115,26 +115,26 @@ extension TreeNode { extension AVLTree { subscript(key: Key) -> Payload? { - get { return search(key) } - set { insert(key, newValue) } + get { return search(input: key) } + set { insert(key: key, payload: newValue) } } - public func search(_ input: Key) -> Payload? { - if let result = search(input, root) { + public func search(input: Key) -> Payload? { + if let result = search(key: input, node: root) { return result.payload } else { return nil } } - fileprivate func search(_ key: Key, _ node: Node?) -> Node? { + fileprivate func search(key: Key, node: Node?) -> Node? { if let node = node { if key == node.key { return node } else if key < node.key { - return search(key, node.leftChild) + return search(key: key, node: node.leftChild) } else { - return search(key, node.rightChild) + return search(key: key, node: node.rightChild) } } return nil @@ -144,31 +144,31 @@ extension AVLTree { // MARK: - Inserting new items extension AVLTree { - public func insert(_ key: Key, _ payload: Payload? = nil) { + public func insert(key: Key, payload: Payload? = nil) { if let root = root { - insert(key, payload, root) + insert(input: key, payload: payload, node: root) } else { root = Node(key: key, payload: payload) } size += 1 } - fileprivate func insert(_ input: Key, _ payload: Payload?, _ node: Node) { + private func insert(input: Key, payload: Payload?, node: Node) { if input < node.key { if let child = node.leftChild { - insert(input, payload, child) + insert(input: input, payload: payload, node: child) } else { let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.leftChild = child - balance(child) + balance(node: child) } } else { if let child = node.rightChild { - insert(input, payload, child) + insert(input: input, payload: payload, node: child) } else { let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.rightChild = child - balance(child) + balance(node: child) } } } @@ -177,37 +177,37 @@ extension AVLTree { // MARK: - Balancing tree extension AVLTree { - fileprivate func updateHeightUpwards(_ node: Node?) { + fileprivate func updateHeightUpwards(node: Node?) { if let node = node { let lHeight = node.leftChild?.height ?? 0 let rHeight = node.rightChild?.height ?? 0 node.height = max(lHeight, rHeight) + 1 - updateHeightUpwards(node.parent) + updateHeightUpwards(node: node.parent) } } - fileprivate func lrDifference(_ node: Node?) -> Int { + fileprivate func lrDifference(node: Node?) -> Int { let lHeight = node?.leftChild?.height ?? 0 let rHeight = node?.rightChild?.height ?? 0 return lHeight - rHeight } - fileprivate func balance(_ node: Node?) { + fileprivate func balance(node: Node?) { guard let node = node else { return } - updateHeightUpwards(node.leftChild) - updateHeightUpwards(node.rightChild) + updateHeightUpwards(node: node.leftChild) + updateHeightUpwards(node: node.rightChild) var nodes = [Node?](repeating: nil, count: 3) var subtrees = [Node?](repeating: nil, count: 4) let nodeParent = node.parent - let lrFactor = lrDifference(node) + let lrFactor = lrDifference(node: node) if lrFactor > 1 { // left-left or left-right - if lrDifference(node.leftChild) > 0 { + if lrDifference(node: node.leftChild) > 0 { // left-left nodes[0] = node nodes[2] = node.leftChild @@ -230,7 +230,7 @@ extension AVLTree { } } else if lrFactor < -1 { // right-left or right-right - if lrDifference(node.rightChild) < 0 { + if lrDifference(node: node.rightChild) < 0 { // right-right nodes[1] = node nodes[2] = node.rightChild @@ -253,7 +253,7 @@ extension AVLTree { } } else { // Don't need to balance 'node', go for parent - balance(node.parent) + balance(node: node.parent) return } @@ -285,19 +285,19 @@ extension AVLTree { nodes[0]?.rightChild = subtrees[3] subtrees[3]?.parent = nodes[0] - updateHeightUpwards(nodes[1]) // Update height from left - updateHeightUpwards(nodes[0]) // Update height from right + updateHeightUpwards(node: nodes[1]) // Update height from left + updateHeightUpwards(node: nodes[0]) // Update height from right - balance(nodes[2]?.parent) + balance(node: nodes[2]?.parent) } } // MARK: - Displaying tree extension AVLTree { - fileprivate func display(_ node: Node?, level: Int) { + fileprivate func display(node: Node?, level: Int) { if let node = node { - display(node.rightChild, level: level + 1) + display(node: node.rightChild, level: level + 1) print("") if node.isRoot { print("Root -> ", terminator: "") @@ -306,12 +306,12 @@ extension AVLTree { print(" ", terminator: "") } print("(\(node.key):\(node.height))", terminator: "") - display(node.leftChild, level: level + 1) + display(node: node.leftChild, level: level + 1) } } - public func display(_ node: Node) { - display(node, level: 0) + public func display(node: Node) { + display(node: node, level: 0) print("") } } @@ -319,17 +319,17 @@ extension AVLTree { // MARK: - Delete node extension AVLTree { - public func delete(_ key: Key) { + public func delete(key: Key) { if size == 1 { root = nil size -= 1 - } else if let node = search(key, root) { - delete(node) + } else if let node = search(key: key, node: root) { + delete(node: node) size -= 1 } } - fileprivate func delete(_ node: Node) { + private func delete(node: Node) { if node.isLeaf { // Just remove and balance up if let parent = node.parent { @@ -344,7 +344,7 @@ extension AVLTree { parent.rightChild = nil } - balance(parent) + balance(node: parent) } else { // at root root = nil @@ -354,11 +354,11 @@ extension AVLTree { if let replacement = node.leftChild?.maximum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload - delete(replacement) + delete(node: replacement) } else if let replacement = node.rightChild?.minimum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload - delete(replacement) + delete(node: replacement) } } } diff --git a/AVL Tree/Tests/AVLTreeTests.swift b/AVL Tree/Tests/AVLTreeTests.swift index 637f499e9..51607d7c3 100644 --- a/AVL Tree/Tests/AVLTreeTests.swift +++ b/AVL Tree/Tests/AVLTreeTests.swift @@ -37,7 +37,7 @@ class AVLTreeTests: XCTestCase { self.tree?.autopopulateWithNodes(5) for i in 6...10 { - self.tree?.insert(i) + self.tree?.insert(key: i) do { try self.tree?.inOrderCheckBalanced(self.tree?.root) } catch _ { @@ -50,7 +50,7 @@ class AVLTreeTests: XCTestCase { self.tree?.autopopulateWithNodes(5) for i in 1...6 { - self.tree?.delete(i) + self.tree?.delete(key: i) do { try self.tree?.inOrderCheckBalanced(self.tree?.root) } catch _ { @@ -68,7 +68,7 @@ class AVLTreeTests: XCTestCase { func testSingleInsertionPerformance() { self.measure { - self.tree?.insert(5, "E") + self.tree?.insert(key: 5, payload: "E") } } @@ -80,14 +80,14 @@ class AVLTreeTests: XCTestCase { func testSearchExistentOnSmallTreePerformance() { self.measure { - self.tree?.search(2) + self.tree?.search(input: 2) } } func testSearchExistentElementOnLargeTreePerformance() { self.measure { self.tree?.autopopulateWithNodes(500) - self.tree?.search(400) + self.tree?.search(input: 400) } } @@ -106,19 +106,19 @@ class AVLTreeTests: XCTestCase { } func testDeleteExistentKey() { - self.tree?.delete(1) - XCTAssertNil(self.tree?.search(1), "Key should not exist anymore") + self.tree?.delete(key: 1) + XCTAssertNil(self.tree?.search(input: 1), "Key should not exist anymore") } func testDeleteNotExistentKey() { - self.tree?.delete(1056) - XCTAssertNil(self.tree?.search(1056), "Key should not exist") + self.tree?.delete(key: 1056) + XCTAssertNil(self.tree?.search(input: 1056), "Key should not exist") } func testInsertSize() { let tree = AVLTree() for i in 0...5 { - tree.insert(i, "") + tree.insert(key: i, payload: "") XCTAssertEqual(tree.size, i + 1, "Insert didn't update size correctly!") } } @@ -134,15 +134,15 @@ class AVLTreeTests: XCTestCase { for p in permutations { let tree = AVLTree() - tree.insert(1, "five") - tree.insert(2, "four") - tree.insert(3, "three") - tree.insert(4, "two") - tree.insert(5, "one") + tree.insert(key: 1, payload: "five") + tree.insert(key: 2, payload: "four") + tree.insert(key: 3, payload: "three") + tree.insert(key: 4, payload: "two") + tree.insert(key: 5, payload: "one") var count = tree.size for i in p { - tree.delete(i) + tree.delete(key: i) count -= 1 XCTAssertEqual(tree.size, count, "Delete didn't update size correctly!") } @@ -154,7 +154,7 @@ extension AVLTree where Key : SignedInteger { func autopopulateWithNodes(_ count: Int) { var k: Key = 1 for _ in 0...count { - self.insert(k) + self.insert(key: k) k = k + 1 } } From b094e0fde016e4cb19693a5eb3c67745c6bd9b02 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Thu, 18 Aug 2016 23:45:28 +1200 Subject: [PATCH 0044/1275] Updating travis build to Xcode 8. Commenting out projects that have not yet been migrated. --- .travis.yml | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f13f64eb..b01dfd26a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 sudo: false install: @@ -8,34 +8,34 @@ install: script: -- xctool test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests -- xctool test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Graph/Graph.xcodeproj -scheme GraphTests -- xctool test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests -- xctool test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests -- xctool test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests +# - xctool test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests + - xctool test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Graph/Graph.xcodeproj -scheme GraphTests +# - xctool test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests +# - xctool test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests +# - xctool test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests From 8df51248547fe53cf199bc6ad7cea39d8e85d8d4 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Thu, 18 Aug 2016 23:51:01 +1200 Subject: [PATCH 0045/1275] Removing "expression not used" warnings in test --- AVL Tree/Tests/AVLTreeTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AVL Tree/Tests/AVLTreeTests.swift b/AVL Tree/Tests/AVLTreeTests.swift index 51607d7c3..7765c6d29 100644 --- a/AVL Tree/Tests/AVLTreeTests.swift +++ b/AVL Tree/Tests/AVLTreeTests.swift @@ -80,14 +80,14 @@ class AVLTreeTests: XCTestCase { func testSearchExistentOnSmallTreePerformance() { self.measure { - self.tree?.search(input: 2) + print(self.tree?.search(input: 2)) } } func testSearchExistentElementOnLargeTreePerformance() { self.measure { self.tree?.autopopulateWithNodes(500) - self.tree?.search(input: 400) + print(self.tree?.search(input: 400)) } } From f0ad3f504b4bcf7bff71dd58ac37916990e59fc5 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:05:37 +1200 Subject: [PATCH 0046/1275] Disabling swift lint until all projects can be built in Xcode 8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b01dfd26a..0cb6dc728 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ sudo: false install: -- ./install_swiftlint.sh +# - ./install_swiftlint.sh script: From 9537cf8722778a7ecdaa0b3bf5bc9109e12da4c2 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:09:55 +1200 Subject: [PATCH 0047/1275] Trying to resolve build error "*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Got error while trying to deserialize event 'User defaults from command line:': The data is not in the correct format.'" --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0cb6dc728..b8199a4a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: objective-c osx_image: xcode8 -sudo: false +# sudo: false install: From 2813695209a888e6f01364d79d9c3cc2a60f3fad Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:14:20 +1200 Subject: [PATCH 0048/1275] Changing to xcodebuild as xctool fails to run tests. Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Got error while trying to deserialize event 'User defaults from command line:': The data is not in the correct format.' --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b8199a4a3..228faab79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: # - xctool test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests # - xctool test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests - - xctool test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests + - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests # - xctool test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests # - xctool test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests # - xctool test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests From 0267f61a4abd42606c7d5be4c7c5cec189944ad7 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:20:27 +1200 Subject: [PATCH 0049/1275] Changing xctool to xcodebuild for all tests --- .travis.yml | 60 ++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 228faab79..970f85aa8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,34 +8,34 @@ install: script: -# - xctool test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests -# - xctool test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests +# - 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 -# - xctool test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Graph/Graph.xcodeproj -scheme GraphTests -# - xctool test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests -# - xctool test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests -# - xctool test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests +# - xcodebuild test -project ./Binary\ Search/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 ./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 ./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.xcodeproj -scheme Tests +# - xcodebuild test -project ./Run-Length\ Encoding/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 From c104087a821fef3b2058095ea70490a152d7fc80 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:35:32 +1200 Subject: [PATCH 0050/1275] Updating playground --- AVL Tree/AVLTree.playground/Contents.swift | 22 ++-- .../AVLTree.playground/Sources/AVLTree.swift | 108 +++++++++--------- .../AVLTree.playground/timeline.xctimeline | 6 - 3 files changed, 65 insertions(+), 71 deletions(-) delete mode 100644 AVL Tree/AVLTree.playground/timeline.xctimeline diff --git a/AVL Tree/AVLTree.playground/Contents.swift b/AVL Tree/AVLTree.playground/Contents.swift index 2b8ee8b59..409dfdc49 100644 --- a/AVL Tree/AVLTree.playground/Contents.swift +++ b/AVL Tree/AVLTree.playground/Contents.swift @@ -2,26 +2,26 @@ let tree = AVLTree() -tree.insert(5, "five") +tree.insert(key: 5, payload: "five") print(tree) -tree.insert(4, "four") +tree.insert(key: 4, payload: "four") print(tree) -tree.insert(3, "three") +tree.insert(key: 3, payload: "three") print(tree) -tree.insert(2, "two") +tree.insert(key: 2, payload: "two") print(tree) -tree.insert(1, "one") +tree.insert(key: 1, payload: "one") print(tree) print(tree.debugDescription) -let node = tree.search(2) // "two" +let node = tree.search(input: 2) // "two" -tree.delete(5) -tree.delete(2) -tree.delete(1) -tree.delete(4) -tree.delete(3) +tree.delete(key: 5) +tree.delete(key: 2) +tree.delete(key: 1) +tree.delete(key: 4) +tree.delete(key: 3) diff --git a/AVL Tree/AVLTree.playground/Sources/AVLTree.swift b/AVL Tree/AVLTree.playground/Sources/AVLTree.swift index 580a51e8e..b4b97f0d6 100644 --- a/AVL Tree/AVLTree.playground/Sources/AVLTree.swift +++ b/AVL Tree/AVLTree.playground/Sources/AVLTree.swift @@ -23,13 +23,13 @@ public class TreeNode { public typealias Node = TreeNode - public var payload: Payload? + var payload: Payload? - private var key: Key + fileprivate var key: Key internal var leftChild: Node? internal var rightChild: Node? - private var height: Int - weak private var parent: Node? + fileprivate var height: Int + weak fileprivate var parent: Node? public init(key: Key, payload: Payload?, leftChild: Node?, rightChild: Node?, parent: Node?, height: Int) { self.key = key @@ -51,46 +51,46 @@ public class TreeNode { self.init(key: key, payload: nil) } - public var isRoot: Bool { + var isRoot: Bool { return parent == nil } - public var isLeaf: Bool { + var isLeaf: Bool { return rightChild == nil && leftChild == nil } - public var isLeftChild: Bool { + var isLeftChild: Bool { return parent?.leftChild === self } - public var isRightChild: Bool { + var isRightChild: Bool { return parent?.rightChild === self } - public var hasLeftChild: Bool { + var hasLeftChild: Bool { return leftChild != nil } - public var hasRightChild: Bool { + var hasRightChild: Bool { return rightChild != nil } - public var hasAnyChild: Bool { + var hasAnyChild: Bool { return leftChild != nil || rightChild != nil } - public var hasBothChildren: Bool { + var hasBothChildren: Bool { return leftChild != nil && rightChild != nil } } // MARK: - The AVL tree -public class AVLTree { +open class AVLTree { public typealias Node = TreeNode - private(set) public var root: Node? - private(set) public var size = 0 + fileprivate(set) var root: Node? + fileprivate(set) var size = 0 public init() { } } @@ -115,26 +115,26 @@ extension TreeNode { extension AVLTree { subscript(key: Key) -> Payload? { - get { return search(key) } - set { insert(key, newValue) } + get { return search(input: key) } + set { insert(key: key, payload: newValue) } } public func search(input: Key) -> Payload? { - if let result = search(input, root) { + if let result = search(key: input, node: root) { return result.payload } else { return nil } } - private func search(key: Key, _ node: Node?) -> Node? { + fileprivate func search(key: Key, node: Node?) -> Node? { if let node = node { if key == node.key { return node } else if key < node.key { - return search(key, node.leftChild) + return search(key: key, node: node.leftChild) } else { - return search(key, node.rightChild) + return search(key: key, node: node.rightChild) } } return nil @@ -144,31 +144,31 @@ extension AVLTree { // MARK: - Inserting new items extension AVLTree { - public func insert(key: Key, _ payload: Payload? = nil) { + public func insert(key: Key, payload: Payload? = nil) { if let root = root { - insert(key, payload, root) + insert(input: key, payload: payload, node: root) } else { root = Node(key: key, payload: payload) } size += 1 } - private func insert(input: Key, _ payload: Payload?, _ node: Node) { + private func insert(input: Key, payload: Payload?, node: Node) { if input < node.key { if let child = node.leftChild { - insert(input, payload, child) + insert(input: input, payload: payload, node: child) } else { let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.leftChild = child - balance(child) + balance(node: child) } } else { if let child = node.rightChild { - insert(input, payload, child) + insert(input: input, payload: payload, node: child) } else { let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.rightChild = child - balance(child) + balance(node: child) } } } @@ -177,37 +177,37 @@ extension AVLTree { // MARK: - Balancing tree extension AVLTree { - private func updateHeightUpwards(node: Node?) { + fileprivate func updateHeightUpwards(node: Node?) { if let node = node { let lHeight = node.leftChild?.height ?? 0 let rHeight = node.rightChild?.height ?? 0 node.height = max(lHeight, rHeight) + 1 - updateHeightUpwards(node.parent) + updateHeightUpwards(node: node.parent) } } - private func lrDifference(node: Node?) -> Int { + fileprivate func lrDifference(node: Node?) -> Int { let lHeight = node?.leftChild?.height ?? 0 let rHeight = node?.rightChild?.height ?? 0 return lHeight - rHeight } - private func balance(node: Node?) { + fileprivate func balance(node: Node?) { guard let node = node else { return } - updateHeightUpwards(node.leftChild) - updateHeightUpwards(node.rightChild) + updateHeightUpwards(node: node.leftChild) + updateHeightUpwards(node: node.rightChild) - var nodes = [Node?](count: 3, repeatedValue: nil) - var subtrees = [Node?](count: 4, repeatedValue: nil) + var nodes = [Node?](repeating: nil, count: 3) + var subtrees = [Node?](repeating: nil, count: 4) let nodeParent = node.parent - let lrFactor = lrDifference(node) + let lrFactor = lrDifference(node: node) if lrFactor > 1 { // left-left or left-right - if lrDifference(node.leftChild) > 0 { + if lrDifference(node: node.leftChild) > 0 { // left-left nodes[0] = node nodes[2] = node.leftChild @@ -230,7 +230,7 @@ extension AVLTree { } } else if lrFactor < -1 { // right-left or right-right - if lrDifference(node.rightChild) < 0 { + if lrDifference(node: node.rightChild) < 0 { // right-right nodes[1] = node nodes[2] = node.rightChild @@ -253,7 +253,7 @@ extension AVLTree { } } else { // Don't need to balance 'node', go for parent - balance(node.parent) + balance(node: node.parent) return } @@ -285,19 +285,19 @@ extension AVLTree { nodes[0]?.rightChild = subtrees[3] subtrees[3]?.parent = nodes[0] - updateHeightUpwards(nodes[1]) // Update height from left - updateHeightUpwards(nodes[0]) // Update height from right + updateHeightUpwards(node: nodes[1]) // Update height from left + updateHeightUpwards(node: nodes[0]) // Update height from right - balance(nodes[2]?.parent) + balance(node: nodes[2]?.parent) } } // MARK: - Displaying tree extension AVLTree { - private func display(node: Node?, level: Int) { + fileprivate func display(node: Node?, level: Int) { if let node = node { - display(node.rightChild, level: level + 1) + display(node: node.rightChild, level: level + 1) print("") if node.isRoot { print("Root -> ", terminator: "") @@ -306,12 +306,12 @@ extension AVLTree { print(" ", terminator: "") } print("(\(node.key):\(node.height))", terminator: "") - display(node.leftChild, level: level + 1) + display(node: node.leftChild, level: level + 1) } } public func display(node: Node) { - display(node, level: 0) + display(node: node, level: 0) print("") } } @@ -323,8 +323,8 @@ extension AVLTree { if size == 1 { root = nil size -= 1 - } else if let node = search(key, root) { - delete(node) + } else if let node = search(key: key, node: root) { + delete(node: node) size -= 1 } } @@ -344,21 +344,21 @@ extension AVLTree { parent.rightChild = nil } - balance(parent) + balance(node: parent) } else { // at root root = nil } } else { // Handle stem cases - if let replacement = node.leftChild?.maximum() where replacement !== node { + if let replacement = node.leftChild?.maximum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload - delete(replacement) - } else if let replacement = node.rightChild?.minimum() where replacement !== node { + delete(node: replacement) + } else if let replacement = node.rightChild?.minimum() , replacement !== node { node.key = replacement.key node.payload = replacement.payload - delete(replacement) + delete(node: replacement) } } } diff --git a/AVL Tree/AVLTree.playground/timeline.xctimeline b/AVL Tree/AVLTree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/AVL Tree/AVLTree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From cd9c8246e7c14c89503b642ee25ab12888a30f63 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Fri, 19 Aug 2016 00:45:38 +1200 Subject: [PATCH 0051/1275] Updating readme. Removing mentions of methods that are not contained in the AVLTree.swift file. --- AVL Tree/README.markdown | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 744d9a272..159f9e1dc 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -56,11 +56,7 @@ Most of the code in [AVLTree.swift](AVLTree.swift) is just regular [binary searc > **Note:** If you're a bit fuzzy on the regular operations of a binary search tree, I suggest you [catch up on those first](../Binary Search Tree/). It will make the rest of the AVL tree easier to understand. -The interesting bits are in the following methods: - -- `updateBalance()`. Called after inserting a new node. This may cause the node's parent to be rebalanced. -- `rebalance()`. Figures out how to rotate the nodes to restore the balance. -- `rotateRight()` and `rotateLeft()` perform the actual rotations. +The interesting bits are in the `balance()` method which is called after inserting or deleting a node. ## See also From aec3405f297ae40832057b8b29486ca54e012c17 Mon Sep 17 00:00:00 2001 From: lenli Date: Fri, 19 Aug 2016 18:00:48 -0400 Subject: [PATCH 0052/1275] Upgrade binary search code and test to Swift 3.0 --- .../BinarySearch.playground/Contents.swift | 59 ++------ .../Sources/BinarySearch.swift | 52 +++++++ Binary Search/BinarySearch.swift | 64 ++++++--- Binary Search/README.markdown | 131 +++++++++--------- .../project.pbxproj | 30 ++-- .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Tests.xcscheme | 26 ++-- 7 files changed, 207 insertions(+), 155 deletions(-) create mode 100644 Binary Search/BinarySearch.playground/Sources/BinarySearch.swift rename Binary Search/Tests/{Tests.xcodeproj => BinarySearchTests.xcodeproj}/project.pbxproj (89%) rename Binary Search/Tests/{Tests.xcodeproj => BinarySearchTests.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename Binary Search/Tests/{Tests.xcodeproj => BinarySearchTests.xcodeproj}/xcshareddata/xcschemes/Tests.xcscheme (77%) diff --git a/Binary Search/BinarySearch.playground/Contents.swift b/Binary Search/BinarySearch.playground/Contents.swift index fdfd37d8f..cccf9f8ac 100644 --- a/Binary Search/BinarySearch.playground/Contents.swift +++ b/Binary Search/BinarySearch.playground/Contents.swift @@ -4,53 +4,16 @@ let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 41, 23] // Binary search requires that the array is sorted from low to high -let sorted = numbers.sort() +let sorted = numbers.sorted() -/* - The recursive version of binary search. -*/ -func binarySearch(a: [T], key: T, range: Range) -> Int? { - if range.startIndex >= range.endIndex { - return nil - } else { - let midIndex = range.startIndex + (range.endIndex - range.startIndex) / 2 - if a[midIndex] > key { - return binarySearch(a, key: key, range: range.startIndex ..< midIndex) - } else if a[midIndex] < key { - return binarySearch(a, key: key, range: midIndex + 1 ..< range.endIndex) - } else { - return midIndex - } - } -} +// Using recursive solution +binarySearch(a: sorted, key: 2, range: 0 ..< sorted.count) // gives 0 +binarySearch(a: sorted, key: 67, range: 0 ..< sorted.count) // gives 18 +binarySearch(a: sorted, key: 43, range: 0 ..< sorted.count) // gives 13 +binarySearch(a: sorted, key: 42, range: 0 ..< sorted.count) // nil -binarySearch(sorted, key: 2, range: 0 ..< sorted.count) // gives 0 -binarySearch(sorted, key: 67, range: 0 ..< sorted.count) // gives 18 -binarySearch(sorted, key: 43, range: 0 ..< sorted.count) // gives 13 -binarySearch(sorted, key: 42, range: 0 ..< sorted.count) // nil - -/* - 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. -*/ -func binarySearch(a: [T], key: T) -> Int? { - var range = 0..(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: a, key: key, range: range.lowerBound ..< midIndex) + } else if a[midIndex] < key { + return binarySearch(a: 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.swift b/Binary Search/BinarySearch.swift index 5bcdf4152..d6623e355 100644 --- a/Binary Search/BinarySearch.swift +++ b/Binary Search/BinarySearch.swift @@ -1,24 +1,52 @@ -/* - Binary Search +/** + 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! + **/ - Recursively splits the array in half until the value is found. +import Foundation - If there is more than one occurrence of the search key in the array, then - there is no guarantee which one it finds. +// The recursive version of binary search. - Note: The array must be sorted! -*/ -func binarySearch(a: [T], key: T) -> Int? { - var range = 0..(_ a: [T], key: T, range: Range) -> Int? { + if range.lowerBound >= range.upperBound { + return nil } else { - range.endIndex = midIndex + 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 + } } - } - return nil +} + +/** + 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/README.markdown b/Binary Search/README.markdown index 8c5d8f0f1..6fb6e9985 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -16,12 +16,12 @@ The built-in `indexOf()` function performs a [linear search](../Linear Search/). ```swift func linearSearch(a: [T], _ key: T) -> Int? { - for i in 0 ..< a.count { - if a[i] == key { - return i - } - } - return nil +for i in 0 ..< a.count { +if a[i] == key { +return i +} +} +return nil } ``` @@ -58,27 +58,27 @@ Here is a recursive implementation of binary search in Swift: ```swift func binarySearch(a: [T], key: T, range: Range) -> Int? { - if range.startIndex >= range.endIndex { - // If we get here, then the search key is not present in the array. - return nil - - } else { - // Calculate where to split the array. - let midIndex = range.startIndex + (range.endIndex - range.startIndex) / 2 - - // Is the search key in the left half? - if a[midIndex] > key { - return binarySearch(a, key: key, range: range.startIndex ..< midIndex) - - // Is the search key in the right half? - } else if a[midIndex] < key { - return binarySearch(a, key: key, range: midIndex + 1 ..< range.endIndex) - - // If we get here, then we've found the search key! - } else { - return midIndex - } - } +if range.lowerBound >= range.upperBound { +// If we get here, then the search key is not present in the array. +return nil + +} else { +// Calculate where to split the array. +let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 + +// Is the search key in the left half? +if a[midIndex] > key { +return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) + +// Is the search key in the right half? +} else if a[midIndex] < key { +return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) + +// If we get here, then we've found the search key! +} else { +return midIndex +} +} } ``` @@ -94,7 +94,7 @@ Note that the `numbers` array is sorted. The binary search algorithm does not wo I said that binary search works by splitting the array in half, but we don't actually create two new arrays. Instead, we keep track of these splits using a Swift `Range` object. Initially, this range covers the entire array, `0 ..< numbers.count`. As we split the array, the range becomes smaller and smaller. -> **Note:** One thing to be aware of is that `range.endIndex` always points one beyond the last element. In the example, the range is `0..<19` because there are 19 numbers in the array, and so `range.startIndex = 0` and `range.endIndex = 19`. But in our array the last element is at index 18, not 19, since we start counting from 0. Just keep this in mind when working with ranges: the `endIndex` is always one more than the index of the last element. +> **Note:** One thing to be aware of is that `range.upperBound` always points one beyond the last element. In the example, the range is `0..<19` because there are 19 numbers in the array, and so `range.lowerBound = 0` and `range.upperBound = 19`. But in our array the last element is at index 18, not 19, since we start counting from 0. Just keep this in mind when working with ranges: the `upperBound` is always one more than the index of the last element. ## Stepping through the example @@ -102,76 +102,76 @@ It might be useful to look at how the algorithm works in detail. The array from the above example consists of 19 numbers and looks like this when sorted: - [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] +[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] We're trying to determine if the number `43` is in this array. To split the array in half, we need to know the index of the object in the middle. That's determined by this line: ```swift - let midIndex = range.startIndex + (range.endIndex - range.startIndex) / 2 +let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 ``` -Initially, the range has `startIndex = 0` and `endIndex = 19`. Filling in these values, we find that `midIndex` is `0 + (19 - 0)/2 = 19/2 = 9`. It's actually `9.5` but because we're using integers, the answer is rounded down. +Initially, the range has `lowerBound = 0` and `upperBound = 19`. Filling in these values, we find that `midIndex` is `0 + (19 - 0)/2 = 19/2 = 9`. It's actually `9.5` but because we're using integers, the answer is rounded down. In the next figure, the `*` shows the middle item. As you can see, the number of items on each side is the same, so we're split right down the middle. - [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] - * +[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] +* Now binary search will determine which half to use. The relevant section from the code is: ```swift - if a[midIndex] > key { - // use left half - } else if a[midIndex] < key { - // use right half - } else { - return midIndex - } +if a[midIndex] > key { +// use left half +} else if a[midIndex] < key { +// use right half +} else { +return midIndex +} ``` In this case, `a[midIndex] = 29`. That's less than the search key, so we can safely conclude that the search key will never be in the left half of the array. After all, the left half only contains numbers smaller than `29`. Hence, the search key must be in the right half somewhere (or not in the array at all). -Now we can simply repeat the binary search, but on the array interval from `midIndex + 1` to `range.endIndex`: +Now we can simply repeat the binary search, but on the array interval from `midIndex + 1` to `range.upperBound`: - [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] +[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] Since we no longer need to concern ourselves with the left half of the array, I've marked that with `x`'s. From now on we'll only look at the right half, which starts at array index 10. We calculate the index of the new middle element: `midIndex = 10 + (19 - 10)/2 = 14`, and split the array down the middle again. - [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] - * +[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] +* As you can see, `a[14]` is indeed the middle element of the array's right half. Is the search key greater or smaller than `a[14]`? It's smaller because `43 < 47`. This time we're taking the left half and ignore the larger numbers on the right: - [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] +[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] The new `midIndex` is here: - [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] - * +[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] +* The search key is greater than `37`, so continue with the right side: - [ x, x, x, x, x, x, x, x, x, x | x, x | 41, 43 | x, x, x, x, x ] - * +[ x, x, x, x, x, x, x, x, x, x | x, x | 41, 43 | x, x, x, x, x ] +* Again, the search key is greater, so split once more and take the right side: - [ x, x, x, x, x, x, x, x, x, x | x, x | x | 43 | x, x, x, x, x ] - * +[ x, x, x, x, x, x, x, x, x, x | x, x | x | 43 | x, x, x, x, x ] +* And now we're done. The search key equals the array element we're looking at, so we've finally found what we were searching for: number `43` is at array index `13`. w00t! It may have seemed like a lot of work, but in reality it only took four steps to find the search key in the array, which sounds about right because `log_2(19) = 4.23`. With a linear search, it would have taken 14 steps. -What would happen if we were to search for `42` instead of `43`? In that case, we can't split up the array any further. The `range.endIndex` becomes smaller than `range.startIndex`. That tells the algorithm the search key is not in the array and it returns `nil`. +What would happen if we were to search for `42` instead of `43`? In that case, we can't split up the array any further. The `range.upperBound` becomes smaller than `range.lowerBound`. That tells the algorithm the search key is not in the array and it returns `nil`. -> **Note:** Many implementations of binary search calculate `midIndex = (startIndex + endIndex) / 2`. This contains a subtle bug that only appears with very large arrays, because `startIndex + endIndex` may overflow the maximum number an integer can hold. This situation is unlikely to happen on a 64-bit CPU, but it definitely can on 32-bit machines. +> **Note:** Many implementations of binary search calculate `midIndex = (lowerBound + upperBound) / 2`. This contains a subtle bug that only appears with very large arrays, because `lowerBound + upperBound` may overflow the maximum number an integer can hold. This situation is unlikely to happen on a 64-bit CPU, but it definitely can on 32-bit machines. ## Iterative vs recursive @@ -181,18 +181,19 @@ Here is an iterative implementation of binary search in Swift: ```swift func binarySearch(a: [T], key: T) -> Int? { - var range = 0.. + BuildableName = "BinarySearchTests.xctest" + BlueprintName = "BinarySearchTests" + ReferencedContainer = "container:BinarySearchTests.xcodeproj"> @@ -33,9 +33,9 @@ + BuildableName = "BinarySearchTests.xctest" + BlueprintName = "BinarySearchTests" + ReferencedContainer = "container:BinarySearchTests.xcodeproj"> @@ -56,9 +56,9 @@ + BuildableName = "BinarySearchTests.xctest" + BlueprintName = "BinarySearchTests" + ReferencedContainer = "container:BinarySearchTests.xcodeproj"> @@ -74,9 +74,9 @@ + BuildableName = "BinarySearchTests.xctest" + BlueprintName = "BinarySearchTests" + ReferencedContainer = "container:BinarySearchTests.xcodeproj"> From fba86e174042e95692f8e8b3a6e989bdba5b4141 Mon Sep 17 00:00:00 2001 From: lenli Date: Fri, 19 Aug 2016 18:14:22 -0400 Subject: [PATCH 0053/1275] Fix code indentation on Binary Search readme --- Binary Search/README.markdown | 86 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Binary Search/README.markdown b/Binary Search/README.markdown index 6fb6e9985..0faa46128 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -16,12 +16,12 @@ The built-in `indexOf()` function performs a [linear search](../Linear Search/). ```swift func linearSearch(a: [T], _ key: T) -> Int? { -for i in 0 ..< a.count { -if a[i] == key { -return i -} -} -return nil + for i in 0 ..< a.count { + if a[i] == key { + return i + } + } + return nil } ``` @@ -58,27 +58,27 @@ Here is a recursive implementation of binary search in Swift: ```swift func binarySearch(a: [T], key: T, range: Range) -> Int? { -if range.lowerBound >= range.upperBound { -// If we get here, then the search key is not present in the array. -return nil - -} else { -// Calculate where to split the array. -let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 - -// Is the search key in the left half? -if a[midIndex] > key { -return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) - -// Is the search key in the right half? -} else if a[midIndex] < key { -return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) - -// If we get here, then we've found the search key! -} else { -return midIndex -} -} + if range.lowerBound >= range.upperBound { + // If we get here, then the search key is not present in the array. + return nil + + } else { + // Calculate where to split the array. + let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 + + // Is the search key in the left half? + if a[midIndex] > key { + return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) + + // Is the search key in the right half? + } else if a[midIndex] < key { + return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) + + // If we get here, then we've found the search key! + } else { + return midIndex + } + } } ``` @@ -123,11 +123,11 @@ Now binary search will determine which half to use. The relevant section from th ```swift if a[midIndex] > key { -// use left half + // use left half } else if a[midIndex] < key { -// use right half + // use right half } else { -return midIndex + return midIndex } ``` @@ -181,19 +181,19 @@ Here is an iterative implementation of binary search in Swift: ```swift 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 + 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 } ``` From 232c92f1760601e35e8e9f3fe87df6706e6ccb6a Mon Sep 17 00:00:00 2001 From: lenli Date: Fri, 19 Aug 2016 18:19:55 -0400 Subject: [PATCH 0054/1275] Fix array midpoint figures in Binary Search readme --- Binary Search/README.markdown | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Binary Search/README.markdown b/Binary Search/README.markdown index 0faa46128..0aa039254 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -102,7 +102,7 @@ It might be useful to look at how the algorithm works in detail. The array from the above example consists of 19 numbers and looks like this when sorted: -[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] + [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] We're trying to determine if the number `43` is in this array. @@ -116,8 +116,8 @@ Initially, the range has `lowerBound = 0` and `upperBound = 19`. Filling in thes In the next figure, the `*` shows the middle item. As you can see, the number of items on each side is the same, so we're split right down the middle. -[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] -* + [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 ] + * Now binary search will determine which half to use. The relevant section from the code is: @@ -135,35 +135,35 @@ In this case, `a[midIndex] = 29`. That's less than the search key, so we can saf Now we can simply repeat the binary search, but on the array interval from `midIndex + 1` to `range.upperBound`: -[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] + [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] Since we no longer need to concern ourselves with the left half of the array, I've marked that with `x`'s. From now on we'll only look at the right half, which starts at array index 10. We calculate the index of the new middle element: `midIndex = 10 + (19 - 10)/2 = 14`, and split the array down the middle again. -[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] -* + [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43, 47, 53, 59, 61, 67 ] + * As you can see, `a[14]` is indeed the middle element of the array's right half. Is the search key greater or smaller than `a[14]`? It's smaller because `43 < 47`. This time we're taking the left half and ignore the larger numbers on the right: -[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] + [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] The new `midIndex` is here: -[ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] -* + [ x, x, x, x, x, x, x, x, x, x | 31, 37, 41, 43 | x, x, x, x, x ] + * The search key is greater than `37`, so continue with the right side: -[ x, x, x, x, x, x, x, x, x, x | x, x | 41, 43 | x, x, x, x, x ] -* + [ x, x, x, x, x, x, x, x, x, x | x, x | 41, 43 | x, x, x, x, x ] + * Again, the search key is greater, so split once more and take the right side: -[ x, x, x, x, x, x, x, x, x, x | x, x | x | 43 | x, x, x, x, x ] -* + [ x, x, x, x, x, x, x, x, x, x | x, x | x | 43 | x, x, x, x, x ] + * And now we're done. The search key equals the array element we're looking at, so we've finally found what we were searching for: number `43` is at array index `13`. w00t! From 19cc32e3d6d0ccd9c9e507b2f52a9679c44823a9 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Sat, 20 Aug 2016 20:47:51 +1200 Subject: [PATCH 0055/1275] Enabling binary search tree tests. Removed unused xcodeproj file. --- .travis.yml | 2 +- .../project.pbxproj | 20 ++++++++-------- .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Tests.xcscheme | 24 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) rename Binary Search/Tests/{BinarySearchTests.xcodeproj => Tests.xcodeproj}/project.pbxproj (92%) rename Binary Search/Tests/{BinarySearchTests.xcodeproj => Tests.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename Binary Search/Tests/{BinarySearchTests.xcodeproj => Tests.xcodeproj}/xcshareddata/xcschemes/Tests.xcscheme (78%) diff --git a/.travis.yml b/.travis.yml index 970f85aa8..0ed853d81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ 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 ./Binary\ Search/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 diff --git a/Binary Search/Tests/BinarySearchTests.xcodeproj/project.pbxproj b/Binary Search/Tests/Tests.xcodeproj/project.pbxproj similarity index 92% rename from Binary Search/Tests/BinarySearchTests.xcodeproj/project.pbxproj rename to Binary Search/Tests/Tests.xcodeproj/project.pbxproj index 2db8ac5b6..6e29252ec 100644 --- a/Binary Search/Tests/BinarySearchTests.xcodeproj/project.pbxproj +++ b/Binary Search/Tests/Tests.xcodeproj/project.pbxproj @@ -12,7 +12,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 7B2BBC801C779D720067B71D /* BinarySearchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BinarySearchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 7B80C3CD1C77A256003CECC7 /* BinarySearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTests.swift; sourceTree = SOURCE_ROOT; }; 7B80C3CF1C77A263003CECC7 /* BinarySearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearch.swift; path = ../BinarySearch.swift; sourceTree = SOURCE_ROOT; }; @@ -40,7 +40,7 @@ 7B2BBC721C779D710067B71D /* Products */ = { isa = PBXGroup; children = ( - 7B2BBC801C779D720067B71D /* BinarySearchTests.xctest */, + 7B2BBC801C779D720067B71D /* Tests.xctest */, ); name = Products; sourceTree = ""; @@ -59,9 +59,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 7B2BBC7F1C779D720067B71D /* BinarySearchTests */ = { + 7B2BBC7F1C779D720067B71D /* Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "BinarySearchTests" */; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */; buildPhases = ( 7B2BBC7C1C779D720067B71D /* Sources */, 7B2BBC7D1C779D720067B71D /* Frameworks */, @@ -71,9 +71,9 @@ ); dependencies = ( ); - name = BinarySearchTests; + name = Tests; productName = TestsTests; - productReference = 7B2BBC801C779D720067B71D /* BinarySearchTests.xctest */; + productReference = 7B2BBC801C779D720067B71D /* Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -92,7 +92,7 @@ }; }; }; - buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "BinarySearchTests" */; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -105,7 +105,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 7B2BBC7F1C779D720067B71D /* BinarySearchTests */, + 7B2BBC7F1C779D720067B71D /* Tests */, ); }; /* End PBXProject section */ @@ -245,7 +245,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "BinarySearchTests" */ = { + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 7B2BBC871C779D720067B71D /* Debug */, @@ -254,7 +254,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "BinarySearchTests" */ = { + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 7B2BBC8D1C779D720067B71D /* Debug */, diff --git a/Binary Search/Tests/BinarySearchTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Binary Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Binary Search/Tests/BinarySearchTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Binary Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Binary Search/Tests/BinarySearchTests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme similarity index 78% rename from Binary Search/Tests/BinarySearchTests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme rename to Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index d6cd9152b..14f27f777 100644 --- a/Binary Search/Tests/BinarySearchTests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "Tests.xctest" + BlueprintName = "Tests" + ReferencedContainer = "container:Tests.xcodeproj"> @@ -33,9 +33,9 @@ + BuildableName = "Tests.xctest" + BlueprintName = "Tests" + ReferencedContainer = "container:Tests.xcodeproj"> @@ -56,9 +56,9 @@ + BuildableName = "Tests.xctest" + BlueprintName = "Tests" + ReferencedContainer = "container:Tests.xcodeproj"> @@ -74,9 +74,9 @@ + BuildableName = "Tests.xctest" + BlueprintName = "Tests" + ReferencedContainer = "container:Tests.xcodeproj"> From 20236b26099c0a4041f1043e26aa46281c229ca4 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Sat, 20 Aug 2016 20:55:31 +1200 Subject: [PATCH 0056/1275] Removing "a" label from binarySearch method in playground so it matches BinarySearch.swift. Applying same change to readme. --- .../BinarySearch.playground/Contents.swift | 16 ++++++++-------- .../Sources/BinarySearch.swift | 8 ++++---- Binary Search/README.markdown | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Binary Search/BinarySearch.playground/Contents.swift b/Binary Search/BinarySearch.playground/Contents.swift index cccf9f8ac..f673f25c4 100644 --- a/Binary Search/BinarySearch.playground/Contents.swift +++ b/Binary Search/BinarySearch.playground/Contents.swift @@ -7,13 +7,13 @@ let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 4 let sorted = numbers.sorted() // Using recursive solution -binarySearch(a: sorted, key: 2, range: 0 ..< sorted.count) // gives 0 -binarySearch(a: sorted, key: 67, range: 0 ..< sorted.count) // gives 18 -binarySearch(a: sorted, key: 43, range: 0 ..< sorted.count) // gives 13 -binarySearch(a: sorted, key: 42, range: 0 ..< sorted.count) // nil +binarySearch(sorted, key: 2, range: 0 ..< sorted.count) // gives 0 +binarySearch(sorted, key: 67, range: 0 ..< sorted.count) // gives 18 +binarySearch(sorted, key: 43, range: 0 ..< sorted.count) // gives 13 +binarySearch(sorted, key: 42, range: 0 ..< sorted.count) // nil // Using iterative solution -binarySearch(a: sorted, key: 2) // gives 0 -binarySearch(a: sorted, key: 67) // gives 18 -binarySearch(a: sorted, key: 43) // gives 13 -binarySearch(a: sorted, key: 42) // nil +binarySearch(sorted, key: 2) // gives 0 +binarySearch(sorted, key: 67) // gives 18 +binarySearch(sorted, key: 43) // gives 13 +binarySearch(sorted, key: 42) // nil diff --git a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift b/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift index a7a24bd3a..d6623e355 100644 --- a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift +++ b/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift @@ -13,15 +13,15 @@ import Foundation // The recursive version of binary search. -public func binarySearch(a: [T], key: T, range: Range) -> Int? { +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: a, key: key, range: range.lowerBound ..< midIndex) + return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) } else if a[midIndex] < key { - return binarySearch(a: a, key: key, range: midIndex + 1 ..< range.upperBound) + return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) } else { return midIndex } @@ -35,7 +35,7 @@ public func binarySearch(a: [T], key: T, range: Range) -> In uses a while loop, while the other calls itself recursively. **/ -public func binarySearch(a: [T], key: T) -> Int? { +public func binarySearch(_ a: [T], key: T) -> Int? { var lowerBound = 0 var upperBound = a.count while lowerBound < upperBound { diff --git a/Binary Search/README.markdown b/Binary Search/README.markdown index 0aa039254..c65d0b5fd 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -15,7 +15,7 @@ numbers.indexOf(43) // returns 15 The built-in `indexOf()` function performs a [linear search](../Linear Search/). In code that looks something like this: ```swift -func linearSearch(a: [T], _ key: T) -> Int? { +func linearSearch(_ a: [T], _ key: T) -> Int? { for i in 0 ..< a.count { if a[i] == key { return i @@ -45,7 +45,7 @@ Sounds great, but there is a downside to using binary search: the array must be Here's how binary search works: -- Split the array in half and determine whether the thing you're looking for, known as the *search key*, is in the left half or in the right half. +- Split the array in half and determine whether the thing you're looking for, known as the *search key*, is in the left half or in the right half. - How do you determine in which half the search key is? This is why you sorted the array first, so you can do a simple `<` or `>` comparison. - If the search key is in the left half, you repeat the process there: split the left half into two even smaller pieces and look in which piece the search key must lie. (Likewise for when it's the right half.) - This repeats until the search key is found. If the array cannot be split up any further, you must regrettably conclude that the search key is not present in the array. @@ -57,7 +57,7 @@ Now you know why it's called a "binary" search: in every step it splits the arra Here is a recursive implementation of binary search in Swift: ```swift -func binarySearch(a: [T], key: T, range: Range) -> Int? { +func binarySearch(_ a: [T], key: T, range: Range) -> Int? { if range.lowerBound >= range.upperBound { // If we get here, then the search key is not present in the array. return nil @@ -180,7 +180,7 @@ Binary search is recursive in nature because you apply the same logic over and o Here is an iterative implementation of binary search in Swift: ```swift -func binarySearch(a: [T], key: T) -> Int? { +func binarySearch(_ a: [T], key: T) -> Int? { var lowerBound = 0 var upperBound = a.count while lowerBound < upperBound { From 6e77eba6b8c242c09093a160d90dee5ee3e92828 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Sat, 20 Aug 2016 22:57:42 -0600 Subject: [PATCH 0057/1275] Updated Bubble Sort description Added the runtime, memory and a better description of bubble sort. The implementation was not added but it is good to know the concept. --- Bubble Sort/README.markdown | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 1c3d89798..8660d6d54 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,4 +1,13 @@ # Bubble Sort -This is a horrible algorithm. There is no reason why you should have to know it. +Bubble sort is a sorting algorthim 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 comparision is then moved onto the next pair and so on and so forth. This is done until the the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. +Runtime: +- Average: O(N^2) +- Worst: O(N^2) + +Memory: +- O(1) + +Implementation: +The implemenatation will not be shown because as you can see from the average and worst runtimes this is a very inefficent algorithm but having a grasp of the concept will help in getting to know the basics of simple sorting algorthims. From 68f581965f060a2725446bb95c3cbaaa4344b1f6 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Sat, 20 Aug 2016 23:09:03 -0600 Subject: [PATCH 0058/1275] Updated formatting and grammar errors --- Bubble Sort/README.markdown | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 8660d6d54..ceb2a98cb 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,13 +1,14 @@ # Bubble Sort -Bubble sort is a sorting algorthim 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 comparision is then moved onto the next pair and so on and so forth. This is done until the 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 the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. -Runtime: +##### Runtime: - Average: O(N^2) - Worst: O(N^2) -Memory: +##### Memory: - O(1) -Implementation: -The implemenatation will not be shown because as you can see from the average and worst runtimes this is a very inefficent algorithm but having a grasp of the concept will help in getting to know the basics of simple sorting algorthims. +### Implementation: + +The implementation will not be shown because as you can see from the average and worst runtimes this is a very inefficient algorithm but having a grasp of the concept will help in getting to know the basics of simple sorting algorithms. From a5411848ff096e8da74e7d8cc9ba3e35f3069ee7 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Sun, 21 Aug 2016 19:10:44 +0200 Subject: [PATCH 0059/1275] Add SkipList --- Skip-List/SkipList.swift | 266 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 Skip-List/SkipList.swift diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift new file mode 100644 index 000000000..b07cd98c8 --- /dev/null +++ b/Skip-List/SkipList.swift @@ -0,0 +1,266 @@ +// The MIT License (MIT) + +// Copyright (c) 2016 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. + + +import Foundation + + +// Stack from : https://github.com/raywenderlich/swift-algorithm-club/tree/master/Stack +public struct Stack { + private var array = [T]() + + public var isEmpty: Bool { + return array.isEmpty + } + + public var count: Int { + return array.count + } + + public mutating func push(element: T) { + array.append(element) + } + + public mutating func pop() -> T? { + return array.popLast() + } + + public func peek() -> T? { + return array.last + } +} + +extension Stack: SequenceType { + public func generate() -> AnyGenerator { + var curr = self + return AnyGenerator { + _ -> T? in + return curr.pop() + } + } +} + + +func random() -> Bool { + #if os(Linux) + return random() % 2 == 0 + #elseif os(OSX) + return arc4random_uniform(2) == 1 + #endif +} + + + +class DataNode{ + internal typealias Node = DataNode + + internal var key : Key? + internal var data : Payload? + internal var _next : Node? + internal var _down : Node? + + internal var next: Node? { + get { return self._next } + set(value) { self._next = value } + } + + internal var down:Node? { + get { return self._down } + set(value) { self._down = value } + } + + init(key:Key, data:Payload){ + self.key = key + self.data = data + } + + init(header: Bool){ + } + +} + + +class SkipList{ + internal typealias Node = DataNode + internal var head: Node? + + private func find_head(key:Key) -> Node? { + var current = self.head + var found: Bool = false + + while !found { + if let curr = current { + if curr.next == nil { current = curr.down } + else { + if curr.next!.key == key { found = true } + else { + if key < curr.next!.key{ current = curr.down } + else { current = curr.next } + } + } + } else { + break + } + } + + if found { + return current + } else { + return nil + } + } + + + private func insert_head(key:Key, data:Payload) -> Void { + + self.head = Node(header: true) + var temp = Node(key:key, data:data) + self.head!.next = temp + var top = temp + + while random() { + let newhead = Node(header: true) + temp = Node(key:key, data:data) + temp.down = top + newhead.next = temp + newhead.down = self.head + self.head = newhead + top = temp + } + } + + private func insert_rest(key:Key, data:Payload) -> Void { + var stack = Stack() + var current_head: Node? = self.head + + while current_head != nil { + + if let next = current_head!._next { + if next.key > key { + stack.push(current_head!) + current_head = next + } else { + current_head = next + } + + } else { + stack.push(current_head!) + current_head = current_head!.down + } + + } + + let lowest = stack.pop() + var temp = Node(key:key, data:data) + temp.next = lowest!.next + lowest!.next = temp + var top = temp + + while random() { + if stack.isEmpty { + let newhead = Node(header: true) + temp = Node(key:key, data:data) + temp.down = top + newhead.next = temp + newhead.down = self.head + self.head = newhead + top = temp + } else { + let next = stack.pop() + temp = Node(key:key, data:data) + temp.down = top + temp.next = next!.next + next!.next = temp + top = temp + } + } + } + + func search(key:Key) -> Payload? { + guard let item = self.find_head(key) else { + return nil + } + + return item.next!.data + } + + func remove(key:Key) -> Void { + guard let item = self.find_head(key) else { + return + } + + var curr = Optional(item) + + while curr != nil { + let node = curr!.next + + if node!.key != key { curr = node ; continue } + + let node_next = node!.next + curr!.next = node_next + curr = curr!.down + + } + + } + + func insert(key: Key, data:Payload){ + if self.head != nil{ + if let node = self.find_head(key) { + + var curr = node.next + while curr != nil && curr!.key == key{ + curr!.data = data + curr = curr!.down + } + + } else { + self.insert_rest(key, data:data) + } + + } else { + self.insert_head(key, data:data) + } + } + +} + + +class Map{ + var collection: SkipList + + init(){ + self.collection = SkipList() + } + + func insert(key:Key, data: Payload){ + self.collection.insert(key, data:data) + } + + func get(key:Key) -> Payload?{ + return self.collection.search(key) + } + + func remove(key:Key) -> Void { + return self.collection.remove(key) + } +} From 28df4f3ab785436bf08b1b6f1751f865bc59660c Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 21 Aug 2016 19:25:31 +0200 Subject: [PATCH 0060/1275] Update README.md --- Skip-List/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Skip-List/README.md b/Skip-List/README.md index 8b1378917..ca1dce7ae 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -1 +1,3 @@ +# Skip List +> Skip lists are a probabilistic data structure that seem likely to supplant balanced trees as the implementation method of choice for many applications. Skip list algorithms have the same asymptotic expected time bounds as balanced trees and are simpler, faster and use less space. -**[William Pugh](https://en.wikipedia.org/wiki/William_Pugh)** From 96f58f76902b7ce30142dfa4a1853642b0869ec4 Mon Sep 17 00:00:00 2001 From: Mark Baxter Date: Fri, 26 Aug 2016 08:59:23 -0700 Subject: [PATCH 0061/1275] Swift 3 --- .../Palindromes.playground/Contents.swift | 22 +++++++++---------- Palindromes/Palindromes.swift | 8 +++---- Palindromes/README.markdown | 12 +++++----- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index b548182af..0df899937 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -2,7 +2,7 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) let length: Int = mutableText.characters.count guard length >= 1 else { @@ -11,9 +11,9 @@ public func palindromeCheck (text: String?) -> Bool { if length == 1 { return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { - let range = Range(mutableText.startIndex.successor()..(mutableText.index(mutableText.startIndex, offsetBy: 1).. Bool { } // Test to check that non-palindromes are handled correctly: -palindromeCheck("owls") +palindromeCheck(text: "owls") // Test to check that palindromes are accurately found (regardless of case and whitespace: -palindromeCheck("lol") -palindromeCheck("race car") -palindromeCheck("Race fast Safe car") +palindromeCheck(text: "lol") +palindromeCheck(text: "race car") +palindromeCheck(text: "Race fast Safe car") // Test to check that palindromes are found regardless of case: -palindromeCheck("HelloLLEH") +palindromeCheck(text: "HelloLLEH") // Test that nil and empty Strings return false: -palindromeCheck("") -palindromeCheck(nil) +palindromeCheck(text: "") +palindromeCheck(text: nil) diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index 61e7740ab..1e61cc1ca 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -2,7 +2,7 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) let length: Int = mutableText.characters.count guard length >= 1 else { @@ -11,9 +11,9 @@ public func palindromeCheck (text: String?) -> Bool { if length == 1 { return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { - let range = Range(mutableText.startIndex.successor()..(mutableText.index(mutableText.startIndex, offsetBy: 1).. Bool { if let text = text { - let mutableText = text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).lowercaseString + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) let length: Int = mutableText.characters.count - guard length >= 1 { + guard length >= 1 else { return false } if length == 1 { return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.endIndex.predecessor()] { - let range = Range(mutableText.startIndex.successor()..(mutableText.index(mutableText.startIndex, offsetBy: 1).. Bool { This code can be tested in a playground using the following: ```swift -palindromeCheck("Race car") +palindromeCheck(text: "Race car") ``` Since the phrase "Race car" is a palindrome, this will return true. From 5f1b0715d5181b89e600fa8c64e74ff91f8c35cc Mon Sep 17 00:00:00 2001 From: Mark Baxter Date: Fri, 26 Aug 2016 09:11:30 -0700 Subject: [PATCH 0062/1275] Swift 3 --- Palindromes/Palindromes.playground/Contents.swift | 2 +- Palindromes/Palindromes.swift | 2 +- Palindromes/README.markdown | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index 0df899937..f1a85c073 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -2,7 +2,7 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() let length: Int = mutableText.characters.count guard length >= 1 else { diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index 1e61cc1ca..2082dbb4d 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -2,7 +2,7 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() let length: Int = mutableText.characters.count guard length >= 1 else { diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 6d0ff8ef7..12f868251 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -28,7 +28,7 @@ Here is a recursive implementation of this in Swift: ```swift func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()) + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() let length: Int = mutableText.characters.count guard length >= 1 else { From be653b21e366c8225c07f7bc19ae790abb381b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Mon, 29 Aug 2016 11:08:07 +0200 Subject: [PATCH 0063/1275] Migrate Array2D algorithm to Swift 3 --- Array2D/Array2D.playground/Contents.swift | 4 ++-- Array2D/Array2D.swift | 4 ++-- Array2D/Tests/Array2DTests.swift | 4 ++-- Array2D/Tests/Tests.xcodeproj/project.pbxproj | 3 +++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 0bcb7b5b9..7064de59c 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -6,12 +6,12 @@ public struct Array2D { public let columns: Int public let rows: Int - private var array: [T] + fileprivate var array: [T] public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = .init(count: rows*columns, repeatedValue: initialValue) + array = .init(repeatElement(initialValue, count: rows*columns)) } public subscript(column: Int, row: Int) -> T { diff --git a/Array2D/Array2D.swift b/Array2D/Array2D.swift index 6177974d7..6d6c01902 100644 --- a/Array2D/Array2D.swift +++ b/Array2D/Array2D.swift @@ -6,12 +6,12 @@ public struct Array2D { public let columns: Int public let rows: Int - private var array: [T] + fileprivate var array: [T] public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = .init(count: rows*columns, repeatedValue: initialValue) + array = .init(repeating: initialValue, count: rows*columns) } public subscript(column: Int, row: Int) -> T { diff --git a/Array2D/Tests/Array2DTests.swift b/Array2D/Tests/Array2DTests.swift index f4019a03a..b30769ac4 100644 --- a/Array2D/Tests/Array2DTests.swift +++ b/Array2D/Tests/Array2DTests.swift @@ -43,7 +43,7 @@ class Array2DTest: XCTestCase { } func testPerformanceOnSmallArray() { - self.measureBlock { + self.measure { self.printArrayWith(columns: 2, rows: 2, inititalValue: 1) } } @@ -54,7 +54,7 @@ class Array2DTest: XCTestCase { // } // } - private func printArrayWith(columns columns: Int, rows: Int, inititalValue: Int) { + fileprivate func printArrayWith(columns: Int, rows: Int, inititalValue: Int) { let array = Array2D(columns: columns, rows: rows, initialValue: 4) for r in 0.. Date: Mon, 29 Aug 2016 11:18:20 +0200 Subject: [PATCH 0064/1275] Uncomment Array2D in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0ed853d81..1eba40123 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ install: 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 ./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 ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests From 99c00720289b9396b45c9045fea67ee983fbacf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Mon, 29 Aug 2016 14:36:12 +0200 Subject: [PATCH 0065/1275] Migrate Stack to Swift 3 --- Stack/Stack.playground/Contents.swift | 6 +++--- Stack/Stack.swift | 10 +++++----- Stack/Tests/Tests.xcodeproj/project.pbxproj | 3 +++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 4f4f826f2..24b5e7176 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -12,7 +12,7 @@ */ public struct Stack { - private var array = [T]() + fileprivate var array = [T]() public var count: Int { return array.count @@ -36,10 +36,10 @@ public struct Stack { } // Create a stack and put some elements on it already. -var stackOfNames = Stack(array: ["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) +var stackOfNames = Stack(array:["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) // Add an element to the top of the stack. -stackOfNames.push("Mike") +stackOfNames.push(element: "Mike") // The stack is now ["Carl", "Lisa", "Stephanie", "Jeff", "Wade", "Mike"] print(stackOfNames.array) diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 454b66fa0..49edaf4cb 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -4,7 +4,7 @@ Push and pop are O(1) operations. */ public struct Stack { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -14,7 +14,7 @@ public struct Stack { return array.count } - public mutating func push(element: T) { + public mutating func push(_ element: T) { array.append(element) } @@ -27,10 +27,10 @@ public struct Stack { } } -extension Stack: SequenceType { - public func generate() -> AnyGenerator { +extension Stack: Sequence { + public func makeIterator() -> AnyIterator { var curr = self - return AnyGenerator { + return AnyIterator { _ -> T? in return curr.pop() } diff --git a/Stack/Tests/Tests.xcodeproj/project.pbxproj b/Stack/Tests/Tests.xcodeproj/project.pbxproj index a36d7c51d..5ec8dc987 100644 --- a/Stack/Tests/Tests.xcodeproj/project.pbxproj +++ b/Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -220,6 +221,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; }; name = Debug; }; @@ -231,6 +233,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; }; name = Release; }; From 9ecfd88d02fff6d73a70e4e63ad41c6ed5931051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Mon, 29 Aug 2016 14:40:44 +0200 Subject: [PATCH 0066/1275] Revert "Migrate Stack to Swift 3" This reverts commit 99c00720289b9396b45c9045fea67ee983fbacf5. --- Stack/Stack.playground/Contents.swift | 6 +++--- Stack/Stack.swift | 10 +++++----- Stack/Tests/Tests.xcodeproj/project.pbxproj | 3 --- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 24b5e7176..4f4f826f2 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -12,7 +12,7 @@ */ public struct Stack { - fileprivate var array = [T]() + private var array = [T]() public var count: Int { return array.count @@ -36,10 +36,10 @@ public struct Stack { } // Create a stack and put some elements on it already. -var stackOfNames = Stack(array:["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) +var stackOfNames = Stack(array: ["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) // Add an element to the top of the stack. -stackOfNames.push(element: "Mike") +stackOfNames.push("Mike") // The stack is now ["Carl", "Lisa", "Stephanie", "Jeff", "Wade", "Mike"] print(stackOfNames.array) diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 49edaf4cb..454b66fa0 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -4,7 +4,7 @@ Push and pop are O(1) operations. */ public struct Stack { - fileprivate var array = [T]() + private var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -14,7 +14,7 @@ public struct Stack { return array.count } - public mutating func push(_ element: T) { + public mutating func push(element: T) { array.append(element) } @@ -27,10 +27,10 @@ public struct Stack { } } -extension Stack: Sequence { - public func makeIterator() -> AnyIterator { +extension Stack: SequenceType { + public func generate() -> AnyGenerator { var curr = self - return AnyIterator { + return AnyGenerator { _ -> T? in return curr.pop() } diff --git a/Stack/Tests/Tests.xcodeproj/project.pbxproj b/Stack/Tests/Tests.xcodeproj/project.pbxproj index 5ec8dc987..a36d7c51d 100644 --- a/Stack/Tests/Tests.xcodeproj/project.pbxproj +++ b/Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -88,7 +88,6 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; }; }; }; @@ -221,7 +220,6 @@ 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; }; name = Debug; }; @@ -233,7 +231,6 @@ 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; }; name = Release; }; From d6378f859dbf0d0fe65cfd1c69d90cc49f37714c Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 12:15:29 +1200 Subject: [PATCH 0067/1275] Fixed warning when opening array 2d test project --- Array2D/Tests/Tests.xcodeproj/project.pbxproj | 7 ++++++- .../Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Array2D/Tests/Tests.xcodeproj/project.pbxproj b/Array2D/Tests/Tests.xcodeproj/project.pbxproj index acacd28ea..a0fb1480b 100644 --- a/Array2D/Tests/Tests.xcodeproj/project.pbxproj +++ b/Array2D/Tests/Tests.xcodeproj/project.pbxproj @@ -83,7 +83,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -146,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -190,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; diff --git a/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 30 Aug 2016 12:38:14 +1200 Subject: [PATCH 0068/1275] Fixing NSCharacterSet.whitespaces() warning --- Palindromes/Palindromes.playground/Contents.swift | 4 ++-- Palindromes/Palindromes.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index f1a85c073..20df10ee4 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -1,8 +1,8 @@ import Cocoa -public func palindromeCheck (text: String?) -> Bool { +public func palindromeCheck(text: String?) -> Bool { if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() let length: Int = mutableText.characters.count guard length >= 1 else { diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index 2082dbb4d..b873af3b0 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -2,7 +2,7 @@ import Cocoa public func palindromeCheck (text: String?) -> Bool { if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() + let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() let length: Int = mutableText.characters.count guard length >= 1 else { From 9646535ec738fa6a72f2202ecd363a0ac7a1a434 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 12:39:07 +1200 Subject: [PATCH 0069/1275] Spacing --- Palindromes/Palindromes.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index b873af3b0..036ce3d34 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -1,6 +1,6 @@ import Cocoa -public func palindromeCheck (text: String?) -> Bool { +public func palindromeCheck(text: String?) -> Bool { if let text = text { let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() let length: Int = mutableText.characters.count From 93e1eeab430ff108e44182963f8fc053331e4501 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 13:16:39 +1200 Subject: [PATCH 0070/1275] Updating to Swift 3 --- Union-Find/README.markdown | 22 +++++++++---------- .../UnionFind.playground/Contents.swift | 14 ++++++------ Union-Find/UnionFind.swift | 14 ++++++------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Union-Find/README.markdown b/Union-Find/README.markdown index 1d674e965..5102f6b89 100644 --- a/Union-Find/README.markdown +++ b/Union-Find/README.markdown @@ -9,7 +9,7 @@ What do we mean by this? For example, the Union-Find data structure could be kee [ g, d, c ] [ i, j ] -These sets are disjoint because they have no members in common. +These sets are disjoint because they have no members in common. Union-Find supports three basic operations: @@ -41,9 +41,9 @@ Example: If `parent` looks like this, parent [ 1, 1, 1, 0, 2, 0, 6, 6, 6 ] i 0 1 2 3 4 5 6 7 8 - + then the tree structure looks like: - + 1 6 / \ / \ 0 2 7 8 @@ -63,7 +63,7 @@ Note that the `parent[]` of a root node points to itself. So `parent[1] = 1` and Let's look at the implementation of these basic operations, starting with adding a new set. ```swift -public mutating func addSetWith(element: T) { +public mutating func addSetWith(_ element: T) { index[element] = parent.count // 1 parent.append(parent.count) // 2 size.append(1) // 3 @@ -83,7 +83,7 @@ When you add a new element, this actually adds a new subset containing just that Often we want to determine whether we already have a set that contains a given element. That's what the **Find** operation does. In our `UnionFind` data structure it is called `setOf()`: ```swift -public mutating func setOf(element: T) -> Int? { +public mutating func setOf(_ element: T) -> Int? { if let indexOfElement = index[element] { return setByIndex(indexOfElement) } else { @@ -95,7 +95,7 @@ public mutating func setOf(element: T) -> Int? { This looks up the element's index in the `index` dictionary and then uses a helper method to find the set that this element belongs to: ```swift -private mutating func setByIndex(index: Int) -> Int { +private mutating func setByIndex(_ index: Int) -> Int { if parent[index] == index { // 1 return index } else { @@ -109,7 +109,7 @@ Because we're dealing with a tree structure, this is a recursive method. Recall that each set is represented by a tree and that the index of the root node serves as the number that identifies the set. We're going to find the root node of the tree that the element we're searching for belongs to, and return its index. -1. First, we check if the given index represents a root node (i.e. a node whose `parent` points back to the node itself). If so, we're done. +1. First, we check if the given index represents a root node (i.e. a node whose `parent` points back to the node itself). If so, we're done. 2. Otherwise we recursively call this method on the parent of the current node. And then we do a **very important thing**: we overwrite the parent of the current node with the index of root node, in effect reconnecting the node directly to the root of the tree. The next time we call this method, it will execute faster because the path to the root of the tree is now much shorter. Without that optimization, this method's complexity is **O(n)** but now in combination with the size optimization (covered in the Union section) it is almost **O(1)**. @@ -130,8 +130,8 @@ Now if we need to call `setOf(4)` again, we no longer have to go through node `2 There is also a helper method to check that two elements are in the same set: ```swift -public mutating func inSameSet(firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { +public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { return firstSet == secondSet } else { return false @@ -146,8 +146,8 @@ Since this calls `setOf()` it also optimizes the tree. The final operation is **Union**, which combines two sets into one larger set. ```swift -public mutating func unionSetsContaining(firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { // 1 +public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { // 1 if firstSet != secondSet { // 2 if size[firstSet] < size[secondSet] { // 3 parent[firstSet] = secondSet // 4 diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 5747b15b5..09649b938 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -5,13 +5,13 @@ public struct UnionFind { private var parent = [Int]() private var size = [Int]() - public mutating func addSetWith(element: T) { + public mutating func addSetWith(_ element: T) { index[element] = parent.count parent.append(parent.count) size.append(1) } - private mutating func setByIndex(index: Int) -> Int { + private mutating func setByIndex(_ index: Int) -> Int { if parent[index] == index { return index } else { @@ -20,7 +20,7 @@ public struct UnionFind { } } - public mutating func setOf(element: T) -> Int? { + public mutating func setOf(_ element: T) -> Int? { if let indexOfElement = index[element] { return setByIndex(indexOfElement) } else { @@ -28,8 +28,8 @@ public struct UnionFind { } } - public mutating func unionSetsContaining(firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { if firstSet != secondSet { if size[firstSet] < size[secondSet] { parent[firstSet] = secondSet @@ -42,8 +42,8 @@ public struct UnionFind { } } - public mutating func inSameSet(firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { return firstSet == secondSet } else { return false diff --git a/Union-Find/UnionFind.swift b/Union-Find/UnionFind.swift index 4323b80d4..506cdc1fe 100644 --- a/Union-Find/UnionFind.swift +++ b/Union-Find/UnionFind.swift @@ -12,13 +12,13 @@ public struct UnionFind { private var parent = [Int]() private var size = [Int]() - public mutating func addSetWith(element: T) { + public mutating func addSetWith(_ element: T) { index[element] = parent.count parent.append(parent.count) size.append(1) } - private mutating func setByIndex(index: Int) -> Int { + private mutating func setByIndex(_ index: Int) -> Int { if parent[index] == index { return index } else { @@ -27,7 +27,7 @@ public struct UnionFind { } } - public mutating func setOf(element: T) -> Int? { + public mutating func setOf(_ element: T) -> Int? { if let indexOfElement = index[element] { return setByIndex(indexOfElement) } else { @@ -35,8 +35,8 @@ public struct UnionFind { } } - public mutating func unionSetsContaining(firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { if firstSet != secondSet { if size[firstSet] < size[secondSet] { parent[firstSet] = secondSet @@ -49,8 +49,8 @@ public struct UnionFind { } } - public mutating func inSameSet(firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), secondSet = setOf(secondElement) { + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { return firstSet == secondSet } else { return false From 310f110de8614fc65589158422bc671519a275bb Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 13:30:51 +1200 Subject: [PATCH 0071/1275] Updating tree to Swift3 --- Tree/README.markdown | 12 ++++++------ Tree/Tree.playground/Contents.swift | 6 +++--- Tree/Tree.swift | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Tree/README.markdown b/Tree/README.markdown index 52a46c597..5cf3e6beb 100644 --- a/Tree/README.markdown +++ b/Tree/README.markdown @@ -10,7 +10,7 @@ Nodes have links to their children and usually to their parent as well. The chil ![A tree](Images/ParentChildren.png) -A node without a parent is the *root* node. A node without children is a *leaf* node. +A node without a parent is the *root* node. A node without children is a *leaf* node. The pointers in a tree do not form cycles. This is not a tree: @@ -25,15 +25,15 @@ Here's a basic implementation in Swift: ```swift public class TreeNode { public var value: T - + public var parent: TreeNode? public var children = [TreeNode]() public init(value: T) { self.value = value } - - public func addChild(node: TreeNode) { + + public func addChild(_ node: TreeNode) { children.append(node) node.parent = self } @@ -49,7 +49,7 @@ extension TreeNode: CustomStringConvertible { public var description: String { var s = "\(value)" if !children.isEmpty { - s += " {" + children.map { $0.description }.joinWithSeparator(", ") + "}" + s += " {" + children.map { $0.description }.joined(separator: ", ") + "}" } return s } @@ -129,7 +129,7 @@ Here's the code: ```swift extension TreeNode where T: Equatable { - func search(value: T) -> TreeNode? { + func search(_ value: T) -> TreeNode? { if value == self.value { return self } diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index c8ee8fe71..7b3c97005 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -10,7 +10,7 @@ public class TreeNode { self.value = value } - public func addChild(node: TreeNode) { + public func addChild(_ node: TreeNode) { children.append(node) node.parent = self } @@ -20,7 +20,7 @@ extension TreeNode: CustomStringConvertible { public var description: String { var s = "\(value)" if !children.isEmpty { - s += " {" + children.map { $0.description }.joinWithSeparator(", ") + "}" + s += " {" + children.map { $0.description }.joined(separator: ", ") + "}" } return s } @@ -71,7 +71,7 @@ teaNode.parent teaNode.parent!.parent extension TreeNode where T: Equatable { - func search(value: T) -> TreeNode? { + func search(_ value: T) -> TreeNode? { if value == self.value { return self } diff --git a/Tree/Tree.swift b/Tree/Tree.swift index 39d1f3df5..00119c963 100644 --- a/Tree/Tree.swift +++ b/Tree/Tree.swift @@ -8,7 +8,7 @@ public class TreeNode { self.value = value } - public func addChild(node: TreeNode) { + public func addChild(_ node: TreeNode) { children.append(node) node.parent = self } @@ -18,14 +18,14 @@ extension TreeNode: CustomStringConvertible { public var description: String { var s = "\(value)" if !children.isEmpty { - s += " {" + children.map { $0.description }.joinWithSeparator(", ") + "}" + s += " {" + children.map { $0.description }.joined(separator: ", ") + "}" } return s } } extension TreeNode where T: Equatable { - public func search(value: T) -> TreeNode? { + public func search(_ value: T) -> TreeNode? { if value == self.value { return self } From 8680a97bc576c937d13cb9156c59662e636ce6de Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 17:59:17 +1200 Subject: [PATCH 0072/1275] Updating to Swift3 --- .../BitSet.playground/Sources/BitSet.swift | 22 +++++----- Bit Set/BitSet.swift | 22 +++++----- Bit Set/README.markdown | 44 +++++++++---------- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index 46f51dbba..d8985bd13 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -11,7 +11,7 @@ public struct BitSet { */ private let N = 64 public typealias Word = UInt64 - private(set) public var words: [Word] + fileprivate(set) public var words: [Word] private let allOnes = ~Word() @@ -22,11 +22,11 @@ public struct BitSet { // Round up the count to the next multiple of 64. let n = (size + (N-1)) / N - words = .init(count: n, repeatedValue: 0) + 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) { + private func indexOf(_ i: Int) -> (Int, Word) { precondition(i >= 0) precondition(i < size) let o = i / N @@ -52,7 +52,7 @@ public struct BitSet { that we're not using, or bitwise operations between two differently sized BitSets will go wrong. */ - private mutating func clearUnusedBits() { + fileprivate mutating func clearUnusedBits() { words[words.count - 1] &= lastWordMask() } @@ -63,7 +63,7 @@ public struct BitSet { } /* Sets the bit at the specified index to 1. */ - public mutating func set(i: Int) { + public mutating func set(_ i: Int) { let (j, m) = indexOf(i) words[j] |= m } @@ -77,7 +77,7 @@ public struct BitSet { } /* Sets the bit at the specified index to 0. */ - public mutating func clear(i: Int) { + public mutating func clear(_ i: Int) { let (j, m) = indexOf(i) words[j] &= ~m } @@ -90,14 +90,14 @@ public struct BitSet { } /* Changes 0 into 1 and 1 into 0. Returns the new value of the bit. */ - public mutating func flip(i: Int) -> Bool { + public mutating func flip(_ i: Int) -> 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 { + public func isSet(_ i: Int) -> Bool { let (j, m) = indexOf(i) return (words[j] & m) != 0 } @@ -158,7 +158,7 @@ extension BitSet: Hashable { /* Based on the hashing code from Java's BitSet. */ public var hashValue: Int { var h = Word(1234) - for i in words.count.stride(to: 0, by: -1) { + for i in stride(from: words.count, to: 0, by: -1) { h ^= words[i - 1] &* Word(i) } return Int((h >> 32) ^ h) @@ -167,13 +167,13 @@ extension BitSet: Hashable { // MARK: - Bitwise operations -extension BitSet: BitwiseOperationsType { +extension BitSet: BitwiseOperations { public static var allZeros: BitSet { return BitSet(size: 64) } } -private func copyLargest(lhs: BitSet, _ rhs: BitSet) -> BitSet { +private func copyLargest(_ lhs: BitSet, _ rhs: BitSet) -> BitSet { return (lhs.words.count > rhs.words.count) ? lhs : rhs } diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift index 46f51dbba..d8985bd13 100644 --- a/Bit Set/BitSet.swift +++ b/Bit Set/BitSet.swift @@ -11,7 +11,7 @@ public struct BitSet { */ private let N = 64 public typealias Word = UInt64 - private(set) public var words: [Word] + fileprivate(set) public var words: [Word] private let allOnes = ~Word() @@ -22,11 +22,11 @@ public struct BitSet { // Round up the count to the next multiple of 64. let n = (size + (N-1)) / N - words = .init(count: n, repeatedValue: 0) + 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) { + private func indexOf(_ i: Int) -> (Int, Word) { precondition(i >= 0) precondition(i < size) let o = i / N @@ -52,7 +52,7 @@ public struct BitSet { that we're not using, or bitwise operations between two differently sized BitSets will go wrong. */ - private mutating func clearUnusedBits() { + fileprivate mutating func clearUnusedBits() { words[words.count - 1] &= lastWordMask() } @@ -63,7 +63,7 @@ public struct BitSet { } /* Sets the bit at the specified index to 1. */ - public mutating func set(i: Int) { + public mutating func set(_ i: Int) { let (j, m) = indexOf(i) words[j] |= m } @@ -77,7 +77,7 @@ public struct BitSet { } /* Sets the bit at the specified index to 0. */ - public mutating func clear(i: Int) { + public mutating func clear(_ i: Int) { let (j, m) = indexOf(i) words[j] &= ~m } @@ -90,14 +90,14 @@ public struct BitSet { } /* Changes 0 into 1 and 1 into 0. Returns the new value of the bit. */ - public mutating func flip(i: Int) -> Bool { + public mutating func flip(_ i: Int) -> 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 { + public func isSet(_ i: Int) -> Bool { let (j, m) = indexOf(i) return (words[j] & m) != 0 } @@ -158,7 +158,7 @@ extension BitSet: Hashable { /* Based on the hashing code from Java's BitSet. */ public var hashValue: Int { var h = Word(1234) - for i in words.count.stride(to: 0, by: -1) { + for i in stride(from: words.count, to: 0, by: -1) { h ^= words[i - 1] &* Word(i) } return Int((h >> 32) ^ h) @@ -167,13 +167,13 @@ extension BitSet: Hashable { // MARK: - Bitwise operations -extension BitSet: BitwiseOperationsType { +extension BitSet: BitwiseOperations { public static var allZeros: BitSet { return BitSet(size: 64) } } -private func copyLargest(lhs: BitSet, _ rhs: BitSet) -> BitSet { +private func copyLargest(_ lhs: BitSet, _ rhs: BitSet) -> BitSet { return (lhs.words.count > rhs.words.count) ? lhs : rhs } diff --git a/Bit Set/README.markdown b/Bit Set/README.markdown index 85d55e06e..6bb6e7c89 100644 --- a/Bit Set/README.markdown +++ b/Bit Set/README.markdown @@ -18,7 +18,7 @@ public struct BitSet { private let N = 64 public typealias Word = UInt64 - private(set) public var words: [Word] + fileprivate(set) public var words: [Word] public init(size: Int) { precondition(size > 0) @@ -26,7 +26,7 @@ public struct BitSet { // Round up the count to the next multiple of 64. let n = (size + (N-1)) / N - words = .init(count: n, repeatedValue: 0) + words = [Word](repeating: 0, count: n) } ``` @@ -47,7 +47,7 @@ then the `BitSet` allocates an array of three words. Each word has 64 bits and t Most of the operations on `BitSet` take the index of the bit as a parameter, so it's useful to have a way to find which word contains that bit. ```swift - private func indexOf(i: Int) -> (Int, Word) { + private func indexOf(_ i: Int) -> (Int, Word) { precondition(i >= 0) precondition(i < size) let o = i / N @@ -77,7 +77,7 @@ Note that the mask is always 64 bits because we look at the data one word at a t Now that we know where to find a bit, setting it to 1 is easy: ```swift - public mutating func set(i: Int) { + public mutating func set(_ i: Int) { let (j, m) = indexOf(i) words[j] |= m } @@ -88,7 +88,7 @@ This looks up the word index and the mask, then performs a bitwise OR between th Clearing the bit -- i.e. changing it to 0 -- is just as easy: ```swift - public mutating func clear(i: Int) { + public mutating func clear(_ i: Int) { let (j, m) = indexOf(i) words[j] &= ~m } @@ -99,7 +99,7 @@ Instead of a bitwise OR we now do a bitwise AND with the inverse of the mask. So To see if a bit is set we also use the bitwise AND but without inverting: ```swift - public func isSet(i: Int) -> Bool { + public func isSet(_ i: Int) -> Bool { let (j, m) = indexOf(i) return (words[j] & m) != 0 } @@ -127,15 +127,15 @@ print(bits) This will print the three words that the 140-bit `BitSet` uses to store everything: ```swift -0010000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000010000000000000000000000000000 -1000000000000000000000000000000000000000000000000000000000000000 +0010000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000010000000000000000000000000000 +1000000000000000000000000000000000000000000000000000000000000000 ``` Something else that's fun to do with bits is flipping them. This changes 0 into 1 and 1 into 0. Here's `flip()`: ```swift - public mutating func flip(i: Int) -> Bool { + public mutating func flip(_ i: Int) -> Bool { let (j, m) = indexOf(i) words[j] ^= m return (words[j] & m) != 0 @@ -170,17 +170,17 @@ There is also `setAll()` to make all the bits 1. However, this has to deal with First, we copy ones into all the words in our array. The array is now: ```swift -1111111111111111111111111111111111111111111111111111111111111111 -1111111111111111111111111111111111111111111111111111111111111111 -1111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111 ``` But this is incorrect... Since we don't use most of the last word, we should leave those bits at 0: ```swift -1111111111111111111111111111111111111111111111111111111111111111 -1111111111111111111111111111111111111111111111111111111111111111 -1111111111110000000000000000000000000000000000000000000000000000 +1111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111 +1111111111110000000000000000000000000000000000000000000000000000 ``` Instead of 192 one-bits we now have only 140 one-bits. The fact that the last word may not be completely filled up means that we always have to treat this last word specially. @@ -189,7 +189,7 @@ Setting those "leftover" bits to 0 is what the `clearUnusedBits()` helper functi This uses some advanced bit manipulation, so pay close attention: -```swift +```swift private func lastWordMask() -> Word { let diff = words.count*N - size // 1 if diff > 0 { @@ -199,7 +199,7 @@ This uses some advanced bit manipulation, so pay close attention: return ~Word() } } - + private mutating func clearUnusedBits() { words[words.count - 1] &= lastWordMask() // 4 } @@ -211,15 +211,15 @@ Here's what it does, step-by-step: 2) Create a mask that is all 0's, except the highest bit that's still valid is a 1. In our example, that would be: - 0000000000010000000000000000000000000000000000000000000000000000 + 0000000000010000000000000000000000000000000000000000000000000000 3) Subtract 1 to turn it into: - 1111111111100000000000000000000000000000000000000000000000000000 + 1111111111100000000000000000000000000000000000000000000000000000 and add the high bit back in to get: - 1111111111110000000000000000000000000000000000000000000000000000 + 1111111111110000000000000000000000000000000000000000000000000000 There are now 12 one-bits in this word because `140 - 2*64 = 12`. @@ -236,7 +236,7 @@ The first one only uses the first 4 bits; the second one uses 8 bits. The first 00100011 -------- OR 10101111 - + That is wrong since two of those 1-bits aren't supposed to be here. The correct way to do it is: 10000000 unused bits set to 0 first! From e6cfec424571c1c5afed292fb4159b5e8b766df9 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 30 Aug 2016 18:27:49 +1200 Subject: [PATCH 0073/1275] Updating to Swift3 --- .travis.yml | 2 +- .../BloomFilter.playground/Contents.swift | 18 ++-- Bloom Filter/BloomFilter.swift | 16 ++-- Bloom Filter/README.markdown | 16 ++-- Bloom Filter/Tests/BloomFilterTests.swift | 88 +++++++++---------- .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 7 files changed, 80 insertions(+), 72 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1eba40123..5b31c3085 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Binary\ Search/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 ./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 diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index ce59eecaa..d5e7d2dc6 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -1,31 +1,31 @@ //: Playground - noun: a place where people can play public class BloomFilter { - private var array: [Bool] - private var hashFunctions: [T -> Int] + fileprivate var array: [Bool] + private var hashFunctions: [(T) -> Int] - public init(size: Int = 1024, hashFunctions: [T -> Int]) { - self.array = .init(count: size, repeatedValue: false) + public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) self.hashFunctions = hashFunctions } - private func computeHashes(value: T) -> [Int] { + private func computeHashes(_ value: T) -> [Int] { return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } } - public func insert(element: T) { + public func insert(_ element: T) { for hashValue in computeHashes(element) { array[hashValue] = true } } - public func insert(values: [T]) { + public func insert(_ values: [T]) { for value in values { insert(value) } } - public func query(value: T) -> Bool { + public func query(_ value: T) -> Bool { let hashValues = computeHashes(value) // Map hashes to indices in the Bloom Filter @@ -37,7 +37,7 @@ public class BloomFilter { // only that it may be. If the query returns false, however, // you can be certain that the value was not added. - let exists = results.reduce(true, combine: { $0 && $1 }) + let exists = results.reduce(true, { $0 && $1 }) return exists } diff --git a/Bloom Filter/BloomFilter.swift b/Bloom Filter/BloomFilter.swift index 97a982f48..03b5333f1 100644 --- a/Bloom Filter/BloomFilter.swift +++ b/Bloom Filter/BloomFilter.swift @@ -1,29 +1,29 @@ public class BloomFilter { private var array: [Bool] - private var hashFunctions: [T -> Int] + private var hashFunctions: [(T) -> Int] - public init(size: Int = 1024, hashFunctions: [T -> Int]) { - self.array = .init(count: size, repeatedValue: false) + public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) self.hashFunctions = hashFunctions } - private func computeHashes(value: T) -> [Int] { + private func computeHashes(_ value: T) -> [Int] { return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } } - public func insert(element: T) { + public func insert(_ element: T) { for hashValue in computeHashes(element) { array[hashValue] = true } } - public func insert(values: [T]) { + public func insert(_ values: [T]) { for value in values { insert(value) } } - public func query(value: T) -> Bool { + public func query(_ value: T) -> Bool { let hashValues = computeHashes(value) // Map hashes to indices in the Bloom Filter @@ -35,7 +35,7 @@ public class BloomFilter { // only that it may be. If the query returns false, however, // you can be certain that the value was not added. - let exists = results.reduce(true, combine: { $0 && $1 }) + let exists = results.reduce(true, { $0 && $1 }) return exists } diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index 3e37ee50b..a85d71be4 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -58,11 +58,11 @@ Performance of a Bloom Filter is **O(k)** where **k** is the number of hashing f ## The code -The code is quite straightforward. The internal bit array is set to a fixed length on initialization, which cannot be mutated once it is initialized. +The code is quite straightforward. The internal bit array is set to a fixed length on initialization, which cannot be mutated once it is initialized. ```swift -public init(size: Int = 1024, hashFunctions: [T -> Int]) { - self.array = .init(count: size, repeatedValue: false) +public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) self.hashFunctions = hashFunctions } ``` @@ -72,7 +72,7 @@ Several hash functions should be specified at initialization. Which hash functio Insertion just flips the required bits to `true`: ```swift -public func insert(element: T) { +public func insert(_ element: T) { for hashValue in computeHashes(element) { array[hashValue] = true } @@ -82,7 +82,7 @@ public func insert(element: T) { This uses the `computeHashes()` function, which loops through the specified `hashFunctions` and returns an array of indices: ```swift -private func computeHashes(value: T) -> [Int] { +private func computeHashes(_ value: T) -> [Int] { return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } } ``` @@ -90,14 +90,14 @@ private func computeHashes(value: T) -> [Int] { And querying checks to make sure the bits at the hashed values are `true`: ```swift -public func query(value: T) -> Bool { +public func query(_ value: T) -> Bool { let hashValues = computeHashes(value) let results = hashValues.map() { hashValue in array[hashValue] } - let exists = results.reduce(true, combine: { $0 && $1 }) + let exists = results.reduce(true, { $0 && $1 }) return exists } ``` -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. +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.* diff --git a/Bloom Filter/Tests/BloomFilterTests.swift b/Bloom Filter/Tests/BloomFilterTests.swift index ffac8192d..82bf4fb8f 100644 --- a/Bloom Filter/Tests/BloomFilterTests.swift +++ b/Bloom Filter/Tests/BloomFilterTests.swift @@ -1,76 +1,76 @@ import XCTest /* Two hash functions, adapted from - http://www.cse.yorku.ca/~oz/hash.html */ + http://www.cse.yorku.ca/~oz/hash.html */ -func djb2(x: String) -> Int { - var hash = 5381 +func djb2(_ x: String) -> Int { + var hash = 5381 - for char in x.characters { - hash = ((hash << 5) &+ hash) &+ char.hashValue - } + for char in x.characters { + hash = ((hash << 5) &+ hash) &+ char.hashValue + } - return Int(hash) + return Int(hash) } -func sdbm(x: String) -> Int { - var hash = 0 +func sdbm(_ x: String) -> Int { + var hash = 0 - for char in x.characters { - hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash - } + for char in x.characters { + hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash + } - return Int(hash) + return Int(hash) } class BloomFilterTests: XCTestCase { - func testSingleHashFunction() { - let bloom = BloomFilter(hashFunctions: [djb2]) + func testSingleHashFunction() { + let bloom = BloomFilter(hashFunctions: [djb2]) - bloom.insert("Hello world!") + bloom.insert("Hello world!") - let result_good = bloom.query("Hello world!") - let result_bad = bloom.query("Hello world") + let result_good = bloom.query("Hello world!") + let result_bad = bloom.query("Hello world") - XCTAssertTrue(result_good) - XCTAssertFalse(result_bad) - } + XCTAssertTrue(result_good) + XCTAssertFalse(result_bad) + } - func testEmptyFilter() { - let bloom = BloomFilter(hashFunctions: [djb2]) + func testEmptyFilter() { + let bloom = BloomFilter(hashFunctions: [djb2]) - let empty = bloom.isEmpty() + let empty = bloom.isEmpty() - XCTAssertTrue(empty) - } + XCTAssertTrue(empty) + } - func testMultipleHashFunctions() { - let bloom = BloomFilter(hashFunctions: [djb2, sdbm]) + func testMultipleHashFunctions() { + let bloom = BloomFilter(hashFunctions: [djb2, sdbm]) - bloom.insert("Hello world!") + bloom.insert("Hello world!") - let result_good = bloom.query("Hello world!") - let result_bad = bloom.query("Hello world") + let result_good = bloom.query("Hello world!") + let result_bad = bloom.query("Hello world") - XCTAssertTrue(result_good) - XCTAssertFalse(result_bad) - } + XCTAssertTrue(result_good) + XCTAssertFalse(result_bad) + } - func testFalsePositive() { - let bloom = BloomFilter(size: 5, hashFunctions: [djb2, sdbm]) + func testFalsePositive() { + let bloom = BloomFilter(size: 5, hashFunctions: [djb2, sdbm]) - bloom.insert(["hello", "elloh", "llohe", "lohel", "ohell"]) + bloom.insert(["hello", "elloh", "llohe", "lohel", "ohell"]) - print("Inserted") + print("Inserted") - let query = bloom.query("This wasn't inserted!") + let query = bloom.query("This wasn't inserted!") - // This is true even though we did not insert the value in the Bloom filter; - // the Bloom filter is capable of producing false positives but NOT - // false negatives. + // This is true even though we did not insert the value in the Bloom filter; + // the Bloom filter is capable of producing false positives but NOT + // false negatives. - XCTAssertTrue(query) - } + XCTAssertTrue(query) + } } diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj index d413110c9..20998a80e 100644 --- a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj @@ -83,11 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -145,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -189,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -209,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -220,6 +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; }; name = Debug; }; @@ -231,6 +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; }; name = Release; }; diff --git a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 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: Tue, 30 Aug 2016 11:33:34 +0200 Subject: [PATCH 0074/1275] Updating Stack to Swift 3 --- Stack/Stack.playground/Contents.swift | 4 ++-- Stack/Stack.swift | 10 +++++----- Stack/Tests/Tests.xcodeproj/project.pbxproj | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 4f4f826f2..12c29faa0 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -12,7 +12,7 @@ */ public struct Stack { - private var array = [T]() + fileprivate var array = [T]() public var count: Int { return array.count @@ -39,7 +39,7 @@ public struct Stack { var stackOfNames = Stack(array: ["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) // Add an element to the top of the stack. -stackOfNames.push("Mike") +stackOfNames.push(element: "Mike") // The stack is now ["Carl", "Lisa", "Stephanie", "Jeff", "Wade", "Mike"] print(stackOfNames.array) diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 454b66fa0..49edaf4cb 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -4,7 +4,7 @@ Push and pop are O(1) operations. */ public struct Stack { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -14,7 +14,7 @@ public struct Stack { return array.count } - public mutating func push(element: T) { + public mutating func push(_ element: T) { array.append(element) } @@ -27,10 +27,10 @@ public struct Stack { } } -extension Stack: SequenceType { - public func generate() -> AnyGenerator { +extension Stack: Sequence { + public func makeIterator() -> AnyIterator { var curr = self - return AnyGenerator { + return AnyIterator { _ -> T? in return curr.pop() } diff --git a/Stack/Tests/Tests.xcodeproj/project.pbxproj b/Stack/Tests/Tests.xcodeproj/project.pbxproj index a36d7c51d..5ec8dc987 100644 --- a/Stack/Tests/Tests.xcodeproj/project.pbxproj +++ b/Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -220,6 +221,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; }; name = Debug; }; @@ -231,6 +233,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; }; name = Release; }; From 8d4636648f751297d9b99e66f2170c564aed246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Tue, 30 Aug 2016 11:38:23 +0200 Subject: [PATCH 0075/1275] Uncomment Stack tests --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1eba40123..f430659e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ install: 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 ./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 ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests @@ -37,5 +37,5 @@ script: # - 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 ./Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests From adf2f61a6403d60ac0915bc234e29b6cc6712245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Tue, 30 Aug 2016 11:46:19 +0200 Subject: [PATCH 0076/1275] Fix .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f430659e0..2be5210c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ 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 ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests +# - xcodebuild test -project ./Binary\ Search/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 From 5ad3bb022e98b21b7a3a1d11d6cb32d5b4eff26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Tue, 30 Aug 2016 14:04:52 +0200 Subject: [PATCH 0077/1275] Update push method, update to recommended settings --- .travis.yml | 6 +++--- Stack/README.markdown | 4 ++-- Stack/Stack.playground/Contents.swift | 4 ++-- Stack/Tests/Tests.xcodeproj/project.pbxproj | 7 ++++++- .../Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2be5210c4..7ac58cd33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,9 @@ install: 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 ./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 ./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 diff --git a/Stack/README.markdown b/Stack/README.markdown index 17770643b..9d157f290 100644 --- a/Stack/README.markdown +++ b/Stack/README.markdown @@ -42,7 +42,7 @@ A stack is easy to create in Swift. It's just a wrapper around an array that jus ```swift public struct Stack { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -52,7 +52,7 @@ public struct Stack { return array.count } - public mutating func push(element: T) { + public mutating func push(_ element: T) { array.append(element) } diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 12c29faa0..f086ca817 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -22,7 +22,7 @@ public struct Stack { return array.isEmpty } - public mutating func push(element: T) { + public mutating func push(_ element: T) { array.append(element) } @@ -39,7 +39,7 @@ public struct Stack { var stackOfNames = Stack(array: ["Carl", "Lisa", "Stephanie", "Jeff", "Wade"]) // Add an element to the top of the stack. -stackOfNames.push(element: "Mike") +stackOfNames.push("Mike") // The stack is now ["Carl", "Lisa", "Stephanie", "Jeff", "Wade", "Mike"] print(stackOfNames.array) diff --git a/Stack/Tests/Tests.xcodeproj/project.pbxproj b/Stack/Tests/Tests.xcodeproj/project.pbxproj index 5ec8dc987..8924fc935 100644 --- a/Stack/Tests/Tests.xcodeproj/project.pbxproj +++ b/Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -83,7 +83,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -146,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -190,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; diff --git a/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 30 Aug 2016 15:15:28 +0200 Subject: [PATCH 0078/1275] Update Queue to Swift 3 --- .travis.yml | 2 +- Queue/Queue-Optimized.swift | 6 +++--- Queue/Queue-Simple.swift | 4 ++-- Queue/Queue.playground/Contents.swift | 4 ++-- Queue/README.markdown | 10 +++++----- Queue/Tests/Tests.xcodeproj/project.pbxproj | 10 +++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1eba40123..ff451b26e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ script: # - 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 ./Queue/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index 5a9d04394..ad6999295 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -7,8 +7,8 @@ Enqueuing and dequeuing are O(1) operations. */ public struct Queue { - private var array = [T?]() - private var head = 0 + fileprivate var array = [T?]() + fileprivate var head = 0 public var isEmpty: Bool { return count == 0 @@ -18,7 +18,7 @@ public struct Queue { return array.count - head } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Queue/Queue-Simple.swift b/Queue/Queue-Simple.swift index 6d3c197ee..27fbdee4d 100644 --- a/Queue/Queue-Simple.swift +++ b/Queue/Queue-Simple.swift @@ -8,7 +8,7 @@ implemented with a linked list, then both would be O(1). */ public struct Queue { - private var array = [T]() + fileprivate var array = [T]() public var count: Int { return array.count @@ -18,7 +18,7 @@ public struct Queue { return array.isEmpty } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index 0c48afd5b..6b771ccd1 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -12,7 +12,7 @@ */ public struct Queue { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -22,7 +22,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Queue/README.markdown b/Queue/README.markdown index 92118d37b..f7779aa69 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -46,7 +46,7 @@ Here is a very simplistic implementation of a queue in Swift. It's just a wrappe ```swift public struct Queue { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -56,7 +56,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } @@ -136,8 +136,8 @@ Here is how you could implement this version of `Queue`: ```swift public struct Queue { - private var array = [T?]() - private var head = 0 + fileprivate var array = [T?]() + fileprivate var head = 0 public var isEmpty: Bool { return count == 0 @@ -147,7 +147,7 @@ public struct Queue { return array.count - head } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj index ac23063a5..a554fd16e 100644 --- a/Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -83,11 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -145,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -189,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -209,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -220,6 +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; }; name = Debug; }; @@ -231,6 +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; }; name = Release; }; diff --git a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 30 Aug 2016 15:18:15 +0200 Subject: [PATCH 0079/1275] Fix .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ff451b26e..278aba883 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,5 +37,5 @@ script: # - 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 ./Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests From 8527a528c451b04d6e9c8a2ed4f54c77dfa9b831 Mon Sep 17 00:00:00 2001 From: Nemanja Vlahovic Date: Tue, 30 Aug 2016 22:21:21 +0200 Subject: [PATCH 0080/1275] Fix spaces in .travis.yml --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 278aba883..c2ac363d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,9 @@ install: 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 ./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 ./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 @@ -29,7 +29,7 @@ script: # - 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 ./Queue/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests @@ -37,5 +37,5 @@ script: # - 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 ./Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests From 7d1c4a3a3b11ba5583df7d14bcc1e43ba48fdfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Wed, 31 Aug 2016 09:56:45 +0200 Subject: [PATCH 0081/1275] Update Insertion Sort to Swift 3 --- .../InsertionSort.playground/Contents.swift | 4 +-- Insertion Sort/InsertionSort.swift | 2 +- Insertion Sort/README.markdown | 6 ++-- .../Tests/Tests.xcodeproj/project.pbxproj | 10 +++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Quicksort/Tests/SortingTestHelpers.swift | 34 +++++++++---------- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 867feb190..b25916b23 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -func insertionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { var a = array for x in 1..(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] insertionSort(list, <) -insertionSort(list, >) +insertionSort(list, >) \ No newline at end of file diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 886054e53..5d8a9565b 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -1,4 +1,4 @@ -func insertionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } var a = array diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index b67541669..286d92ed1 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -90,7 +90,7 @@ This was a description of the inner loop of the insertion sort algorithm, which Here is an implementation of insertion sort in Swift: ```swift -func insertionSort(array: [Int]) -> [Int] { +func insertionSort(_ array: [Int]) -> [Int] { var a = array // 1 for x in 1.. [Int] { +func insertionSort(_ array: [Int]) -> [Int] { var a = array for x in 1..(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { ``` The array has type `[T]` where `T` is the placeholder type for the generics. Now `insertionSort()` will accept any kind of array, whether it contains numbers, strings, or something else. diff --git a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj index f8c23899c..ee3ca1cae 100644 --- a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -224,6 +230,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; }; name = Debug; }; @@ -235,6 +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_VERSION = 3.0; }; 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 8ef8d8581..14f27f777 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 @@ [Int] { +func randomArray(_ size: Int) -> [Int] { var a = [Int]() for _ in 1...size { a.append(Int(arc4random_uniform(1000))) @@ -9,16 +9,16 @@ func randomArray(size: Int) -> [Int] { return a } -func arrayIsSortedLowToHigh(a: [Int]) -> Bool { +func arrayIsSortedLowToHigh(_ a: [Int]) -> Bool { for x in 1.. a[x] { return false } } return true } -typealias SortFunction = [Int] -> [Int] +typealias SortFunction = ([Int]) -> [Int] -func checkSortingRandomArray(sortFunction: SortFunction) { +func checkSortingRandomArray(_ sortFunction: SortFunction) { let numberOfIterations = 100 for _ in 1...numberOfIterations { let a = randomArray(Int(arc4random_uniform(100)) + 1) @@ -28,73 +28,73 @@ func checkSortingRandomArray(sortFunction: SortFunction) { } } -func checkSortingEmptyArray(sortFunction: SortFunction) { +func checkSortingEmptyArray(_ sortFunction: SortFunction) { let a = [Int]() let s = sortFunction(a) XCTAssertEqual(s.count, 0) } -func checkSortingArrayOneElement(sortFunction: SortFunction) { +func checkSortingArrayOneElement(_ sortFunction: SortFunction) { let a = [123] let s = sortFunction(a) XCTAssertEqual(s, [123]) } -func checkSortingArrayTwoElementsInOrder(sortFunction: SortFunction) { +func checkSortingArrayTwoElementsInOrder(_ sortFunction: SortFunction) { let a = [123, 456] let s = sortFunction(a) XCTAssertEqual(s, [123, 456]) } -func checkSortingArrayTwoElementsOutOfOrder(sortFunction: SortFunction) { +func checkSortingArrayTwoElementsOutOfOrder(_ sortFunction: SortFunction) { let a = [456, 123] let s = sortFunction(a) XCTAssertEqual(s, [123, 456]) } -func checkSortingArrayTwoEqualElements(sortFunction: SortFunction) { +func checkSortingArrayTwoEqualElements(_ sortFunction: SortFunction) { let a = [123, 123] let s = sortFunction(a) XCTAssertEqual(s, [123, 123]) } -func checkSortingArrayThreeElementsABC(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsABC(_ sortFunction: SortFunction) { let a = [2, 4, 6] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortingArrayThreeElementsACB(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsACB(_ sortFunction: SortFunction) { let a = [2, 6, 4] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortingArrayThreeElementsBAC(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsBAC(_ sortFunction: SortFunction) { let a = [4, 2, 6] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortingArrayThreeElementsBCA(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsBCA(_ sortFunction: SortFunction) { let a = [4, 6, 2] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortingArrayThreeElementsCAB(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsCAB(_ sortFunction: SortFunction) { let a = [6, 2, 4] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortingArrayThreeElementsCBA(sortFunction: SortFunction) { +func checkSortingArrayThreeElementsCBA(_ sortFunction: SortFunction) { let a = [6, 4, 2] let s = sortFunction(a) XCTAssertEqual(s, [2, 4, 6]) } -func checkSortAlgorithm(sortFunction: SortFunction) { +func checkSortAlgorithm(_ sortFunction: SortFunction) { checkSortingEmptyArray(sortFunction) checkSortingArrayOneElement(sortFunction) checkSortingArrayTwoElementsInOrder(sortFunction) @@ -109,6 +109,6 @@ func checkSortAlgorithm(sortFunction: SortFunction) { checkSortingRandomArray(sortFunction) } -func checkSortAlgorithm(sortFunction: ([Int], (Int, Int) -> Bool) -> [Int]) { +func checkSortAlgorithm(_ sortFunction: @escaping ([Int], (Int, Int) -> Bool) -> [Int]) { checkSortAlgorithm { a in sortFunction(a, <) } } From a50e2879edd581fcc3c8b8388dde19dc4877e114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Wed, 31 Aug 2016 10:01:20 +0200 Subject: [PATCH 0082/1275] Update travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1eba40123..6b1fe2dff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ script: # - 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 ./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 ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests @@ -37,5 +37,5 @@ script: # - 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 ./Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests From 8f0447566427f089789a29e01dbdc60e97bf2d01 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Wed, 31 Aug 2016 21:18:13 +1200 Subject: [PATCH 0083/1275] Update .travis.yml Removed space before insertion sort tests. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 32f43c129..8cf0b486b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ script: # - 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 ./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 ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests From 283ba84440385e36965943aa0581e6b81d917d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Wed, 31 Aug 2016 13:27:13 +0200 Subject: [PATCH 0084/1275] Update Merge Sort to Swift 3 --- Merge Sort/MergeSort.playground/Contents.swift | 6 +++--- Merge Sort/MergeSort.swift | 6 +++--- Merge Sort/README.markdown | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index a71a90136..ac166131e 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -1,6 +1,6 @@ /* Top-down recursive version */ -func mergeSort(array: [Int]) -> [Int] { +func mergeSort(_ array: [Int]) -> [Int] { guard array.count > 1 else { return array } let middleIndex = array.count / 2 let leftArray = mergeSort(Array(array[0.. [Int] { return merge(leftPile: leftArray, rightPile: rightArray) } -func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { var leftIndex = 0 var rightIndex = 0 var orderedPile = [Int]() @@ -48,7 +48,7 @@ let sortedArray = mergeSort(array) /* Bottom-up iterative version */ -func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func mergeSortBottomUp(_ a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { let n = a.count var z = [a, a] // the two working arrays var d = 0 // z[d] is used for reading, z[1 - d] for writing diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index 968484dd1..20316663f 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -6,7 +6,7 @@ // // -func mergeSort(array: [Int]) -> [Int] { +func mergeSort(_ array: [Int]) -> [Int] { guard array.count > 1 else { return array } let middleIndex = array.count / 2 let leftArray = mergeSort(Array(array[0.. [Int] { return merge(leftPile: leftArray, rightPile: rightArray) } -func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { var leftIndex = 0 var rightIndex = 0 var orderedPile = [Int]() @@ -59,7 +59,7 @@ func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] { To avoid allocating many temporary array objects, it uses double-buffering with just two arrays. */ -func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func mergeSortBottomUp(_ a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { let n = a.count var z = [a, a] // the two working arrays var d = 0 // z[d] is used for reading, z[1 - d] for writing diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index a24c71f2f..3ff69fdd5 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -42,7 +42,7 @@ You're left with only two piles and `[9]` finally gets its chance to merge, resu Here's what merge sort may look like in Swift: ```swift -func mergeSort(array: [Int]) -> [Int] { +func mergeSort(_ array: [Int]) -> [Int] { guard array.count > 1 else { return array } // 1 let middleIndex = array.count / 2 // 2 @@ -70,7 +70,7 @@ A step-by-step explanation of how the code works: Here's the merging algorithm: ```swift -func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { // 1 var leftIndex = 0 var rightIndex = 0 @@ -162,7 +162,7 @@ The implementation of merge sort you've seen so far is called "top-down" because Time to step up the game a little. :-) Here is a complete bottom-up implementation in Swift: ```swift -func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func mergeSortBottomUp(_ a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { let n = a.count var z = [a, a] // 1 From 33b6e653c03765fbaad06423bd2122de4199686e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Wed, 31 Aug 2016 13:46:09 +0200 Subject: [PATCH 0085/1275] Update Linear Search to Swift 3 --- Linear Search/LinearSearch.playground/Contents.swift | 4 ++-- Linear Search/LinearSearch.swift | 4 ++-- Linear Search/README.markdown | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Linear Search/LinearSearch.playground/Contents.swift b/Linear Search/LinearSearch.playground/Contents.swift index 02fb6e940..34e859fa3 100644 --- a/Linear Search/LinearSearch.playground/Contents.swift +++ b/Linear Search/LinearSearch.playground/Contents.swift @@ -1,7 +1,7 @@ //: Playground - noun: a place where people can play -func linearSearch(array: [T], _ object: T) -> Int? { - for (index, obj) in array.enumerate() where obj == object { +func linearSearch(_ array: [T], _ object: T) -> Int? { + for (index, obj) in array.enumerated() where obj == object { return index } return nil diff --git a/Linear Search/LinearSearch.swift b/Linear Search/LinearSearch.swift index fe64ef24e..882795180 100644 --- a/Linear Search/LinearSearch.swift +++ b/Linear Search/LinearSearch.swift @@ -1,5 +1,5 @@ -func linearSearch(array: [T], _ object: T) -> Int? { - for (index, obj) in array.enumerate() where obj == object { +func linearSearch(_ array: [T], _ object: T) -> Int? { + for (index, obj) in array.enumerated() where obj == object { return index } return nil diff --git a/Linear Search/README.markdown b/Linear Search/README.markdown index 115dd7ee2..4649f4fc4 100644 --- a/Linear Search/README.markdown +++ b/Linear Search/README.markdown @@ -17,8 +17,8 @@ We compare the number `2` from the array to our number `2` and notice they are e Here is a simple implementation of linear search in Swift: ```swift -func linearSearch(array: [T], _ object: T) -> Int? { - for (index, obj) in array.enumerate() where obj == object { +func linearSearch(_ array: [T], _ object: T) -> Int? { + for (index, obj) in array.enumerated() where obj == object { return index } return nil From 7f627a21b2beb5cf9f72c77eccb151ef66231d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nemanja=20Vlahovic=CC=81?= Date: Wed, 31 Aug 2016 14:02:17 +0200 Subject: [PATCH 0086/1275] Update Count Occurrences to Swift 3 --- Count Occurrences/CountOccurrences.playground/Contents.swift | 4 ++-- Count Occurrences/CountOccurrences.swift | 2 +- Count Occurrences/README.markdown | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index b90ba12ce..cbb43c868 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { +func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { func leftBoundary() -> Int { var low = 0 var high = a.count @@ -53,7 +53,7 @@ func createArray() -> [Int] { } } } - return a.sort(<) + return a.sorted() } for _ in 0..<10 { diff --git a/Count Occurrences/CountOccurrences.swift b/Count Occurrences/CountOccurrences.swift index 57c75c735..10dd12c4f 100644 --- a/Count Occurrences/CountOccurrences.swift +++ b/Count Occurrences/CountOccurrences.swift @@ -2,7 +2,7 @@ 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 countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { func leftBoundary() -> Int { var low = 0 var high = a.count diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index be8c2061e..90a9ec2f3 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,7 +22,7 @@ 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 countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { func leftBoundary() -> Int { var low = 0 var high = a.count From ecae2cc08805bc2be1a22d4482a9d97e86d1776a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Simk=C3=B3?= Date: Thu, 1 Sep 2016 10:53:51 +0200 Subject: [PATCH 0087/1275] migrated to Swift 3 --- B-Tree/BTree.swift | 419 +++++++++++------- B-Tree/Tests/Tests.xcodeproj/project.pbxproj | 10 +- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- B-Tree/Tests/Tests/BTreeNodeTests.swift | 16 +- B-Tree/Tests/Tests/BTreeTests.swift | 36 +- 5 files changed, 303 insertions(+), 180 deletions(-) diff --git a/B-Tree/BTree.swift b/B-Tree/BTree.swift index 16c4eabe4..f5638ea4e 100644 --- a/B-Tree/BTree.swift +++ b/B-Tree/BTree.swift @@ -21,17 +21,17 @@ // SOFTWARE. /* - B-Tree - - A B-Tree is a self-balancing search tree, in which nodes can have more than two children. + * B-Tree + * + * A B-Tree is a self-balancing search tree, in which nodes can have more than two children. */ // MARK: - BTreeNode class class BTreeNode { - unowned var ownerTree: BTree + unowned var owner: BTree - private var keys = [Key]() + fileprivate var keys = [Key]() var values = [Value]() var children: [BTreeNode]? @@ -43,13 +43,13 @@ class BTreeNode { return keys.count } - init(ownerTree: BTree) { - self.ownerTree = ownerTree + init(owner: BTree) { + self.owner = owner } - convenience init(ownerTree: BTree, keys: [Key], + convenience init(owner: BTree, keys: [Key], values: [Value], children: [BTreeNode]? = nil) { - self.init(ownerTree: ownerTree) + self.init(owner: owner) self.keys += keys self.values += values self.children = children @@ -59,19 +59,26 @@ class BTreeNode { // MARK: BTreeNode extesnion: Searching extension BTreeNode { - func valueForKey(key: Key) -> Value? { + + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ + func value(for key: Key) -> Value? { var index = keys.startIndex - while index.successor() < keys.endIndex && keys[index] < key { - index = index.successor() + while (index + 1) < keys.endIndex && keys[index] < key { + index = (index + 1) } if key == keys[index] { return values[index] } else if key < keys[index] { - return children?[index].valueForKey(key) + return children?[index].value(for: key) } else { - return children?[index.successor()].valueForKey(key) + return children?[(index + 1)].value(for: key) } } } @@ -79,7 +86,14 @@ extension BTreeNode { // MARK: BTreeNode extension: Travelsals extension BTreeNode { - func traverseKeysInOrder(@noescape process: Key -> Void) { + + /** + * Traverses the keys in order, executes `process` for every key. + * + * - Parameters: + * - process: the closure to be executed for every key + */ + func traverseKeysInOrder(_ process: (Key) -> Void) { for i in 0.. ownerTree.order * 2 { - splitChild(children![index], atIndex: index) + children![index].insert(value, for: key) + if children![index].numberOfKeys > owner.order * 2 { + split(children![index], at: index) } } } - private func splitChild(child: BTreeNode, atIndex index: Int) { + /** + * Splits `child` at `index`. + * The key-value pair at `index` gets moved up to the parent node, + * or if there is not an parent node, then a new parent node is created. + * + * - Parameters: + * - child: the child to be split + * - index: the index of the key, which will be moved up to the parent + */ + fileprivate func split(_ child: BTreeNode, at index: Int) { let middleIndex = child.numberOfKeys / 2 - keys.insert(child.keys[middleIndex], atIndex: index) - values.insert(child.values[middleIndex], atIndex: index) - child.keys.removeAtIndex(middleIndex) - child.values.removeAtIndex(middleIndex) + keys.insert(child.keys[middleIndex], at: index) + values.insert(child.values[middleIndex], at: index) + child.keys.remove(at: middleIndex) + child.values.remove(at: middleIndex) let rightSibling = BTreeNode( - ownerTree: ownerTree, - keys: Array(child.keys[middleIndex..= 0 && - children![index.predecessor()].numberOfKeys > ownerTree.order { - - moveKeyAtIndex(index.predecessor(), toNode: child, - fromNode: children![index.predecessor()], atPosition: .Left) - - } else if index.successor() < children!.count && - children![index.successor()].numberOfKeys > ownerTree.order { - - moveKeyAtIndex(index, toNode: child, - fromNode: children![index.successor()], atPosition: .Right) - - } else if index.predecessor() >= 0 { - mergeChild(child, withIndex: index, toNodeAtPosition: .Left) + if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { + move(keyAt: (index - 1), to: child, from: children![(index - 1)], at: .left) + } else if (index + 1) < children!.count && children![(index + 1)].numberOfKeys > owner.order { + move(keyAt: index, to: child, from: children![(index + 1)], at: .right) + } else if (index - 1) >= 0 { + merge(child, at: index, to: .left) } else { - mergeChild(child, withIndex: index, toNodeAtPosition: .Right) + merge(child, at: index, to: .right) } } - private func moveKeyAtIndex(keyIndex: Int, toNode targetNode: BTreeNode, - fromNode: BTreeNode, atPosition position: BTreeNodePosition) { + /** + * Moves the key at the specified `index` from `node` to + * the `targetNode` at `position` + * + * - Parameters: + * - index: the index of the key to be moved in `node` + * - targetNode: the node to move the key into + * - node: the node to move the key from + * - position: the position of the from node relative to the targetNode + */ + fileprivate func move(keyAt index: Int, to targetNode: BTreeNode, + from node: BTreeNode, at position: BTreeNodePosition) { switch position { - case .Left: - targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.startIndex) - targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.startIndex) - keys[keyIndex] = fromNode.keys.last! - values[keyIndex] = fromNode.values.last! - fromNode.keys.removeLast() - fromNode.values.removeLast() + case .left: + targetNode.keys.insert(keys[index], at: targetNode.keys.startIndex) + targetNode.values.insert(values[index], at: targetNode.values.startIndex) + keys[index] = node.keys.last! + values[index] = node.values.last! + node.keys.removeLast() + node.values.removeLast() if !targetNode.isLeaf { - targetNode.children!.insert(fromNode.children!.last!, - atIndex: targetNode.children!.startIndex) - fromNode.children!.removeLast() + targetNode.children!.insert(node.children!.last!, + at: targetNode.children!.startIndex) + node.children!.removeLast() } - case .Right: - targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.endIndex) - targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.endIndex) - keys[keyIndex] = fromNode.keys.first! - values[keyIndex] = fromNode.values.first! - fromNode.keys.removeFirst() - fromNode.values.removeFirst() + case .right: + targetNode.keys.insert(keys[index], at: targetNode.keys.endIndex) + targetNode.values.insert(values[index], at: targetNode.values.endIndex) + keys[index] = node.keys.first! + values[index] = node.values.first! + node.keys.removeFirst() + node.values.removeFirst() if !targetNode.isLeaf { - targetNode.children!.insert(fromNode.children!.first!, - atIndex: targetNode.children!.endIndex) - fromNode.children!.removeFirst() + targetNode.children!.insert(node.children!.first!, + at: targetNode.children!.endIndex) + node.children!.removeFirst() } } } - private func mergeChild(child: BTreeNode, withIndex index: Int, toNodeAtPosition position: BTreeNodePosition) { + /** + * Merges `child` at `position` to the node at the `position`. + * + * - Parameters: + * - child: the child to be merged + * - index: the index of the child in the current node + * - position: the position of the node to merge into + */ + fileprivate func merge(_ child: BTreeNode, at index: Int, to position: BTreeNodePosition) { switch position { - case .Left: + case .left: // We can merge to the left sibling - children![index.predecessor()].keys = children![index.predecessor()].keys + - [keys[index.predecessor()]] + child.keys + children![(index - 1)].keys = children![(index - 1)].keys + + [keys[(index - 1)]] + child.keys - children![index.predecessor()].values = children![index.predecessor()].values + - [values[index.predecessor()]] + child.values + children![(index - 1)].values = children![(index - 1)].values + + [values[(index - 1)]] + child.values - keys.removeAtIndex(index.predecessor()) - values.removeAtIndex(index.predecessor()) + keys.remove(at: (index - 1)) + values.remove(at: (index - 1)) if !child.isLeaf { - children![index.predecessor()].children = - children![index.predecessor()].children! + child.children! + children![(index - 1)].children = + children![(index - 1)].children! + child.children! } - case .Right: + case .right: // We should merge to the right sibling - children![index.successor()].keys = child.keys + [keys[index]] + - children![index.successor()].keys + children![(index + 1)].keys = child.keys + [keys[index]] + + children![(index + 1)].keys - children![index.successor()].values = child.values + [values[index]] + - children![index.successor()].values + children![(index + 1)].values = child.values + [values[index]] + + children![(index + 1)].values - keys.removeAtIndex(index) - values.removeAtIndex(index) + keys.remove(at: index) + values.remove(at: index) if !child.isLeaf { - children![index.successor()].children = - child.children! + children![index.successor()].children! + children![(index + 1)].children = + child.children! + children![(index + 1)].children! } } - children!.removeAtIndex(index) + children!.remove(at: index) } } // MARK: BTreeNode extension: Conversion extension BTreeNode { - func inorderArrayFromKeys() -> [Key] { + /** + * Returns an array which contains the keys from the current node + * and its descendants in order. + */ + var inorderArrayFromKeys: [Key] { var array = [Key] () for i in 0.. { - +open class BTree { /** - The order of the B-Tree - - The number of keys in every node should be in the [order, 2*order] range, - except the root node which is allowed to contain less keys than the value of order. + * The order of the B-Tree + * + * The number of keys in every node should be in the [order, 2*order] range, + * except the root node which is allowed to contain less keys than the value of order. */ - public let order: Int + open let order: Int - /// The root node of the tree + /** + * The root node of the tree + */ var rootNode: BTreeNode! - private(set) public var numberOfKeys = 0 + fileprivate(set) open var numberOfKeys = 0 /** - Designated initializer for the tree - - - parameters: - - order: The order of the tree. + * Designated initializer for the tree + * + * - Parameters: + * - order: The order of the tree. */ public init?(order: Int) { guard order > 0 else { @@ -362,14 +435,20 @@ public class BTree { return nil } self.order = order - rootNode = BTreeNode(ownerTree: self) + rootNode = BTreeNode(owner: self) } } // MARK: BTree extension: Travelsals extension BTree { - public func traverseKeysInOrder(@noescape process: Key -> Void) { + /** + * Traverses the keys in order, executes `process` for every key. + * + * - Parameters: + * - process: the closure to be executed for every key + */ + public func traverseKeysInOrder(_ process: (Key) -> Void) { rootNode.traverseKeysInOrder(process) } } @@ -377,6 +456,12 @@ extension BTree { // MARK: BTree extension: Subscript extension BTree { + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ public subscript (key: Key) -> Value? { return valueForKey(key) } @@ -385,52 +470,71 @@ extension BTree { // MARK: BTree extension: Value for Key extension BTree { - public func valueForKey(key: Key) -> Value? { + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ + public func valueForKey(_ key: Key) -> Value? { guard rootNode.numberOfKeys > 0 else { return nil } - return rootNode.valueForKey(key) + return rootNode.value(for: key) } } // MARK: BTree extension: Insertion extension BTree { - public func insertValue(value: Value, forKey key: Key) { - rootNode.insertValue(value, forKey: key) + /** + * Inserts the `value` for the `key` into the tree. + * + * - Parameters: + * - value: the value to be inserted for `key` + * - key: the key for the `value` + */ + public func insert(_ value: Value, for key: Key) { + rootNode.insert(value, for: key) if rootNode.numberOfKeys > order * 2 { splitRoot() } } - private func splitRoot() { + /** + * Splits the root node of the tree. + * + * - Precondition: + * The root node of the tree contains `order` * 2 keys. + */ + fileprivate func splitRoot() { let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 let newRoot = BTreeNode( - ownerTree: self, + owner: self, keys: [rootNode.keys[middleIndexOfOldRoot]], values: [rootNode.values[middleIndexOfOldRoot]], children: [rootNode] ) - rootNode.keys.removeAtIndex(middleIndexOfOldRoot) - rootNode.values.removeAtIndex(middleIndexOfOldRoot) + rootNode.keys.remove(at: middleIndexOfOldRoot) + rootNode.values.remove(at: middleIndexOfOldRoot) let newRightChild = BTreeNode( - ownerTree: self, - keys: Array(rootNode.keys[middleIndexOfOldRoot.. 0 else { return } - rootNode.removeKey(key) + rootNode.remove(key) if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { rootNode = rootNode.children!.first! @@ -458,15 +568,20 @@ extension BTree { // MARK: BTree extension: Conversion extension BTree { - public func inorderArrayFromKeys() -> [Key] { - return rootNode.inorderArrayFromKeys() + /** + * The keys of the tree in order. + */ + public var inorderArrayFromKeys: [Key] { + return rootNode.inorderArrayFromKeys } } // MARK: BTree extension: Decription extension BTree: CustomStringConvertible { - // Returns a String containing the preorder representation of the nodes + /** + * Returns a String containing the preorder representation of the nodes. + */ public var description: String { return rootNode.description } diff --git a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj index 0780f04c8..79552bbe5 100644 --- a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj +++ b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -85,11 +85,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Viktor Szilárd Simkó"; TargetAttributes = { C66702771D0EEE25008CD769 = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; }; }; }; @@ -148,8 +149,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -226,6 +232,7 @@ PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -238,6 +245,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index d9200547d..9d6c542ae 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 @@ (order: 2)! + let owner = BTree(order: 2)! var root: BTreeNode! var leftChild: BTreeNode! var rightChild: BTreeNode! @@ -18,11 +18,11 @@ class BTreeNodeTests: XCTestCase { override func setUp() { super.setUp() - root = BTreeNode(ownerTree: ownerTree) - leftChild = BTreeNode(ownerTree: ownerTree) - rightChild = BTreeNode(ownerTree: ownerTree) + root = BTreeNode(owner: owner) + leftChild = BTreeNode(owner: owner) + rightChild = BTreeNode(owner: owner) - root.insertValue(1, forKey: 1) + root.insert(1, for: 1) root.children = [leftChild, rightChild] } @@ -36,9 +36,9 @@ class BTreeNodeTests: XCTestCase { } func testOwner() { - XCTAssert(root.ownerTree === ownerTree) - XCTAssert(leftChild.ownerTree === ownerTree) - XCTAssert(rightChild.ownerTree === ownerTree) + XCTAssert(root.owner === owner) + XCTAssert(leftChild.owner === owner) + XCTAssert(rightChild.owner === owner) } func testNumberOfKeys() { diff --git a/B-Tree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift index 947781478..231a423e2 100644 --- a/B-Tree/Tests/Tests/BTreeTests.swift +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -45,7 +45,7 @@ class BTreeTests: XCTestCase { } func testInsertToEmptyTree() { - bTree.insertValue(1, forKey: 1) + bTree.insert(1, for: 1) XCTAssertEqual(bTree[1]!, 1) } @@ -56,7 +56,7 @@ class BTreeTests: XCTestCase { } func testInorderArrayFromEmptyTree() { - XCTAssertEqual(bTree.inorderArrayFromKeys(), [Int]()) + XCTAssertEqual(bTree.inorderArrayFromKeys, [Int]()) } func testDescriptionOfEmptyTree() { @@ -67,7 +67,7 @@ class BTreeTests: XCTestCase { func testInorderTravelsal() { for i in 1...20 { - bTree.insertValue(i, forKey: i) + bTree.insert(i, for: i) } var j = 1 @@ -82,7 +82,7 @@ class BTreeTests: XCTestCase { func testSearchForMaximum() { for i in 1...20 { - bTree.insertValue(i, forKey: i) + bTree.insert(i, for: i) } XCTAssertEqual(bTree.valueForKey(20)!, 20) @@ -90,7 +90,7 @@ class BTreeTests: XCTestCase { func testSearchForMinimum() { for i in 1...20 { - bTree.insertValue(i, forKey: i) + bTree.insert(i, for: i) } XCTAssertEqual(bTree.valueForKey(1)!, 1) @@ -118,7 +118,7 @@ class BTreeTests: XCTestCase { func testRemoveMaximum() { for i in 1...20 { - bTree.insertValue(i, forKey: i) + bTree.insert(i, for: i) } bTree.removeKey(20) @@ -184,7 +184,7 @@ class BTreeTests: XCTestCase { XCTAssertEqual(bTree.numberOfKeys, 20) - for i in (1...20).reverse() { + for i in (1...20).reversed() { bTree.removeKey(i) } @@ -202,24 +202,24 @@ class BTreeTests: XCTestCase { func testInorderArray() { bTree.insertKeysUpTo(20) - let returnedArray = bTree.inorderArrayFromKeys() + let returnedArray = bTree.inorderArrayFromKeys let targetArray = Array(1...20) XCTAssertEqual(returnedArray, targetArray) } } -enum BTreeError: ErrorType { - case TooManyNodes - case TooFewNodes +enum BTreeError: Error { + case tooManyNodes + case tooFewNodes } extension BTreeNode { func checkBalanced(isRoot root: Bool) throws { - if numberOfKeys > ownerTree.order * 2 { - throw BTreeError.TooManyNodes - } else if !root && numberOfKeys < ownerTree.order { - throw BTreeError.TooFewNodes + if numberOfKeys > owner.order * 2 { + throw BTreeError.tooManyNodes + } else if !root && numberOfKeys < owner.order { + throw BTreeError.tooFewNodes } if !isLeaf { @@ -230,13 +230,13 @@ extension BTreeNode { } } -extension BTree where Key: SignedIntegerType, Value: SignedIntegerType { - func insertKeysUpTo(to: Int) { +extension BTree where Key: SignedInteger, Value: SignedInteger { + func insertKeysUpTo(_ to: Int) { var k: Key = 1 var v: Value = 1 for _ in 1...to { - insertValue(v, forKey: k) + insert(v, for: k) k = k + 1 v = v + 1 } From 9b3458e6fb974d2e1c02a4df6790a54e7c435975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Simk=C3=B3?= Date: Thu, 1 Sep 2016 10:56:05 +0200 Subject: [PATCH 0088/1275] updated .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8cf0b486b..edfe5e624 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ script: # - 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 ./B-Tree/Tests/Tests.xcodeproj -scheme Tests # - 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 From 7f71ac77f17565f94444843d0c854c345aaa5298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Simk=C3=B3?= Date: Thu, 1 Sep 2016 12:16:42 +0200 Subject: [PATCH 0089/1275] corrected method naming --- B-Tree/BTree.swift | 45 +++++++++++++++-------------- B-Tree/Tests/Tests/BTreeTests.swift | 22 +++++++------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/B-Tree/BTree.swift b/B-Tree/BTree.swift index f5638ea4e..e6494af0a 100644 --- a/B-Tree/BTree.swift +++ b/B-Tree/BTree.swift @@ -29,10 +29,13 @@ // MARK: - BTreeNode class class BTreeNode { + /** + * The tree that owns the node. + */ unowned var owner: BTree fileprivate var keys = [Key]() - var values = [Value]() + fileprivate var values = [Value]() var children: [BTreeNode]? var isLeaf: Bool { @@ -147,7 +150,7 @@ extension BTreeNode { * - child: the child to be split * - index: the index of the key, which will be moved up to the parent */ - fileprivate func split(_ child: BTreeNode, at index: Int) { + private func split(_ child: BTreeNode, at index: Int) { let middleIndex = child.numberOfKeys / 2 keys.insert(child.keys[middleIndex], at: index) values.insert(child.values[middleIndex], at: index) @@ -188,7 +191,7 @@ private enum BTreeNodePosition { } extension BTreeNode { - fileprivate var inorderPredecessor: BTreeNode { + private var inorderPredecessor: BTreeNode { if isLeaf { return self } else { @@ -221,7 +224,7 @@ extension BTreeNode { values[index] = predecessor.values.last! children![index].remove(keys[index]) if children![index].numberOfKeys < owner.order { - fix(children![index], at: index) + fix(child: children![index], at: index) } } } else if key < keys[index] { @@ -230,7 +233,7 @@ extension BTreeNode { if let leftChild = children?[index] { leftChild.remove(key) if leftChild.numberOfKeys < owner.order { - fix(leftChild, at: index) + fix(child: leftChild, at: index) } } else { print("The key:\(key) is not in the tree.") @@ -241,7 +244,7 @@ extension BTreeNode { if let rightChild = children?[(index + 1)] { rightChild.remove(key) if rightChild.numberOfKeys < owner.order { - fix(rightChild, at: (index + 1)) + fix(child: rightChild, at: (index + 1)) } } else { print("The key:\(key) is not in the tree") @@ -259,16 +262,16 @@ extension BTreeNode { * - child: the child to be fixed * - index: the index of the child to be fixed in the current node */ - fileprivate func fix(_ child: BTreeNode, at index: Int) { + private func fix(child: BTreeNode, at index: Int) { if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { - move(keyAt: (index - 1), to: child, from: children![(index - 1)], at: .left) + move(keyAtIndex: (index - 1), to: child, from: children![(index - 1)], at: .left) } else if (index + 1) < children!.count && children![(index + 1)].numberOfKeys > owner.order { - move(keyAt: index, to: child, from: children![(index + 1)], at: .right) + move(keyAtIndex: index, to: child, from: children![(index + 1)], at: .right) } else if (index - 1) >= 0 { - merge(child, at: index, to: .left) + merge(child: child, atIndex: index, to: .left) } else { - merge(child, at: index, to: .right) + merge(child: child, atIndex: index, to: .right) } } @@ -282,7 +285,7 @@ extension BTreeNode { * - node: the node to move the key from * - position: the position of the from node relative to the targetNode */ - fileprivate func move(keyAt index: Int, to targetNode: BTreeNode, + private func move(keyAtIndex index: Int, to targetNode: BTreeNode, from node: BTreeNode, at position: BTreeNodePosition) { switch position { case .left: @@ -321,7 +324,7 @@ extension BTreeNode { * - index: the index of the child in the current node * - position: the position of the node to merge into */ - fileprivate func merge(_ child: BTreeNode, at index: Int, to position: BTreeNodePosition) { + private func merge(child: BTreeNode, atIndex index: Int, to position: BTreeNodePosition) { switch position { case .left: // We can merge to the left sibling @@ -407,21 +410,21 @@ extension BTreeNode: CustomStringConvertible { // MARK: - BTree class -open class BTree { +public class BTree { /** * The order of the B-Tree * * The number of keys in every node should be in the [order, 2*order] range, * except the root node which is allowed to contain less keys than the value of order. */ - open let order: Int + public let order: Int - /** + /** * The root node of the tree */ var rootNode: BTreeNode! - fileprivate(set) open var numberOfKeys = 0 + fileprivate(set) public var numberOfKeys = 0 /** * Designated initializer for the tree @@ -463,7 +466,7 @@ extension BTree { * - key: the key of the value to be returned */ public subscript (key: Key) -> Value? { - return valueForKey(key) + return value(for: key) } } @@ -476,7 +479,7 @@ extension BTree { * - Parameters: * - key: the key of the value to be returned */ - public func valueForKey(_ key: Key) -> Value? { + public func value(for key: Key) -> Value? { guard rootNode.numberOfKeys > 0 else { return nil } @@ -509,7 +512,7 @@ extension BTree { * - Precondition: * The root node of the tree contains `order` * 2 keys. */ - fileprivate func splitRoot() { + private func splitRoot() { let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 let newRoot = BTreeNode( @@ -552,7 +555,7 @@ extension BTree { * - Parameters: * - key: the key to remove */ - public func removeKey(_ key: Key) { + public func remove(_ key: Key) { guard rootNode.numberOfKeys > 0 else { return } diff --git a/B-Tree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift index 231a423e2..f81016ae7 100644 --- a/B-Tree/Tests/Tests/BTreeTests.swift +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -41,7 +41,7 @@ class BTreeTests: XCTestCase { } func testSearchEmptyTree() { - XCTAssertEqual(bTree.valueForKey(1), nil) + XCTAssertEqual(bTree.value(for: 1), nil) } func testInsertToEmptyTree() { @@ -51,7 +51,7 @@ class BTreeTests: XCTestCase { } func testRemoveFromEmptyTree() { - bTree.removeKey(1) + bTree.remove(1) XCTAssertEqual(bTree.description, "[]") } @@ -85,7 +85,7 @@ class BTreeTests: XCTestCase { bTree.insert(i, for: i) } - XCTAssertEqual(bTree.valueForKey(20)!, 20) + XCTAssertEqual(bTree.value(for: 20)!, 20) } func testSearchForMinimum() { @@ -93,7 +93,7 @@ class BTreeTests: XCTestCase { bTree.insert(i, for: i) } - XCTAssertEqual(bTree.valueForKey(1)!, 1) + XCTAssertEqual(bTree.value(for: 1)!, 1) } // MARK: - Insertion @@ -121,7 +121,7 @@ class BTreeTests: XCTestCase { bTree.insert(i, for: i) } - bTree.removeKey(20) + bTree.remove(20) XCTAssertNil(bTree[20]) @@ -135,7 +135,7 @@ class BTreeTests: XCTestCase { func testRemoveMinimum() { bTree.insertKeysUpTo(20) - bTree.removeKey(1) + bTree.remove(1) XCTAssertNil(bTree[1]) @@ -149,8 +149,8 @@ class BTreeTests: XCTestCase { func testRemoveSome() { bTree.insertKeysUpTo(20) - bTree.removeKey(6) - bTree.removeKey(9) + bTree.remove(6) + bTree.remove(9) XCTAssertNil(bTree[6]) XCTAssertNil(bTree[9]) @@ -166,8 +166,8 @@ class BTreeTests: XCTestCase { bTree = BTree(order: 2)! bTree.insertKeysUpTo(20) - bTree.removeKey(6) - bTree.removeKey(9) + bTree.remove(6) + bTree.remove(9) XCTAssertNil(bTree[6]) XCTAssertNil(bTree[9]) @@ -185,7 +185,7 @@ class BTreeTests: XCTestCase { XCTAssertEqual(bTree.numberOfKeys, 20) for i in (1...20).reversed() { - bTree.removeKey(i) + bTree.remove(i) } do { From 26b9b64d66b693ee83346c470aefc9f68ae94bb6 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 1 Sep 2016 17:05:20 +0200 Subject: [PATCH 0090/1275] Update README.md --- Skip-List/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index ca1dce7ae..1722e1fe6 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -1,3 +1,8 @@ # Skip List -> Skip lists are a probabilistic data structure that seem likely to supplant balanced trees as the implementation method of choice for many applications. Skip list algorithms have the same asymptotic expected time bounds as balanced trees and are simpler, faster and use less space. -**[William Pugh](https://en.wikipedia.org/wiki/William_Pugh)** +Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. Fast searching is possible by building a hierarchy of sorted linked-lists acting as an express lane to the layer underneath. Layers are created on top of the base layer ( regular sorted linked-list ) probablisticly by coin-flipping. + +A layer consists of a Head node, holding reference to the next and the node below. Each node has also same references similar to the Head node. + +#TODO + - finish readme From 568ae3cded5c0530d50926136f916ec6b499c4ce Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 1 Sep 2016 17:05:56 +0200 Subject: [PATCH 0091/1275] Images folder --- Skip-List/Images/base | 1 + 1 file changed, 1 insertion(+) create mode 100644 Skip-List/Images/base diff --git a/Skip-List/Images/base b/Skip-List/Images/base new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Skip-List/Images/base @@ -0,0 +1 @@ + From afec24cba04b3d084f463c3f5185c7b4af5fee6a Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 1 Sep 2016 17:06:06 +0200 Subject: [PATCH 0092/1275] Delete base --- Skip-List/Images/base | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Skip-List/Images/base diff --git a/Skip-List/Images/base b/Skip-List/Images/base deleted file mode 100644 index 8b1378917..000000000 --- a/Skip-List/Images/base +++ /dev/null @@ -1 +0,0 @@ - From 6db2dd7758a6f0bcadab6be316489887a7814b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szil=C3=A1rd=20Simk=C3=B3?= Date: Thu, 1 Sep 2016 19:28:19 +0200 Subject: [PATCH 0093/1275] updated README.md --- B-Tree/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/B-Tree/README.md b/B-Tree/README.md index 28b617ca1..493fdedfb 100644 --- a/B-Tree/README.md +++ b/B-Tree/README.md @@ -20,9 +20,9 @@ A second order B-Tree with keys from 1 to 20 looks like this: ```swift class BTreeNode { - unowned var ownerTree: BTree + unowned var owner: BTree - private var keys = [Key]() + fileprivate var keys = [Key]() var children: [BTreeNode]? ... @@ -55,7 +55,7 @@ This is necessary because nodes have to know the order of the tree. ### The code -`valueForKey(_:)` method searches for the given key and if it's in the tree, +`value(for:)` method searches for the given key and if it's in the tree, it returns the value associated with it, else it returns `nil`. ## Insertion @@ -72,7 +72,7 @@ Keys can only be inserted to leaf nodes. After insertion we should check if the number of keys in the node is in the correct range. If there are more keys in the node than `order*2`, we need to split the node. -####Splitting a node +#### Splitting a node 1. Move up the middle key of the node we want to split, to its parent (if it has one). 2. If it hasn't got a parent(it is the root), then create a new root and insert to it. @@ -90,9 +90,9 @@ An insertion to a first order tree looks like this: ### The code -The method `insertValue(_:forKey:)` does the insertion. +The method `insert(_:for:)` does the insertion. After it has inserted a key, as the recursion goes up every node checks the number of keys in its child. -if a node has too many keys, its parent calls the `splitChild(_:atIndex:)` method on it. +if a node has too many keys, its parent calls the `split(child:atIndex:)` method on it. The root node is checked by the tree itself. If the root has too many nodes after the insertion the tree calls the `splitRoot()` method. @@ -112,7 +112,7 @@ After a key have been removed from a node we should check that the node has enou If a node has fewer keys than the order of the tree, then we should move a key to it, or merge it with one of its siblings. -####Moving a key to the child +#### Moving a key to the child If the problematic node has a nearest sibling that has more keys than the order of the tree, we should perform this operation on the tree, else we should merge the node with one of its siblings. @@ -156,13 +156,13 @@ so in the worst case merging also can go up to the root, in which case the heigh ### The code -- `removeKey(_:)` method removes the given key from the tree. After a key has been deleted, +- `remove(_:)` method removes the given key from the tree. After a key has been deleted, every node checks the number of keys in its child. If a child has less nodes than the order of the tree, - it calls the `fixChildWithLessNodesThanOrder(_:atIndex:)` method. + it calls the `fix(childWithTooFewKeys:atIndex:)` method. -- `fixChildWithLessNodesThanOrder(_:atIndex:)` method decides which way to fix the child (by moving a key to it, - or by merging it), then calls `moveKeyAtIndex(keyIndex:toNode:fromNode:atPosition:)` or - `mergeChild(_:withIndex:toNodeAtPosition:)` method according to its choice. +- `fix(childWithTooFewKeys:atIndex:)` method decides which way to fix the child (by moving a key to it, + or by merging it), then calls `move(keyAtIndex:to:from:at:)` or + `merge(child:atIndex:to:)` method according to its choice. ## See also From 3bc80955f527274fc3ab4a9f4dedf71198b77e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Simk=C3=B3?= Date: Thu, 1 Sep 2016 19:31:15 +0200 Subject: [PATCH 0094/1275] corrected comments, tweaked method naming --- B-Tree/BTree.swift | 21 +++++++++++---------- B-Tree/Tests/Tests/BTreeTests.swift | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/B-Tree/BTree.swift b/B-Tree/BTree.swift index e6494af0a..52cda4e43 100644 --- a/B-Tree/BTree.swift +++ b/B-Tree/BTree.swift @@ -136,7 +136,7 @@ extension BTreeNode { } else { children![index].insert(value, for: key) if children![index].numberOfKeys > owner.order * 2 { - split(children![index], at: index) + split(child: children![index], atIndex: index) } } } @@ -150,7 +150,7 @@ extension BTreeNode { * - child: the child to be split * - index: the index of the key, which will be moved up to the parent */ - private func split(_ child: BTreeNode, at index: Int) { + private func split(child: BTreeNode, atIndex index: Int) { let middleIndex = child.numberOfKeys / 2 keys.insert(child.keys[middleIndex], at: index) values.insert(child.values[middleIndex], at: index) @@ -224,7 +224,7 @@ extension BTreeNode { values[index] = predecessor.values.last! children![index].remove(keys[index]) if children![index].numberOfKeys < owner.order { - fix(child: children![index], at: index) + fix(childWithTooFewKeys: children![index], atIndex: index) } } } else if key < keys[index] { @@ -233,7 +233,7 @@ extension BTreeNode { if let leftChild = children?[index] { leftChild.remove(key) if leftChild.numberOfKeys < owner.order { - fix(child: leftChild, at: index) + fix(childWithTooFewKeys: leftChild, atIndex: index) } } else { print("The key:\(key) is not in the tree.") @@ -244,7 +244,7 @@ extension BTreeNode { if let rightChild = children?[(index + 1)] { rightChild.remove(key) if rightChild.numberOfKeys < owner.order { - fix(child: rightChild, at: (index + 1)) + fix(childWithTooFewKeys: rightChild, atIndex: (index + 1)) } } else { print("The key:\(key) is not in the tree") @@ -253,16 +253,17 @@ extension BTreeNode { } /** - * Fixes the `child` at `index`. - * If `child` contains too many children then it moves a child to one of - * `child`'s neighbouring nodes. - * If `child` contains too few children then it merges it with one of its neighbours. + * Fixes `childWithTooFewKeys` by either moving a key to it from + * one of its neighbouring nodes, or by merging. + * + * - Precondition: + * `childWithTooFewKeys` must have less keys than the order of the tree. * * - Parameters: * - child: the child to be fixed * - index: the index of the child to be fixed in the current node */ - private func fix(child: BTreeNode, at index: Int) { + private func fix(childWithTooFewKeys child: BTreeNode, atIndex index: Int) { if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { move(keyAtIndex: (index - 1), to: child, from: children![(index - 1)], at: .left) diff --git a/B-Tree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift index f81016ae7..c8db17fa3 100644 --- a/B-Tree/Tests/Tests/BTreeTests.swift +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -108,7 +108,7 @@ class BTreeTests: XCTestCase { } do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -126,7 +126,7 @@ class BTreeTests: XCTestCase { XCTAssertNil(bTree[20]) do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -140,7 +140,7 @@ class BTreeTests: XCTestCase { XCTAssertNil(bTree[1]) do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -156,7 +156,7 @@ class BTreeTests: XCTestCase { XCTAssertNil(bTree[9]) do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -173,7 +173,7 @@ class BTreeTests: XCTestCase { XCTAssertNil(bTree[9]) do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -189,7 +189,7 @@ class BTreeTests: XCTestCase { } do { - try bTree.checkBalanced() + try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } @@ -215,7 +215,7 @@ enum BTreeError: Error { } extension BTreeNode { - func checkBalanced(isRoot root: Bool) throws { + func checkBalance(isRoot root: Bool) throws { if numberOfKeys > owner.order * 2 { throw BTreeError.tooManyNodes } else if !root && numberOfKeys < owner.order { @@ -224,7 +224,7 @@ extension BTreeNode { if !isLeaf { for child in children! { - try child.checkBalanced(isRoot: false) + try child.checkBalance(isRoot: false) } } } @@ -242,7 +242,7 @@ extension BTree where Key: SignedInteger, Value: SignedInteger { } } - func checkBalanced() throws { - try rootNode.checkBalanced(isRoot: true) + func checkBalance() throws { + try rootNode.checkBalance(isRoot: true) } } From 25a82a8b9769805fc413a592441726c326a14258 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Sep 2016 09:20:39 +0200 Subject: [PATCH 0095/1275] Update README.md --- Skip-List/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 1722e1fe6..fc98a4768 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -2,7 +2,7 @@ Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. Fast searching is possible by building a hierarchy of sorted linked-lists acting as an express lane to the layer underneath. Layers are created on top of the base layer ( regular sorted linked-list ) probablisticly by coin-flipping. -A layer consists of a Head node, holding reference to the next and the node below. Each node has also same references similar to the Head node. +A layer consists of a Head node, holding reference to the next and the node below. Each node also holds references similar to the Head node. #TODO - finish readme From c20c4dec42a0281d930fb800134ba48c4bb0d33a Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Sep 2016 09:41:01 +0200 Subject: [PATCH 0096/1275] Update README.md --- Skip-List/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index fc98a4768..7c6ca754f 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -1,8 +1,6 @@ # Skip List -Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. Fast searching is possible by building a hierarchy of sorted linked-lists acting as an express lane to the layer underneath. Layers are created on top of the base layer ( regular sorted linked-list ) probablisticly by coin-flipping. - -A layer consists of a Head node, holding reference to the next and the node below. Each node also holds references similar to the Head node. +Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. The building blocks are hierarchy of layers (regular sorted linked-lists), created probablisticly by coin flipping, each acting as an express lane to the layer underneath, therefore making fast O(log n) search possible by skipping lanes. A layer consists of a Head node, holding reference to the subsequent and the node below. Each node also holds similar references as the Head node. #TODO - finish readme From e1ab353a76d48e18915013edfa8d3303996254ce Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Fri, 2 Sep 2016 09:43:08 +0200 Subject: [PATCH 0097/1275] Add schematic image --- Skip-List/Intro.png | Bin 0 -> 21910 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Skip-List/Intro.png diff --git a/Skip-List/Intro.png b/Skip-List/Intro.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb64865d5d93747e5d2700376b2969b21f8aa9e GIT binary patch literal 21910 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 literal 0 HcmV?d00001 From 587aa152ff1d0f8c477a2ad9a5547b1cec756b90 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Fri, 2 Sep 2016 09:44:37 +0200 Subject: [PATCH 0098/1275] Add schematic image --- Skip-List/Intro.png | Bin 21910 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Skip-List/Intro.png diff --git a/Skip-List/Intro.png b/Skip-List/Intro.png deleted file mode 100644 index 0bb64865d5d93747e5d2700376b2969b21f8aa9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21910 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 From 5a0c71e2be157476105e9c833c9f2e719c64a30c Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Fri, 2 Sep 2016 09:45:13 +0200 Subject: [PATCH 0099/1275] Add schematic image --- Skip-List/Images/Intro.png | Bin 0 -> 21910 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Skip-List/Images/Intro.png diff --git a/Skip-List/Images/Intro.png b/Skip-List/Images/Intro.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb64865d5d93747e5d2700376b2969b21f8aa9e GIT binary patch literal 21910 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 literal 0 HcmV?d00001 From 78048a69052819b0affc90ebc5e1f5f34bc0e68e Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Sep 2016 09:46:56 +0200 Subject: [PATCH 0100/1275] Update README.md --- Skip-List/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Skip-List/README.md b/Skip-List/README.md index 7c6ca754f..5b2607b96 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -2,5 +2,7 @@ Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. The building blocks are hierarchy of layers (regular sorted linked-lists), created probablisticly by coin flipping, each acting as an express lane to the layer underneath, therefore making fast O(log n) search possible by skipping lanes. A layer consists of a Head node, holding reference to the subsequent and the node below. Each node also holds similar references as the Head node. +![Schematic view](Images/Intro.png +) #TODO - finish readme From 3f66f8413845b22653f91e1326a92ba0c01ea739 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Sep 2016 17:32:02 +0200 Subject: [PATCH 0101/1275] Update README.md --- Skip-List/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 5b2607b96..f65609fb2 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -1,6 +1,6 @@ # Skip List -Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. The building blocks are hierarchy of layers (regular sorted linked-lists), created probablisticly by coin flipping, each acting as an express lane to the layer underneath, therefore making fast O(log n) search possible by skipping lanes. A layer consists of a Head node, holding reference to the subsequent and the node below. Each node also holds similar references as the Head node. +Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. The building blocks are hierarchy of layers (regular sorted linked-lists), created probablisticly by coin flipping, each acting as an express lane to the layer underneath, therefore making fast O(log n) search possible by skipping lanes and reducing travel distance. A layer consists of a Head node, holding reference to the subsequent and the node below. Each node also holds similar references as the Head node. ![Schematic view](Images/Intro.png ) From 297f9c25e638d9c760c5756ac7a4f1a00ecdf259 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Fri, 2 Sep 2016 18:13:11 +0200 Subject: [PATCH 0102/1275] New Images --- Skip-List/Images/Insert1.png | Bin 0 -> 8064 bytes Skip-List/Images/Insert10.png | Bin 0 -> 11662 bytes Skip-List/Images/Insert11.png | Bin 0 -> 11517 bytes Skip-List/Images/Insert12.png | Bin 0 -> 18755 bytes Skip-List/Images/Insert2.png | Bin 0 -> 11545 bytes Skip-List/Images/Insert3.png | Bin 0 -> 7420 bytes Skip-List/Images/Insert4.png | Bin 0 -> 7550 bytes Skip-List/Images/Insert5.png | Bin 0 -> 11124 bytes Skip-List/Images/Insert6.png | Bin 0 -> 11045 bytes Skip-List/Images/Insert8.png | Bin 0 -> 10902 bytes Skip-List/Images/Insert9.png | Bin 0 -> 11692 bytes Skip-List/Images/Search1.png | Bin 0 -> 18947 bytes Skip-List/Images/insert7.png | Bin 0 -> 11052 bytes 13 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Skip-List/Images/Insert1.png create mode 100644 Skip-List/Images/Insert10.png create mode 100644 Skip-List/Images/Insert11.png create mode 100644 Skip-List/Images/Insert12.png create mode 100644 Skip-List/Images/Insert2.png create mode 100644 Skip-List/Images/Insert3.png create mode 100644 Skip-List/Images/Insert4.png create mode 100644 Skip-List/Images/Insert5.png create mode 100644 Skip-List/Images/Insert6.png create mode 100644 Skip-List/Images/Insert8.png create mode 100644 Skip-List/Images/Insert9.png create mode 100644 Skip-List/Images/Search1.png create mode 100644 Skip-List/Images/insert7.png diff --git a/Skip-List/Images/Insert1.png b/Skip-List/Images/Insert1.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1a5959d07a3be6f5d3d5c327169025e90b7c02 GIT binary patch literal 8064 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 TD~I^U;%84=ohtm@>CS%u{E!-? literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert10.png b/Skip-List/Images/Insert10.png new file mode 100644 index 0000000000000000000000000000000000000000..eaec313b3b90ac8447aa0579c6477e977970d350 GIT binary patch literal 11662 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 E1qH?G=>Px# literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert11.png b/Skip-List/Images/Insert11.png new file mode 100644 index 0000000000000000000000000000000000000000..3c637093c27707b683eef78adda59c0c5787f1d4 GIT binary patch literal 11517 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 literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert12.png b/Skip-List/Images/Insert12.png new file mode 100644 index 0000000000000000000000000000000000000000..408356a6f973a483bc6e5f66c71dbbc75eec8352 GIT binary patch literal 18755 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 Mk$ICRq~-Dd05m3}IRF3v literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert2.png b/Skip-List/Images/Insert2.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa0940197a8c0ce9130cd8d1d63e5f544e42f0f GIT binary patch literal 11545 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 I)&9}{0)NDwL;wH) literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert3.png b/Skip-List/Images/Insert3.png new file mode 100644 index 0000000000000000000000000000000000000000..08f1b78bbb63f7488d23dc33f35600c62a9a408b GIT binary patch literal 7420 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 literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert4.png b/Skip-List/Images/Insert4.png new file mode 100644 index 0000000000000000000000000000000000000000..779ad7dd863efe58ba05b58d321d4058d545ec9c GIT binary patch literal 7550 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 literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert6.png b/Skip-List/Images/Insert6.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b44c3b0141fa4275e41d2fab5c715bf26b224e GIT binary patch literal 11045 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 AxBvhE literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert8.png b/Skip-List/Images/Insert8.png new file mode 100644 index 0000000000000000000000000000000000000000..2eecd75e454e51491cc97a282721a7f5c09948d6 GIT binary patch literal 10902 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 literal 0 HcmV?d00001 diff --git a/Skip-List/Images/Insert9.png b/Skip-List/Images/Insert9.png new file mode 100644 index 0000000000000000000000000000000000000000..f63345bddae66b57ba90cc6e9a19253709930528 GIT binary patch literal 11692 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

<7D6cDRzo58 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 xg_{s$bDFVX-2 literal 0 HcmV?d00001 diff --git a/Skip-List/Images/insert7.png b/Skip-List/Images/insert7.png new file mode 100644 index 0000000000000000000000000000000000000000..d92f607f73a5e7acf3dc5d04bc1c88e70adbd08b GIT binary patch literal 11052 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 Lp->`c5%_-qSsc3D literal 0 HcmV?d00001 From 1a880aad0336b13a46c987bd15bdb6257c09d681 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Sep 2016 18:38:55 +0200 Subject: [PATCH 0103/1275] Update README.md --- Skip-List/README.md | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index f65609fb2..64f221a23 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -4,5 +4,41 @@ Skip List is a probablistic data-structure with same efficiency as AVL tree or R ![Schematic view](Images/Intro.png ) -#TODO - - finish readme + + +#Inserting + +1. Inserting a new element in initial state where no prior layer is created yet begins by construction of a Head node with a reference to data node (just like regular lists). After this operation coin-flipping starts to determine wether a new layer must be created. When positive, a new layer containing Head and data node ( similar to previous layer ) is created and head is updated to reference the new layer and the head node underneath. Subsequently data node is also updated to reference the node below; until coin-flip function return a negative value to terminate this process. + +2. After initial state, we start at top most layer to find a node where its value is less than the new value and its next node value is greater-equal/nil than new value. Then we use this node to travel to layer underneath until we reach the layer 0 where the element must be inserted first, after this node. Node references must be updated accordingly by back tracing the path to the top. If the first element in the layer does not meet the criteria, same procedure is used to travel to the layer below using the head node. + + +**Example** + + +1 - Inserting 10 in initial state with coin flips (0) + +![Inserting first element](Images/Insert1.png) + + +2 - 12 inserted with coin flips (1,1,0) + + +3 - Inserting 13. with coin flips (0) + +![Inserting first element](Images/Insert5.png) +![Inserting first element](Images/Insert6.png) +![Inserting first element](Images/insert7.png) +![Inserting first element](Images/Insert8.png) +![Inserting first element](Images/Insert9.png) + + +#Searching + +TODO + +#See also + +[Skip List on Wikipedia](https://en.wikipedia.org/wiki/Skip_list) + +Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) From c8cfb08c8a6165a9c887d0c424de49ca66685ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Simk=C3=B3?= Date: Sat, 3 Sep 2016 16:20:47 +0200 Subject: [PATCH 0104/1275] updated playground --- B-Tree/BTree.playground/Contents.swift | 14 +- B-Tree/BTree.playground/Sources/BTree.swift | 419 +++++++++++++------- 2 files changed, 276 insertions(+), 157 deletions(-) diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift index 186718bbd..8238fe5a5 100644 --- a/B-Tree/BTree.playground/Contents.swift +++ b/B-Tree/BTree.playground/Contents.swift @@ -4,15 +4,15 @@ import Foundation let bTree = BTree(order: 1)! -bTree.insertValue(1, forKey: 1) -bTree.insertValue(2, forKey: 2) -bTree.insertValue(3, forKey: 3) -bTree.insertValue(4, forKey: 4) +bTree.insert(1, for: 1) +bTree.insert(2, for: 2) +bTree.insert(3, for: 3) +bTree.insert(4, for: 4) -bTree.valueForKey(3) +bTree.value(for: 3) bTree[3] -bTree.removeKey(2) +bTree.remove(2) bTree.traverseKeysInOrder { key in @@ -23,4 +23,4 @@ bTree.numberOfKeys bTree.order -bTree.inorderArrayFromKeys() \ No newline at end of file +bTree.inorderArrayFromKeys diff --git a/B-Tree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift index 16c4eabe4..52cda4e43 100644 --- a/B-Tree/BTree.playground/Sources/BTree.swift +++ b/B-Tree/BTree.playground/Sources/BTree.swift @@ -21,18 +21,21 @@ // SOFTWARE. /* - B-Tree - - A B-Tree is a self-balancing search tree, in which nodes can have more than two children. + * B-Tree + * + * A B-Tree is a self-balancing search tree, in which nodes can have more than two children. */ // MARK: - BTreeNode class class BTreeNode { - unowned var ownerTree: BTree + /** + * The tree that owns the node. + */ + unowned var owner: BTree - private var keys = [Key]() - var values = [Value]() + fileprivate var keys = [Key]() + fileprivate var values = [Value]() var children: [BTreeNode]? var isLeaf: Bool { @@ -43,13 +46,13 @@ class BTreeNode { return keys.count } - init(ownerTree: BTree) { - self.ownerTree = ownerTree + init(owner: BTree) { + self.owner = owner } - convenience init(ownerTree: BTree, keys: [Key], + convenience init(owner: BTree, keys: [Key], values: [Value], children: [BTreeNode]? = nil) { - self.init(ownerTree: ownerTree) + self.init(owner: owner) self.keys += keys self.values += values self.children = children @@ -59,19 +62,26 @@ class BTreeNode { // MARK: BTreeNode extesnion: Searching extension BTreeNode { - func valueForKey(key: Key) -> Value? { + + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ + func value(for key: Key) -> Value? { var index = keys.startIndex - while index.successor() < keys.endIndex && keys[index] < key { - index = index.successor() + while (index + 1) < keys.endIndex && keys[index] < key { + index = (index + 1) } if key == keys[index] { return values[index] } else if key < keys[index] { - return children?[index].valueForKey(key) + return children?[index].value(for: key) } else { - return children?[index.successor()].valueForKey(key) + return children?[(index + 1)].value(for: key) } } } @@ -79,7 +89,14 @@ extension BTreeNode { // MARK: BTreeNode extension: Travelsals extension BTreeNode { - func traverseKeysInOrder(@noescape process: Key -> Void) { + + /** + * Traverses the keys in order, executes `process` for every key. + * + * - Parameters: + * - process: the closure to be executed for every key + */ + func traverseKeysInOrder(_ process: (Key) -> Void) { for i in 0.. ownerTree.order * 2 { - splitChild(children![index], atIndex: index) + children![index].insert(value, for: key) + if children![index].numberOfKeys > owner.order * 2 { + split(child: children![index], atIndex: index) } } } - private func splitChild(child: BTreeNode, atIndex index: Int) { + /** + * Splits `child` at `index`. + * The key-value pair at `index` gets moved up to the parent node, + * or if there is not an parent node, then a new parent node is created. + * + * - Parameters: + * - child: the child to be split + * - index: the index of the key, which will be moved up to the parent + */ + private func split(child: BTreeNode, atIndex index: Int) { let middleIndex = child.numberOfKeys / 2 - keys.insert(child.keys[middleIndex], atIndex: index) - values.insert(child.values[middleIndex], atIndex: index) - child.keys.removeAtIndex(middleIndex) - child.values.removeAtIndex(middleIndex) + keys.insert(child.keys[middleIndex], at: index) + values.insert(child.values[middleIndex], at: index) + child.keys.remove(at: middleIndex) + child.values.remove(at: middleIndex) let rightSibling = BTreeNode( - ownerTree: ownerTree, - keys: Array(child.keys[middleIndex..= 0 && - children![index.predecessor()].numberOfKeys > ownerTree.order { - - moveKeyAtIndex(index.predecessor(), toNode: child, - fromNode: children![index.predecessor()], atPosition: .Left) - - } else if index.successor() < children!.count && - children![index.successor()].numberOfKeys > ownerTree.order { - - moveKeyAtIndex(index, toNode: child, - fromNode: children![index.successor()], atPosition: .Right) - - } else if index.predecessor() >= 0 { - mergeChild(child, withIndex: index, toNodeAtPosition: .Left) + if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { + move(keyAtIndex: (index - 1), to: child, from: children![(index - 1)], at: .left) + } else if (index + 1) < children!.count && children![(index + 1)].numberOfKeys > owner.order { + move(keyAtIndex: index, to: child, from: children![(index + 1)], at: .right) + } else if (index - 1) >= 0 { + merge(child: child, atIndex: index, to: .left) } else { - mergeChild(child, withIndex: index, toNodeAtPosition: .Right) + merge(child: child, atIndex: index, to: .right) } } - private func moveKeyAtIndex(keyIndex: Int, toNode targetNode: BTreeNode, - fromNode: BTreeNode, atPosition position: BTreeNodePosition) { + /** + * Moves the key at the specified `index` from `node` to + * the `targetNode` at `position` + * + * - Parameters: + * - index: the index of the key to be moved in `node` + * - targetNode: the node to move the key into + * - node: the node to move the key from + * - position: the position of the from node relative to the targetNode + */ + private func move(keyAtIndex index: Int, to targetNode: BTreeNode, + from node: BTreeNode, at position: BTreeNodePosition) { switch position { - case .Left: - targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.startIndex) - targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.startIndex) - keys[keyIndex] = fromNode.keys.last! - values[keyIndex] = fromNode.values.last! - fromNode.keys.removeLast() - fromNode.values.removeLast() + case .left: + targetNode.keys.insert(keys[index], at: targetNode.keys.startIndex) + targetNode.values.insert(values[index], at: targetNode.values.startIndex) + keys[index] = node.keys.last! + values[index] = node.values.last! + node.keys.removeLast() + node.values.removeLast() if !targetNode.isLeaf { - targetNode.children!.insert(fromNode.children!.last!, - atIndex: targetNode.children!.startIndex) - fromNode.children!.removeLast() + targetNode.children!.insert(node.children!.last!, + at: targetNode.children!.startIndex) + node.children!.removeLast() } - case .Right: - targetNode.keys.insert(keys[keyIndex], atIndex: targetNode.keys.endIndex) - targetNode.values.insert(values[keyIndex], atIndex: targetNode.values.endIndex) - keys[keyIndex] = fromNode.keys.first! - values[keyIndex] = fromNode.values.first! - fromNode.keys.removeFirst() - fromNode.values.removeFirst() + case .right: + targetNode.keys.insert(keys[index], at: targetNode.keys.endIndex) + targetNode.values.insert(values[index], at: targetNode.values.endIndex) + keys[index] = node.keys.first! + values[index] = node.values.first! + node.keys.removeFirst() + node.values.removeFirst() if !targetNode.isLeaf { - targetNode.children!.insert(fromNode.children!.first!, - atIndex: targetNode.children!.endIndex) - fromNode.children!.removeFirst() + targetNode.children!.insert(node.children!.first!, + at: targetNode.children!.endIndex) + node.children!.removeFirst() } } } - private func mergeChild(child: BTreeNode, withIndex index: Int, toNodeAtPosition position: BTreeNodePosition) { + /** + * Merges `child` at `position` to the node at the `position`. + * + * - Parameters: + * - child: the child to be merged + * - index: the index of the child in the current node + * - position: the position of the node to merge into + */ + private func merge(child: BTreeNode, atIndex index: Int, to position: BTreeNodePosition) { switch position { - case .Left: + case .left: // We can merge to the left sibling - children![index.predecessor()].keys = children![index.predecessor()].keys + - [keys[index.predecessor()]] + child.keys + children![(index - 1)].keys = children![(index - 1)].keys + + [keys[(index - 1)]] + child.keys - children![index.predecessor()].values = children![index.predecessor()].values + - [values[index.predecessor()]] + child.values + children![(index - 1)].values = children![(index - 1)].values + + [values[(index - 1)]] + child.values - keys.removeAtIndex(index.predecessor()) - values.removeAtIndex(index.predecessor()) + keys.remove(at: (index - 1)) + values.remove(at: (index - 1)) if !child.isLeaf { - children![index.predecessor()].children = - children![index.predecessor()].children! + child.children! + children![(index - 1)].children = + children![(index - 1)].children! + child.children! } - case .Right: + case .right: // We should merge to the right sibling - children![index.successor()].keys = child.keys + [keys[index]] + - children![index.successor()].keys + children![(index + 1)].keys = child.keys + [keys[index]] + + children![(index + 1)].keys - children![index.successor()].values = child.values + [values[index]] + - children![index.successor()].values + children![(index + 1)].values = child.values + [values[index]] + + children![(index + 1)].values - keys.removeAtIndex(index) - values.removeAtIndex(index) + keys.remove(at: index) + values.remove(at: index) if !child.isLeaf { - children![index.successor()].children = - child.children! + children![index.successor()].children! + children![(index + 1)].children = + child.children! + children![(index + 1)].children! } } - children!.removeAtIndex(index) + children!.remove(at: index) } } // MARK: BTreeNode extension: Conversion extension BTreeNode { - func inorderArrayFromKeys() -> [Key] { + /** + * Returns an array which contains the keys from the current node + * and its descendants in order. + */ + var inorderArrayFromKeys: [Key] { var array = [Key] () for i in 0.. { - /** - The order of the B-Tree - - The number of keys in every node should be in the [order, 2*order] range, - except the root node which is allowed to contain less keys than the value of order. + * The order of the B-Tree + * + * The number of keys in every node should be in the [order, 2*order] range, + * except the root node which is allowed to contain less keys than the value of order. */ public let order: Int - /// The root node of the tree + /** + * The root node of the tree + */ var rootNode: BTreeNode! - private(set) public var numberOfKeys = 0 + fileprivate(set) public var numberOfKeys = 0 /** - Designated initializer for the tree - - - parameters: - - order: The order of the tree. + * Designated initializer for the tree + * + * - Parameters: + * - order: The order of the tree. */ public init?(order: Int) { guard order > 0 else { @@ -362,14 +439,20 @@ public class BTree { return nil } self.order = order - rootNode = BTreeNode(ownerTree: self) + rootNode = BTreeNode(owner: self) } } // MARK: BTree extension: Travelsals extension BTree { - public func traverseKeysInOrder(@noescape process: Key -> Void) { + /** + * Traverses the keys in order, executes `process` for every key. + * + * - Parameters: + * - process: the closure to be executed for every key + */ + public func traverseKeysInOrder(_ process: (Key) -> Void) { rootNode.traverseKeysInOrder(process) } } @@ -377,60 +460,85 @@ extension BTree { // MARK: BTree extension: Subscript extension BTree { + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ public subscript (key: Key) -> Value? { - return valueForKey(key) + return value(for: key) } } // MARK: BTree extension: Value for Key extension BTree { - public func valueForKey(key: Key) -> Value? { + /** + * Returns the value for a given `key`, returns nil if the `key` is not found. + * + * - Parameters: + * - key: the key of the value to be returned + */ + public func value(for key: Key) -> Value? { guard rootNode.numberOfKeys > 0 else { return nil } - return rootNode.valueForKey(key) + return rootNode.value(for: key) } } // MARK: BTree extension: Insertion extension BTree { - public func insertValue(value: Value, forKey key: Key) { - rootNode.insertValue(value, forKey: key) + /** + * Inserts the `value` for the `key` into the tree. + * + * - Parameters: + * - value: the value to be inserted for `key` + * - key: the key for the `value` + */ + public func insert(_ value: Value, for key: Key) { + rootNode.insert(value, for: key) if rootNode.numberOfKeys > order * 2 { splitRoot() } } + /** + * Splits the root node of the tree. + * + * - Precondition: + * The root node of the tree contains `order` * 2 keys. + */ private func splitRoot() { let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 let newRoot = BTreeNode( - ownerTree: self, + owner: self, keys: [rootNode.keys[middleIndexOfOldRoot]], values: [rootNode.values[middleIndexOfOldRoot]], children: [rootNode] ) - rootNode.keys.removeAtIndex(middleIndexOfOldRoot) - rootNode.values.removeAtIndex(middleIndexOfOldRoot) + rootNode.keys.remove(at: middleIndexOfOldRoot) + rootNode.values.remove(at: middleIndexOfOldRoot) let newRightChild = BTreeNode( - ownerTree: self, - keys: Array(rootNode.keys[middleIndexOfOldRoot.. 0 else { return } - rootNode.removeKey(key) + rootNode.remove(key) if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { rootNode = rootNode.children!.first! @@ -458,15 +572,20 @@ extension BTree { // MARK: BTree extension: Conversion extension BTree { - public func inorderArrayFromKeys() -> [Key] { - return rootNode.inorderArrayFromKeys() + /** + * The keys of the tree in order. + */ + public var inorderArrayFromKeys: [Key] { + return rootNode.inorderArrayFromKeys } } // MARK: BTree extension: Decription extension BTree: CustomStringConvertible { - // Returns a String containing the preorder representation of the nodes + /** + * Returns a String containing the preorder representation of the nodes. + */ public var description: String { return rootNode.description } From 9035cddfca64d7814e774ab86dab36259338eea0 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Tue, 6 Sep 2016 21:24:02 +1200 Subject: [PATCH 0105/1275] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 76799365d..d0f565651 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Binary\ Search/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 ./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 From 3945383d306ac027f779461789d6b0deddca4348 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 7 Sep 2016 05:01:56 -0700 Subject: [PATCH 0106/1275] Migrated over to Swift 3 --- Heap/Heap.swift | 56 +++++++++---------- Heap/README.markdown | 4 +- Heap/Tests/HeapTests.swift | 42 +++++++------- Heap/Tests/Tests.xcodeproj/project.pbxproj | 10 +++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 61 insertions(+), 53 deletions(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index bf7031abe..eba7ca1cf 100644 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -8,14 +8,14 @@ public struct Heap { var elements = [T]() /** Determines whether this is a max-heap (>) or min-heap (<). */ - private var isOrderedBefore: (T, T) -> Bool + fileprivate var isOrderedBefore: (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. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort } @@ -24,9 +24,9 @@ public struct Heap { * the elements are inserted into the heap in the order determined by the * sort function. */ - public init(array: [T], sort: (T, T) -> Bool) { + public init(array: [T], sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort - buildHeap(array) + buildHeap(fromArray: array) } /* @@ -43,9 +43,9 @@ public struct Heap { * Converts an array to a max-heap or min-heap in a bottom-up manner. * Performance: This runs pretty much in O(n). */ - private mutating func buildHeap(array: [T]) { + fileprivate 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: (elements.count/2 - 1), through: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) } } @@ -62,7 +62,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 indexOfParent(i: Int) -> Int { + @inline(__always) func parentIndex(ofIndex i: Int) -> Int { return (i - 1) / 2 } @@ -71,7 +71,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 indexOfLeftChild(i: Int) -> Int { + @inline(__always) func leftChildIndex(ofIndex i: Int) -> Int { return 2*i + 1 } @@ -80,7 +80,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 indexOfRightChild(i: Int) -> Int { + @inline(__always) func rightChildIndex(ofIndex i: Int) -> Int { return 2*i + 2 } @@ -96,12 +96,12 @@ public struct Heap { * 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). */ - public mutating func insert(value: T) { + public mutating func insert(_ value: T) { elements.append(value) shiftUp(index: elements.count - 1) } - public mutating func insert(sequence: S) { + public mutating func insert(_ sequence: S) where S.Iterator.Element == T { for value in sequence { insert(value) } @@ -123,7 +123,7 @@ public struct Heap { * Removes the root node from the heap. For a max-heap, this is the maximum * value; for a min-heap it is the minimum value. Performance: O(log n). */ - public mutating func remove() -> T? { + @discardableResult public mutating func remove() -> T? { if elements.isEmpty { return nil } else if elements.count == 1 { @@ -142,14 +142,14 @@ public struct Heap { * 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. */ - public mutating func removeAtIndex(i: Int) -> T? { - guard i < elements.count else { return nil } + public mutating func removeAt(index: Int) -> T? { + guard index < elements.count else { return nil } let size = elements.count - 1 - if i != size { - swap(&elements[i], &elements[size]) - shiftDown(index: i, heapSize: size) - shiftUp(index: i) + if index != size { + swap(&elements[index], &elements[size]) + shiftDown(index: index, heapSize: size) + shiftUp(index: index) } return elements.removeLast() } @@ -158,15 +158,15 @@ 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 index: Int) { + mutating func shiftUp(index: Int) { var childIndex = index let child = elements[childIndex] - var parentIndex = indexOfParent(childIndex) + var parentIndex = self.parentIndex(ofIndex: childIndex) while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { elements[childIndex] = elements[parentIndex] childIndex = parentIndex - parentIndex = indexOfParent(childIndex) + parentIndex = self.parentIndex(ofIndex: childIndex) } elements[childIndex] = child @@ -180,11 +180,11 @@ public struct Heap { * 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 index: Int, heapSize: Int) { + mutating func shiftDown(index: Int, heapSize: Int) { var parentIndex = index while true { - let leftChildIndex = indexOfLeftChild(parentIndex) + let leftChildIndex = self.leftChildIndex(ofIndex: parentIndex) let rightChildIndex = leftChildIndex + 1 // Figure out which comes first if we order them by the sort function: @@ -212,16 +212,16 @@ extension Heap where T: Equatable { /** * Searches the heap for the given element. Performance: O(n). */ - public func indexOf(element: T) -> Int? { - return indexOf(element, 0) + public func index(of element: T) -> Int? { + return index(of: element, 0) } - private func indexOf(element: T, _ i: Int) -> Int? { + 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 = indexOf(element, indexOfLeftChild(i)) { return j } - if let j = indexOf(element, indexOfRightChild(i)) { return j } + if let j = index(of: element, self.leftChildIndex(ofIndex: i)) { return j } + if let j = index(of: element, self.rightChildIndex(ofIndex: i)) { return j } return nil } } diff --git a/Heap/README.markdown b/Heap/README.markdown index fb5092fe3..88ea25eeb 100644 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -260,7 +260,7 @@ It can be convenient to convert an array into a heap. This just shuffles the arr In code it would look like this: ```swift - private mutating func buildHeap(array: [T]) { + private mutating func buildHeap(fromArray array: [T]) { for value in array { insert(value) } @@ -274,7 +274,7 @@ If you didn't gloss over the math section, you'd have seen that for any heap the In code: ```swift - private mutating func buildHeap(array: [T]) { + private mutating func buildHeap(fromArray array: [T]) { elements = array for i in (elements.count/2 - 1).stride(through: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index 6178a8094..c5b479f14 100644 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -7,11 +7,11 @@ import XCTest class HeapTests: XCTestCase { - private func verifyMaxHeap(h: Heap) -> Bool { + fileprivate func verifyMaxHeap(_ h: Heap) -> Bool { for i in 0.. 0 && h.elements[parent] < h.elements[i] { return false } @@ -19,11 +19,11 @@ class HeapTests: XCTestCase { return true } - private func verifyMinHeap(h: Heap) -> Bool { + fileprivate func verifyMinHeap(_ h: Heap) -> Bool { for i in 0.. 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 } @@ -31,14 +31,14 @@ class HeapTests: XCTestCase { return true } - private func isPermutation(array1: [Int], _ array2: [Int]) -> Bool { + fileprivate func isPermutation(_ array1: [Int], _ array2: [Int]) -> Bool { var a1 = array1 var a2 = array2 if a1.count != a2.count { return false } while a1.count > 0 { - if let i = a2.indexOf(a1[0]) { - a1.removeAtIndex(0) - a2.removeAtIndex(i) + if let i = a2.index(of: a1[0]) { + a1.remove(at: 0) + a2.remove(at: i) } else { return false } @@ -161,7 +161,7 @@ class HeapTests: XCTestCase { XCTAssertEqual(heap.elements, [1, 1, 1, 1, 1]) } - private func randomArray(n: Int) -> [Int] { + fileprivate func randomArray(_ n: Int) -> [Int] { var a = [Int]() for _ in 0.. Date: Thu, 8 Sep 2016 07:55:54 -0700 Subject: [PATCH 0107/1275] Updated playground to Swift 3 --- .../Contents.swift | 30 +++++----- .../Sources/BinarySearchTree.swift | 56 +++++++++---------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 4c2a6c358..6d73585b5 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,21 +1,21 @@ //: Playground - noun: a place where people can play let tree = BinarySearchTree(value: 7) -tree.insert(2) -tree.insert(5) -tree.insert(10) -tree.insert(9) -tree.insert(1) +tree.insert(value: 2) +tree.insert(value: 5) +tree.insert(value: 10) +tree.insert(value: 9) +tree.insert(value: 1) tree tree.debugDescription let tree2 = BinarySearchTree(array: [7, 2, 5, 10, 9, 1]) -tree.search(5) -tree.search(2) -tree.search(7) -tree.search(6) +tree.search(value: 5) +tree.search(value: 2) +tree.search(value: 7) +tree.search(value: 6) tree.traverseInOrder { value in print(value) } @@ -24,7 +24,7 @@ tree.toArray() tree.minimum() tree.maximum() -if let node2 = tree.search(2) { +if let node2 = tree.search(value: 2) { node2.remove() node2 print(tree) @@ -34,25 +34,25 @@ tree.height() tree.predecessor() tree.successor() -if let node10 = tree.search(10) { +if let node10 = tree.search(value: 10) { node10.depth() // 1 node10.height() // 1 node10.predecessor() node10.successor() // nil } -if let node9 = tree.search(9) { +if let node9 = tree.search(value: 9) { node9.depth() // 2 node9.height() // 0 node9.predecessor() node9.successor() } -if let node1 = tree.search(1) { +if let node1 = tree.search(value: 1) { // This makes it an invalid binary search tree because 100 is greater // than the root, 7, and so must be in the right branch not in the left. tree.isBST(minValue: Int.min, maxValue: Int.max) // true - node1.insert(100) - tree.search(100) // nil + node1.insert(value: 100) + tree.search(value: 100) // nil tree.isBST(minValue: Int.min, maxValue: Int.max) // false } 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 a58ac075a..f4960380e 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -10,10 +10,10 @@ you should insert new values in randomized order, not in sorted order. */ public class BinarySearchTree { - private(set) public var value: T - private(set) public var parent: BinarySearchTree? - private(set) public var left: BinarySearchTree? - private(set) public var right: BinarySearchTree? + fileprivate(set) public var value: T + fileprivate(set) public var parent: BinarySearchTree? + fileprivate(set) public var left: BinarySearchTree? + fileprivate(set) public var right: BinarySearchTree? public init(value: T) { self.value = value @@ -22,8 +22,8 @@ public class BinarySearchTree { public convenience init(array: [T]) { precondition(array.count > 0) self.init(value: array.first!) - for v in array.dropFirst() { - insert(v, parent: self) + for v in array.dropFirst() { + insert(value: v, parent: self) } } @@ -74,20 +74,20 @@ extension BinarySearchTree { Performance: runs in O(h) time, where h is the height of the tree. */ public func insert(value: T) { - insert(value, parent: self) + insert(value: value, parent: self) } - private func insert(value: T, parent: BinarySearchTree) { + fileprivate func insert(value: T, parent: BinarySearchTree) { if value < self.value { if let left = left { - left.insert(value, parent: left) + left.insert(value: value, parent: left) } else { left = BinarySearchTree(value: value) left?.parent = parent } } else { if let right = right { - right.insert(value, parent: right) + right.insert(value: value, parent: right) } else { right = BinarySearchTree(value: value) right?.parent = parent @@ -108,7 +108,7 @@ extension BinarySearchTree { Performance: runs in O(h) time, where h is the height of the tree. */ - public func remove() -> BinarySearchTree? { + @discardableResult public func remove() -> BinarySearchTree? { let replacement: BinarySearchTree? if let left = left { @@ -126,7 +126,7 @@ extension BinarySearchTree { replacement = nil } - reconnectParentToNode(replacement) + reconnectParentTo(node: replacement) // The current node is no longer part of the tree, so clean it up. parent = nil @@ -136,7 +136,7 @@ extension BinarySearchTree { return replacement } - private func removeNodeWithTwoChildren(left: BinarySearchTree, _ right: BinarySearchTree) -> BinarySearchTree { + private func removeNodeWithTwoChildren(_ left: BinarySearchTree, _ right: BinarySearchTree) -> BinarySearchTree { // This node has two children. It must be replaced by the smallest // child that is larger than this node's value, which is the leftmost // descendent of the right child. @@ -164,7 +164,7 @@ extension BinarySearchTree { return successor } - private func reconnectParentToNode(node: BinarySearchTree?) { + private func reconnectParentTo(node: BinarySearchTree?) { if let parent = parent { if isLeftChild { parent.left = node @@ -211,7 +211,7 @@ extension BinarySearchTree { */ public func contains(value: T) -> Bool { - return search(value) != nil + return search(value: value) != nil } /* @@ -298,32 +298,32 @@ extension BinarySearchTree { // MARK: - Traversal extension BinarySearchTree { - public func traverseInOrder(@noescape process: T -> Void) { - left?.traverseInOrder(process) + public func traverseInOrder(process: (T) -> Void) { + left?.traverseInOrder(process: process) process(value) - right?.traverseInOrder(process) + right?.traverseInOrder(process: process) } - public func traversePreOrder(@noescape process: T -> Void) { + public func traversePreOrder(process: (T) -> Void) { process(value) - left?.traversePreOrder(process) - right?.traversePreOrder(process) + left?.traversePreOrder(process: process) + right?.traversePreOrder(process: process) } - public func traversePostOrder(@noescape process: T -> Void) { - left?.traversePostOrder(process) - right?.traversePostOrder(process) + public func traversePostOrder(process: (T) -> Void) { + left?.traversePostOrder(process: process) + right?.traversePostOrder(process: process) process(value) } /* Performs an in-order traversal and collects the results in an array. */ - public func map(@noescape formula: T -> T) -> [T] { + public func map(formula: (T) -> T) -> [T] { var a = [T]() - if let left = left { a += left.map(formula) } + if let left = left { a += left.map(formula: formula) } a.append(formula(value)) - if let right = right { a += right.map(formula) } + if let right = right { a += right.map(formula: formula) } return a } } @@ -332,7 +332,7 @@ extension BinarySearchTree { Is this binary tree a valid binary search tree? */ extension BinarySearchTree { - 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 b502621861aa6bef64ba755736a0de3f509985fc Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 8 Sep 2016 07:59:12 -0700 Subject: [PATCH 0108/1275] Migration to Swift 3 --- .../BinarySearchTree.playground/Contents.swift | 18 ++++++++++-------- .../Sources/BinarySearchTree.swift | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift index 217cb489e..12fbba81d 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift @@ -2,13 +2,15 @@ // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.Leaf(7) -tree = tree.insert(2) -tree = tree.insert(5) -tree = tree.insert(10) -tree = tree.insert(9) -tree = tree.insert(1) +tree = tree.insert(newValue: 2) +tree = tree.insert(newValue: 5) +tree = tree.insert(newValue: 10) +tree = tree.insert(newValue: 9) +tree = tree.insert(newValue: 1) print(tree) -tree.search(10) -tree.search(1) -tree.search(11) +tree.search(x: 10) +tree.search(x: 1) +tree.search(x: 11) + + diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift index ce2868bbf..b692efdc4 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -44,9 +44,9 @@ public enum BinarySearchTree { case .Node(let left, let value, let right): if newValue < value { - return .Node(left.insert(newValue), value, right) + return .Node(left.insert(newValue: newValue), value, right) } else { - return .Node(left, value, right.insert(newValue)) + return .Node(left, value, right.insert(newValue: newValue)) } } } @@ -63,9 +63,9 @@ public enum BinarySearchTree { return (x == y) ? self : nil case let .Node(left, y, right): if x < y { - return left.search(x) + return left.search(x: x) } else if y < x { - return right.search(x) + return right.search(x: x) } else { return self } @@ -73,7 +73,7 @@ public enum BinarySearchTree { } public func contains(x: T) -> Bool { - return search(x) != nil + return search(x: x) != nil } /* From b88fb4d7bb422e81981b6ddfaef52a2f07fe649b Mon Sep 17 00:00:00 2001 From: Nemanja Vlahovic Date: Sat, 10 Sep 2016 19:22:35 +0200 Subject: [PATCH 0109/1275] Update Selection Sort to Swift 3 --- Selection Sort/README.markdown | 2 +- Selection Sort/SelectionSort.playground/Contents.swift | 2 +- Selection Sort/SelectionSort.swift | 2 +- Selection Sort/Tests/Tests.xcodeproj/project.pbxproj | 10 +++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index 6eb019ab1..c583b47ea 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -59,7 +59,7 @@ As you can see, selection sort is an *in-place* sort because everything happens Here is an implementation of selection sort in Swift: ```swift -func selectionSort(array: [Int]) -> [Int] { +func selectionSort(_ array: [Int]) -> [Int] { guard array.count > 1 else { return array } // 1 var a = array // 2 diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index dd57e9c3a..bd8c7cccf 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -func selectionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } var a = array for x in 0 ..< a.count - 1 { diff --git a/Selection Sort/SelectionSort.swift b/Selection Sort/SelectionSort.swift index 9d7b45ad8..e02c87259 100644 --- a/Selection Sort/SelectionSort.swift +++ b/Selection Sort/SelectionSort.swift @@ -1,4 +1,4 @@ -func selectionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } var a = array diff --git a/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj b/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj index 11aefac3c..a42f3dc3f 100644 --- a/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -224,6 +230,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; }; name = Debug; }; @@ -235,6 +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_VERSION = 3.0; }; name = Release; }; diff --git a/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 10 Sep 2016 19:30:13 +0200 Subject: [PATCH 0110/1275] Uncomment selection sort tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8cf0b486b..bdda5eb7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ script: # - xcodebuild test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Run-Length\ Encoding/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 ./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 From 7480ea45bf0091251a86e9d2ddd7264d6047284a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 10 Sep 2016 16:00:30 -0700 Subject: [PATCH 0111/1275] Marking the Swift file to read that it is currently undergoing refactoring --- Trie/trie.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Trie/trie.swift b/Trie/trie.swift index 9ebfba8bc..8227d0243 100644 --- a/Trie/trie.swift +++ b/Trie/trie.swift @@ -1,3 +1,5 @@ +/// TODO: - Undergoing refactoring. + /* Queue implementation (taken from repository, needed for findPrefix()) */ From 8a679ffae71e2dd0e1999d1abee43de74426e1ef Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 10 Sep 2016 16:39:06 -0700 Subject: [PATCH 0112/1275] Adds a playground with the first step of refactoring the implementation. --- Trie/Trie.playground/Contents.swift | 0 Trie/Trie.playground/Sources/Node.swift | 64 ++++++ Trie/Trie.playground/Sources/Queue.swift | 31 +++ Trie/Trie.playground/Sources/Trie.swift | 212 ++++++++++++++++++ Trie/Trie.playground/contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + 6 files changed, 318 insertions(+) create mode 100644 Trie/Trie.playground/Contents.swift create mode 100644 Trie/Trie.playground/Sources/Node.swift create mode 100644 Trie/Trie.playground/Sources/Queue.swift create mode 100644 Trie/Trie.playground/Sources/Trie.swift create mode 100644 Trie/Trie.playground/contents.xcplayground create mode 100644 Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Trie/Trie.playground/Contents.swift b/Trie/Trie.playground/Contents.swift new file mode 100644 index 000000000..e69de29bb diff --git a/Trie/Trie.playground/Sources/Node.swift b/Trie/Trie.playground/Sources/Node.swift new file mode 100644 index 000000000..72600af2f --- /dev/null +++ b/Trie/Trie.playground/Sources/Node.swift @@ -0,0 +1,64 @@ +/// A Trie (prefix tree) +/// +/// Some of the functionality of the trie makes use of the Queue implementation for this project +/// +/// Every node in the Trie stores a bit of information pertaining to what it references: +/// -Character (letter of an inserted word) +/// -Parent (Letter that comes before the current letter in some word) +/// -Children (Words that have more letters than available in the prefix) +/// -isAWord (Does the current letter mark the end of a known inserted word?) +/// -visited (Mainly for the findPrefix() function) +public class Node { + public var character: String + public var parent: Node? + public var children: [String: Node] + public var isAWord: Bool + public var visited: Bool // only for findPrefix + + init(character: String, parent: Node?) { + self.character = character + self.children = [:] + self.isAWord = false + self.parent = parent + self.visited = false + } + + /// Returns `true` if the node is a leaf node, false otherwise. + var isLeaf: Bool { + return children.count == 0 + } + + /// Changes the parent of the current node to the passed in node. + /// + /// - parameter node: A `Node` object. + func setParent(node: Node) { + parent = node + } + + /// Returns the child node that holds the specific passed letter. + /// + /// - parameter character: A `String` + /// + /// - returns: The `Node` object that contains the `character`. + func getChildAt(character: String) -> Node { + return children[character]! + } + + /// Returns whether or not the current node marks the end of a valid word. + var isValidWord: Bool { + return isAWord + } + + + /// Returns whether or not the current node is the root of the trie. + var isRoot: Bool { + return character == "" + } +} + +// MARK: - CustomStringConvertible +extension Node: CustomStringConvertible { + public var description: String { + return "" + } +} diff --git a/Trie/Trie.playground/Sources/Queue.swift b/Trie/Trie.playground/Sources/Queue.swift new file mode 100644 index 000000000..81bde190a --- /dev/null +++ b/Trie/Trie.playground/Sources/Queue.swift @@ -0,0 +1,31 @@ +/// Queue implementation taken from the repository. +public struct Queue { + private var array: [T?] = [] + private var head = 0 + + public var isEmpty: Bool { + return count == 0 + } + + public var count: Int { + return array.count - head + } + + public mutating func enqueue(element: T) { + array.append(element) + } + + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + array[head] = nil + head += 1 + + let percentage = Double(head) / Double(array.count) + if array.count > 50 && percentage > 0.25 { + array.removeFirst(head) + head = 0 + } + + return element + } +} diff --git a/Trie/Trie.playground/Sources/Trie.swift b/Trie/Trie.playground/Sources/Trie.swift new file mode 100644 index 000000000..053bd7113 --- /dev/null +++ b/Trie/Trie.playground/Sources/Trie.swift @@ -0,0 +1,212 @@ +/// The Trie class has the following attributes: +/// -root (the root of the trie) +/// -wordList (the words that currently exist in the trie) +/// -wordCount (the number of words in the trie) +public class Trie { + private var root = Node(character: "", parent: nil) + private(set) var wordList: [String] = [] + private(set) var wordCount = 0 + + init(words: Set) { + words.forEach { insert(word: $0) } + } + + /// Merge two `Trie` objects into one and returns the merged `Trie` + /// + /// - parameter other: Another `Trie` + /// + /// - returns: The newly unioned `Trie`. + func merge(other: Trie) -> Trie { + let newWordList = Set(wordList + other.wordList) + return Trie(words: newWordList) + } + + /// Looks for a specific key and returns a tuple that has a reference to the node (if found) and true/false depending on if it was found. + /// + /// - parameter key: A `String` that you would like to find. + /// + /// - returns: A tuple containing the an optional `Node`. If the key is found, it will return a non-nil `Node`. The second part of the tuple contains a bool indicating whether it was found or not. + func find(key: String) -> (node: Node?, found: Bool) { + var currentNode = root + + for character in key.characters { + if currentNode.children["\(character)"] == nil { + return (nil, false) + } + currentNode = currentNode.children["\(character)"]! + } + return (currentNode, currentNode.isValidWord) + } + + /// Returns true if the `Trie` is empty, false otherwise. + var isEmpty: Bool { + return wordCount == 0 + } + + /// Checks if the a word is currently in the `Trie`. + /// + /// - parameter word: A `String` you want to check. + /// + /// - returns: Returns `true` if the word exists in the `Trie`. False otherwise. + func contains(word: String) -> Bool { + return find(key: word.lowercased()).found + } + + func isPrefix(_ prefix: String) -> (node: Node?, found: Bool) { + let prefix = prefix.lowercased() + var currentNode = root + + for character in prefix.characters { + if currentNode.children["\(character)"] == nil { + return (nil, false) + } + + currentNode = currentNode.children["\(character)"]! + } + + if currentNode.children.count > 0 { + return (currentNode, true) + } + + return (nil, false) + } + + /// Inserts a word into the trie. Returns a tuple containing the word attempted to tbe added, and true/false depending on whether or not the insertion was successful. + /// + /// - parameter word: A `String`. + /// + /// - returns: A tuple containing the word attempted to be added, and whether it was successful. + @discardableResult func insert(word: String) -> (word: String, inserted: Bool) { + let word = word.lowercased() + guard !contains(word: word), !word.isEmpty else { return (word, false) } + + var currentNode = root + var length = word.characters.count + + var index = 0 + var character = word.characters.first! + + while let child = currentNode.children["\(character)"] { + currentNode = child + length -= 1 + index += 1 + + if length == 0 { + currentNode.isAWord = true + wordList.append(word) + wordCount += 1 + return (word, true) + } + + character = Array(word.characters)[index] + } + + let remainingCharacters = String(word.characters.suffix(length)) + for character in remainingCharacters.characters { + currentNode.children["\(character)"] = Node(character: "\(character)", parent: currentNode) + currentNode = currentNode.children["\(character)"]! + } + + currentNode.isAWord = true + wordList.append(word) + wordCount += 1 + return (word, true) + } + + /// Attempts to insert all words from input array. Returns a tuple containing the input array and true if some of the words were successfully added, false if none were added. + /// + /// - parameter words: An array of `String` objects. + /// + /// - returns: A tuple stating whether all the words were inserted. + func insert(words: [String]) -> (wordList: [String], inserted: Bool) { + var successful: Bool = false + for word in wordList { + successful = insert(word: word).inserted || successful + } + + return (wordList, successful) + } + + /// Removes the specified key from the `Trie` if it exists, returns tuple containing the word attempted to be removed and true/false if the removal was successful. + /// + /// - parameter word: A `String` to be removed. + /// + /// - returns: A tuple containing the word to be removed, and a `Bool` indicating whether removal was successful or not. + @discardableResult func remove(word: String) -> (word: String, removed: Bool) { + let word = word.lowercased() + + guard contains(word: word) else { return (word, false) } + var currentNode = root + + for character in word.characters { + currentNode = currentNode.getChildAt(character: "\(character)") + } + + if currentNode.children.count > 0 { + currentNode.isAWord = false + } else { + var character = currentNode.character + while currentNode.children.count == 0 && !currentNode.isRoot { + currentNode = currentNode.parent! + currentNode.children[character]!.parent = nil + character = currentNode.character + } + } + + wordCount -= 1 + + var index = 0 + for item in wordList { + if item == word { + wordList.remove(at: index) + } + index += 1 + } + + return (word, true) + } + + func find(prefix: String) -> [String] { + guard isPrefix(prefix).found else { return [] } + var queue = Queue() + let node = isPrefix(prefix).node! + + var wordsWithPrefix: [String] = [] + let word = prefix + var tmp = "" + queue.enqueue(element: node) + + while let current = queue.dequeue() { + for (_, child) in current.children { + if !child.visited { + queue.enqueue(element: child) + child.visited = true + if child.isValidWord { + var currentNode = child + while currentNode !== node { + tmp += currentNode.character + currentNode = currentNode.parent! + } + tmp = "\(tmp.characters.reversed())" + wordsWithPrefix.append(word + tmp) + tmp = "" + } + } + } + } + + return wordsWithPrefix + } + + func removeAll() { + for word in wordList { + remove(word: word) + } + } +} + +extension Trie: CustomStringConvertible { + public var description: String { + return "" + } +} diff --git a/Trie/Trie.playground/contents.xcplayground b/Trie/Trie.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Trie/Trie.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata b/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 1da1118e1ff00d21ae02025c5a222631925d2e55 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 12 Sep 2016 08:28:58 -0700 Subject: [PATCH 0113/1275] Refactored implementation of Trie. Leaving the old implementation in a folder for future reference. --- Trie/{ => Old Implementation}/trie.swift | 0 Trie/Trie.playground/Contents.swift | 16 ++ Trie/Trie.playground/Sources/Node.swift | 71 ++----- Trie/Trie.playground/Sources/Queue.swift | 31 --- Trie/Trie.playground/Sources/Trie.swift | 229 +++++------------------ 5 files changed, 80 insertions(+), 267 deletions(-) rename Trie/{ => Old Implementation}/trie.swift (100%) delete mode 100644 Trie/Trie.playground/Sources/Queue.swift diff --git a/Trie/trie.swift b/Trie/Old Implementation/trie.swift similarity index 100% rename from Trie/trie.swift rename to Trie/Old Implementation/trie.swift diff --git a/Trie/Trie.playground/Contents.swift b/Trie/Trie.playground/Contents.swift index e69de29bb..89a160c8d 100644 --- a/Trie/Trie.playground/Contents.swift +++ b/Trie/Trie.playground/Contents.swift @@ -0,0 +1,16 @@ +let trie = Trie() + +trie.insert(word: "apple") +trie.insert(word: "ap") +trie.insert(word: "a") + +trie.contains(word: "apple") +trie.contains(word: "ap") +trie.contains(word: "a") + +trie.remove(word: "apple") +trie.contains(word: "a") +trie.contains(word: "apple") + +trie.insert(word: "apple") +trie.contains(word: "apple") diff --git a/Trie/Trie.playground/Sources/Node.swift b/Trie/Trie.playground/Sources/Node.swift index 72600af2f..56faed3e5 100644 --- a/Trie/Trie.playground/Sources/Node.swift +++ b/Trie/Trie.playground/Sources/Node.swift @@ -1,64 +1,21 @@ -/// A Trie (prefix tree) -/// -/// Some of the functionality of the trie makes use of the Queue implementation for this project -/// -/// Every node in the Trie stores a bit of information pertaining to what it references: -/// -Character (letter of an inserted word) -/// -Parent (Letter that comes before the current letter in some word) -/// -Children (Words that have more letters than available in the prefix) -/// -isAWord (Does the current letter mark the end of a known inserted word?) -/// -visited (Mainly for the findPrefix() function) -public class Node { - public var character: String - public var parent: Node? - public var children: [String: Node] - public var isAWord: Bool - public var visited: Bool // only for findPrefix +public final class TrieNode { + public var value: T? + public weak var parent: TrieNode? + public var children: [T: TrieNode] = [:] + public var isTerminating = false - init(character: String, parent: Node?) { - self.character = character - self.children = [:] - self.isAWord = false - self.parent = parent - self.visited = false - } - - /// Returns `true` if the node is a leaf node, false otherwise. - var isLeaf: Bool { - return children.count == 0 - } - - /// Changes the parent of the current node to the passed in node. - /// - /// - parameter node: A `Node` object. - func setParent(node: Node) { - parent = node - } + init() {} - /// Returns the child node that holds the specific passed letter. - /// - /// - parameter character: A `String` - /// - /// - returns: The `Node` object that contains the `character`. - func getChildAt(character: String) -> Node { - return children[character]! - } - - /// Returns whether or not the current node marks the end of a valid word. - var isValidWord: Bool { - return isAWord - } - - - /// Returns whether or not the current node is the root of the trie. - var isRoot: Bool { - return character == "" + init(value: T, parent: TrieNode? = nil) { + self.value = value + self.parent = parent } } -// MARK: - CustomStringConvertible -extension Node: CustomStringConvertible { - public var description: String { - return "" +// MARK: - Insertion +public extension TrieNode { + func add(child: T) { + guard children[child] == nil else { return } + children[child] = TrieNode(value: child, parent: self) } } diff --git a/Trie/Trie.playground/Sources/Queue.swift b/Trie/Trie.playground/Sources/Queue.swift deleted file mode 100644 index 81bde190a..000000000 --- a/Trie/Trie.playground/Sources/Queue.swift +++ /dev/null @@ -1,31 +0,0 @@ -/// Queue implementation taken from the repository. -public struct Queue { - private var array: [T?] = [] - private var head = 0 - - public var isEmpty: Bool { - return count == 0 - } - - public var count: Int { - return array.count - head - } - - public mutating func enqueue(element: T) { - array.append(element) - } - - public mutating func dequeue() -> T? { - guard head < array.count, let element = array[head] else { return nil } - array[head] = nil - head += 1 - - let percentage = Double(head) / Double(array.count) - if array.count > 50 && percentage > 0.25 { - array.removeFirst(head) - head = 0 - } - - return element - } -} diff --git a/Trie/Trie.playground/Sources/Trie.swift b/Trie/Trie.playground/Sources/Trie.swift index 053bd7113..ddce0ba84 100644 --- a/Trie/Trie.playground/Sources/Trie.swift +++ b/Trie/Trie.playground/Sources/Trie.swift @@ -2,211 +2,82 @@ /// -root (the root of the trie) /// -wordList (the words that currently exist in the trie) /// -wordCount (the number of words in the trie) -public class Trie { - private var root = Node(character: "", parent: nil) - private(set) var wordList: [String] = [] - private(set) var wordCount = 0 +public final class Trie { + typealias Node = TrieNode + fileprivate let root: Node - init(words: Set) { - words.forEach { insert(word: $0) } + public init() { + root = TrieNode() } - - /// Merge two `Trie` objects into one and returns the merged `Trie` - /// - /// - parameter other: Another `Trie` - /// - /// - returns: The newly unioned `Trie`. - func merge(other: Trie) -> Trie { - let newWordList = Set(wordList + other.wordList) - return Trie(words: newWordList) - } - - /// Looks for a specific key and returns a tuple that has a reference to the node (if found) and true/false depending on if it was found. - /// - /// - parameter key: A `String` that you would like to find. - /// - /// - returns: A tuple containing the an optional `Node`. If the key is found, it will return a non-nil `Node`. The second part of the tuple contains a bool indicating whether it was found or not. - func find(key: String) -> (node: Node?, found: Bool) { +} + +// MARK: - Basic Methods +public extension Trie { + func insert(word: String) { + guard !word.isEmpty else { return } var currentNode = root - for character in key.characters { - if currentNode.children["\(character)"] == nil { - return (nil, false) - } - currentNode = currentNode.children["\(character)"]! - } - return (currentNode, currentNode.isValidWord) - } - - /// Returns true if the `Trie` is empty, false otherwise. - var isEmpty: Bool { - return wordCount == 0 - } - - /// Checks if the a word is currently in the `Trie`. - /// - /// - parameter word: A `String` you want to check. - /// - /// - returns: Returns `true` if the word exists in the `Trie`. False otherwise. - func contains(word: String) -> Bool { - return find(key: word.lowercased()).found - } - - func isPrefix(_ prefix: String) -> (node: Node?, found: Bool) { - let prefix = prefix.lowercased() - var currentNode = root + var characters = Array(word.lowercased().characters) + var currentIndex = 0 - for character in prefix.characters { - if currentNode.children["\(character)"] == nil { - return (nil, false) + while currentIndex < characters.count { + let character = characters[currentIndex] + if let child = currentNode.children[character] { + currentNode = child + } else { + currentNode.add(child: character) + currentNode = currentNode.children[character]! } - currentNode = currentNode.children["\(character)"]! - } - - if currentNode.children.count > 0 { - return (currentNode, true) + currentIndex += 1 + if currentIndex == characters.count { + currentNode.isTerminating = true + } } - - return (nil, false) } - /// Inserts a word into the trie. Returns a tuple containing the word attempted to tbe added, and true/false depending on whether or not the insertion was successful. - /// - /// - parameter word: A `String`. - /// - /// - returns: A tuple containing the word attempted to be added, and whether it was successful. - @discardableResult func insert(word: String) -> (word: String, inserted: Bool) { - let word = word.lowercased() - guard !contains(word: word), !word.isEmpty else { return (word, false) } - + func contains(word: String) -> Bool { + guard !word.isEmpty else { return false } var currentNode = root - var length = word.characters.count - var index = 0 - var character = word.characters.first! + var characters = Array(word.lowercased().characters) + var currentIndex = 0 - while let child = currentNode.children["\(character)"] { + while currentIndex < characters.count, let child = currentNode.children[characters[currentIndex]] { currentNode = child - length -= 1 - index += 1 - - if length == 0 { - currentNode.isAWord = true - wordList.append(word) - wordCount += 1 - return (word, true) - } - - character = Array(word.characters)[index] - } - - let remainingCharacters = String(word.characters.suffix(length)) - for character in remainingCharacters.characters { - currentNode.children["\(character)"] = Node(character: "\(character)", parent: currentNode) - currentNode = currentNode.children["\(character)"]! + currentIndex += 1 } - currentNode.isAWord = true - wordList.append(word) - wordCount += 1 - return (word, true) - } - - /// Attempts to insert all words from input array. Returns a tuple containing the input array and true if some of the words were successfully added, false if none were added. - /// - /// - parameter words: An array of `String` objects. - /// - /// - returns: A tuple stating whether all the words were inserted. - func insert(words: [String]) -> (wordList: [String], inserted: Bool) { - var successful: Bool = false - for word in wordList { - successful = insert(word: word).inserted || successful + if currentIndex == characters.count && currentNode.isTerminating { + return true + } else { + return false } - - return (wordList, successful) } - /// Removes the specified key from the `Trie` if it exists, returns tuple containing the word attempted to be removed and true/false if the removal was successful. - /// - /// - parameter word: A `String` to be removed. - /// - /// - returns: A tuple containing the word to be removed, and a `Bool` indicating whether removal was successful or not. - @discardableResult func remove(word: String) -> (word: String, removed: Bool) { - let word = word.lowercased() - - guard contains(word: word) else { return (word, false) } + func remove(word: String) { + guard !word.isEmpty else { return } var currentNode = root - for character in word.characters { - currentNode = currentNode.getChildAt(character: "\(character)") + var characters = Array(word.lowercased().characters) + var currentIndex = 0 + + while currentIndex < characters.count { + let character = characters[currentIndex] + guard let child = currentNode.children[character] else { return } + currentNode = child + currentIndex += 1 } if currentNode.children.count > 0 { - currentNode.isAWord = false + currentNode.isTerminating = false } else { - var character = currentNode.character - while currentNode.children.count == 0 && !currentNode.isRoot { - currentNode = currentNode.parent! - currentNode.children[character]!.parent = nil - character = currentNode.character - } - } - - wordCount -= 1 - - var index = 0 - for item in wordList { - if item == word { - wordList.remove(at: index) - } - index += 1 - } - - return (word, true) - } - - func find(prefix: String) -> [String] { - guard isPrefix(prefix).found else { return [] } - var queue = Queue() - let node = isPrefix(prefix).node! - - var wordsWithPrefix: [String] = [] - let word = prefix - var tmp = "" - queue.enqueue(element: node) - - while let current = queue.dequeue() { - for (_, child) in current.children { - if !child.visited { - queue.enqueue(element: child) - child.visited = true - if child.isValidWord { - var currentNode = child - while currentNode !== node { - tmp += currentNode.character - currentNode = currentNode.parent! - } - tmp = "\(tmp.characters.reversed())" - wordsWithPrefix.append(word + tmp) - tmp = "" - } - } + var character = currentNode.value + while currentNode.children.count == 0, let parent = currentNode.parent, !parent.isTerminating { + currentNode = parent + currentNode.children[character!] = nil + character = currentNode.value } } - - return wordsWithPrefix - } - - func removeAll() { - for word in wordList { - remove(word: word) - } - } -} - -extension Trie: CustomStringConvertible { - public var description: String { - return "" } } From 931e85bfb6d6fee122451840ea7cd044dd895763 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 12 Sep 2016 13:48:25 -0700 Subject: [PATCH 0114/1275] Refactored README fileg --- Trie/ReadMe.md | 294 ++++++++++++++++++------------------------- Trie/images/trie.png | Bin 0 -> 174737 bytes 2 files changed, 119 insertions(+), 175 deletions(-) create mode 100644 Trie/images/trie.png diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 844eb1df0..a1cd7757b 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -1,220 +1,164 @@ # Trie -##What is a Trie? -A trie (also known as a prefix tree, or radix tree in some other (but different) implementations) is a special type of tree used to store associative data structures where the key item is normally of type String. Each node in the trie is typically not associated with a value containing strictly itself, but more so is linked to some common prefix that precedes it in levels above it. Oftentimes, true key-value pairs are associated with the leaves of the trie, but they are not limited to this. +## What is a Trie? -##Why a Trie? -Tries are very useful simply for the fact that it has some advantages over other data structures, like the binary tree or a hash map. These advantages include: -* Looking up keys is typically faster in the worst case when compared to other data structures. -* Unlike a hash map, a trie need not worry about key collisions -* No need for hasing, as each key will have a unique path in the trie -* Tries, by implementation, can be by default alphabetically ordered. +A `Trie`, (also known as a prefix tree, or radix tree in some other implementations) is a special type of tree used to store associative data structures. A `Trie` for a dictionary might look like this: +![A Trie](Images/trie.png) -##Common Algorithms +Storing the English language is a primary use case for a `Trie`. Each node in the `Trie` would representing a single character of a word. A series of nodes then make up a word. -###Find (or any general lookup function) -Tries make looking up keys a trivial task, as all one has to do is walk over the nodes until we either hit a null reference or we find the key in question. +## Why a Trie? -The algorithm would be as follows: -``` - let node be the root of the trie - - for each character in the key - if the child of node with value character is null - return false (key doesn't exist in trie) - else - node = child of node with value character (move to the next node) - return true (key exists in trie and was found -``` +Tries are very useful for certain situations. Here are some of the advantages: -And in swift: -```swift -func find(key: String) -> (node: Node?, found: Bool) { - var currentNode = self.root - - for c in key.characters { - if currentNode.children[String(c)] == nil { - return(nil, false) - } - currentNode = currentNode.children[String(c)]! - } +* Looking up values typically have a better worst-case time complexity. +* Unlike a hash map, a `Trie` does not need to worry about key collisions. +* Doesn't utilize hashing to guarantee a unique path to elements. +* `Trie` structures can be alphabetically ordered by default. - return(currentNode, currentNode.isValidWord()) - } -``` +## Common Algorithms -###Insertion -Insertion is also a trivial task with a Trie, as all one needs to do is walk over the nodes until we either halt on a node that we must mark as a key, or we reach a point where we need to add extra nodes to represent it. +### Contains (or any general lookup method) -Let's walk through the algorithm: +`Trie` structures are great for lookup operations. For `Trie` structures that model the English language, finding a particular word is a matter of a few pointer traversals: -``` - let S be the root node of our tree - let word be the input key - let length be the length of the key - +```swift +func contains(word: String) -> Bool { + guard !word.isEmpty else { return false } + + // 1 + var currentNode = root - find(word) - if the word was found - return false - else - - for each character in word - if child node with value character does not exist - break - else - node = child node with value character - decrement length - - if length != 0 - let suffix be the remaining characters in the key defined by the shortened length - - for each character in suffix - create a new node with value character and let it be the child of node - node = newly created child now - mark node as a valid key - else - mark node as valid key + // 2 + var characters = Array(word.lowercased().characters) + var currentIndex = 0 + + // 3 + while currentIndex < characters.count, + let child = currentNode.children[character[currentIndex]] { + + currentNode = child + currentIndex += 1 + } + + // 4 + if currentIndex == characters.count && currentNode.isTerminating { + return true + } else { + return false + } +} ``` -And the corresponding swift code: +The `contains` method is fairly straightforward: -```swift - func insert(w: String) -> (word: String, inserted: Bool) { - - let word = w.lowercaseString - var currentNode = self.root - var length = word.characters.count +1. Create a reference to the `root`. This reference will allow you to walk down a chain of nodes. +2. Keep track of the characters of the word you're trying to match. +3. Walk the pointer down the nodes. +4. `isTerminating` is a boolean flag for whether or not this node is the end of a word. If this `if` condition is satisfied, it means you are able to find the word in the `trie`. - if self.contains(word) { - return (w, false) - } +### Insertion - var index = 0 - var c = Array(word.characters)[index] +Insertion into a `Trie` requires you to walk over the nodes until you either halt on a node that must be marked as `terminating`, or reach a point where you need to add extra nodes. - while let child = currentNode.children[String(c)] { - currentNode = child - length -= 1 - index += 1 +```swift +func insert(word: String) { + guard !word.isEmpty else { return } - if(length == 0) { - currentNode.isWord() - wordList.append(w) - wordCount += 1 - return (w, true) - } + // 1 + var currentNode = root + + // 2 + var characters = Array(word.lowercased().characters) + var currentIndex = 0 + + // 3 + while currentIndex < characters.count { + let character = characters[currentIndex] - c = Array(word.characters)[index] + // 4 + if let child = currentNode.children[character] { + currentNode = child + } else { + currentNode.add(child: character) + currentNode = currentNode.children[character]! } + + currentIndex += 1 - let remainingChars = String(word.characters.suffix(length)) - for c in remainingChars.characters { - currentNode.children[String(c)] = Node(c: String(c), p: currentNode) - currentNode = currentNode.children[String(c)]! + // 5 + if currentIndex == characters.count { + currentNode.isTerminating = true } - - currentNode.isWord() - wordList.append(w) - wordCount += 1 - return (w, true) } - +} ``` -###Removal -Removing keys from the trie is a little more tricky, as there a few more cases that we have to take into account the fact that keys may exist that are actually sub-strings of other valid keys. That being said, it isn't as simple a process to just delete the nodes for a specific key, as we could be deleting references/nodes necessary for already exisitng keys! +1. Once again, you create a reference to the root node. You'll move this reference down a chain of nodes. +2. Keep track of the word you want to insert. +3. Begin walking through your word letter by letter +4. Sometimes, the required node to insert already exists. That is the case for two words inside the `Trie` that shares letters (i.e "Apple", "App"). If a letter already exists, you'll reuse it, and simply traverse deeper down the chain. Otherwise, you'll create a new node representing the letter. +5. Once you get to the end, you mark `isTerminating` to true to mark that specific node as the end of a word. -The algorithm would be as follows: - -``` - - let word be the key to remove - let node be the root of the trie - - find(word) - if word was not found - return false - else - - for each character in word - node = child node with value character - - if node has more than just 1 child node - Mark node as an invalid key, since removing it would remove nodes still in use - else - while node has no valid children and node is not the root node - let character = node's value - node = the parent of node - delete node's child node with value character - return true -``` +### Removal +Removing keys from the trie is a little tricky, as there are a few more cases you'll need to take into account. Nodes in a `Trie` may be shared between different words. Consider the two words "Apple" and "App". Inside a `Trie`, the chain of nodes representing "App" is shared with "Apple". - -and the corresponding swift code: +If you'd like to remove "Apple", you'll need to take care to leave the "App" chain in tact. ```swift - func remove(w: String) -> (word: String, removed: Bool){ - let word = w.lowercaseString - - if(!self.contains(w)) { - return (w, false) - } - var currentNode = self.root +func remove(word: String) { + guard !word.isEmpty else { return } - for c in word.characters { - currentNode = currentNode.getChildAt(String(c)) - } - - if currentNode.numChildren() > 0 { - currentNode.isNotWord() - } else { - var character = currentNode.char() - while(currentNode.numChildren() == 0 && !currentNode.isRoot()) { - currentNode = currentNode.getParent() - currentNode.children[character]!.setParent(nil) - currentNode.children[character]!.update(nil) - currentNode.children[character] = nil - character = currentNode.char() - } - } - - wordCount -= 1 - - var index = 0 - for item in wordList{ - if item == w { - wordList.removeAtIndex(index) - } - index += 1 + // 1 + var currentNode = root + + // 2 + var characters = Array(word.lowercased().characters) + var currentIndex = 0 + + // 3 + while currentIndex < characters.count { + let character = characters[currentIndex] + guard let child = currentNode.children[character] else { return } + currentNode = child + currentIndex += 1 + } + + // 4 + if currentNode.children.count > 0 { + currentNode.isTerminating = false + } else { + var character = currentNode.value + while currentNode.children.count == 0, let parent = currentNode.parent, !parent.isTerminating { + currentNode = parent + currentNode.children[character!] = nil + character = currentNode.value } - - return (w, true) } - +} ``` +1. Once again, you create a reference to the root node. +2. Keep track of the word you want to remove. +3. Attempt to walk to the terminating node of the word. The `guard` statement will return if it can't find one of the letters; It's possible to call `remove` on a non-existant entry. +4. If you reach the node representing the last letter of the word you want to remove, you'll have 2 cases to deal with. Either it's a leaf node, or it has more children. If it has more children, it means the node is used for other words. In that case, you'll just mark `isTerminating` to false. In the other case, you'll delete the nodes. -###Running Times +### Time Complexity -Let n be the length of some key in the trie +Let n be the length of some value in the `Trie`. -* Find(...) : In the Worst case O(n) -* Insert(...) : O(n) -* Remove(...) : O(n) +* `contains` - Worst case O(n) +* `insert` - O(n) +* `remove` - O(n) -###Other Notable Operations +### Other Notable Operations -* Count: Returns the number of keys in the trie ( O(1) ) -* getWords: Returns a list containing all keys in the trie ( *O(1) ) -* isEmpty: Returns true f the trie is empty, false otherwise ( *O(1) ) -* contains: Returns true if the trie has a given key, false otherwise ( O(n) ) - -`* denotes that running time may vary depending on implementation +* `count`: Returns the number of keys in the `Trie` - O(1) +* `words`: Returns a list containing all the keys in the `Trie` - O(1) +* `isEmpty`: Returns `true` if the `Trie` is empty, `false` otherwise - O(1) See also [Wikipedia entry for Trie](https://en.wikipedia.org/wiki/Trie). -*Written for the Swift Algorithm Club by Christian Encarnacion* - +*Written for the Swift Algorithm Club by Christian Encarnacion. Refactored by Kelvin Lau* diff --git a/Trie/images/trie.png b/Trie/images/trie.png new file mode 100644 index 0000000000000000000000000000000000000000..00dacc0080cd596cc1d2934e2b5f2a15abb7ae1c GIT binary patch literal 174737 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

`8OzWVS<5_7y)1- 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%0D!S1G`PQ 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 caA^F`e#~HF)@`jl{0uFVdQ&MBb@07dCJ3;+NC literal 0 HcmV?d00001 From b563b932f903c732790f2e363a7e294483e4665b Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 12 Sep 2016 13:51:20 -0700 Subject: [PATCH 0115/1275] Fixed spacing --- Trie/ReadMe.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index a1cd7757b..ee101a0a9 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -30,11 +30,11 @@ func contains(word: String) -> Bool { // 1 var currentNode = root - // 2 + // 2 var characters = Array(word.lowercased().characters) var currentIndex = 0 - // 3 + // 3 while currentIndex < characters.count, let child = currentNode.children[character[currentIndex]] { @@ -42,7 +42,7 @@ func contains(word: String) -> Bool { currentIndex += 1 } - // 4 + // 4 if currentIndex == characters.count && currentNode.isTerminating { return true } else { @@ -69,15 +69,15 @@ func insert(word: String) { // 1 var currentNode = root - // 2 + // 2 var characters = Array(word.lowercased().characters) var currentIndex = 0 - // 3 + // 3 while currentIndex < characters.count { let character = characters[currentIndex] - // 4 + // 4 if let child = currentNode.children[character] { currentNode = child } else { @@ -87,7 +87,7 @@ func insert(word: String) { currentIndex += 1 - // 5 + // 5 if currentIndex == characters.count { currentNode.isTerminating = true } @@ -111,14 +111,14 @@ If you'd like to remove "Apple", you'll need to take care to leave the "App" cha func remove(word: String) { guard !word.isEmpty else { return } - // 1 + // 1 var currentNode = root - // 2 + // 2 var characters = Array(word.lowercased().characters) var currentIndex = 0 - // 3 + // 3 while currentIndex < characters.count { let character = characters[currentIndex] guard let child = currentNode.children[character] else { return } @@ -126,7 +126,7 @@ func remove(word: String) { currentIndex += 1 } - // 4 + // 4 if currentNode.children.count > 0 { currentNode.isTerminating = false } else { From 0faf88a574d5ea8c923819c63cd394eb503eeecb Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 12 Sep 2016 13:51:49 -0700 Subject: [PATCH 0116/1275] Fixed a typo. --- Trie/ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index ee101a0a9..3e3dad3a6 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -4,7 +4,7 @@ A `Trie`, (also known as a prefix tree, or radix tree in some other implementations) is a special type of tree used to store associative data structures. A `Trie` for a dictionary might look like this: -![A Trie](Images/trie.png) +![A Trie](images/trie.png) Storing the English language is a primary use case for a `Trie`. Each node in the `Trie` would representing a single character of a word. A series of nodes then make up a word. From 8035d8dccf919099ae581ef899ed5558fce938b1 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 12 Sep 2016 18:03:20 -0700 Subject: [PATCH 0117/1275] Init & Claim Karatsuba Multiplication Algorithm --- Karatsuba Multiplication/KaratsubaMultiplication.swift | 9 +++++++++ Karatsuba Multiplication/README.markdown | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.swift create mode 100644 Karatsuba Multiplication/README.markdown diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift new file mode 100644 index 000000000..725b87939 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -0,0 +1,9 @@ +// +// KaratsubaMultiplication.swift +// +// +// Created by Richard Ash on 9/12/16. +// +// + +import Foundation diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown new file mode 100644 index 000000000..0afd91b0c --- /dev/null +++ b/Karatsuba Multiplication/README.markdown @@ -0,0 +1,8 @@ +# Karatsuba Multiplication + +TODO: Explanation/Examples + + + + +*Written for Swift Algorithm Club by Richard Ash* From b6c05be12875e17e1734b4438eb9e72869aeb228 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 12 Sep 2016 18:04:23 -0700 Subject: [PATCH 0118/1275] Added implmentation for the Karatsuba Algorithm --- .../Contents.swift | 57 +++++++++++++++++++ .../contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 7 +++ .../KaratsubaMultiplication.swift | 25 ++++++++ 4 files changed, 93 insertions(+) create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.playground/contents.xcplayground create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift new file mode 100644 index 000000000..bf4454956 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -0,0 +1,57 @@ +//: Playground - noun: a place where people can play + +import Foundation + +infix operator ^^ { associativity left precedence 160 } +func ^^ (radix: Int, power: Int) -> Int { + return Int(pow(Double(radix), Double(power))) +} + +// Long Multiplication - O(n^2) +func multiply(num1: Int, _ num2: Int, base: Int = 10) -> Int { + let num1Array = String(num1).characters.reverse().map{ Int(String($0))! } + let num2Array = String(num2).characters.reverse().map{ Int(String($0))! } + + var product = Array(count: num1Array.count + num2Array.count, repeatedValue: 0) + + 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.reverse().map{ String($0) }.reduce("", combine: +))! +} + +// Karatsuba Multiplication - O(nlogn) +func karatsuba(num1: Int, _ num2: Int) -> Int { + let num1Array = String(num1).characters + let num2Array = String(num2).characters + + guard num1Array.count > 1 && num2Array.count > 1 else { + return multiply(num1, num2) + } + + let n = max(num1Array.count, num2Array.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, c) + let bd = karatsuba(b, d) + let adPluscd = karatsuba(a+b, c+d) - ac - bd + + let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd + + return product +} + +print(multiply(236742342, 1231234224)) +print(karatsuba(236742342, 1231234224)) \ No newline at end of file diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/contents.xcplayground b/Karatsuba Multiplication/KaratsubaMultiplication.playground/contents.xcplayground new file mode 100644 index 000000000..9f5f2f40c --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index 725b87939..a315d7494 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -7,3 +7,28 @@ // import Foundation + +func karatsuba(num1: Int, _ num2: Int) -> Int { + let num1Array = String(num1).characters + let num2Array = String(num2).characters + + guard num1Array.count > 1 && num2Array.count > 1 else { + return num1 * num2 + } + + let n = max(num1Array.count, num2Array.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, c) + let bd = karatsuba(b, d) + let adPluscd = karatsuba(a+b, c+d) - ac - bd + + let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd + + return product +} \ No newline at end of file From 8d03fea237fb50ab1420dcd1614dfb903e5629e7 Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 16:33:55 -0400 Subject: [PATCH 0119/1275] Updated Linked List playground to swift 3 --- .../LinkedList.playground/Contents.swift | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index cc7ed3d59..5c05c1a3e 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -13,7 +13,7 @@ public class LinkedListNode { public class LinkedList { public typealias Node = LinkedListNode - private var head: Node? + fileprivate var head: Node? public var isEmpty: Bool { return head == nil @@ -61,7 +61,7 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAtIndex(index) + let node = nodeAtIndex(index: index) assert(node != nil) return node!.value } @@ -94,7 +94,7 @@ public class LinkedList { } public func insert(value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index) + let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = Node(value: value) newNode.previous = prev @@ -129,13 +129,13 @@ public class LinkedList { public func removeLast() -> T { assert(!isEmpty) - return removeNode(last!) + return removeNode(node: last!) } public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index) + let node = nodeAtIndex(index: index) assert(node != nil) - return removeNode(node!) + return removeNode(node: node!) } } @@ -164,22 +164,22 @@ extension LinkedList { } extension LinkedList { - public func map(transform: T -> U) -> LinkedList { + public func map(transform: (T) -> U) -> LinkedList { let result = LinkedList() var node = head while node != nil { - result.append(transform(node!.value)) + result.append(value: transform(node!.value)) node = node!.next } return result } - public func filter(predicate: T -> Bool) -> LinkedList { + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head while node != nil { if predicate(node!.value) { - result.append(node!.value) + result.append(value: node!.value) } node = node!.next } @@ -195,13 +195,13 @@ list.isEmpty // true list.first // nil list.last // nil -list.append("Hello") +list.append(value: "Hello") list.isEmpty list.first!.value // "Hello" list.last!.value // "Hello" list.count // 1 -list.append("World") +list.append(value: "World") list.first!.value // "Hello" list.last!.value // "World" list.count // 2 @@ -211,15 +211,15 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.nodeAtIndex(0)!.value // "Hello" -list.nodeAtIndex(1)!.value // "World" -list.nodeAtIndex(2) // nil +list.nodeAtIndex(index: 0)!.value // "Hello" +list.nodeAtIndex(index: 1)!.value // "World" +list.nodeAtIndex(index: 2) // nil list[0] // "Hello" list[1] // "World" //list[2] // crash! -list.insert("Swift", atIndex: 1) +list.insert(value: "Swift", atIndex: 1) list[0] list[1] list[2] @@ -227,8 +227,8 @@ print(list) list.reverse() // [World, Swift, Hello] -list.nodeAtIndex(0)!.value = "Universe" -list.nodeAtIndex(1)!.value = "Swifty" +list.nodeAtIndex(index: 0)!.value = "Universe" +list.nodeAtIndex(index: 1)!.value = "Swifty" let m = list.map { s in s.characters.count } m // [8, 6, 5] let f = list.filter { s in s.characters.count > 5 } @@ -237,7 +237,7 @@ f // [Universe, Swifty] //list.removeAll() //list.isEmpty -list.removeNode(list.first!) // "Hello" +list.removeNode(node: list.first!) // "Hello" list.count // 2 list[0] // "Swift" list[1] // "World" @@ -246,5 +246,5 @@ list.removeLast() // "World" list.count // 1 list[0] // "Swift" -list.removeAtIndex(0) // "Swift" +list.removeAtIndex(index: 0) // "Swift" list.count // 0 From 900811288a73e20e1c17c5b80d852f0c120b56f3 Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 16:48:40 -0400 Subject: [PATCH 0120/1275] Updated LinkedList.swift for Swift 3 --- .../Sources/LinkedList.swift | 191 ++++++++++++++++++ Linked List/LinkedList.swift | 20 +- 2 files changed, 201 insertions(+), 10 deletions(-) create mode 100755 Linked List/LinkedList.playground/Sources/LinkedList.swift diff --git a/Linked List/LinkedList.playground/Sources/LinkedList.swift b/Linked List/LinkedList.playground/Sources/LinkedList.swift new file mode 100755 index 000000000..ef95a0b58 --- /dev/null +++ b/Linked List/LinkedList.playground/Sources/LinkedList.swift @@ -0,0 +1,191 @@ +/* + Doubly-linked list + + Most operations on the linked list have complexity O(n). +*/ +public class LinkedListNode { + var value: T + var next: LinkedListNode? + weak var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } +} + +public class LinkedList { + public typealias Node = LinkedListNode + + private var head: Node? + + public var isEmpty: Bool { + return head == nil + } + + public var first: Node? { + return head + } + + public var last: Node? { + if var node = head { + while case let next? = node.next { + node = next + } + return node + } else { + return nil + } + } + + public var count: Int { + if var node = head { + var c = 1 + while case let next? = node.next { + node = next + c += 1 + } + return c + } else { + return 0 + } + } + + public func nodeAtIndex(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 + } + } + return nil + } + + public subscript(index: Int) -> T { + let node = nodeAtIndex(index) + assert(node != nil) + return node!.value + } + + public func append(value: T) { + let newNode = Node(value: value) + if let lastNode = last { + newNode.previous = lastNode + lastNode.next = newNode + } else { + head = newNode + } + } + + 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 (prev, next) = nodesBeforeAndAfter(index) + + let newNode = Node(value: value) + newNode.previous = prev + newNode.next = next + prev?.next = newNode + next?.previous = newNode + + if prev == nil { + head = newNode + } + } + + public func removeAll() { + head = nil + } + + public func removeNode(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 + } + + public func removeLast() -> T { + assert(!isEmpty) + return removeNode(last!) + } + + public func removeAtIndex(index: Int) -> T { + let node = nodeAtIndex(index) + assert(node != nil) + return removeNode(node!) + } +} + +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 += ", " } + } + return s + "]" + } +} + +extension LinkedList { + public func reverse() { + var node = head + while let currentNode = node { + node = currentNode.next + swap(¤tNode.next, ¤tNode.previous) + head = currentNode + } + } +} + +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 + } + 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 + } + return result + } +} diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index ef95a0b58..336775c3c 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -16,7 +16,7 @@ public class LinkedListNode { public class LinkedList { public typealias Node = LinkedListNode - private var head: Node? + fileprivate var head: Node? public var isEmpty: Bool { return head == nil @@ -64,7 +64,7 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAtIndex(index) + let node = nodeAtIndex(index: index) assert(node != nil) return node!.value } @@ -97,7 +97,7 @@ public class LinkedList { } public func insert(value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index) + let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = Node(value: value) newNode.previous = prev @@ -132,13 +132,13 @@ public class LinkedList { public func removeLast() -> T { assert(!isEmpty) - return removeNode(last!) + return removeNode(node: last!) } public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index) + let node = nodeAtIndex(index: index) assert(node != nil) - return removeNode(node!) + return removeNode(node: node!) } } @@ -167,22 +167,22 @@ extension LinkedList { } extension LinkedList { - public func map(transform: T -> U) -> LinkedList { + public func map(transform: (T)-> U) -> LinkedList { let result = LinkedList() var node = head while node != nil { - result.append(transform(node!.value)) + result.append(value: transform(node!.value)) node = node!.next } return result } - public func filter(predicate: T -> Bool) -> LinkedList { + public func filter(predicate: (T)-> Bool) -> LinkedList { let result = LinkedList() var node = head while node != nil { if predicate(node!.value) { - result.append(node!.value) + result.append(value: node!.value) } node = node!.next } From bd5b4c0fbcf18adb32f698fcd0f68afee1a8232e Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 16:50:29 -0400 Subject: [PATCH 0121/1275] Removed LinkedList.swift from playground It was added by mistake --- .../Sources/LinkedList.swift | 191 ------------------ 1 file changed, 191 deletions(-) delete mode 100755 Linked List/LinkedList.playground/Sources/LinkedList.swift diff --git a/Linked List/LinkedList.playground/Sources/LinkedList.swift b/Linked List/LinkedList.playground/Sources/LinkedList.swift deleted file mode 100755 index ef95a0b58..000000000 --- a/Linked List/LinkedList.playground/Sources/LinkedList.swift +++ /dev/null @@ -1,191 +0,0 @@ -/* - Doubly-linked list - - Most operations on the linked list have complexity O(n). -*/ -public class LinkedListNode { - var value: T - var next: LinkedListNode? - weak var previous: LinkedListNode? - - public init(value: T) { - self.value = value - } -} - -public class LinkedList { - public typealias Node = LinkedListNode - - private var head: Node? - - public var isEmpty: Bool { - return head == nil - } - - public var first: Node? { - return head - } - - public var last: Node? { - if var node = head { - while case let next? = node.next { - node = next - } - return node - } else { - return nil - } - } - - public var count: Int { - if var node = head { - var c = 1 - while case let next? = node.next { - node = next - c += 1 - } - return c - } else { - return 0 - } - } - - public func nodeAtIndex(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 - } - } - return nil - } - - public subscript(index: Int) -> T { - let node = nodeAtIndex(index) - assert(node != nil) - return node!.value - } - - public func append(value: T) { - let newNode = Node(value: value) - if let lastNode = last { - newNode.previous = lastNode - lastNode.next = newNode - } else { - head = newNode - } - } - - 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 (prev, next) = nodesBeforeAndAfter(index) - - let newNode = Node(value: value) - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { - head = newNode - } - } - - public func removeAll() { - head = nil - } - - public func removeNode(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 - } - - public func removeLast() -> T { - assert(!isEmpty) - return removeNode(last!) - } - - public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index) - assert(node != nil) - return removeNode(node!) - } -} - -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 += ", " } - } - return s + "]" - } -} - -extension LinkedList { - public func reverse() { - var node = head - while let currentNode = node { - node = currentNode.next - swap(¤tNode.next, ¤tNode.previous) - head = currentNode - } - } -} - -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 - } - 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 - } - return result - } -} From b2fe7f39ccfedaf816d4a9c69ac3455ebd7db67b Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 16:56:45 -0400 Subject: [PATCH 0122/1275] Changed naming of functions to fit the Swift 3 style Functions like nodeAtIndex(index: Int) are now nodeAt(index: Int) --- .../LinkedList.playground/Contents.swift | 28 +++++++++---------- Linked List/LinkedList.swift | 14 +++++----- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 5c05c1a3e..2078c0baf 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -47,7 +47,7 @@ public class LinkedList { } } - public func nodeAtIndex(index: Int) -> Node? { + public func nodeAt(index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -61,7 +61,7 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAtIndex(index: index) + let node = nodeAt(index: index) assert(node != nil) return node!.value } @@ -111,7 +111,7 @@ public class LinkedList { head = nil } - public func removeNode(node: Node) -> T { + public func remove(node: Node) -> T { let prev = node.previous let next = node.next @@ -129,13 +129,13 @@ public class LinkedList { public func removeLast() -> T { assert(!isEmpty) - return removeNode(node: last!) + return remove(node: last!) } - public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index: index) + public func removeAt(index: Int) -> T { + let node = nodeAt(index: index) assert(node != nil) - return removeNode(node: node!) + return remove(node: node!) } } @@ -211,9 +211,9 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.nodeAtIndex(index: 0)!.value // "Hello" -list.nodeAtIndex(index: 1)!.value // "World" -list.nodeAtIndex(index: 2) // nil +list.nodeAt(index: 0)!.value // "Hello" +list.nodeAt(index: 1)!.value // "World" +list.nodeAt(index: 2) // nil list[0] // "Hello" list[1] // "World" @@ -227,8 +227,8 @@ print(list) list.reverse() // [World, Swift, Hello] -list.nodeAtIndex(index: 0)!.value = "Universe" -list.nodeAtIndex(index: 1)!.value = "Swifty" +list.nodeAt(index: 0)!.value = "Universe" +list.nodeAt(index: 1)!.value = "Swifty" let m = list.map { s in s.characters.count } m // [8, 6, 5] let f = list.filter { s in s.characters.count > 5 } @@ -237,7 +237,7 @@ f // [Universe, Swifty] //list.removeAll() //list.isEmpty -list.removeNode(node: list.first!) // "Hello" +list.remove(node: list.first!) // "Hello" list.count // 2 list[0] // "Swift" list[1] // "World" @@ -246,5 +246,5 @@ list.removeLast() // "World" list.count // 1 list[0] // "Swift" -list.removeAtIndex(index: 0) // "Swift" +list.removeAt(index: 0) // "Swift" list.count // 0 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 336775c3c..8d95c4ac1 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -50,7 +50,7 @@ public class LinkedList { } } - public func nodeAtIndex(index: Int) -> Node? { + public func nodeAt(index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -64,7 +64,7 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAtIndex(index: index) + let node = nodeAt(index: index) assert(node != nil) return node!.value } @@ -114,7 +114,7 @@ public class LinkedList { head = nil } - public func removeNode(node: Node) -> T { + public func remove(node: Node) -> T { let prev = node.previous let next = node.next @@ -132,13 +132,13 @@ public class LinkedList { public func removeLast() -> T { assert(!isEmpty) - return removeNode(node: last!) + return remove(node: last!) } - public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index: index) + public func removeAt(index: Int) -> T { + let node = nodeAt(index: index) assert(node != nil) - return removeNode(node: node!) + return remove(node: node!) } } From b0baae91b1681c187fe7f8df37e296b733a1988e Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 17:19:59 -0400 Subject: [PATCH 0123/1275] Updated tests to swift 3 and fixed playground There was a better way to do the naming. Instead of doing nodeAt(index: Int), I changed it to nodeAt(_ index: Int) which allows you to call nodeAt(3) instead of nodeAt(index: 3) --- .../LinkedList.playground/Contents.swift | 20 ++++---- Linked List/LinkedList.swift | 48 +++++++++---------- Linked List/Tests/LinkedListTests.swift | 34 ++++++------- .../Tests/Tests.xcodeproj/project.pbxproj | 3 ++ 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 2078c0baf..72dcffe02 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -47,7 +47,7 @@ public class LinkedList { } } - public func nodeAt(index: Int) -> Node? { + public func nodeAt(_ index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -61,7 +61,7 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAt(index: index) + let node = nodeAt(index) assert(node != nil) return node!.value } @@ -132,8 +132,8 @@ public class LinkedList { return remove(node: last!) } - public func removeAt(index: Int) -> T { - let node = nodeAt(index: index) + public func removeAt(_ index: Int) -> T { + let node = nodeAt(index) assert(node != nil) return remove(node: node!) } @@ -211,9 +211,9 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.nodeAt(index: 0)!.value // "Hello" -list.nodeAt(index: 1)!.value // "World" -list.nodeAt(index: 2) // nil +list.nodeAt(0)!.value // "Hello" +list.nodeAt(1)!.value // "World" +list.nodeAt(2) // nil list[0] // "Hello" list[1] // "World" @@ -227,8 +227,8 @@ print(list) list.reverse() // [World, Swift, Hello] -list.nodeAt(index: 0)!.value = "Universe" -list.nodeAt(index: 1)!.value = "Swifty" +list.nodeAt(0)!.value = "Universe" +list.nodeAt(1)!.value = "Swifty" let m = list.map { s in s.characters.count } m // [8, 6, 5] let f = list.filter { s in s.characters.count > 5 } @@ -246,5 +246,5 @@ list.removeLast() // "World" list.count // 1 list[0] // "Swift" -list.removeAt(index: 0) // "Swift" +list.removeAt(0) // "Swift" list.count // 0 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 8d95c4ac1..306743354 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -3,7 +3,7 @@ Most operations on the linked list have complexity O(n). */ -public class LinkedListNode { +open class LinkedListNode { var value: T var next: LinkedListNode? weak var previous: LinkedListNode? @@ -13,20 +13,20 @@ public class LinkedListNode { } } -public class LinkedList { +open class LinkedList { public typealias Node = LinkedListNode fileprivate var head: Node? - public var isEmpty: Bool { + open var isEmpty: Bool { return head == nil } - public var first: Node? { + open var first: Node? { return head } - public var last: Node? { + open var last: Node? { if var node = head { while case let next? = node.next { node = next @@ -37,7 +37,7 @@ public class LinkedList { } } - public var count: Int { + open var count: Int { if var node = head { var c = 1 while case let next? = node.next { @@ -50,7 +50,7 @@ public class LinkedList { } } - public func nodeAt(index: Int) -> Node? { + open func nodeAt(_ index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -63,13 +63,13 @@ public class LinkedList { return nil } - public subscript(index: Int) -> T { - let node = nodeAt(index: index) + open subscript(index: Int) -> T { + let node = nodeAt(index) assert(node != nil) return node!.value } - public func append(value: T) { + open func append(_ value: T) { let newNode = Node(value: value) if let lastNode = last { newNode.previous = lastNode @@ -79,7 +79,7 @@ public class LinkedList { } } - private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { + fileprivate func nodesBeforeAndAfter(_ index: Int) -> (Node?, Node?) { assert(index >= 0) var i = index @@ -96,8 +96,8 @@ public class LinkedList { return (prev, next) } - public func insert(value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index: index) + open func insert(_ value: T, atIndex index: Int) { + let (prev, next) = nodesBeforeAndAfter(index) let newNode = Node(value: value) newNode.previous = prev @@ -110,11 +110,11 @@ public class LinkedList { } } - public func removeAll() { + open func removeAll() { head = nil } - public func remove(node: Node) -> T { + open func remove(_ node: Node) -> T { let prev = node.previous let next = node.next @@ -130,15 +130,15 @@ public class LinkedList { return node.value } - public func removeLast() -> T { + open func removeLast() -> T { assert(!isEmpty) - return remove(node: last!) + return remove(last!) } - public func removeAt(index: Int) -> T { - let node = nodeAt(index: index) + open func removeAt(_ index: Int) -> T { + let node = nodeAt(index) assert(node != nil) - return remove(node: node!) + return remove(node!) } } @@ -167,22 +167,22 @@ extension LinkedList { } extension LinkedList { - public func map(transform: (T)-> U) -> LinkedList { + public func map(_ transform: (T)-> U) -> LinkedList { let result = LinkedList() var node = head while node != nil { - result.append(value: transform(node!.value)) + result.append(transform(node!.value)) node = node!.next } return result } - public func filter(predicate: (T)-> Bool) -> LinkedList { + public func filter(_ predicate: (T)-> Bool) -> LinkedList { let result = LinkedList() var node = head while node != nil { if predicate(node!.value) { - result.append(value: node!.value) + result.append(node!.value) } node = node!.next } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 4bdc0adae..beba84299 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -3,7 +3,7 @@ import XCTest class LinkedListTest: XCTestCase { let numbers = [8, 2, 10, 9, 7, 5] - private func buildList() -> LinkedList { + fileprivate func buildList() -> LinkedList { let list = LinkedList() for number in numbers { list.append(number) @@ -88,7 +88,7 @@ class LinkedListTest: XCTestCase { func testNodeAtIndexInEmptyList() { let list = LinkedList() - let node = list.nodeAtIndex(0) + let node = list.nodeAt(0) XCTAssertNil(node) } @@ -96,7 +96,7 @@ class LinkedListTest: XCTestCase { let list = LinkedList() list.append(123) - let node = list.nodeAtIndex(0) + let node = list.nodeAt(0) XCTAssertNotNil(node) XCTAssertEqual(node!.value, 123) XCTAssertTrue(node === list.first) @@ -108,21 +108,21 @@ class LinkedListTest: XCTestCase { let nodeCount = list.count XCTAssertEqual(nodeCount, numbers.count) - XCTAssertNil(list.nodeAtIndex(-1)) - XCTAssertNil(list.nodeAtIndex(nodeCount)) + XCTAssertNil(list.nodeAt(-1)) + XCTAssertNil(list.nodeAt(nodeCount)) - let first = list.nodeAtIndex(0) + let first = list.nodeAt(0) XCTAssertNotNil(first) XCTAssertTrue(first === list.first) XCTAssertEqual(first!.value, numbers[0]) - let last = list.nodeAtIndex(nodeCount - 1) + let last = list.nodeAt(nodeCount - 1) XCTAssertNotNil(last) XCTAssertTrue(last === list.last) XCTAssertEqual(last!.value, numbers[nodeCount - 1]) for i in 0..() list.append(123) - let value = list.removeAtIndex(0) + let value = list.removeAt(0) XCTAssertEqual(value, 123) XCTAssertTrue(list.isEmpty) @@ -181,16 +181,16 @@ class LinkedListTest: XCTestCase { func testRemoveAtIndex() { let list = buildList() - let prev = list.nodeAtIndex(2) - let next = list.nodeAtIndex(3) + let prev = list.nodeAt(2) + let next = list.nodeAt(3) let nodeCount = list.count list.insert(444, atIndex: 3) - let value = list.removeAtIndex(3) + let value = list.removeAt(3) XCTAssertEqual(value, 444) - let node = list.nodeAtIndex(3) + let node = list.nodeAt(3) XCTAssertTrue(next === node) XCTAssertTrue(prev!.next === node) XCTAssertTrue(node!.previous === prev) diff --git a/Linked List/Tests/Tests.xcodeproj/project.pbxproj b/Linked List/Tests/Tests.xcodeproj/project.pbxproj index 7c6a2020a..3a29f5677 100644 --- a/Linked List/Tests/Tests.xcodeproj/project.pbxproj +++ b/Linked List/Tests/Tests.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -220,6 +221,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; }; name = Debug; }; @@ -231,6 +233,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; }; name = Release; }; From 9857da6a63ddfdc22d1246d199a1030bbdfab662 Mon Sep 17 00:00:00 2001 From: Tulio Troncoso Date: Tue, 13 Sep 2016 17:28:12 -0400 Subject: [PATCH 0124/1275] Updated README.md --- Linked List/README.markdown | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index e78735350..7b2ec0c0d 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -216,7 +216,7 @@ 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 nodeAtIndex(index: Int) -> Node? { + public func nodeAt(_ index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -235,16 +235,16 @@ The loop looks a little different but it does the same thing: it starts at `head Try it out: ```swift -list.nodeAtIndex(0)!.value // "Hello" -list.nodeAtIndex(1)!.value // "World" -list.nodeAtIndex(2) // nil +list.nodeAt(0)!.value // "Hello" +list.nodeAt(1)!.value // "World" +list.nodeAt(2) // nil ``` For fun we can implement a `subscript` method too: ```swift public subscript(index: Int) -> T { - let node = nodeAtIndex(index) + let node = nodeAt(index) assert(node != nil) return node!.value } @@ -367,7 +367,7 @@ If you had a tail pointer, you'd set it to `nil` here too. Next we'll add some functions that let you remove individual nodes. If you already have a reference to the node, then using `removeNode()` is the most optimal because you don't need to iterate through the list to find the node first. ```swift - public func removeNode(node: Node) -> T { + public func remove(node: Node) -> T { let prev = node.previous let next = node.next @@ -391,24 +391,24 @@ Don't forget the `head` pointer! If this was the first node in the list then `he Try it out: ```swift -list.removeNode(list.first!) // "Hello" +list.remove(list.first!) // "Hello" list.count // 2 list[0] // "Swift" list[1] // "World" ``` -If you don't have a reference to the node, you can use `removeLast()` or `removeAtIndex()`: +If you don't have a reference to the node, you can use `removeLast()` or `removeAt()`: ```swift public func removeLast() -> T { assert(!isEmpty) - return removeNode(last!) + return remove(node: last!) } - public func removeAtIndex(index: Int) -> T { - let node = nodeAtIndex(index) + public func removeAt(_ index: Int) -> T { + let node = nodeAt(index) assert(node != nil) - return removeNode(node!) + return remove(node: node!) } ``` @@ -419,7 +419,7 @@ list.removeLast() // "World" list.count // 1 list[0] // "Swift" -list.removeAtIndex(0) // "Swift" +list.removeAt(0) // "Swift" list.count // 0 ``` From 5fbcd67b80b1f3295456341e857660e8db160ed8 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 15 Sep 2016 18:08:04 -0700 Subject: [PATCH 0125/1275] Converted playground and fixed README for swift 3. --- .../BinaryTree.playground/Contents.swift | 18 +++++++++--------- Binary Tree/README.markdown | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index b953b6a71..b35e90c27 100644 --- a/Binary Tree/BinaryTree.playground/Contents.swift +++ b/Binary Tree/BinaryTree.playground/Contents.swift @@ -53,26 +53,26 @@ tree.count // 12 extension BinaryTree { - public func traverseInOrder(@noescape process: T -> Void) { + public func traverseInOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { - left.traverseInOrder(process) + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - public func traversePreOrder(@noescape process: T -> Void) { + public func traversePreOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { process(value) - left.traversePreOrder(process) - right.traversePreOrder(process) + left.traversePreOrder(process: process) + right.traversePreOrder(process: process) } } - public func traversePostOrder(@noescape process: T -> Void) { + public func traversePostOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index 24498b035..4b5fe7180 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -111,26 +111,26 @@ Something you often need to do with trees is traverse them, i.e. look at all the Here is how you'd implement that: ```swift - public func traverseInOrder(@noescape process: T -> Void) { + public func traverseInOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { - left.traverseInOrder(process) + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - public func traversePreOrder(@noescape process: T -> Void) { + public func traversePreOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { process(value) - left.traversePreOrder(process) - right.traversePreOrder(process) + left.traversePreOrder(process: process) + right.traversePreOrder(process: process) } } - public func traversePostOrder(@noescape process: T -> Void) { + public func traversePostOrder(process: (T) -> Void) { if case let .Node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } From 68be8b845f00c5c8eb284b46a534e448f69a630a Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 16 Sep 2016 14:08:30 +0200 Subject: [PATCH 0126/1275] rbtree implementation --- Red-Black Tree 2/RBTree.swift | Bin 0 -> 1104 bytes Red-Black Tree 2/README.markdown | 10 + .../Contents.swift | 9 + .../Sources/RBTree.swift | 486 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + 6 files changed, 516 insertions(+) create mode 100644 Red-Black Tree 2/RBTree.swift create mode 100644 Red-Black Tree 2/README.markdown create mode 100644 Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift create mode 100644 Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift create mode 100644 Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground create mode 100644 Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Red-Black Tree 2/RBTree.swift b/Red-Black Tree 2/RBTree.swift new file mode 100644 index 0000000000000000000000000000000000000000..0ed831f72932e9675aa57dc32405330ef33285a7 GIT binary patch literal 1104 zcmZ{jzi-n(6vxkL3PtLWv`CEr2@5eGR5zhc+R|2{af}3|FtiC%7stM~R-HJq9idJX z)CqN9U}QjuKY*bdv??1TBNDJNBGCbupyB(RyQD_qN#DEAd-weAr|Z7I$zTmDi2E5Z zDVL^bIzw#`<`);fw9>iV{WAG$k!BsGFbW9ErxXT@&^ zHV@gb{KlXf6Y+E^#ZECs^AL|iwAU)+K~JF<&=8cyzOq-5e8PYDIO+d6h>xe2|8D0v zkzaU{^k-it{kebqdEu+5LhJmD{u}fg8pgR?fX1PDXbGZq(%F~yce8WA9Hii0FcjNG zFq!O$69DGUfL;xnFcoy*0i0 z^jw918KOHanK!3&W7^OruT@M<*9)e0U9U`Q72PP7r)G>|si@2KKca7-@1x0{VpJ=S z{+!@@E4Ae%)3@6V-i&TLXxufI2Y2{Ze=i3(hZ5zZcbaY;*gGR)Y4nE4;>U6W)^+1n z#k|LzPKVY&HU`n(u@`%I|KL?Im;pZ%ya3)2Tm`=sTsy({!FwW}QW=ZHy$yoDig*V6 zLvR*+MdXZthXjv;bAnZHRd4|;>nn$hy_a>s7>aG=kg<;(withArray: array) +tree.insert(5) +tree.insert(8) +tree.insert(2) +tree.delete(6) +tree.delete(8) \ No newline at end of file diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift new file mode 100644 index 000000000..c5bcd0a3e --- /dev/null +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -0,0 +1,486 @@ + +private enum RBTColor { + case Red + case Black + case DoubleBlack +} + +public class RBTNode { + fileprivate var color: RBTColor = .Red + public var value: T! = nil + public var right: RBTNode! + public var left: RBTNode! + public var parent: RBTNode! + + init(tree: RBTree) { + right = tree.nullLeaf + left = tree.nullLeaf + parent = tree.nullLeaf + } + + init() { + //This method is here to support the creation of a nullLeaf + } + + public var isLeftChild: Bool { + return self.parent.left === self + } + + public var isRightChild: Bool { + return self.parent.right === self + } + + public var grandparent: RBTNode { + return parent.parent + } + + public var sibling: RBTNode! { + if isLeftChild { + return self.parent.right + } else if isRightChild { + return self.parent.left + } else { + return nil + } + } + + public var uncle: RBTNode { + return parent.sibling + } + + fileprivate var isRed: Bool { + return color == .Red + } + + fileprivate var isBlack: Bool { + return color == .Black + } + + fileprivate var isDoubleBlack: Bool { + return color == .DoubleBlack + } +} + +public class RBTree { + public var root: RBTNode + fileprivate let nullLeaf: RBTNode + + public init() { + nullLeaf = RBTNode() + nullLeaf.color = .Black + root = nullLeaf + } + + public convenience init(withValue value: T) { + self.init() + insert(value) + } + + public convenience init(withArray array: [T]) { + self.init() + insert(array) + } + + public func insert(_ value: T) { + let newNode = RBTNode(tree: self) + newNode.value = value + insertNode(n: newNode) + } + + public func insert(_ values: [T]) { + for value in values { + print(value) + insert(value) + } + } + + public func delete(_ value: T) { + let nodeToDelete = find(value) + if nodeToDelete !== nullLeaf { + deleteNode(n: nodeToDelete) + } + } + + public func find(_ value: T) -> RBTNode { + let foundNode = findNode(rootNode: root, value: value) + return foundNode + } + + public func minimum(n: RBTNode) -> RBTNode { + var min = n + if n.left !== nullLeaf { + min = minimum(n: n.left) + } + + return min + } + + public func maximum(n: RBTNode) -> RBTNode { + var max = n + if n.right !== nullLeaf { + max = maximum(n: n.right) + } + + return max + } + + public func verify() { + if self.root === nullLeaf { + print("The tree is empty") + return + } + property1() + property2(n: self.root) + property3() + } + + private func findNode(rootNode: RBTNode, value: T) -> RBTNode { + var nextNode = rootNode + if rootNode !== nullLeaf && value != rootNode.value { + if value < rootNode.value { + nextNode = findNode(rootNode: rootNode.left, value: value) + } else { + nextNode = findNode(rootNode: rootNode.right, value: value) + } + } + + return nextNode + } + + private func insertNode(n: RBTNode) { + BSTInsertNode(n: n, parent: root) + insertCase1(n: n) + } + + private func BSTInsertNode(n: RBTNode, parent: RBTNode) { + if parent === nullLeaf { + self.root = n + } else if n.value < parent.value { + if parent.left !== nullLeaf { + BSTInsertNode(n: n, parent: parent.left) + } else { + parent.left = n + parent.left.parent = parent + } + } else { + if parent.right !== nullLeaf { + BSTInsertNode(n: n, parent: parent.right) + } else { + parent.right = n + parent.right.parent = parent + } + } + } + + // if node is root change color to black, else move on + private func insertCase1(n: RBTNode) { + if n === root { + n.color = .Black + } else { + insertCase2(n: n) + } + } + + // if parent of node is not black, and node is not root move on + private func insertCase2(n: RBTNode) { + if !n.parent.isBlack { + insertCase3(n: n) + } + } + + // if uncle is red do stuff otherwise move to 4 + private func insertCase3(n: RBTNode) { + if n.uncle.isRed { // node must have grandparent as children of root have a black parent + // both parent and uncle are red, so grandparent must be black. + n.parent.color = .Black + n.uncle.color = .Black + n.grandparent.color = .Red + // now both parent and uncle are black and grandparent is red. + // we repeat for the grandparent + insertCase1(n: n.grandparent) + } else { + insertCase4(n: n) + } + } + + // parent is red, grandparent is black, uncle is black + // There are 4 cases left: + // - left left + // - left right + // - right right + // - right left + + // the cases "left right" and "right left" can be rotated into the other two + // so if either of the two is detected we apply a rotation and then move on to + // deal with the final two cases, if neither is detected we move on to those cases anyway + private func insertCase4(n: RBTNode) { + if n.parent.isLeftChild && n.isRightChild { // left right case + leftRotate(n: n.parent) + insertCase5(n: n.left) + } else if n.parent.isRightChild && n.isLeftChild { // right left case + rightRotate(n: n.parent) + insertCase5(n: n.right) + } + } + + private func insertCase5(n: RBTNode) { + // swap color of parent and grandparent + // parent is red grandparent is black + n.parent.color = .Black + n.grandparent.color = .Red + + if n.isLeftChild { // left left case + rightRotate(n: n.grandparent) + } else { // right right case + leftRotate(n: n.grandparent) + } + } + + private func deleteNode(n: RBTNode) { + var toDel = n + + if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.parent === nullLeaf { + self.root = nullLeaf + return + } + + if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.isRed { + if toDel.isLeftChild { + toDel.parent.left = nullLeaf + } else { + toDel.parent.right = nullLeaf + } + return + } + + if toDel.left !== nullLeaf && toDel.right !== nullLeaf { + let pred = maximum(n: toDel.left) + toDel.value = pred.value + toDel = pred + } + + // from here toDel has at most 1 non nullLeaf child + + var child: RBTNode + if toDel.left !== nullLeaf { + child = toDel.left + } else { + child = toDel.right + } + + if toDel.isRed || child.isRed { + child.color = .Black + + if toDel.isLeftChild { + toDel.parent.left = child + } else { + toDel.parent.right = child + } + + if child !== nullLeaf { + child.parent = toDel.parent + } + } else { // both toDel and child are black + + var sibling = toDel.sibling + + if toDel.isLeftChild { + toDel.parent.left = child + } else { + toDel.parent.right = child + } + if child !== nullLeaf { + child.parent = toDel.parent + } + child.color = .DoubleBlack + + while child.isDoubleBlack || (child.parent !== nullLeaf && child.parent != nil) { + if sibling!.isBlack { + + var leftRedChild: RBTNode! = nil + if sibling!.left.isRed { + leftRedChild = sibling!.left + } + var rightRedChild: RBTNode! = nil + if sibling!.right.isRed { + rightRedChild = sibling!.right + } + + if leftRedChild != nil || rightRedChild != nil { // at least one of sibling's children are red + child.color = .Black + if sibling!.isLeftChild { + if leftRedChild != nil { // left left case + sibling!.left.color = .Black + let tempColor = sibling!.parent.color + sibling!.parent.color = sibling!.color + sibling!.color = tempColor + rightRotate(n: sibling!.parent) + } else { // left right case + if sibling!.parent.isRed { + sibling!.parent.color = .Black + } else { + sibling!.right.color = .Black + } + leftRotate(n: sibling!) + rightRotate(n: sibling!.grandparent) + } + } else { + if rightRedChild != nil { // right right case + sibling!.right.color = .Black + let tempColor = sibling!.parent.color + sibling!.parent.color = sibling!.color + sibling!.color = tempColor + leftRotate(n: sibling!.parent) + } else { // right left case + if sibling!.parent.isRed { + sibling!.parent.color = .Black + } else { + sibling!.left.color = .Black + } + rightRotate(n: sibling!) + leftRotate(n: sibling!.grandparent) + } + } + break + } else { // both sibling's children are black + child.color = .Black + sibling!.color = .Red + if sibling!.parent.isRed { + sibling!.parent.color = .Black + break + } + sibling!.parent.color = .DoubleBlack + child = sibling!.parent + sibling = child.sibling + } + } else { // sibling is red + sibling!.color = .Black + + if sibling!.isLeftChild { // left case + rightRotate(n: sibling!.parent) + sibling = sibling!.right.left + sibling!.parent.color = .Red + } else { // right case + leftRotate(n: sibling!.parent) + sibling = sibling!.left.right + sibling!.parent.color = .Red + } + } + + // sibling check is here for when child is a nullLeaf and thus does not have a parent. + // child is here as sibling can become nil when child is the root + if (sibling != nil && sibling!.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { + child.color = .Black + } + } + } + } + + private func property1() { + + if self.root.isRed { + print("Root is not black") + } + } + + private func property2(n: RBTNode) { + if n === nullLeaf { + return + } + if n.isRed { + if n.left !== nullLeaf && n.left.isRed { + print("Red node: \(n.value), has red left child") + } else if n.right !== nullLeaf && n.right.isRed { + print("Red node: \(n.value), has red right child") + } + } + property2(n: n.left) + property2(n: n.right) + } + + private func property3() { + let bDepth = blackDepth(root: self.root) + + let leaves:[RBTNode] = getLeaves(n: self.root) + + for leaflet in leaves { + var leaf = leaflet + var i = 0 + + while leaf !== nullLeaf { + if leaf.isBlack { + i = i + 1 + } + leaf = leaf.parent + } + + if i != bDepth { + print("black depth: \(bDepth), is not equal (depth: \(i)) for leaf with value: \(leaflet.value)") + } + } + + } + + private func getLeaves(n: RBTNode) -> [RBTNode] { + var leaves = [RBTNode]() + + if n !== nullLeaf { + if n.left === nullLeaf && n.right === nullLeaf { + leaves.append(n) + } else { + let leftLeaves = getLeaves(n: n.left) + let rightLeaves = getLeaves(n: n.right) + + leaves.append(contentsOf: leftLeaves) + leaves.append(contentsOf: rightLeaves) + } + } + + return leaves + } + + private func blackDepth(root: RBTNode) -> Int { + if root === nullLeaf { + return 0 + } else { + let returnValue = root.isBlack ? 1 : 0 + return returnValue + (max(blackDepth(root: root.left), blackDepth(root: root.right))) + } + } + + private func leftRotate(n: RBTNode) { + let newRoot = n.right! + n.right = newRoot.left! + if newRoot.left !== nullLeaf { + newRoot.left.parent = n + } + newRoot.parent = n.parent + if n.parent === nullLeaf { + self.root = newRoot + } else if n.isLeftChild { + n.parent.left = newRoot + } else { + n.parent.right = newRoot + } + newRoot.left = n + n.parent = newRoot + } + + private func rightRotate(n: RBTNode) { + let newRoot = n.left! + n.left = newRoot.right! + if newRoot.right !== nullLeaf { + newRoot.right.parent = n + } + newRoot.parent = n.parent + if n.parent === nullLeaf { + self.root = newRoot + } else if n.isRightChild { + n.parent.right = newRoot + } else { + n.parent.left = newRoot + } + newRoot.right = n + n.parent = newRoot + } +} diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground b/Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata b/Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 7f94c350ab439aeeaecec3eabe365b3d127934df Mon Sep 17 00:00:00 2001 From: "Glenn R. Fisher" Date: Sat, 17 Sep 2016 11:54:48 -0500 Subject: [PATCH 0127/1275] Update hash table for Swift 3.0 --- .../HashTable.playground/Contents.swift | 115 ++----------- .../Sources/HashTable.swift | 153 +++++++++++++++++ .../HashTable.playground/timeline.xctimeline | 6 - Hash Table/HashTable.swift | 159 ------------------ Hash Table/README.markdown | 41 +++-- .../contents.xcworkspacedata | 3 - 6 files changed, 182 insertions(+), 295 deletions(-) create mode 100644 Hash Table/HashTable.playground/Sources/HashTable.swift delete mode 100644 Hash Table/HashTable.playground/timeline.xctimeline delete mode 100644 Hash Table/HashTable.swift diff --git a/Hash Table/HashTable.playground/Contents.swift b/Hash Table/HashTable.playground/Contents.swift index cda0919de..121fb6032 100644 --- a/Hash Table/HashTable.playground/Contents.swift +++ b/Hash Table/HashTable.playground/Contents.swift @@ -1,129 +1,34 @@ //: Playground - noun: a place where people can play -public struct HashTable { - private typealias Element = (key: Key, value: Value) - private typealias Bucket = [Element] - - private var buckets: [Bucket] - private(set) var count = 0 - - public init(capacity: Int) { - assert(capacity > 0) - buckets = .init(count: capacity, repeatedValue: []) - } - - public var isEmpty: Bool { - return count == 0 - } - - private func indexForKey(key: Key) -> Int { - return abs(key.hashValue) % buckets.count - } -} - -extension HashTable { - public subscript(key: Key) -> Value? { - get { - return valueForKey(key) - } - set { - if let value = newValue { - updateValue(value, forKey: key) - } else { - removeValueForKey(key) - } - } - } - - public func valueForKey(key: Key) -> Value? { - let index = indexForKey(key) - - for element in buckets[index] { - if element.key == key { - return element.value - } - } - return nil // key not in hash table - } - - public mutating func updateValue(value: Value, forKey key: Key) -> Value? { - let index = indexForKey(key) - - // Do we already have this key in the bucket? - for (i, element) in buckets[index].enumerate() { - if element.key == key { - let oldValue = element.value - buckets[index][i].value = value - return oldValue - } - } - - // This key isn't in the bucket yet; add it to the chain. - buckets[index].append((key: key, value: value)) - count += 1 - return nil - } - - public mutating func removeValueForKey(key: Key) -> Value? { - let index = indexForKey(key) - - // Find the element in the bucket's chain and remove it. - for (i, element) in buckets[index].enumerate() { - if element.key == key { - buckets[index].removeAtIndex(i) - count -= 1 - return element.value - } - } - return nil // key not in hash table - } - - public mutating func removeAll() { - buckets = .init(count: buckets.count, repeatedValue: []) - count = 0 - } -} - -extension HashTable: CustomStringConvertible { - public var description: String { - return buckets.flatMap { b in b.map { e in "\(e.key) = \(e.value)" } }.joinWithSeparator(", ") - } -} - -extension HashTable: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "" - for (i, bucket) in buckets.enumerate() { - s += "bucket \(i): " + bucket.map { e in "\(e.key) = \(e.value)" }.joinWithSeparator(", ") + "\n" - } - return s - } -} - - - // Playing with hash values + "firstName".hashValue abs("firstName".hashValue) % 5 + "lastName".hashValue abs("lastName".hashValue) % 5 + "hobbies".hashValue abs("hobbies".hashValue) % 5 - - // Playing with the hash table + var hashTable = HashTable(capacity: 5) hashTable["firstName"] = "Steve" hashTable["lastName"] = "Jobs" hashTable["hobbies"] = "Programming Swift" -hashTable.description +print(hashTable) print(hashTable.debugDescription) let x = hashTable["firstName"] hashTable["firstName"] = "Tim" + let y = hashTable["firstName"] hashTable["firstName"] = nil + let z = hashTable["firstName"] + +print(hashTable) +print(hashTable.debugDescription) diff --git a/Hash Table/HashTable.playground/Sources/HashTable.swift b/Hash Table/HashTable.playground/Sources/HashTable.swift new file mode 100644 index 000000000..947737c32 --- /dev/null +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -0,0 +1,153 @@ +/* + Hash Table: A symbol table of generic key-value pairs. + + The key must be `Hashable`, which means it can be transformed into a fairly + unique integer value. The more unique the hash value, the better. + + Hash tables use an internal array of buckets to store key-value pairs. The + hash table's capacity is determined by the number of buckets. This + implementation has a fixed capacity--it does not resize the array as more + key-value pairs are inserted. + + To insert or locate a particular key-value pair, a hash function transforms the + key into an array index. An ideal hash function would guarantee that different + keys map to different indices. In practice, however, this is difficult to + achieve. + + Since different keys can map to the same array index, all hash tables implement + a collision resolution strategy. This implementation uses a strategy called + separate chaining, where key-value pairs that hash to the same index are + "chained together" in a list. For good performance, the capacity of the hash + table should be sufficiently large so that the lists are small. + + A well-sized hash table provides very good average performance. In the + worst-case, however, all keys map to the same bucket, resulting in a list that + that requires O(n) time to traverse. + + Average Worst-Case + Space: O(n) O(n) + Search: O(1) O(n) + Insert: O(1) O(n) + Delete: O(1) O(n) + */ +public struct HashTable: CustomStringConvertible { + private typealias Element = (key: Key, value: Value) + private typealias Bucket = [Element] + private var buckets: [Bucket] + + /// The number of key-value pairs in the hash table. + private(set) public var count = 0 + + /// 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. + */ + public init(capacity: Int) { + assert(capacity > 0) + buckets = Array(repeatElement([], count: capacity)) + } + + /** + Accesses the value associated with + the given key for reading and writing. + */ + public subscript(key: Key) -> Value? { + get { + return value(forKey: key) + } + set { + if let value = newValue { + updateValue(value, forKey: key) + } else { + removeValue(forKey: key) + } + } + } + + /** + Returns the value for the given key. + */ + public func value(forKey key: Key) -> Value? { + let index = self.index(forKey: key) + for element in buckets[index] { + if element.key == key { + return element.value + } + } + return nil // key not in hash table + } + + /** + Updates the value stored in the hash table for the given key, + or adds a new key-value pair if the key does not exist. + */ + @discardableResult public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { + let index = self.index(forKey: key) + + // Do we already have this key in the bucket? + for (i, element) in buckets[index].enumerated() { + if element.key == key { + let oldValue = element.value + buckets[index][i].value = value + return oldValue + } + } + + // This key isn't in the bucket yet; add it to the chain. + buckets[index].append((key: key, value: value)) + count += 1 + return nil + } + + /** + Removes the given key and its + associated value from the hash table. + */ + @discardableResult public mutating func removeValue(forKey key: Key) -> Value? { + let index = self.index(forKey: key) + + // Find the element in the bucket's chain and remove it. + for (i, element) in buckets[index].enumerated() { + if element.key == key { + buckets[index].remove(at: i) + count -= 1 + return element.value + } + } + return nil // key not in hash table + } + + /** + Removes all key-value pairs from the hash table. + */ + public mutating func removeAll() { + buckets = Array(repeatElement([], count: buckets.count)) + count = 0 + } + + /** + Returns the given key's array index. + */ + private func index(forKey key: Key) -> Int { + return abs(key.hashValue) % buckets.count + } +} diff --git a/Hash Table/HashTable.playground/timeline.xctimeline b/Hash Table/HashTable.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Hash Table/HashTable.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Hash Table/HashTable.swift b/Hash Table/HashTable.swift deleted file mode 100644 index 46c73e284..000000000 --- a/Hash Table/HashTable.swift +++ /dev/null @@ -1,159 +0,0 @@ -/* - Hash table - - Allows you to store and retrieve objects by a "key". - - The key must be Hashable, which means it can be converted into a fairly - unique Int that represents the key as a number. The more unique the hash - value, the better. - - The hashed version of the key is used to calculate an index into the array - of "buckets". The capacity of the hash table is how many of these buckets - it has. Ideally, the number of buckets is the same as the maximum number of - items you'll be storing in the HashTable, and each hash value maps to its - own bucket. In practice that is hard to achieve. - - When there is more than one hash value that maps to the same bucket index - -- a "collision" -- they are chained together, using an array. (Note that - more clever ways exist for dealing with the chaining issue.) - - While there are free buckets, inserting/retrieving/removing are O(1). - But when the buckets are full and the chains are long, using the hash table - becomes an O(n) operation. - - Counting the size of the hash table is O(1) because we're caching the count. - - The order of the elements in the hash table is undefined. - - This implementation has a fixed capacity; it does not resize when the table - gets too full. (To do that, you'd allocate a larger array of buckets and then - insert each of the elements into that new array; this is necessary because - the hash values will now map to different bucket indexes.) -*/ -public struct HashTable { - private typealias Element = (key: Key, value: Value) - private typealias Bucket = [Element] - - private var buckets: [Bucket] - private(set) var count = 0 - - public init(capacity: Int) { - assert(capacity > 0) - buckets = .init(count: capacity, repeatedValue: []) - } - - public var isEmpty: Bool { - return count == 0 - } - - private func indexForKey(key: Key) -> Int { - return abs(key.hashValue) % buckets.count - } -} - -// MARK: - Basic operations - -extension HashTable { - public subscript(key: Key) -> Value? { - get { - return valueForKey(key) - } - set { - if let value = newValue { - updateValue(value, forKey: key) - } else { - removeValueForKey(key) - } - } - } - - public func valueForKey(key: Key) -> Value? { - let index = indexForKey(key) - - for element in buckets[index] { - if element.key == key { - return element.value - } - } - return nil // key not in hash table - } - - public mutating func updateValue(value: Value, forKey key: Key) -> Value? { - let index = indexForKey(key) - - // Do we already have this key in the bucket? - for (i, element) in buckets[index].enumerate() { - if element.key == key { - let oldValue = element.value - buckets[index][i].value = value - return oldValue - } - } - - // This key isn't in the bucket yet; add it to the chain. - buckets[index].append((key: key, value: value)) - count += 1 - return nil - } - - public mutating func removeValueForKey(key: Key) -> Value? { - let index = indexForKey(key) - - // Find the element in the bucket's chain and remove it. - for (i, element) in buckets[index].enumerate() { - if element.key == key { - buckets[index].removeAtIndex(i) - count -= 1 - return element.value - } - } - return nil // key not in hash table - } - - public mutating func removeAll() { - buckets = .init(count: buckets.count, repeatedValue: []) - count = 0 - } -} - -// MARK: - Helper methods for inspecting the hash table - -extension HashTable { - public var keys: [Key] { - var a = [Key]() - for bucket in buckets { - for element in bucket { - a.append(element.key) - } - } - return a - } - - public var values: [Value] { - var a = [Value]() - for bucket in buckets { - for element in bucket { - a.append(element.value) - } - } - return a - } -} - -// MARK: - For debugging - -extension HashTable: CustomStringConvertible { - public var description: String { - return buckets.flatMap { b in b.map { e in "\(e.key) = \(e.value)" } }.joinWithSeparator(", ") - } -} - -extension HashTable: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "" - for (i, bucket) in buckets.enumerate() { - s += "bucket \(i): " + bucket.map { e in "\(e.key) = \(e.value)" }.joinWithSeparator(", ") + "\n" - } - return s - } -} diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index 02a2c9578..4399b0f86 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -115,17 +115,15 @@ Let's look at a basic implementation of a hash table in Swift. We'll build it up public struct HashTable { private typealias Element = (key: Key, value: Value) private typealias Bucket = [Element] - private var buckets: [Bucket] - private(set) var count = 0 + + private(set) public var count = 0 + public var isEmpty: Bool { return count == 0 } + public init(capacity: Int) { assert(capacity > 0) - buckets = .init(count: capacity, repeatedValue: []) - } - - public var isEmpty: Bool { - return count == 0 + buckets = Array(repeatElement([], count: capacity)) } ``` @@ -142,7 +140,7 @@ var hashTable = HashTable(capacity: 5) Currently the hash table doesn't do anything yet, so let's add the remaining functionality. First, add a helper method that calculates the array index for a given key: ```swift - private func indexForKey(key: Key) -> Int { + private func index(forKey key: Key) -> Int { return abs(key.hashValue) % buckets.count } ``` @@ -170,24 +168,23 @@ We can do all these things with a `subscript` function: ```swift public subscript(key: Key) -> Value? { get { - return valueForKey(key) + return value(forKey: key) } set { if let value = newValue { updateValue(value, forKey: key) } else { - removeValueForKey(key) + removeValue(forKey: key) } } } ``` -This calls three helper functions to do the actual work. Let's take a look at `valueForKey()` first, which retrieves an object from the hash table. +This calls three helper functions to do the actual work. Let's take a look at `value(forKey:)` first, which retrieves an object from the hash table. ```swift - public func valueForKey(key: Key) -> Value? { - let index = indexForKey(key) - + public func value(forKey key: Key) -> Value? { + let index = self.index(forKey: key) for element in buckets[index] { if element.key == key { return element.value @@ -197,13 +194,13 @@ This calls three helper functions to do the actual work. Let's take a look at `v } ``` -First it calls `indexForKey()` to convert the key into an array index. That gives us the bucket number, but if there were collisions this bucket may be used by more than one key. So `valueForKey()` loops through the chain from that bucket and compares the keys one-by-one. If found, it returns the corresponding value, otherwise it returns `nil`. +First it calls `index(forKey:)` to convert the key into an array index. That gives us the bucket number, but if there were collisions this bucket may be used by more than one key. So `value(forKey:)` loops through the chain from that bucket and compares the keys one-by-one. If found, it returns the corresponding value, otherwise it returns `nil`. -The code to insert a new element or update an existing element lives in `updateValue(forKey)`. It's a little bit more complicated: +The code to insert a new element or update an existing element lives in `updateValue(_:forKey:)`. It's a little bit more complicated: ```swift - public mutating func updateValue(value: Value, forKey key: Key) -> Value? { - let index = indexForKey(key) + public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { + let index = self.index(forKey: key) // Do we already have this key in the bucket? for (i, element) in buckets[index].enumerate() { @@ -228,13 +225,13 @@ As you can see, it's important that chains are kept short (by making the hash ta Removing is similar in that again it loops through the chain: ```swift - public mutating func removeValueForKey(key: Key) -> Value? { - let index = indexForKey(key) + public mutating func removeValue(forKey key: Key) -> Value? { + let index = self.index(forKey: key) // Find the element in the bucket's chain and remove it. - for (i, element) in buckets[index].enumerate() { + for (i, element) in buckets[index].enumerated() { if element.key == key { - buckets[index].removeAtIndex(i) + buckets[index].remove(at: i) count -= 1 return element.value } diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4e0f19dc2..e7288f299 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -868,9 +868,6 @@ - - From 8aeacb054d85a3024675fb0985e369a1e01add86 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Sat, 17 Sep 2016 23:55:39 +0200 Subject: [PATCH 0128/1275] New style / Broken down into extensions --- Skip-List/SkipList.swift | 409 +++++++++++++++++++++------------------ 1 file changed, 218 insertions(+), 191 deletions(-) diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index b07cd98c8..31b4e9144 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -26,241 +26,268 @@ import Foundation // Stack from : https://github.com/raywenderlich/swift-algorithm-club/tree/master/Stack public struct Stack { - private var array = [T]() + fileprivate var array = [T]() - public var isEmpty: Bool { - return array.isEmpty - } + public var isEmpty: Bool { + return array.isEmpty + } - public var count: Int { - return array.count - } + public var count: Int { + return array.count + } - public mutating func push(element: T) { - array.append(element) - } + public mutating func push(_ element: T) { + array.append(element) + } - public mutating func pop() -> T? { - return array.popLast() - } + public mutating func pop() -> T? { + return array.popLast() + } - public func peek() -> T? { - return array.last - } + public func peek() -> T? { + return array.last + } } -extension Stack: SequenceType { - public func generate() -> AnyGenerator { - var curr = self - return AnyGenerator { - _ -> T? in - return curr.pop() - } - } +extension Stack: Sequence { + public func makeIterator() -> AnyIterator { + var curr = self + return AnyIterator { + _ -> T? in + return curr.pop() + } + } } -func random() -> Bool { - #if os(Linux) - return random() % 2 == 0 - #elseif os(OSX) - return arc4random_uniform(2) == 1 - #endif +private func coinFlip() -> Bool { + #if os(Linux) + return random() % 2 == 0 + #elseif os(OSX) + return arc4random_uniform(2) == 1 + #endif } +// MARK: - Node + +public class DataNode { + public typealias Node = DataNode + + var data : Payload? + fileprivate var key : Key? + internal var next : Node? + internal var down : Node? + + public init(key: Key, data: Payload) { + self.key = key + self.data = data + } + + public init(asHead head: Bool){ + } + +} -class DataNode{ - internal typealias Node = DataNode - - internal var key : Key? - internal var data : Payload? - internal var _next : Node? - internal var _down : Node? - - internal var next: Node? { - get { return self._next } - set(value) { self._next = value } - } - internal var down:Node? { - get { return self._down } - set(value) { self._down = value } - } - - init(key:Key, data:Payload){ - self.key = key - self.data = data - } +// MARK: - Skip List - init(header: Bool){ - } - +open class SkipList { + public typealias Node = DataNode + + fileprivate(set) var head: Node? + + public init() { } + } -class SkipList{ - internal typealias Node = DataNode - internal var head: Node? - - private func find_head(key:Key) -> Node? { - var current = self.head - var found: Bool = false - - while !found { - if let curr = current { - if curr.next == nil { current = curr.down } - else { - if curr.next!.key == key { found = true } - else { - if key < curr.next!.key{ current = curr.down } - else { current = curr.next } - } - } + +// MARK: - Searching + +extension SkipList { + + internal func findNode(key: Key) -> Node? { + var currentNode : Node? = self.head + var isFound : Bool = false + + while !isFound { + if let node = currentNode { + + switch node.next { + case .none: + + currentNode = node.down + case .some(let value) where value.key != nil: + + if value.key == key { + isFound = true + break + } + else { + if key < value.key! { + currentNode = node.down } else { - break - } + currentNode = node.next + } + } + + default: + continue } + + } else { + break + } + } - if found { - return current - } else { - return nil - } + if isFound { + return currentNode + } else { + return nil } + } - private func insert_head(key:Key, data:Payload) -> Void { - - self.head = Node(header: true) - var temp = Node(key:key, data:data) - self.head!.next = temp - var top = temp - - while random() { - let newhead = Node(header: true) - temp = Node(key:key, data:data) - temp.down = top - newhead.next = temp - newhead.down = self.head - self.head = newhead - top = temp - } + internal func search(key: Key) -> Payload? { + guard let node = self.findNode(key: key) else { + return nil } - private func insert_rest(key:Key, data:Payload) -> Void { - var stack = Stack() - var current_head: Node? = self.head + return node.next!.data + } + +} + - while current_head != nil { - if let next = current_head!._next { - if next.key > key { - stack.push(current_head!) - current_head = next - } else { - current_head = next - } - - } else { - stack.push(current_head!) - current_head = current_head!.down - } - - } - - let lowest = stack.pop() - var temp = Node(key:key, data:data) - temp.next = lowest!.next - lowest!.next = temp - var top = temp - - while random() { - if stack.isEmpty { - let newhead = Node(header: true) - temp = Node(key:key, data:data) - temp.down = top - newhead.next = temp - newhead.down = self.head - self.head = newhead - top = temp - } else { - let next = stack.pop() - temp = Node(key:key, data:data) - temp.down = top - temp.next = next!.next - next!.next = temp - top = temp - } - } - } - - func search(key:Key) -> Payload? { - guard let item = self.find_head(key) else { - return nil - } +// MARK: - Inserting + +extension SkipList { + private func bootstrapBaseLayer(key: Key, data: Payload) -> Void { + self.head = Node(asHead: true) + var node = Node(key: key, data: data) - return item.next!.data + self.head!.next = node + + var currentTopNode = node + + while coinFlip() { + let newHead = Node(asHead: true) + node = Node(key: key, data: data) + node.down = currentTopNode + newHead.next = node + newHead.down = self.head + self.head = newHead + currentTopNode = node } - func remove(key:Key) -> Void { - guard let item = self.find_head(key) else { - return + } + + + private func insertItem(key: Key, data: Payload) -> Void { + var stack = Stack() + var currentNode: Node? = self.head + + while currentNode != nil { + + if let nextNode = currentNode!.next { + if nextNode.key! > key { + stack.push(currentNode!) + currentNode = currentNode!.down + } else { + currentNode = nextNode } - var curr = Optional(item) + } else { + stack.push(currentNode!) + currentNode = currentNode!.down + } + + } + + let itemAtLayer = stack.pop() + var node = Node(key: key, data: data) + node.next = itemAtLayer!.next + itemAtLayer!.next = node + var currentTopNode = node + + while coinFlip() { + if stack.isEmpty { + let newHead = Node(asHead: true) - while curr != nil { - let node = curr!.next - - if node!.key != key { curr = node ; continue } - - let node_next = node!.next - curr!.next = node_next - curr = curr!.down - - } + node = Node(key: key, data: data) + node.down = currentTopNode + newHead.next = node + newHead.down = self.head + self.head = newHead + currentTopNode = node - } - - func insert(key: Key, data:Payload){ - if self.head != nil{ - if let node = self.find_head(key) { - - var curr = node.next - while curr != nil && curr!.key == key{ - curr!.data = data - curr = curr!.down - } - - } else { - self.insert_rest(key, data:data) - } - - } else { - self.insert_head(key, data:data) + } else { + let nextNode = stack.pop() + + node = Node(key: key, data: data) + node.down = currentTopNode + node.next = nextNode!.next + nextNode!.next = node + currentTopNode = node + } + } + } + + + internal func insert(key: Key, data: Payload) { + if self.head != nil { + if let node = self.findNode(key: key) { + // replace in case key already exists + var currentNode = node.next + while currentNode != nil && currentNode!.key == key { + currentNode!.data = data + currentNode = currentNode!.down } + } else { + self.insertItem(key: key, data: data) + } + + } else { + self.bootstrapBaseLayer(key: key, data: data) } - + } + } -class Map{ - var collection: SkipList +// MARK: - Removing - init(){ - self.collection = SkipList() +extension SkipList { + public func remove(key: Key) -> Void { + guard let item = self.findNode(key: key) else { + return } - func insert(key:Key, data: Payload){ - self.collection.insert(key, data:data) - } - - func get(key:Key) -> Payload?{ - return self.collection.search(key) - } + var currentNode = Optional(item) - func remove(key:Key) -> Void { - return self.collection.remove(key) + while currentNode != nil { + let node = currentNode!.next + + if node!.key != key { + currentNode = node + continue + } + + let nextNode = node!.next + + currentNode!.next = nextNode + currentNode = currentNode!.down + } + + } +} + +extension SkipList { + + public func get(key:Key) -> Payload?{ + return self.search(key: key) + } } From e9ce16b8e3328671537daf3c93e7510fb56458ab Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 17 Sep 2016 18:00:29 -0700 Subject: [PATCH 0129/1275] Fixes syntax in playground for Swift3. --- Quicksort/Quicksort.playground/Contents.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Quicksort/Quicksort.playground/Contents.swift b/Quicksort/Quicksort.playground/Contents.swift index 0894ae61b..da02b69ce 100644 --- a/Quicksort/Quicksort.playground/Contents.swift +++ b/Quicksort/Quicksort.playground/Contents.swift @@ -5,7 +5,7 @@ import Foundation // *** Simple but inefficient version of quicksort *** -func quicksort(a: [T]) -> [T] { +func quicksort(_ a: [T]) -> [T] { guard a.count > 1 else { return a } let pivot = a[a.count/2] @@ -34,7 +34,7 @@ quicksort(list1) partition is [low...p-1]; the right partition is [p+1...high], where p is the return value. */ -func partitionLomuto(inout a: [T], low: Int, high: Int) -> Int { +func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[high] var i = low @@ -53,7 +53,7 @@ var list2 = [ 10, 0, 3, 9, 2, 14, 26, 27, 1, 5, 8, -1, 8 ] partitionLomuto(&list2, low: 0, high: list2.count - 1) list2 -func quicksortLomuto(inout a: [T], low: Int, high: Int) { +func quicksortLomuto(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionLomuto(&a, low: low, high: high) quicksortLomuto(&a, low: low, high: p - 1) @@ -75,7 +75,7 @@ quicksortLomuto(&list2, low: 0, high: list2.count - 1) where p is the return value. The pivot value is placed somewhere inside one of the two partitions, but the algorithm doesn't tell you which one or where. */ -func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { +func partitionHoare(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[low] var i = low - 1 var j = high + 1 @@ -96,7 +96,7 @@ var list3 = [ 8, 0, 3, 9, 2, 14, 10, 27, 1, 5, 8, -1, 26 ] partitionHoare(&list3, low: 0, high: list3.count - 1) list3 -func quicksortHoare(inout a: [T], low: Int, high: Int) { +func quicksortHoare(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionHoare(&a, low: low, high: high) quicksortHoare(&a, low: low, high: p) @@ -111,12 +111,12 @@ quicksortHoare(&list3, low: 0, high: list3.count - 1) // *** Randomized sorting *** /* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { +public func random(min: Int, max: Int) -> Int { assert(min < max) return min + Int(arc4random_uniform(UInt32(max - min + 1))) } -func quicksortRandom(inout a: [T], low: Int, high: Int) { +func quicksortRandom(_ a: inout [T], low: Int, high: Int) { if low < high { let pivotIndex = random(min: low, max: high) (a[pivotIndex], a[high]) = (a[high], a[pivotIndex]) @@ -139,7 +139,7 @@ list4 Swift's swap() doesn't like it if the items you're trying to swap refer to the same memory location. This little wrapper simply ignores such swaps. */ -public func swap(inout a: [T], _ i: Int, _ j: Int) { +public func swap(_ a: inout [T], _ i: Int, _ j: Int) { if i != j { swap(&a[i], &a[j]) } @@ -149,7 +149,7 @@ public func swap(inout a: [T], _ i: Int, _ j: Int) { Dutch national flag partitioning. Returns a tuple with the start and end index of the middle area. */ -func partitionDutchFlag(inout a: [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { +func partitionDutchFlag(_ a: inout [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { let pivot = a[pivotIndex] var smaller = low @@ -175,7 +175,7 @@ var list5 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] partitionDutchFlag(&list5, low: 0, high: list5.count - 1, pivotIndex: 10) list5 -func quicksortDutchFlag(inout a: [T], low: Int, high: Int) { +func quicksortDutchFlag(_ a: inout [T], low: Int, high: Int) { if low < high { let pivotIndex = random(min: low, max: high) let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex) From 35cca84d481a6b20dacbc196b68e0db0d7925594 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 17 Sep 2016 18:04:17 -0700 Subject: [PATCH 0130/1275] Changed README to reflect Swift 3 migration. --- Quicksort/README.markdown | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Quicksort/README.markdown b/Quicksort/README.markdown index 936f9f44c..e3d284333 100644 --- a/Quicksort/README.markdown +++ b/Quicksort/README.markdown @@ -7,7 +7,7 @@ Quicksort is one of the most famous algorithms in history. It was invented way b Here's an implementation in Swift that should be easy to understand: ```swift -func quicksort(a: [T]) -> [T] { +func quicksort(_ a: [T]) -> [T] { guard a.count > 1 else { return a } let pivot = a[a.count/2] @@ -131,7 +131,7 @@ In the first example of quicksort I showed you, partitioning was done by calling Here's an implementation of Lomuto's partitioning scheme in Swift: ```swift -func partitionLomuto(inout a: [T], low: Int, high: Int) -> Int { +func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[high] var i = low @@ -250,7 +250,7 @@ And we return `i`, the index of the pivot element. Let's use this partitioning scheme to build quicksort. Here's the code: ```swift -func quicksortLomuto(inout a: [T], low: Int, high: Int) { +func quicksortLomuto(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionLomuto(&a, low: low, high: high) quicksortLomuto(&a, low: low, high: p - 1) @@ -277,7 +277,7 @@ This partitioning scheme is by Hoare, the inventor of quicksort. Here is the code: ```Swift -func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { +func partitionHoare(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[low] var i = low - 1 var j = high + 1 @@ -318,7 +318,7 @@ The pivot is placed somewhere inside one of the two partitions, but the algorith Because of these differences, the implementation of Hoare's quicksort is slightly different: ```swift -func quicksortHoare(inout a: [T], low: Int, high: Int) { +func quicksortHoare(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionHoare(&a, low: low, high: high) quicksortHoare(&a, low: low, high: p) @@ -380,7 +380,7 @@ Another common solution is to choose the pivot randomly. Sometimes this may resu Here is how you can do quicksort with a randomly chosen pivot: ```swift -func quicksortRandom(inout a: [T], low: Int, high: Int) { +func quicksortRandom(_ a: inout [T], low: Int, high: Int) { if low < high { let pivotIndex = random(min: low, max: high) // 1 @@ -412,7 +412,7 @@ But as you've seen with the Lomuto partitioning scheme, if the pivot occurs more The code for this scheme is: ```swift -func partitionDutchFlag(inout a: [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { +func partitionDutchFlag(_ a: inout [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { let pivot = a[pivotIndex] var smaller = low @@ -461,7 +461,7 @@ Notice how the two `8`s are in the middle now. The return value from `partitionD Here is how you would use it in quicksort: ```swift -func quicksortDutchFlag(inout a: [T], low: Int, high: Int) { +func quicksortDutchFlag(_ a: inout [T], low: Int, high: Int) { if low < high { let pivotIndex = random(min: low, max: high) let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex) From 6f14d9e9c739769b9b756c8d0fbd6ba81031e4c7 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 17 Sep 2016 18:11:28 -0700 Subject: [PATCH 0131/1275] Revised playground code to compile in Swift3. --- .../Sources/BoundedPriorityQueue.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift index 58dc5034e..fc399811d 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift @@ -12,7 +12,7 @@ public class BoundedPriorityQueue { private typealias Node = LinkedListNode private(set) public var count = 0 - private var head: Node? + fileprivate var head: Node? private var tail: Node? private var maxElements: Int @@ -28,7 +28,7 @@ public class BoundedPriorityQueue { return head?.value } - public func enqueue(value: T) { + public func enqueue(_ value: T) { if let node = insert(value, after: findInsertionPoint(value)) { // If the newly inserted node is the last one in the list, then update // the tail pointer. @@ -44,7 +44,7 @@ public class BoundedPriorityQueue { } } - private func insert(value: T, after: Node?) -> Node? { + private func insert(_ value: T, after: Node?) -> Node? { if let previous = after { // If the queue is full and we have to insert at the end of the list, @@ -78,11 +78,11 @@ public class BoundedPriorityQueue { /* Find the node after which to insert the new value. If this returns nil, the new value should be inserted at the head of the list. */ - private func findInsertionPoint(value: T) -> Node? { + private func findInsertionPoint(_ value: T) -> Node? { var node = head var prev: Node? = nil - while let current = node where value < current.value { + while let current = node, value < current.value { prev = node node = current.next } From 6e2f5c199b67469988b452a3266aa1b9ab26da34 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 17 Sep 2016 18:13:20 -0700 Subject: [PATCH 0132/1275] Fixes README file for Swift3. --- Bounded Priority Queue/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Bounded Priority Queue/README.markdown b/Bounded Priority Queue/README.markdown index 8d6ea1804..8d47adefb 100644 --- a/Bounded Priority Queue/README.markdown +++ b/Bounded Priority Queue/README.markdown @@ -35,7 +35,7 @@ public class BoundedPriorityQueue { private typealias Node = LinkedListNode private(set) public var count = 0 - private var head: Node? + fileprivate var head: Node? private var tail: Node? private var maxElements: Int @@ -55,7 +55,7 @@ public class BoundedPriorityQueue { The `BoundedPriorityQueue` class contains a doubly linked list of `LinkedListNode` objects. Nothing special here yet. The fun stuff happens in the `enqueue()` method: ```swift -public func enqueue(value: T) { +public func enqueue(_ value: T) { if let node = insert(value, after: findInsertionPoint(value)) { // If the newly inserted node is the last one in the list, then update // the tail pointer. @@ -71,7 +71,7 @@ public func enqueue(value: T) { } } -private func insert(value: T, after: Node?) -> Node? { +private func insert(_ value: T, after: Node?) -> Node? { if let previous = after { // If the queue is full and we have to insert at the end of the list, @@ -105,7 +105,7 @@ private func insert(value: T, after: Node?) -> Node? { /* Find the node after which to insert the new value. If this returns nil, the new value should be inserted at the head of the list. */ -private func findInsertionPoint(value: T) -> Node? { +private func findInsertionPoint(_ value: T) -> Node? { var node = head var prev: Node? = nil From 562c85c1b0d717c73e4a04d1a0913a5e83732cea Mon Sep 17 00:00:00 2001 From: FarzadShbfn Date: Sun, 18 Sep 2016 15:34:10 +0430 Subject: [PATCH 0133/1275] Upgrade to Swift3 --- GCD/GCD.playground/Contents.swift | 4 ++-- GCD/GCD.swift | 6 +++--- GCD/README.markdown | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index dedf6e293..2e264be93 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,7 +1,7 @@ //: Playground - noun: a place where people can play // Recursive version -func gcd(a: Int, _ b: Int) -> Int { +func gcd(_ a: Int, _ b: Int) -> Int { let r = a % b if r != 0 { return gcd(b, r) @@ -26,7 +26,7 @@ func gcd(m: Int, _ n: Int) -> Int { } */ -func lcm(m: Int, _ n: Int) -> Int { +func lcm(_ m: Int, _ n: Int) -> Int { return m*n / gcd(m, n) } diff --git a/GCD/GCD.swift b/GCD/GCD.swift index dc473ccd4..ce7e7fa78 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.swift @@ -1,7 +1,7 @@ /* Euclid's algorithm for finding the greatest common divisor */ -func gcd(m: Int, _ n: Int) -> Int { +func gcd(_ m: Int, _ n: Int) -> Int { var a = 0 var b = max(m, n) var r = min(m, n) @@ -16,7 +16,7 @@ func gcd(m: Int, _ n: Int) -> Int { /* // Recursive version -func gcd(a: Int, _ b: Int) -> Int { +func gcd(_ a: Int, _ b: Int) -> Int { let r = a % b if r != 0 { return gcd(b, r) @@ -29,6 +29,6 @@ func gcd(a: Int, _ b: Int) -> Int { /* Returns the least common multiple of two numbers. */ -func lcm(m: Int, _ n: Int) -> Int { +func lcm(_ m: Int, _ n: Int) -> Int { return m*n / gcd(m, n) } diff --git a/GCD/README.markdown b/GCD/README.markdown index 1d20fb9cb..07d2de1ca 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -17,7 +17,7 @@ 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 { +func gcd(_ a: Int, _ b: Int) -> Int { let r = a % b if r != 0 { return gcd(b, r) @@ -68,7 +68,7 @@ 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 { +func gcd(_ m: Int, _ n: Int) -> Int { var a = 0 var b = max(m, n) var r = min(m, n) @@ -101,7 +101,7 @@ We can calculate the LCM using Euclid's algorithm too: In code: ```swift -func lcm(m: Int, _ n: Int) -> Int { +func lcm(_ m: Int, _ n: Int) -> Int { return m*n / gcd(m, n) } ``` From ab02cf521de7eca87ff67f5001b0f546844d5593 Mon Sep 17 00:00:00 2001 From: FarzadShbfn Date: Sun, 18 Sep 2016 15:54:01 +0430 Subject: [PATCH 0134/1275] Update to Swift3 --- .../SegmentTree.playground/Contents.swift | 192 +++++++++--------- .../contents.xcplayground | 2 +- .../timeline.xctimeline | 6 - Segment Tree/SegmentTree.swift | 116 +++++------ 4 files changed, 155 insertions(+), 161 deletions(-) delete mode 100644 Segment Tree/SegmentTree.playground/timeline.xctimeline diff --git a/Segment Tree/SegmentTree.playground/Contents.swift b/Segment Tree/SegmentTree.playground/Contents.swift index 14b7f57cf..6b33b2f44 100644 --- a/Segment Tree/SegmentTree.playground/Contents.swift +++ b/Segment Tree/SegmentTree.playground/Contents.swift @@ -1,64 +1,64 @@ //: Playground - noun: a place where people can play public class SegmentTree { - - private var value: T - private var function: (T, T) -> T - private var leftBound: Int - private var rightBound: Int - private var leftChild: SegmentTree? - private var rightChild: SegmentTree? - - public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) { - self.leftBound = leftBound - self.rightBound = rightBound - self.function = function - - if leftBound == rightBound { - value = array[leftBound] - } else { - let middle = (leftBound + rightBound) / 2 - leftChild = SegmentTree(array: array, leftBound: leftBound, rightBound: middle, function: function) - rightChild = SegmentTree(array: array, leftBound: middle+1, rightBound: rightBound, function: function) - value = function(leftChild!.value, rightChild!.value) - } - } - - public convenience init(array: [T], function: (T, T) -> T) { - self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) - } - - public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T { - if self.leftBound == leftBound && self.rightBound == rightBound { - return self.value - } - - guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } - guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } - - if leftChild.rightBound < leftBound { - return rightChild.queryWithLeftBound(leftBound, rightBound: rightBound) - } else if rightChild.leftBound > rightBound { - return leftChild.queryWithLeftBound(leftBound, rightBound: rightBound) - } else { - let leftResult = leftChild.queryWithLeftBound(leftBound, rightBound: leftChild.rightBound) - let rightResult = rightChild.queryWithLeftBound(rightChild.leftBound, rightBound: rightBound) - return function(leftResult, rightResult) - } - } - - public func replaceItemAtIndex(index: Int, withItem item: T) { - if leftBound == rightBound { - value = item - } else if let leftChild = leftChild, rightChild = rightChild { - if leftChild.rightBound >= index { - leftChild.replaceItemAtIndex(index, withItem: item) - } else { - rightChild.replaceItemAtIndex(index, withItem: item) - } - value = function(leftChild.value, rightChild.value) - } - } + + private var value: T + private var function: (T, T) -> T + private var leftBound: Int + private var rightBound: Int + private var leftChild: SegmentTree? + private var rightChild: SegmentTree? + + public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) { + self.leftBound = leftBound + self.rightBound = rightBound + self.function = function + + if leftBound == rightBound { + value = array[leftBound] + } else { + let middle = (leftBound + rightBound) / 2 + leftChild = SegmentTree(array: array, leftBound: leftBound, rightBound: middle, function: function) + rightChild = SegmentTree(array: array, leftBound: middle+1, rightBound: rightBound, function: function) + value = function(leftChild!.value, rightChild!.value) + } + } + + public convenience init(array: [T], function: @escaping (T, T) -> T) { + self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) + } + + public func query(withLeftBound: Int, rightBound: Int) -> T { + if self.leftBound == leftBound && self.rightBound == rightBound { + return self.value + } + + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + if leftChild.rightBound < leftBound { + return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) + } else if rightChild.leftBound > rightBound { + return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) + } else { + let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(withLeftBound:rightChild.leftBound, rightBound: rightBound) + return function(leftResult, rightResult) + } + } + + public func replaceItem(at index: Int, withItem item: T) { + if leftBound == rightBound { + value = item + } else if let leftChild = leftChild, let rightChild = rightChild { + if leftChild.rightBound >= index { + leftChild.replaceItem(at: index, withItem: item) + } else { + rightChild.replaceItem(at: index, withItem: item) + } + value = function(leftChild.value, rightChild.value) + } + } } @@ -68,42 +68,42 @@ let array = [1, 2, 3, 4] let sumSegmentTree = SegmentTree(array: array, function: +) -print(sumSegmentTree.queryWithLeftBound(0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10 -print(sumSegmentTree.queryWithLeftBound(1, rightBound: 2)) // 2 + 3 = 5 -print(sumSegmentTree.queryWithLeftBound(0, rightBound: 0)) // 1 = 1 +print(sumSegmentTree.query(withLeftBound: 0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10 +print(sumSegmentTree.query(withLeftBound: 1, rightBound: 2)) // 2 + 3 = 5 +print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 1 = 1 -sumSegmentTree.replaceItemAtIndex(0, withItem: 2) //our array now is [2, 2, 3, 4] +sumSegmentTree.replaceItem(at: 0, withItem: 2) //our array now is [2, 2, 3, 4] -print(sumSegmentTree.queryWithLeftBound(0, rightBound: 0)) // 2 = 2 -print(sumSegmentTree.queryWithLeftBound(0, rightBound: 1)) // 2 + 2 = 4 +print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 2 = 2 +print(sumSegmentTree.query(withLeftBound: 0, rightBound: 1)) // 2 + 2 = 4 //you can use any associative function (i.e (a+b)+c == a+(b+c)) as function for segment tree -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 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 gcdArray = [2, 4, 6, 3, 5] let gcdSegmentTree = SegmentTree(array: gcdArray, function: gcd) -print(gcdSegmentTree.queryWithLeftBound(0, rightBound: 1)) // gcd(2, 4) = 2 -print(gcdSegmentTree.queryWithLeftBound(2, rightBound: 3)) // gcd(6, 3) = 3 -print(gcdSegmentTree.queryWithLeftBound(1, rightBound: 3)) // gcd(4, 6, 3) = 1 -print(gcdSegmentTree.queryWithLeftBound(0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1 +print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 1)) // gcd(2, 4) = 2 +print(gcdSegmentTree.query(withLeftBound: 2, rightBound: 3)) // gcd(6, 3) = 3 +print(gcdSegmentTree.query(withLeftBound: 1, rightBound: 3)) // gcd(4, 6, 3) = 1 +print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1 -gcdSegmentTree.replaceItemAtIndex(3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5] +gcdSegmentTree.replaceItem(at: 3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5] -print(gcdSegmentTree.queryWithLeftBound(3, rightBound: 4)) // gcd(10, 5) = 5 +print(gcdSegmentTree.query(withLeftBound: 3, rightBound: 4)) // gcd(10, 5) = 5 //example of segment tree which finds minimum on given range @@ -111,12 +111,12 @@ let minArray = [2, 4, 1, 5, 3] let minSegmentTree = SegmentTree(array: minArray, function: min) -print(minSegmentTree.queryWithLeftBound(0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1 -print(minSegmentTree.queryWithLeftBound(0, rightBound: 1)) // min(2, 4) = 2 +print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1 +print(minSegmentTree.query(withLeftBound: 0, rightBound: 1)) // min(2, 4) = 2 -minSegmentTree.replaceItemAtIndex(2, withItem: 10) // minArray now is [2, 4, 10, 5, 3] +minSegmentTree.replaceItem(at: 2, withItem: 10) // minArray now is [2, 4, 10, 5, 3] -print(minSegmentTree.queryWithLeftBound(0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2 +print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2 //type of elements in array can be any type which has some associative function @@ -124,16 +124,16 @@ let stringArray = ["a", "b", "c", "A", "B", "C"] let stringSegmentTree = SegmentTree(array: stringArray, function: +) -print(stringSegmentTree.queryWithLeftBound(0, rightBound: 1)) // "a"+"b" = "ab" -print(stringSegmentTree.queryWithLeftBound(2, rightBound: 3)) // "c"+"A" = "cA" -print(stringSegmentTree.queryWithLeftBound(1, rightBound: 3)) // "b"+"c"+"A" = "bcA" -print(stringSegmentTree.queryWithLeftBound(0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC" +print(stringSegmentTree.query(withLeftBound: 0, rightBound: 1)) // "a"+"b" = "ab" +print(stringSegmentTree.query(withLeftBound: 2, rightBound: 3)) // "c"+"A" = "cA" +print(stringSegmentTree.query(withLeftBound: 1, rightBound: 3)) // "b"+"c"+"A" = "bcA" +print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC" -stringSegmentTree.replaceItemAtIndex(0, withItem: "I") -stringSegmentTree.replaceItemAtIndex(1, withItem: " like") -stringSegmentTree.replaceItemAtIndex(2, withItem: " algorithms") -stringSegmentTree.replaceItemAtIndex(3, withItem: " and") -stringSegmentTree.replaceItemAtIndex(4, withItem: " swift") -stringSegmentTree.replaceItemAtIndex(5, withItem: "!") +stringSegmentTree.replaceItem(at: 0, withItem: "I") +stringSegmentTree.replaceItem(at: 1, withItem: " like") +stringSegmentTree.replaceItem(at: 2, withItem: " algorithms") +stringSegmentTree.replaceItem(at: 3, withItem: " and") +stringSegmentTree.replaceItem(at: 4, withItem: " swift") +stringSegmentTree.replaceItem(at: 5, withItem: "!") -print(stringSegmentTree.queryWithLeftBound(0, rightBound: 5)) +print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5)) diff --git a/Segment Tree/SegmentTree.playground/contents.xcplayground b/Segment Tree/SegmentTree.playground/contents.xcplayground index 06828af92..16f9952aa 100644 --- a/Segment Tree/SegmentTree.playground/contents.xcplayground +++ b/Segment Tree/SegmentTree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Segment Tree/SegmentTree.playground/timeline.xctimeline b/Segment Tree/SegmentTree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Segment Tree/SegmentTree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Segment Tree/SegmentTree.swift b/Segment Tree/SegmentTree.swift index 608d5151a..b360d409a 100644 --- a/Segment Tree/SegmentTree.swift +++ b/Segment Tree/SegmentTree.swift @@ -8,62 +8,62 @@ */ public class SegmentTree { - - private var value: T - private var function: (T, T) -> T - private var leftBound: Int - private var rightBound: Int - private var leftChild: SegmentTree? - private var rightChild: SegmentTree? - - public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) { - self.leftBound = leftBound - self.rightBound = rightBound - self.function = function - - if leftBound == rightBound { - value = array[leftBound] - } else { - let middle = (leftBound + rightBound) / 2 - leftChild = SegmentTree(array: array, leftBound: leftBound, rightBound: middle, function: function) - rightChild = SegmentTree(array: array, leftBound: middle+1, rightBound: rightBound, function: function) - value = function(leftChild!.value, rightChild!.value) - } - } - - public convenience init(array: [T], function: (T, T) -> T) { - self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) - } - - public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T { - if self.leftBound == leftBound && self.rightBound == rightBound { - return self.value - } - - guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } - guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } - - if leftChild.rightBound < leftBound { - return rightChild.queryWithLeftBound(leftBound, rightBound: rightBound) - } else if rightChild.leftBound > rightBound { - return leftChild.queryWithLeftBound(leftBound, rightBound: rightBound) - } else { - let leftResult = leftChild.queryWithLeftBound(leftBound, rightBound: leftChild.rightBound) - let rightResult = rightChild.queryWithLeftBound(rightChild.leftBound, rightBound: rightBound) - return function(leftResult, rightResult) - } - } - - public func replaceItemAtIndex(index: Int, withItem item: T) { - if leftBound == rightBound { - value = item - } else if let leftChild = leftChild, rightChild = rightChild { - if leftChild.rightBound >= index { - leftChild.replaceItemAtIndex(index, withItem: item) - } else { - rightChild.replaceItemAtIndex(index, withItem: item) - } - value = function(leftChild.value, rightChild.value) - } - } + + private var value: T + private var function: (T, T) -> T + private var leftBound: Int + private var rightBound: Int + private var leftChild: SegmentTree? + private var rightChild: SegmentTree? + + public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) { + self.leftBound = leftBound + self.rightBound = rightBound + self.function = function + + if leftBound == rightBound { + value = array[leftBound] + } else { + let middle = (leftBound + rightBound) / 2 + leftChild = SegmentTree(array: array, leftBound: leftBound, rightBound: middle, function: function) + rightChild = SegmentTree(array: array, leftBound: middle+1, rightBound: rightBound, function: function) + value = function(leftChild!.value, rightChild!.value) + } + } + + public convenience init(array: [T], function: @escaping (T, T) -> T) { + self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) + } + + public func query(withLeftBound: Int, rightBound: Int) -> T { + if self.leftBound == leftBound && self.rightBound == rightBound { + return self.value + } + + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + if leftChild.rightBound < leftBound { + return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) + } else if rightChild.leftBound > rightBound { + return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) + } else { + let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(withLeftBound:rightChild.leftBound, rightBound: rightBound) + return function(leftResult, rightResult) + } + } + + public func replaceItem(at index: Int, withItem item: T) { + if leftBound == rightBound { + value = item + } else if let leftChild = leftChild, let rightChild = rightChild { + if leftChild.rightBound >= index { + leftChild.replaceItem(at: index, withItem: item) + } else { + rightChild.replaceItem(at: index, withItem: item) + } + value = function(leftChild.value, rightChild.value) + } + } } From f7ecb1ae4a886a8983670ce77e5bed3e6cde0890 Mon Sep 17 00:00:00 2001 From: FarzadShbfn Date: Sun, 18 Sep 2016 16:08:19 +0430 Subject: [PATCH 0135/1275] Updated ReadMe for Swift3 --- Segment Tree/README.markdown | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Segment Tree/README.markdown b/Segment Tree/README.markdown index 0bb6d8da5..15b1a3227 100644 --- a/Segment Tree/README.markdown +++ b/Segment Tree/README.markdown @@ -73,7 +73,7 @@ The `leftBound` and `rightBound` of each node are marked in red. Here's how we create a node of the segment tree: ```swift -public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) { +public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) { self.leftBound = leftBound self.rightBound = rightBound self.function = function @@ -111,7 +111,7 @@ We go through all this trouble so we can efficiently query the tree. Here's the code: ```swift - public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T { + public func query(withLeftBound: leftBound: Int, rightBound: Int) -> T { // 1 if self.leftBound == leftBound && self.rightBound == rightBound { return self.value @@ -122,16 +122,16 @@ Here's the code: // 2 if leftChild.rightBound < leftBound { - return rightChild.queryWithLeftBound(leftBound, rightBound: rightBound) + return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) // 3 } else if rightChild.leftBound > rightBound { - return leftChild.queryWithLeftBound(leftBound, rightBound: rightBound) + return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) // 4 } else { - let leftResult = leftChild.queryWithLeftBound(leftBound, rightBound: leftChild.rightBound) - let rightResult = rightChild.queryWithLeftBound(rightChild.leftBound, rightBound: rightBound) + let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(withLeftBound: rightChild.leftBound, rightBound: rightBound) return function(leftResult, rightResult) } } @@ -162,10 +162,10 @@ let array = [1, 2, 3, 4] let sumSegmentTree = SegmentTree(array: array, function: +) -sumSegmentTree.queryWithLeftBound(0, rightBound: 3) // 1 + 2 + 3 + 4 = 10 -sumSegmentTree.queryWithLeftBound(1, rightBound: 2) // 2 + 3 = 5 -sumSegmentTree.queryWithLeftBound(0, rightBound: 0) // just 1 -sumSegmentTree.queryWithLeftBound(3, rightBound: 3) // just 4 +sumSegmentTree.query(withLeftBound: 0, rightBound: 3) // 1 + 2 + 3 + 4 = 10 +sumSegmentTree.query(withLeftBound: 1, rightBound: 2) // 2 + 3 = 5 +sumSegmentTree.query(withLeftBound: 0, rightBound: 0) // just 1 +sumSegmentTree.query(withLeftBound: 3, rightBound: 3) // just 4 ``` Querying the tree takes **O(log n)** time. @@ -177,21 +177,21 @@ The value of a node in the segment tree depends on the nodes below it. So if we Here is the code: ```swift - public func replaceItemAtIndex(index: Int, withItem item: T) { + public func replaceItem(at index: Int, withItem item: T) { if leftBound == rightBound { value = item } else if let leftChild = leftChild, rightChild = rightChild { if leftChild.rightBound >= index { - leftChild.replaceItemAtIndex(index, withItem: item) + leftChild.replaceItem(at: index, withItem: item) } else { - rightChild.replaceItemAtIndex(index, withItem: item) + rightChild.replaceItem(at: index, withItem: item) } value = function(leftChild.value, rightChild.value) } } ``` -As usual, this works with recursion. If the node is a leaf, we just change its value. If the node is not a leaf, then we recursively call `replaceItemAtIndex()` to update its children. After that, we recalculate the node's own value so that it is up-to-date again. +As usual, this works with recursion. If the node is a leaf, we just change its value. If the node is not a leaf, then we recursively call `replaceItem(at: )` to update its children. After that, we recalculate the node's own value so that it is up-to-date again. Replacing an item takes **O(log n)** time. From a03d083365ba342e16ca44d2a5695f31e1cd22c6 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Mon, 19 Sep 2016 00:13:14 +0200 Subject: [PATCH 0136/1275] update documentation --- Skip-List/README.md | 96 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 64f221a23..5c569e177 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -1,30 +1,95 @@ # Skip List -Skip List is a probablistic data-structure with same efficiency as AVL tree or Red-Black tree. The building blocks are hierarchy of layers (regular sorted linked-lists), created probablisticly by coin flipping, each acting as an express lane to the layer underneath, therefore making fast O(log n) search possible by skipping lanes and reducing travel distance. A layer consists of a Head node, holding reference to the subsequent and the node below. Each node also holds similar references as the Head node. +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 and is relatively simpler to +implement compared to other map data structures. -![Schematic view](Images/Intro.png -) +A skip list *S* consists of series of sorted linked lists *{L0, ..., Ln}*, +layered hierarchicaly and each layer *L* stores a subset of items in layer *L0* +in incremental order. The items in layers *{L1, ... Ln}* are chosen at random +based on a coin flipping function with probability 1/2 . For traversing, every +item in a layer hold references to the node below and the next node. This +layers serve as express lanes to the layer underneath them, effectively making +fast O(log n) searching possible by skipping lanes and reducing travel distance +and in worse case searching degrades to O (n), as expected with regular linked +list. +For a skip list *S*: + +1. List *L0* contains every inserted item. +2. For lists *{L1, ..., Ln}*, *Li* contains a randomly generated subset of the + items in *Li-1* +3. Height is determined by coin-flipping. + +![Schematic view](Images/Intro.png) +Figure 1 + + +#Searching + +Searching for element *N* starts by traversing from top most layer *Ln* until +*L0*. + +Our objective is to find an element *K* such that its value at the rightmost +position of current layer, is less-than target item and its subsequent node has +a greater-equal value or nil ( * K.key < N.key <= (K.next.key or nil)* ). if +value of *K.next* is equal to *N*, search is terminated and we return *K.next*, +otherwise drop underneath using *K.down* to the node below ( at layer Ln-1 ) and +repeat the process until *L0* where *K.down* is `nil` which indicates that level +is *L0* and item doesn't exists. + + +###Example: + +![Inserting first element](Images/Insert5.png) #Inserting -1. Inserting a new element in initial state where no prior layer is created yet begins by construction of a Head node with a reference to data node (just like regular lists). After this operation coin-flipping starts to determine wether a new layer must be created. When positive, a new layer containing Head and data node ( similar to previous layer ) is created and head is updated to reference the new layer and the head node underneath. Subsequently data node is also updated to reference the node below; until coin-flip function return a negative value to terminate this process. +Inserting element *N* has a similar process as searching. It starts by +traversing from top most layer *Ln* until *L0*. We need to keep track of our +traversal path using a stack. It helps us to traverse the path upward when +coin-flipping starts, so we can insert our new element and update references to +it. -2. After initial state, we start at top most layer to find a node where its value is less than the new value and its next node value is greater-equal/nil than new value. Then we use this node to travel to layer underneath until we reach the layer 0 where the element must be inserted first, after this node. Node references must be updated accordingly by back tracing the path to the top. If the first element in the layer does not meet the criteria, same procedure is used to travel to the layer below using the head node. +Our objective is to find a element *K* such that its value at the rightmost +position of layer *Ln*, is less-than new item and its subsequent node has a +greater-equal value or nil ( * K.key < N.key < (K.next.key or nil)* ). Push +element *K* to the stack and with element *K*, go down using *K.down* to the +node below ( at layer Ln-1 ) and repeat the process ( forward searching ) up +until *L0* where *K.down* is `nil` which indicates that level is *L0*. We +terminate the process when *K.down* is nil. +At *L0*, *N* can be inserted after *K*. -**Example** +Here is the interesting part. We use coin flipping function to randomly create +layers. +When coin flip function returns 0, the whole process is finished but when +returns 1, there are two possibilities: -1 - Inserting 10 in initial state with coin flips (0) +1. Stack is empty ( Level is *L0* / -*Ln* or at uninitialized stage) +2. Stack has items ( traversing upward is possible ) -![Inserting first element](Images/Insert1.png) +In case 1: +A new layer M* is created with a head node *NM* referencing head node of layer +below and *NM.next* referencing new element *N*. New element *N* referecing +element *N* at previous layer. -2 - 12 inserted with coin flips (1,1,0) +In case 2: +repeat until stack is empty Pop an item *F* from stack and update the references +accordingly. *F.next* will be *K.next* and *K.next* will be *F* + +when stack is empty Create a new layer consisintg of a head node *NM* +referencing head node of layer below and *NM.next* referencing new element +*N*. New element *N* referencing element *N* at previous layer. + -3 - Inserting 13. with coin flips (0) +###Example: + +Inserting 13. with coin flips (0) ![Inserting first element](Images/Insert5.png) ![Inserting first element](Images/Insert6.png) @@ -33,7 +98,16 @@ Skip List is a probablistic data-structure with same efficiency as AVL tree or R ![Inserting first element](Images/Insert9.png) -#Searching + +Inserting 20. with 4 times coin flips (1) +![Inserting first element](Images/Insert9.png) +![Inserting first element](Images/Insert10.png) +![Inserting first element](Images/insert11.png) +![Inserting first element](Images/Insert12.png) + +#Removing + +Removing works similar to insert procedure. TODO From 23e776b334b69f3ede8a98282c2cd0726118870e Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Sep 2016 00:16:04 +0200 Subject: [PATCH 0137/1275] Update README.md --- Skip-List/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 5c569e177..575005ddc 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -102,7 +102,7 @@ Inserting 13. with coin flips (0) Inserting 20. with 4 times coin flips (1) ![Inserting first element](Images/Insert9.png) ![Inserting first element](Images/Insert10.png) -![Inserting first element](Images/insert11.png) +![Inserting first element](Images/Insert11.png) ![Inserting first element](Images/Insert12.png) #Removing From 8519c48d9f7f235f52a92b22f8fdb4a904e1f2e8 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Sep 2016 00:18:53 +0200 Subject: [PATCH 0138/1275] Update README.md --- Skip-List/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 575005ddc..664684621 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -22,7 +22,7 @@ For a skip list *S*: items in *Li-1* 3. Height is determined by coin-flipping. -![Schematic view](Images/Intro.png) +![Schematic view](Images/Search.png) Figure 1 From 512b603a7acf860b4af0aac124ecfa5794a8ecd8 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Sep 2016 00:19:13 +0200 Subject: [PATCH 0139/1275] Update README.md --- Skip-List/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 664684621..6d47f05df 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -22,7 +22,7 @@ For a skip list *S*: items in *Li-1* 3. Height is determined by coin-flipping. -![Schematic view](Images/Search.png) +![Schematic view](Images/Search1.png) Figure 1 From 87d81428ad852ee84f82a0e5f9583da9134c25c3 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Sep 2016 00:19:36 +0200 Subject: [PATCH 0140/1275] Update README.md --- Skip-List/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 6d47f05df..5c39e3db8 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -22,7 +22,7 @@ For a skip list *S*: items in *Li-1* 3. Height is determined by coin-flipping. -![Schematic view](Images/Search1.png) +![Schematic view](Images/Intro.png) Figure 1 @@ -42,7 +42,7 @@ is *L0* and item doesn't exists. ###Example: -![Inserting first element](Images/Insert5.png) +![Inserting first element](Images/Search1.png) #Inserting From 5891a6b4b9d26d97b837d2fcfe2b93e50043fcb4 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Sep 2016 00:20:59 +0200 Subject: [PATCH 0141/1275] Update README.md --- Skip-List/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Skip-List/README.md b/Skip-List/README.md index 5c39e3db8..d3824952b 100644 --- a/Skip-List/README.md +++ b/Skip-List/README.md @@ -33,7 +33,7 @@ Searching for element *N* starts by traversing from top most layer *Ln* until Our objective is to find an element *K* such that its value at the rightmost position of current layer, is less-than target item and its subsequent node has -a greater-equal value or nil ( * K.key < N.key <= (K.next.key or nil)* ). if +a greater-equal value or nil ( *K.key < N.key <= (K.next.key or nil)* ). if value of *K.next* is equal to *N*, search is terminated and we return *K.next*, otherwise drop underneath using *K.down* to the node below ( at layer Ln-1 ) and repeat the process until *L0* where *K.down* is `nil` which indicates that level @@ -54,7 +54,7 @@ it. Our objective is to find a element *K* such that its value at the rightmost position of layer *Ln*, is less-than new item and its subsequent node has a -greater-equal value or nil ( * K.key < N.key < (K.next.key or nil)* ). Push +greater-equal value or nil ( *K.key < N.key < (K.next.key or nil)* ). Push element *K* to the stack and with element *K*, go down using *K.down* to the node below ( at layer Ln-1 ) and repeat the process ( forward searching ) up until *L0* where *K.down* is `nil` which indicates that level is *L0*. We @@ -68,7 +68,7 @@ layers. When coin flip function returns 0, the whole process is finished but when returns 1, there are two possibilities: -1. Stack is empty ( Level is *L0* / -*Ln* or at uninitialized stage) +1. Stack is empty ( Level is *L0* /- *Ln* or at uninitialized stage) 2. Stack has items ( traversing upward is possible ) In case 1: From a8b5ef93d12b8399586427624dac24cecb760e42 Mon Sep 17 00:00:00 2001 From: Kauserali Hafizji Date: Mon, 19 Sep 2016 21:20:22 +0530 Subject: [PATCH 0142/1275] Palindromes now work with strings with even length --- Palindromes/Palindromes.playground/Contents.swift | 8 +++----- Palindromes/Palindromes.swift | 6 +----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index 20df10ee4..bb666ee9a 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -5,11 +5,7 @@ public func palindromeCheck(text: String?) -> Bool { let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() let length: Int = mutableText.characters.count - guard length >= 1 else { - return false - } - - if length == 1 { + if length == 1 || length == 0 { return true } else if mutableText[mutableText.startIndex] == mutableText[mutableText.index(mutableText.endIndex, offsetBy: -1)] { let range = Range(mutableText.index(mutableText.startIndex, offsetBy: 1).. Bool { let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() let length: Int = mutableText.characters.count - guard length >= 1 else { - return false - } - - if length == 1 { + if length == 1 || length == 0 { return true } else if mutableText[mutableText.startIndex] == mutableText[mutableText.index(mutableText.endIndex, offsetBy: -1)] { let range = Range(mutableText.index(mutableText.startIndex, offsetBy: 1).. Date: Mon, 19 Sep 2016 20:03:12 +0200 Subject: [PATCH 0143/1275] made enums lowerCamelCase --- .../Sources/RBTree.swift | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift index c5bcd0a3e..9649a2175 100644 --- a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -1,12 +1,12 @@ private enum RBTColor { - case Red - case Black - case DoubleBlack + case red + case black + case doubleBlack } public class RBTNode { - fileprivate var color: RBTColor = .Red + fileprivate var color: RBTColor = .red public var value: T! = nil public var right: RBTNode! public var left: RBTNode! @@ -49,15 +49,15 @@ public class RBTNode { } fileprivate var isRed: Bool { - return color == .Red + return color == .red } fileprivate var isBlack: Bool { - return color == .Black + return color == .black } fileprivate var isDoubleBlack: Bool { - return color == .DoubleBlack + return color == .doubleBlack } } @@ -67,7 +67,7 @@ public class RBTree { public init() { nullLeaf = RBTNode() - nullLeaf.color = .Black + nullLeaf.color = .black root = nullLeaf } @@ -175,7 +175,7 @@ public class RBTree { // if node is root change color to black, else move on private func insertCase1(n: RBTNode) { if n === root { - n.color = .Black + n.color = .black } else { insertCase2(n: n) } @@ -192,9 +192,9 @@ public class RBTree { private func insertCase3(n: RBTNode) { if n.uncle.isRed { // node must have grandparent as children of root have a black parent // both parent and uncle are red, so grandparent must be black. - n.parent.color = .Black - n.uncle.color = .Black - n.grandparent.color = .Red + n.parent.color = .black + n.uncle.color = .black + n.grandparent.color = .red // now both parent and uncle are black and grandparent is red. // we repeat for the grandparent insertCase1(n: n.grandparent) @@ -226,8 +226,8 @@ public class RBTree { private func insertCase5(n: RBTNode) { // swap color of parent and grandparent // parent is red grandparent is black - n.parent.color = .Black - n.grandparent.color = .Red + n.parent.color = .black + n.grandparent.color = .red if n.isLeftChild { // left left case rightRotate(n: n.grandparent) @@ -269,7 +269,7 @@ public class RBTree { } if toDel.isRed || child.isRed { - child.color = .Black + child.color = .black if toDel.isLeftChild { toDel.parent.left = child @@ -292,7 +292,7 @@ public class RBTree { if child !== nullLeaf { child.parent = toDel.parent } - child.color = .DoubleBlack + child.color = .doubleBlack while child.isDoubleBlack || (child.parent !== nullLeaf && child.parent != nil) { if sibling!.isBlack { @@ -307,35 +307,35 @@ public class RBTree { } if leftRedChild != nil || rightRedChild != nil { // at least one of sibling's children are red - child.color = .Black + child.color = .black if sibling!.isLeftChild { if leftRedChild != nil { // left left case - sibling!.left.color = .Black + sibling!.left.color = .black let tempColor = sibling!.parent.color sibling!.parent.color = sibling!.color sibling!.color = tempColor rightRotate(n: sibling!.parent) } else { // left right case if sibling!.parent.isRed { - sibling!.parent.color = .Black + sibling!.parent.color = .black } else { - sibling!.right.color = .Black + sibling!.right.color = .black } leftRotate(n: sibling!) rightRotate(n: sibling!.grandparent) } } else { if rightRedChild != nil { // right right case - sibling!.right.color = .Black + sibling!.right.color = .black let tempColor = sibling!.parent.color sibling!.parent.color = sibling!.color sibling!.color = tempColor leftRotate(n: sibling!.parent) } else { // right left case if sibling!.parent.isRed { - sibling!.parent.color = .Black + sibling!.parent.color = .black } else { - sibling!.left.color = .Black + sibling!.left.color = .black } rightRotate(n: sibling!) leftRotate(n: sibling!.grandparent) @@ -343,34 +343,34 @@ public class RBTree { } break } else { // both sibling's children are black - child.color = .Black - sibling!.color = .Red + child.color = .black + sibling!.color = .red if sibling!.parent.isRed { - sibling!.parent.color = .Black + sibling!.parent.color = .black break } - sibling!.parent.color = .DoubleBlack + sibling!.parent.color = .doubleBlack child = sibling!.parent sibling = child.sibling } } else { // sibling is red - sibling!.color = .Black + sibling!.color = .black if sibling!.isLeftChild { // left case rightRotate(n: sibling!.parent) sibling = sibling!.right.left - sibling!.parent.color = .Red + sibling!.parent.color = .red } else { // right case leftRotate(n: sibling!.parent) sibling = sibling!.left.right - sibling!.parent.color = .Red + sibling!.parent.color = .red } } // sibling check is here for when child is a nullLeaf and thus does not have a parent. // child is here as sibling can become nil when child is the root if (sibling != nil && sibling!.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { - child.color = .Black + child.color = .black } } } From a5397bbe7fd3ed678665980abaffb0ec00e92667 Mon Sep 17 00:00:00 2001 From: Jaap Date: Mon, 19 Sep 2016 20:51:36 +0200 Subject: [PATCH 0144/1275] adopted CustomStringConvertible protocol --- .../Sources/RBTree.swift | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift index 9649a2175..adfd38216 100644 --- a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -5,13 +5,34 @@ private enum RBTColor { case doubleBlack } -public class RBTNode { +public class RBTNode: CustomStringConvertible { fileprivate var color: RBTColor = .red public var value: T! = nil public var right: RBTNode! public var left: RBTNode! public var parent: RBTNode! + public var description: String { + if self.value == nil { + return "null" + } else { + var nodeValue: String + + // If the value is encapsulated by parentheses it is red + // If the value is encapsulated by pipes it is black + // If the value is encapsulated by double pipes it is double black (This should not occur in a verified RBTree) + if self.isRed { + nodeValue = "(\(self.value!))" + } else if self.isBlack{ + nodeValue = "|\(self.value!)|" + } else { + nodeValue = "||\(self.value!)||" + } + + return "(\(self.left.description)<-\(nodeValue)->\(self.right.description))" + } + } + init(tree: RBTree) { right = tree.nullLeaf left = tree.nullLeaf @@ -61,10 +82,14 @@ public class RBTNode { } } -public class RBTree { +public class RBTree: CustomStringConvertible { public var root: RBTNode fileprivate let nullLeaf: RBTNode + public var description: String { + return root.description + } + public init() { nullLeaf = RBTNode() nullLeaf.color = .black From d663d5dfe909b3bde9e3c3391dca3239ebc8d920 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 20 Sep 2016 00:30:39 +0200 Subject: [PATCH 0145/1275] changed sibling property to be non optional and fixed insertion bug --- .../Contents.swift | 25 +++-- .../Sources/RBTree.swift | 98 ++++++++++--------- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift b/Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift index b4fadff92..d55c153d5 100644 --- a/Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift @@ -1,9 +1,20 @@ //: Playground - noun: a place where people can play +import Foundation -let array = [6,78,89,4] -var tree = RBTree(withArray: array) -tree.insert(5) -tree.insert(8) -tree.insert(2) -tree.delete(6) -tree.delete(8) \ No newline at end of file +let tree = RBTree() +let randomMax = Double(0x100000000) +var values = [Double]() +for _ in 0..<1000 { + let value = Double(arc4random()) / randomMax + values.append(value) + tree.insert(value) +} +tree.verify() + +for _ in 0..<1000 { + let rand = arc4random_uniform(UInt32(values.count)) + let index = Int(rand) + let value = values.remove(at: index) + tree.delete(value) +} +tree.verify() diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift index adfd38216..1735798d5 100644 --- a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -55,13 +55,11 @@ public class RBTNode: CustomStringConvertible { return parent.parent } - public var sibling: RBTNode! { + public var sibling: RBTNode { if isLeftChild { return self.parent.right - } else if isRightChild { - return self.parent.left } else { - return nil + return self.parent.left } } @@ -245,6 +243,8 @@ public class RBTree: CustomStringConvertible { } else if n.parent.isRightChild && n.isLeftChild { // right left case rightRotate(n: n.parent) insertCase5(n: n.right) + } else { + insertCase5(n: n) } } @@ -320,81 +320,91 @@ public class RBTree: CustomStringConvertible { child.color = .doubleBlack while child.isDoubleBlack || (child.parent !== nullLeaf && child.parent != nil) { - if sibling!.isBlack { + if sibling.isBlack { var leftRedChild: RBTNode! = nil - if sibling!.left.isRed { - leftRedChild = sibling!.left + if sibling.left.isRed { + leftRedChild = sibling.left } var rightRedChild: RBTNode! = nil - if sibling!.right.isRed { - rightRedChild = sibling!.right + if sibling.right.isRed { + rightRedChild = sibling.right } if leftRedChild != nil || rightRedChild != nil { // at least one of sibling's children are red child.color = .black - if sibling!.isLeftChild { + if sibling.isLeftChild { if leftRedChild != nil { // left left case - sibling!.left.color = .black - let tempColor = sibling!.parent.color - sibling!.parent.color = sibling!.color - sibling!.color = tempColor - rightRotate(n: sibling!.parent) + sibling.left.color = .black + let tempColor = sibling.parent.color + sibling.parent.color = sibling.color + sibling.color = tempColor + rightRotate(n: sibling.parent) } else { // left right case - if sibling!.parent.isRed { - sibling!.parent.color = .black + if sibling.parent.isRed { + sibling.parent.color = .black } else { - sibling!.right.color = .black + sibling.right.color = .black } - leftRotate(n: sibling!) - rightRotate(n: sibling!.grandparent) + leftRotate(n: sibling) + rightRotate(n: sibling.grandparent) } } else { if rightRedChild != nil { // right right case - sibling!.right.color = .black - let tempColor = sibling!.parent.color - sibling!.parent.color = sibling!.color - sibling!.color = tempColor - leftRotate(n: sibling!.parent) + sibling.right.color = .black + let tempColor = sibling.parent.color + sibling.parent.color = sibling.color + sibling.color = tempColor + leftRotate(n: sibling.parent) } else { // right left case - if sibling!.parent.isRed { - sibling!.parent.color = .black + if sibling.parent.isRed { + sibling.parent.color = .black } else { - sibling!.left.color = .black + sibling.left.color = .black } - rightRotate(n: sibling!) - leftRotate(n: sibling!.grandparent) + rightRotate(n: sibling) + leftRotate(n: sibling.grandparent) } } break } else { // both sibling's children are black child.color = .black - sibling!.color = .red - if sibling!.parent.isRed { - sibling!.parent.color = .black + sibling.color = .red + if sibling.parent.isRed { + sibling.parent.color = .black break } - sibling!.parent.color = .doubleBlack - child = sibling!.parent + /* + sibling.parent.color = .doubleBlack + child = sibling.parent sibling = child.sibling + */ + if sibling.parent.parent === nullLeaf { // parent of child is root + break + } else { + sibling.parent.color = .doubleBlack + child = sibling.parent + sibling = child.sibling // can become nill if child is root as parent is nullLeaf + } + //--------------- } } else { // sibling is red - sibling!.color = .black + sibling.color = .black - if sibling!.isLeftChild { // left case - rightRotate(n: sibling!.parent) - sibling = sibling!.right.left - sibling!.parent.color = .red + if sibling.isLeftChild { // left case + rightRotate(n: sibling.parent) + sibling = sibling.right.left + sibling.parent.color = .red } else { // right case - leftRotate(n: sibling!.parent) - sibling = sibling!.left.right - sibling!.parent.color = .red + leftRotate(n: sibling.parent) + sibling = sibling.left.right + sibling.parent.color = .red } } // sibling check is here for when child is a nullLeaf and thus does not have a parent. // child is here as sibling can become nil when child is the root - if (sibling != nil && sibling!.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { + if (sibling.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { child.color = .black } } From 4800819588174de53542fc9a4b791d931e035541 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 20 Sep 2016 02:04:02 +0200 Subject: [PATCH 0146/1275] Updated readme --- Red-Black Tree 2/README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Red-Black Tree 2/README.markdown b/Red-Black Tree 2/README.markdown index abb1c2f55..47fc6a08f 100644 --- a/Red-Black Tree 2/README.markdown +++ b/Red-Black Tree 2/README.markdown @@ -8,3 +8,5 @@ http://www.geeksforgeeks.org/red-black-tree-set-2-insert/ http://www.geeksforgeeks.org/red-black-tree-set-3-delete-2/ Important to note is that the last one doesn't mention a few important details about deletion cases which can be found in the code itself. + +*Written for Swift Algorithm Club by Jaap Wijnen* From 64f93cf4945fadde007756e040dbef4eb0d92ec9 Mon Sep 17 00:00:00 2001 From: Dee Date: Tue, 20 Sep 2016 13:35:59 +0800 Subject: [PATCH 0147/1275] make some conversion --- .../kthLargest.playground/Contents.swift | 34 +++++++++---------- .../xcshareddata/kthLargest.xcscmblueprint | 30 ++++++++++++++++ .../kthLargest.playground/timeline.xctimeline | 6 ---- 3 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 Kth Largest Element/kthLargest.playground/playground.xcworkspace/xcshareddata/kthLargest.xcscmblueprint delete mode 100644 Kth Largest Element/kthLargest.playground/timeline.xctimeline diff --git a/Kth Largest Element/kthLargest.playground/Contents.swift b/Kth Largest Element/kthLargest.playground/Contents.swift index 628892d9c..9fba2b483 100644 --- a/Kth Largest Element/kthLargest.playground/Contents.swift +++ b/Kth Largest Element/kthLargest.playground/Contents.swift @@ -1,9 +1,9 @@ //: Playground - noun: a place where people can play -func kthLargest(a: [Int], k: Int) -> Int? { +func kthLargest(_ a: [Int], _ k: Int) -> Int? { let len = a.count if k > 0 && k <= len { - let sorted = a.sort() + let sorted = a.sorted() return sorted[len - k] } else { return nil @@ -12,15 +12,15 @@ func kthLargest(a: [Int], k: Int) -> Int? { let a = [5, 1, 3, 2, 7, 6, 4] -kthLargest(a, k: 0) -kthLargest(a, k: 1) -kthLargest(a, k: 2) -kthLargest(a, k: 3) -kthLargest(a, k: 4) -kthLargest(a, k: 5) -kthLargest(a, k: 6) -kthLargest(a, k: 7) -kthLargest(a, k: 8) +kthLargest(a, 0) +kthLargest(a, 1) +kthLargest(a, 2) +kthLargest(a, 3) +kthLargest(a, 4) +kthLargest(a, 5) +kthLargest(a, 6) +kthLargest(a, 7) +kthLargest(a, 8) @@ -28,7 +28,7 @@ kthLargest(a, k: 8) import Foundation /* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { +public func random( min: Int, max: Int) -> Int { assert(min < max) return min + Int(arc4random_uniform(UInt32(max - min + 1))) } @@ -37,22 +37,22 @@ public func random(min min: Int, max: Int) -> Int { Swift's swap() doesn't like it if the items you're trying to swap refer to the same memory location. This little wrapper simply ignores such swaps. */ -public func swap(inout a: [T], _ i: Int, _ j: Int) { +public func swap(_ a:inout [T], _ i: Int, _ j: Int) { if i != j { swap(&a[i], &a[j]) } } -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) 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..(array: [T], order k: Int) -> T { return i } - func randomizedSelect(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 { diff --git a/Kth Largest Element/kthLargest.playground/playground.xcworkspace/xcshareddata/kthLargest.xcscmblueprint b/Kth Largest Element/kthLargest.playground/playground.xcworkspace/xcshareddata/kthLargest.xcscmblueprint new file mode 100644 index 000000000..c747b8a38 --- /dev/null +++ b/Kth Largest Element/kthLargest.playground/playground.xcworkspace/xcshareddata/kthLargest.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "CF309AABC690F91A443043D5C69EECB0069B5411", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "CF309AABC690F91A443043D5C69EECB0069B5411" : 9223372036854775807, + "FA0506A44181383605977F2A9C8020B861F7CE04" : 9223372036854775807 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "6CCD70DA-EE44-4E31-98F0-6DA8B083772A", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "CF309AABC690F91A443043D5C69EECB0069B5411" : "swift-algorithm-club\/", + "FA0506A44181383605977F2A9C8020B861F7CE04" : "" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "kthLargest", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Kth Largest Element\/kthLargest.playground", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Deeer\/swift-algorithm-club.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CF309AABC690F91A443043D5C69EECB0069B5411" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Deeer\/CuteSticker.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FA0506A44181383605977F2A9C8020B861F7CE04" + } + ] +} \ No newline at end of file diff --git a/Kth Largest Element/kthLargest.playground/timeline.xctimeline b/Kth Largest Element/kthLargest.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Kth Largest Element/kthLargest.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From b4b572f4dcf580d550f5757f547e761db78a30b1 Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Tue, 20 Sep 2016 22:30:03 +0800 Subject: [PATCH 0148/1275] updated fizzBuzz to swift3 --- Fizz Buzz/FizzBuzz.playground/Contents.swift | 2 +- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ Fizz Buzz/FizzBuzz.playground/timeline.xctimeline | 6 ------ Fizz Buzz/FizzBuzz.swift | 2 +- Fizz Buzz/README.markdown | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata delete mode 100644 Fizz Buzz/FizzBuzz.playground/timeline.xctimeline diff --git a/Fizz Buzz/FizzBuzz.playground/Contents.swift b/Fizz Buzz/FizzBuzz.playground/Contents.swift index 9d7a974fa..ba2f83b15 100644 --- a/Fizz Buzz/FizzBuzz.playground/Contents.swift +++ b/Fizz Buzz/FizzBuzz.playground/Contents.swift @@ -1,4 +1,4 @@ -func fizzBuzz(numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { var result = "" diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Fizz Buzz/FizzBuzz.playground/timeline.xctimeline b/Fizz Buzz/FizzBuzz.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Fizz Buzz/FizzBuzz.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index a801f34ee..b6bb410e7 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,4 +1,4 @@ -func fizzBuzz(numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { var result = "" diff --git a/Fizz Buzz/README.markdown b/Fizz Buzz/README.markdown index e4cf485ff..8c250da27 100644 --- a/Fizz Buzz/README.markdown +++ b/Fizz Buzz/README.markdown @@ -58,7 +58,7 @@ Finding numbers divisible by five: Here is a simple implementation in Swift: ```swift -func fizzBuzz(numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { var result = "" From 3e6623179d8809e27fc9b151a3fd9d1ede4f503d Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 20 Sep 2016 17:58:01 +0200 Subject: [PATCH 0149/1275] updated readme --- Red-Black Tree 2/README.markdown | 119 +++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/Red-Black Tree 2/README.markdown b/Red-Black Tree 2/README.markdown index 47fc6a08f..9496e6318 100644 --- a/Red-Black Tree 2/README.markdown +++ b/Red-Black Tree 2/README.markdown @@ -1,12 +1,119 @@ # Red-Black Tree -Used info from +A Red-Black tree is a special version of a [Binary Search Tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Search%20Tree). Binary search trees(BSTs) can become unbalanced after a lot of insertions/deletions. The only difference between a node from a BST and a Red-Black Tree(RBT) is that RBT nodes have a color property added to them which can either be red or black. A RBT rebalances itself by making sure the following properties hold: -https://en.wikipedia.org/wiki/Red–black_tree -http://www.geeksforgeeks.org/red-black-tree-set-1-introduction-2/ -http://www.geeksforgeeks.org/red-black-tree-set-2-insert/ -http://www.geeksforgeeks.org/red-black-tree-set-3-delete-2/ +## Properties +1. A node is either red or black +2. The root is always black +3. All leaves are black +4. If a node is red, both of its children are black +5. Every path to a leaf contains the same number of black nodes (The amount of black nodes met when going down a RBT is called the black-depth of the tree.) -Important to note is that the last one doesn't mention a few important details about deletion cases which can be found in the code itself. +## Methods +* `insert(_ value: T)` inserts the value into the tree +* `insert(_ values: [T])` inserts an array of values into the tree +* `delete(_ value: T)` deletes the value from the tree +* `find(_ value: T) -> RBTNode` looks for a node in the tree with given value and returns it +* `minimum(n: RBTNode) -> RBTNode` looks for the maximum value of a subtree starting at the given node +* `maximum(n: RBTNode) -> RBTNode` looks for the minimum value of a subtree starting at the given node +* `func verify()` verifies if the tree is still valid. Prints warning messages if this is not the case + +## Rotation + +In order to rebalance their nodes RBTs use an operation known as rotation. You can either left or right rotate a node and its child. Rotating a node and its child swaps the nodes and interchanges their subtrees. Left rotation swaps the parent node with its right child. while right rotation swaps the parent node with its left child. + +Left rotation: +``` +before left rotating p after left rotating p + p b + / \ / \ + a b -> p n + / \ / \ / \ +n n n n a n + / \ + n n +``` +Right rotation: +``` +before right rotating p after right rotating p + p a + / \ / \ + a b -> n p + / \ / \ / \ +n n n n n b + / \ + n n +``` + +## Insertion + +We create a new node with the value to be inserted into the tree. The color of this new node is always red. +We perform a standard BST insert with this node. Now the three might not be a valid RBT anymore. +We now go through several insertion steps in order to make the tree valid again. We call the just inserted node n. +1. We check if n is the rootNode, if so we paint it black and we are done. If not we go to step 2. + +We now know that n at least has a parent as it is not the rootNode. + +2. We check if the parent of n is black if so we are done. If not we go to step 3. + +We now know the parent is also not the root node as the parent is red. Thus n also has a grandparent and thus also an uncle as every node has two children. This uncle may however be a nullLeaf + +3. We check if n's uncle is red. If not we go to 4. If n's uncle is indeed red we recolor uncle and parent to black and n's grandparent to red. We now go back to step 1 performing the same logic on n's grandparent. + +From here there are four cases: +- **The left left case.** n's parent is the left child of its parent and n is the left child of its parent. +- **The left right case** n's parent is the left child of its parent and n is the right child of its parent. +- **The right right case** n's parent is the right child of its parent and n is the right child of its parent. +- **The right left case** n's parent is the right child of its parent and n is the left child of its parent. + +4. Step 4 checks if either the **left right** case or the **right left** case applies to the current situation. + - If we find the **left right case**, we left rotate n's parent and go to step 5 while setting n to n's parent. (This transforms the **left right** case into the **left left** case) + - If we find the **right left case**, we right rotate n's parent and go to step 5 while setting n to n's parent. (This transforms the **right left** case into the **right right** case) + - If we find neither of these two we proceed to step 5. + +n's parent is now red, while n's grandparent is black. + +5. We swap the colors of n's parent and grandparent. + - We either right rotate n's grandparent in case of the **left left** case + - Or we left rotate n's grandparent in case of the **right right** case + +Reaching the end we have successfully made the tree valid again. + +# Deletion + +Deletion is a little more complicated than insertion. In the following we call del the node to be deleted. +First we try and find the node to be deleted using find() +we send the result of find to del. +We now go through the following steps in order to delete the node del. + +First we do a few checks: +- Is del the rootNode if so set the root to a nullLeaf and we are done. +- If del has 2 nullLeaf children and is red. We check if del is either a left or a right child and set del's parent left or right to a nullLeaf. +- If del has two non nullLeaf children we look for the maximum value in del's left subtree. We set del's value to this maximum value and continue to instead delete this maximum node. Which we will now call del. + +Because of these checks we now know that del has at most 1 non nullLeaf child. It has either two nullLeaf children or one nullLeaf and one regular red child. (The child is red otherwise the black-depth wouldn't be the same for every leaf) + +We now call the non nullLeaf child of del, child. If del has two nullLeaf children child will be a nullLeaf. This means child can either be a nullLeaf or a red node. + +We now have three options + +- If del is red its child is a nullLeaf and we can just delete it as it doesn't change the black-depth of the tree. We are done + +- If child is red we recolor it black and child's parent to del's parent. del is now deleted and we are done. + +- Both del and child are black we go through + +If both del and child are black we introduce a new variable sibling. Which is del's sibling. We also replace del with child and recolor it doubleBlack. del is now deleted and child and sibling are siblings. + +We now have to go through a lot of steps in order to remove this doubleBlack color. Which are hard to explain in text without just writing the full code in text. This is due the many possible combination of nodes and colors. The code is commented, but if you don't quite understand please leave me a message. Also part of the deletion is described by the final link in the Also See section. + +## Also see + +* [Wikipedia](https://en.wikipedia.org/wiki/Red–black_tree) +* [GeeksforGeeks - introduction](http://www.geeksforgeeks.org/red-black-tree-set-1-introduction-2/) +* [GeeksforGeeks - insertion](http://www.geeksforgeeks.org/red-black-tree-set-2-insert/) +* [GeeksforGeeks - deletion](http://www.geeksforgeeks.org/red-black-tree-set-3-delete-2/) + +Important to note is that GeeksforGeeks doesn't mention a few deletion cases that do occur. The code however does implement these. *Written for Swift Algorithm Club by Jaap Wijnen* From 551fd6dec6f3490046d31a9ec726a8395c3245a0 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 20 Sep 2016 18:10:37 +0200 Subject: [PATCH 0150/1275] replaced old RBTree with new implementation --- Red-Black Tree 2/RBTree.swift | Bin 1104 -> 0 bytes Red-Black Tree/RBTree.swift | Bin 13367 -> 1104 bytes .../README.markdown | 0 Red-Black Tree/README.md | 69 ------------------ .../Contents.swift | 0 .../Sources/RBTree.swift | 0 .../contents.xcplayground | 0 .../contents.xcworkspacedata | 0 Red-Black Tree/files/fig1.png | Bin 24455 -> 0 bytes Red-Black Tree/files/fig2.png | Bin 40534 -> 0 bytes 10 files changed, 69 deletions(-) delete mode 100644 Red-Black Tree 2/RBTree.swift rename {Red-Black Tree 2 => Red-Black Tree}/README.markdown (100%) delete mode 100644 Red-Black Tree/README.md rename {Red-Black Tree 2 => Red-Black Tree}/Red-Black Tree 2.playground/Contents.swift (100%) rename {Red-Black Tree 2 => Red-Black Tree}/Red-Black Tree 2.playground/Sources/RBTree.swift (100%) rename {Red-Black Tree 2 => Red-Black Tree}/Red-Black Tree 2.playground/contents.xcplayground (100%) rename {Red-Black Tree 2 => Red-Black Tree}/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata (100%) delete mode 100644 Red-Black Tree/files/fig1.png delete mode 100644 Red-Black Tree/files/fig2.png diff --git a/Red-Black Tree 2/RBTree.swift b/Red-Black Tree 2/RBTree.swift deleted file mode 100644 index 0ed831f72932e9675aa57dc32405330ef33285a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1104 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 diff --git a/Red-Black Tree 2/README.markdown b/Red-Black Tree/README.markdown similarity index 100% rename from Red-Black Tree 2/README.markdown rename to Red-Black Tree/README.markdown diff --git a/Red-Black Tree/README.md b/Red-Black Tree/README.md deleted file mode 100644 index e1b887c3a..000000000 --- a/Red-Black Tree/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Red Black Tree -![fig1](files/fig1.png) -Red-black trees are an evolution of binary search trees that aim to keep the tree balanced without affecting the complexity of the primitive operations. This is done by coloring each node in the tree with either red or black and preserving a set of properties that guarantee that the deepest path in the tree is not longer than twice the shortest one. -## Motivation: -* We want a balanced binary search tree -* Height of the tree is O(log n) -* Red-Black Tree is an implementation of a balanced binary search tree - - -## Invariants: -1. Every node is colored either red or black -2. All leaf (nil) nodes are colored with black; if a node’s child is missing then we will assume that it has a nil child in that place and this nil child is always colored black. -3. Both children of a red node must be black nodes. -4. Every path from a node n to a descendent leaf has the same number of black nodes (not counting node n). - -## Methods: - -Since the red-black tree is a balanced BST, it supports the functions: - * find(key) - * Predecessor(key) - * Successor(key) - * Minimum(key) - * maximum(key) - * insert(key) - * delete(key) - -Since an insertion or deletion may violate one of the invariant's of the red-black tree we must either change colors, or perform rotation actions. - -#Rotation -To ensure that its color scheme and properties don’t get thrown off, red-black trees employ a key operation known as rotation. Rotation is a binary operation, between a parent node and one of its children, that swaps nodes and modifys their pointers while preserving the inorder traversal of the tree (so that elements are still sorted). There are two types of rotations: left rotation and right rotation. Left rotation swaps the parent node with its right child, while right rotation swaps the parent node with its left child. -![fig2](files/fig2.png) -###Left-Rotation: -```c++ -y ← x->right -x->right ← y->left -y->left->p ← x -y->p ← x->p -if x->p = Null - then T->root ← y - else if x = x->p->left - then x->p->left ← y - else x->p->right ← y -y->left ← x -x->p ← y -``` -###Right-Rotation: -```c++ -y ← x->left -x->left ← y->right -y->right->p ← x -y->p ← x->p -if x->p = Null - then T->root ← y - else if x = x->p->right - then x->p->right ← y - else x->p->left ← y -y->right ← x -x->p ← y -``` -###Insertion: -When adding a new node to a binary search tree, note that the new node will always be a leaf in the tree. To insert a new node, all we will do is navigate the BST starting from the root. If the new node value is smaller than the current node value, we go left – if it is larger, we go right. When we reach a leaf node, the last step is to attach the new node as a child to this leaf node in a way that preserves the BST constraint. We must recheck the RBTree invariants to see if any were violated - -###Deletion: -The same concept behind red-black tree insertions applies here. Removing a node from a red-black tree makes use of the BST deletion procedure and then restores the red-black tree properties in O(log n). The total running time for the deletion process takes O(log n) time, then, which meets the complexity requirements for the primitive operations. - -See also [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree). - -*Written for the Swift Algorithm Club by Ashwin Raghuraman* - diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift b/Red-Black Tree/Red-Black Tree 2.playground/Contents.swift similarity index 100% rename from Red-Black Tree 2/Red-Black Tree 2.playground/Contents.swift rename to Red-Black Tree/Red-Black Tree 2.playground/Contents.swift diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift similarity index 100% rename from Red-Black Tree 2/Red-Black Tree 2.playground/Sources/RBTree.swift rename to Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground b/Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground similarity index 100% rename from Red-Black Tree 2/Red-Black Tree 2.playground/contents.xcplayground rename to Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground diff --git a/Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata b/Red-Black Tree/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Red-Black Tree 2/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata rename to Red-Black Tree/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Red-Black Tree/files/fig1.png b/Red-Black Tree/files/fig1.png deleted file mode 100644 index 7a91eb6932feddfc00890e16aeec6e1a079a75b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24455 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 SRfALbFQI*$ax9N*;r%bz3+-zF diff --git a/Red-Black Tree/files/fig2.png b/Red-Black Tree/files/fig2.png deleted file mode 100644 index 35b81e61c61f11906814e5503daf19847120a4a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40534 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 From 52a29a16b2efb745a796017236acecf904474f8b Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 20 Sep 2016 18:12:34 +0200 Subject: [PATCH 0151/1275] removed bad alias --- Red-Black Tree/RBTree.swift | Bin 1104 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Red-Black Tree/RBTree.swift diff --git a/Red-Black Tree/RBTree.swift b/Red-Black Tree/RBTree.swift deleted file mode 100644 index 0ed831f72932e9675aa57dc32405330ef33285a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1104 zcmZ{jzi-n(6vxkL3PtLWv`CEr2@5eGR5zhc+R|2{af}3|FtiC%7stM~R-HJq9idJX z)CqN9U}QjuKY*bdv??1TBNDJNBGCbupyB(RyQD_qN#DEAd-weAr|Z7I$zTmDi2E5Z zDVL^bIzw#`<`);fw9>iV{WAG$k!BsGFbW9ErxXT@&^ zHV@gb{KlXf6Y+E^#ZECs^AL|iwAU)+K~JF<&=8cyzOq-5e8PYDIO+d6h>xe2|8D0v zkzaU{^k-it{kebqdEu+5LhJmD{u}fg8pgR?fX1PDXbGZq(%F~yce8WA9Hii0FcjNG zFq!O$69DGUfL;xnFcoy*0i0 z^jw918KOHanK!3&W7^OruT@M<*9)e0U9U`Q72PP7r)G>|si@2KKca7-@1x0{VpJ=S z{+!@@E4Ae%)3@6V-i&TLXxufI2Y2{Ze=i3(hZ5zZcbaY;*gGR)Y4nE4;>U6W)^+1n z#k|LzPKVY&HU`n(u@`%I|KL?Im;pZ%ya3)2Tm`=sTsy({!FwW}QW=ZHy$yoDig*V6 zLvR*+MdXZthXjv;bAnZHRd4|;>nn$hy_a>s7>aG=kg<; Date: Tue, 20 Sep 2016 14:02:16 -0700 Subject: [PATCH 0152/1275] Added credit to previous author. --- 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 9496e6318..d4e86a095 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -116,4 +116,4 @@ We now have to go through a lot of steps in order to remove this doubleBlack col Important to note is that GeeksforGeeks doesn't mention a few deletion cases that do occur. The code however does implement these. -*Written for Swift Algorithm Club by Jaap Wijnen* +*Written for Swift Algorithm Club by Jaap Wijnen. Updated from Ashwin Raghuraman's contribution.* From c4a4c89d644476cbf01cde349156f4223c7280ab Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Wed, 21 Sep 2016 12:06:09 +0800 Subject: [PATCH 0153/1275] deque update to swift 3 updated readme --- Deque/Deque-Optimized.swift | 6 +++--- Deque/Deque-Simple.swift | 4 ++-- Deque/Deque.playground/Contents.swift | 6 +++--- Deque/Deque.playground/timeline.xctimeline | 6 ------ Deque/README.markdown | 10 +++++----- 5 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 Deque/Deque.playground/timeline.xctimeline diff --git a/Deque/Deque-Optimized.swift b/Deque/Deque-Optimized.swift index ea68059c0..17ff89e68 100644 --- a/Deque/Deque-Optimized.swift +++ b/Deque/Deque-Optimized.swift @@ -8,7 +8,7 @@ public struct Deque { private var head: Int private var capacity: Int - public init(capacity: Int = 10) { + public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) array = .init(count: capacity, repeatedValue: nil) head = capacity @@ -22,11 +22,11 @@ public struct Deque { return array.count - head } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } - public mutating func enqueueFront(element: T) { + public mutating func enqueueFront(_ element: T) { if head == 0 { capacity *= 2 let emptySpace = [T?](count: capacity, repeatedValue: nil) diff --git a/Deque/Deque-Simple.swift b/Deque/Deque-Simple.swift index 0ccba0caa..f4f5f0409 100644 --- a/Deque/Deque-Simple.swift +++ b/Deque/Deque-Simple.swift @@ -16,11 +16,11 @@ public struct Deque { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } - public mutating func enqueueFront(element: T) { + public mutating func enqueueFront(_ element: T) { array.insert(element, atIndex: 0) } diff --git a/Deque/Deque.playground/Contents.swift b/Deque/Deque.playground/Contents.swift index 15bf1ee07..9e7b22c02 100644 --- a/Deque/Deque.playground/Contents.swift +++ b/Deque/Deque.playground/Contents.swift @@ -11,12 +11,12 @@ public struct Deque { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } - public mutating func enqueueFront(element: T) { - array.insert(element, atIndex: 0) + public mutating func enqueueFront(_ element: T) { + array.insert(element, at: 0) } public mutating func dequeue() -> T? { diff --git a/Deque/Deque.playground/timeline.xctimeline b/Deque/Deque.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Deque/Deque.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Deque/README.markdown b/Deque/README.markdown index 3329adca0..7671555dc 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -18,11 +18,11 @@ public struct Deque { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } - public mutating func enqueueFront(element: T) { + public mutating func enqueueFront(_ element: T) { array.insert(element, atIndex: 0) } @@ -120,7 +120,7 @@ public struct Deque { private var head: Int private var capacity: Int - public init(capacity: Int = 10) { + public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) array = .init(count: capacity, repeatedValue: nil) head = capacity @@ -134,11 +134,11 @@ public struct Deque { return array.count - head } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } - public mutating func enqueueFront(element: T) { + public mutating func enqueueFront(_ element: T) { // this is explained below } From 4efac1614da03629229c2913da7896ce27199ec0 Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 22 Sep 2016 02:00:24 +0200 Subject: [PATCH 0154/1275] Updated OrderedArray to Swift 3 --- .../OrderedArray.playground/Contents.swift | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index aae146ca2..dfbf67fcb 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -1,10 +1,10 @@ //: Playground - noun: a place where people can play public struct OrderedArray { - private var array = [T]() + fileprivate var array = [T]() public init(array: [T]) { - self.array = array.sort() + self.array = array.sorted() } public var isEmpty: Bool { @@ -20,16 +20,16 @@ public struct OrderedArray { } public mutating func removeAtIndex(index: Int) -> T { - return array.removeAtIndex(index) + return array.remove(at: index) } public mutating func removeAll() { array.removeAll() } - public mutating func insert(newElement: T) -> Int { - let i = findInsertionPoint(newElement) - array.insert(newElement, atIndex: i) + public mutating func insert(_ newElement: T) -> Int { + let i = findInsertionPoint(newElement: newElement) + array.insert(newElement, at: i) return i } @@ -47,18 +47,20 @@ public struct OrderedArray { // Fast version that uses a binary search. private func findInsertionPoint(newElement: T) -> Int { - var range = 0.. Date: Thu, 22 Sep 2016 02:09:38 +0200 Subject: [PATCH 0155/1275] updated readme --- .../OrderedArray.playground/Contents.swift | 4 +- Ordered Array/README.markdown | 52 ++++++++++--------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index dfbf67fcb..1a0320a65 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -28,7 +28,7 @@ public struct OrderedArray { } public mutating func insert(_ newElement: T) -> Int { - let i = findInsertionPoint(newElement: newElement) + let i = findInsertionPoint(newElement) array.insert(newElement, at: i) return i } @@ -46,7 +46,7 @@ public struct OrderedArray { */ // Fast version that uses a binary search. - private func findInsertionPoint(newElement: T) -> Int { + private func findInsertionPoint(_ newElement: T) -> Int { var startIndex = 0 var endIndex = array.count diff --git a/Ordered Array/README.markdown b/Ordered Array/README.markdown index f64e55057..ca088c325 100644 --- a/Ordered Array/README.markdown +++ b/Ordered Array/README.markdown @@ -8,28 +8,28 @@ The implementation is quite basic. It's simply a wrapper around Swift's built-in ```swift public struct OrderedArray { - private var array = [T]() - + fileprivate var array = [T]() + public init(array: [T]) { - self.array = array.sort() + self.array = array.sorted() } public var isEmpty: Bool { return array.isEmpty } - + public var count: Int { return array.count } - + public subscript(index: Int) -> T { return array[index] } - + public mutating func removeAtIndex(index: Int) -> T { - return array.removeAtIndex(index) + return array.remove(at: index) } - + public mutating func removeAll() { array.removeAll() } @@ -47,13 +47,13 @@ As you can see, all these methods simply call the corresponding method on the in What remains is the `insert()` function. Here is an initial stab at it: ```swift - public mutating func insert(newElement: T) -> Int { + public mutating func insert(_ newElement: T) -> Int { let i = findInsertionPoint(newElement) - array.insert(newElement, atIndex: i) + array.insert(newElement, at: i) return i } - private func findInsertionPoint(newElement: T) -> Int { + private func findInsertionPoint(_ newElement: T) -> Int { for i in 0.. **Note:** Quite conveniently, `array.insert(... atIndex: array.count)` adds the new object to the end of the array, so if no suitable insertion point was found we can simply return `array.count` as the index. @@ -81,26 +81,28 @@ a.insert(10) // inserted at index 8 a // [-2, -1, 1, 3, 4, 5, 7, 9, 10] ``` -The array's contents will always be sorted from low to high, now matter what. +The array's contents will always be sorted from low to high, now matter what. Unfortunately, the current `findInsertionPoint()` function is a bit slow. In the worst case, it needs to scan through the entire array. We can speed this up by using a [binary search](../Binary Search) to find the insertion point. Here is the new version: ```swift - private func findInsertionPoint(newElement: T) -> Int { - var range = 0.. Int { + var startIndex = 0 + var endIndex = array.count + + while startIndex < endIndex { + let midIndex = startIndex + (endIndex - startIndex) / 2 + if array[midIndex] == newElement { + return midIndex + } else if array[midIndex] < newElement { + startIndex = midIndex + 1 + } else { + endIndex = midIndex + } } - return range.startIndex + return startIndex } ``` From 9cb0ca2ecffdda661fb4286bf077660c5775b326 Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 22 Sep 2016 02:19:54 +0200 Subject: [PATCH 0156/1275] updated Priority Queue to swift 3 --- Priority Queue/PriorityQueue.swift | 10 +++++----- Priority Queue/README.markdown | 4 ++-- Priority Queue/Tests/Tests.xcodeproj/project.pbxproj | 10 +++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Priority Queue/PriorityQueue.swift b/Priority Queue/PriorityQueue.swift index 757a6c539..92f7b6d3f 100644 --- a/Priority Queue/PriorityQueue.swift +++ b/Priority Queue/PriorityQueue.swift @@ -11,13 +11,13 @@ queue (largest element first) or a min-priority queue (smallest element first). */ public struct PriorityQueue { - private var heap: Heap + fileprivate var heap: Heap /* To create a max-priority queue, supply a > sort function. For a min-priority queue, use <. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { heap = Heap(sort: sort) } @@ -33,7 +33,7 @@ public struct PriorityQueue { return heap.peek() } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { heap.insert(element) } @@ -52,7 +52,7 @@ public struct PriorityQueue { } extension PriorityQueue where T: Equatable { - public func indexOf(element: T) -> Int? { - return heap.indexOf(element) + public func index(of element: T) -> Int? { + return heap.index(of: element) } } diff --git a/Priority Queue/README.markdown b/Priority Queue/README.markdown index 0c04e7445..8308ec16f 100644 --- a/Priority Queue/README.markdown +++ b/Priority Queue/README.markdown @@ -8,7 +8,7 @@ The queue can be a *max-priority* queue (largest element first) or a *min-priori Priority queues are useful for algorithms that need to process a (large) number of items and where you repeatedly need to identify which one is now the biggest or smallest -- or however you define "most important". -Examples of algorithms that can benefit from a priority queue: +Examples of algorithms that can benefit from a priority queue: - Event-driven simulations. Each event is given a timestamp and you want events to be performed in order of their timestamps. The priority queue makes it easy to find the next event that needs to be simulated. - Dijkstra's algorithm for graph searching uses a priority queue to calculate the minimum cost. @@ -39,7 +39,7 @@ Here's a Swift priority queue based on a heap: ```swift public struct PriorityQueue { - private var heap: Heap + fileprivate var heap: Heap public init(sort: (T, T) -> Bool) { heap = Heap(sort: sort) diff --git a/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj index 5c6a20355..77423c57a 100644 --- a/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -224,6 +230,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; }; name = Debug; }; @@ -235,6 +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_VERSION = 3.0; }; name = Release; }; diff --git a/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 22 Sep 2016 02:52:40 +0200 Subject: [PATCH 0157/1275] updated Ordered Set to swift 3 --- .../Example 1.xcplaygroundpage/Contents.swift | 2 +- .../timeline.xctimeline | 21 ++++++++++ .../Example 2.xcplaygroundpage/Contents.swift | 2 +- .../Example 3.xcplaygroundpage/Contents.swift | 6 +-- .../timeline.xctimeline | 6 +++ .../Sources/OrderedSet.swift | 24 +++++------ .../Sources/Player.swift | 2 +- .../Sources/Random.swift | 2 +- Ordered Set/README.markdown | 40 +++++++++---------- 9 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline create mode 100644 Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift b/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift index c1fe6fe11..2420019fc 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift +++ b/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift @@ -4,7 +4,7 @@ var mySet = OrderedSet() // Insert random numbers into the set for _ in 0..<50 { - mySet.insert(random(50, max: 500)) + mySet.insert(random(min: 50, max: 500)) } print(mySet) diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline b/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 000000000..454d1011b --- /dev/null +++ b/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift b/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift index 6fc1f66ed..c30260fff 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift +++ b/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift @@ -23,7 +23,7 @@ print(playerSet.max()) print(playerSet.min()) // We'll find our player now: -let level = playerSet.count - playerSet.indexOf(anotherPlayer)! +let level = playerSet.count - playerSet.index(of: anotherPlayer)! print("\(anotherPlayer.name) is ranked at level \(level) with \(anotherPlayer.points) points") //: [Next](@next) diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift b/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift index 872b5aeb4..52f154c05 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift +++ b/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift @@ -17,6 +17,6 @@ repeatedSet.insert(Player(name: "Player 9", points: 25)) print(repeatedSet) //debugPrint(repeatedSet) -print(repeatedSet.indexOf(Player(name: "Player 5", points: 100))) -print(repeatedSet.indexOf(Player(name: "Random Player", points: 100))) -print(repeatedSet.indexOf(Player(name: "Player 5", points: 1000))) +print(repeatedSet.index(of: Player(name: "Player 5", points: 100))) +print(repeatedSet.index(of: Player(name: "Random Player", points: 100))) +print(repeatedSet.index(of: Player(name: "Player 5", points: 1000))) diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline b/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift index a8b3b0966..8490a3320 100644 --- a/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift +++ b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift @@ -14,7 +14,7 @@ public struct OrderedSet { } // Inserts an item. Performance: O(n) - public mutating func insert(item: T) { + public mutating func insert(_ item: T) { if exists(item) { return // don't add an item if it already exists } @@ -22,7 +22,7 @@ public struct OrderedSet { // Insert new the item just before the one that is larger. for i in 0.. item { - internalSet.insert(item, atIndex: i) + internalSet.insert(item, at: i) return } } @@ -32,19 +32,19 @@ public struct OrderedSet { } // Removes an item if it exists. Performance: O(n) - public mutating func remove(item: T) { - if let index = indexOf(item) { - internalSet.removeAtIndex(index) + 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 indexOf(item) != nil + 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 indexOf(item: T) -> Int? { + public func index(of item: T) -> Int? { var leftBound = 0 var rightBound = count - 1 @@ -64,7 +64,7 @@ public struct OrderedSet { // 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) { + 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] { @@ -73,7 +73,7 @@ public struct OrderedSet { } // Check to the left. - for j in mid.stride(to: 0, by: -1) { + 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] { @@ -105,13 +105,13 @@ public struct OrderedSet { // 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? { + 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? { + public func kSmallest(_ k: Int) -> T? { return k > count || k <= 0 ? nil : internalSet[k - 1] } } diff --git a/Ordered Set/OrderedSet.playground/Sources/Player.swift b/Ordered Set/OrderedSet.playground/Sources/Player.swift index 9357744db..26835b0a8 100644 --- a/Ordered Set/OrderedSet.playground/Sources/Player.swift +++ b/Ordered Set/OrderedSet.playground/Sources/Player.swift @@ -6,7 +6,7 @@ public struct Player: Comparable { public init() { self.name = String.random() - self.points = random(0, max: 5000) + self.points = random(min: 0, max: 5000) } public init(name: String, points: Int) { diff --git a/Ordered Set/OrderedSet.playground/Sources/Random.swift b/Ordered Set/OrderedSet.playground/Sources/Random.swift index b6e1f7736..eccd65df6 100644 --- a/Ordered Set/OrderedSet.playground/Sources/Random.swift +++ b/Ordered Set/OrderedSet.playground/Sources/Random.swift @@ -13,7 +13,7 @@ extension String { for _ in 0.. { 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){ + public mutating func insert(_ item: T){ if exists(item) { return // don't add an item if it already exists } @@ -63,7 +63,7 @@ Lets take a look at the `insert()` function first. This first checks if the item // Insert new the item just before the one that is larger. for i in 0.. item { - internalSet.insert(item, atIndex: i) + internalSet.insert(item, at: i) return } } @@ -82,19 +82,19 @@ 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 = indexOf(item) { - internalSet.removeAtIndex(index) + 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. +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 indexOf(item: T) -> Int? { + public func index(of item: T) -> Int? { var leftBound = 0 var rightBound = count - 1 @@ -115,9 +115,9 @@ The next function is `indexOf()`, which takes in an object of type `T` and retur } ``` -> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary Search). +> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary Search). -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. +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: @@ -147,13 +147,13 @@ Therefore, we also need to check the items with the same value to the right and 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. +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)**: @@ -168,15 +168,15 @@ Since the set is sorted, the following operations are all **O(1)**: return count == 0 ? nil : internalSet[0] } - // Returns the k-th largest element in the set, if k is in the range + // 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? { + 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? { + public func kSmallest(_ k: Int) -> T? { return k > count || k <= 0 ? nil : internalSet[k - 1] } ``` @@ -228,7 +228,7 @@ public struct Player: Comparable { 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 @@ -272,7 +272,7 @@ print("\(anotherPlayer.name) is ranked at level \(level) with \(anotherPlayer.po ### Example 3 -The final example demonstrates the need to look for the right item even after the binary search has completed. +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: @@ -299,7 +299,7 @@ The set looks something like this: The next line looks for `Player 2`: ```swift -print(repeatedSet.indexOf(Player(name: "Player 2", points: 100))) +print(repeatedSet.index(of: Player(name: "Player 2", points: 100))) ``` After the binary search finishes, the value of `mid` is at index 5: @@ -312,7 +312,7 @@ However, this is not `Player 2`. Both `Player 4` and `Player 2` have the same po 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 + mid The code then first checks on the right of `mid` (where the `*` is): From 8e4dbdb2721d8171f7ab95dfa0d478c6b9607691 Mon Sep 17 00:00:00 2001 From: ssarber Date: Fri, 23 Sep 2016 10:57:21 -0700 Subject: [PATCH 0158/1275] Convert to Swift 3 syntax to get rid of Xcode 8 errors --- Counting Sort/CountingSort.playground/Contents.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index 67d416f2f..2d85347ef 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -enum CountingSortError: ErrorType { +enum CountingSortError: Error { case ArrayEmpty } @@ -11,9 +11,9 @@ func countingSort(array: [Int]) throws -> [Int] { // Step 1 // Create an array to store the count of each element - let maxElement = array.maxElement() ?? 0 + let maxElement = array.max() ?? 0 - var countArray = [Int](count: Int(maxElement + 1), repeatedValue: 0) + var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) for element in array { countArray[element] += 1 } @@ -29,7 +29,7 @@ func countingSort(array: [Int]) throws -> [Int] { // Step 3 // Place the element in the final array as per the number of elements before it - var sortedArray = [Int](count: array.count, repeatedValue: 0) + var sortedArray = [Int](repeating: 0, count: array.count) for element in array { countArray[element] -= 1 sortedArray[countArray[element]] = element @@ -38,4 +38,4 @@ func countingSort(array: [Int]) throws -> [Int] { } -try countingSort([10, 9, 8, 7, 1, 2, 7, 3]) +try countingSort(array: [10, 9, 8, 7, 1, 2, 7, 3]) \ No newline at end of file From 17887c35c322a1361c82b8f40b36f636c780101d Mon Sep 17 00:00:00 2001 From: ssarber Date: Fri, 23 Sep 2016 12:16:23 -0700 Subject: [PATCH 0159/1275] Update readme --- Counting Sort/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Counting Sort/README.markdown b/Counting Sort/README.markdown index 55b60104f..959becc8c 100644 --- a/Counting Sort/README.markdown +++ b/Counting Sort/README.markdown @@ -20,9 +20,9 @@ Count 0 1 1 1 0 0 0 2 1 1 1 Here is the code to accomplish this: ```swift - let maxElement = array.maxElement() ?? 0 - - var countArray = [Int](count: Int(maxElement + 1), repeatedValue: 0) + let maxElement = array.max() ?? 0 + + var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) for element in array { countArray[element] += 1 } @@ -62,7 +62,7 @@ Output 1 2 3 7 7 8 9 10 Here is the code for this final step: ```swift - var sortedArray = [Int](count: array.count, repeatedValue: 0) + var sortedArray = [Int](repeating: 0, count: array.count) for element in array { countArray[element] -= 1 sortedArray[countArray[element]] = element From 4470e09fd636ddfad61848dc99ed26e07e6a37f3 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 24 Sep 2016 14:04:23 +0200 Subject: [PATCH 0160/1275] first commit: added Knuth-Morris-Pratt and Z algorithms for string search --- .../Contents.swift | 122 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../timeline.xctimeline | 6 + Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 65 ++++++++++ Z-Algorithm/ZAlgorithm.swift | 66 ++++++++++ .../ZetaAlgorithm.playground/Contents.swift | 95 ++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../timeline.xctimeline | 6 + Z-Algorithm/ZetaAlgorithm.swift | 32 +++++ 11 files changed, 414 insertions(+) create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.swift create mode 100644 Z-Algorithm/ZAlgorithm.swift create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/Contents.swift create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline create mode 100644 Z-Algorithm/ZetaAlgorithm.swift diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift new file mode 100644 index 000000000..147477c80 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -0,0 +1,122 @@ +//: Playground - noun: a place where people can play + + +func ZetaAlgorithm(ptnr: String) -> [Int]? { + + let pattern = Array(ptnr.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} + +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self.characters) + let pattern = Array(ptnr.characters) + + let textLength: Int = text.count + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + var textIndex: Int = 0 + var patternIndex: Int = 0 + var indexes: [Int] = [Int]() + + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ + let zeta = ZetaAlgorithm(ptnr) + + for patternIndex in (1 ..< patternLength).reverse() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] + } + + /* Search stage: scanning the text for pattern matching */ + textIndex = 0 + patternIndex = 0 + + while textIndex + (patternLength - patternIndex - 1) < textLength { + + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + if patternIndex == patternLength { + indexes.append(textIndex - patternIndex) + } + + if patternIndex == 0 { + textIndex = textIndex + 1 + } else { + patternIndex = suffixPrefix[patternIndex - 1] + } + } + + guard !indexes.isEmpty else { + return nil + } + return indexes + } +} + +/* Examples */ + +let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" +dna.indexesOf("CATA") // [20, 64, 130, 140, 166, 234, 255, 270] + +let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" +concert.indexesOf("🎻🎷") // [6] diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift new file mode 100644 index 000000000..5cce1556f --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -0,0 +1,65 @@ +/* Knuth-Morris-Pratt algorithm for pattern/string matching + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self.characters) + let pattern = Array(ptnr.characters) + + let textLength: Int = text.count + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + var textIndex: Int = 0 + var patternIndex: Int = 0 + var indexes: [Int] = [Int]() + + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ + let zeta = ZetaAlgorithm(ptnr) + + for patternIndex in (1 ..< patternLength).reverse() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] + } + + /* Search stage: scanning the text for pattern matching */ + textIndex = 0 + patternIndex = 0 + + while textIndex + (patternLength - patternIndex - 1) < textLength { + + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + if patternIndex == patternLength { + indexes.append(textIndex - patternIndex) + } + + if patternIndex == 0 { + textIndex = textIndex + 1 + } else { + patternIndex = suffixPrefix[patternIndex - 1] + } + } + + guard !indexes.isEmpty else { + return nil + } + return indexes + } +} diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift new file mode 100644 index 000000000..3b6d34908 --- /dev/null +++ b/Z-Algorithm/ZAlgorithm.swift @@ -0,0 +1,66 @@ +/* Z-Algorithm for pattern/string pre-processing + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +func ZetaAlgorithm(ptrn: String) -> [Int]? { + + let pattern = Array(ptrn.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..dfe24ddf6 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -0,0 +1,95 @@ +//: Playground - noun: a place where people can play + + +func ZetaAlgorithm(ptrn: String) -> [Int]? { + + let pattern = Array(ptrn.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} + + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength: Int = pattern.characters.count + let zeta = ZetaAlgorithm(pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + + var indexes: [Int] = [Int]() + + /* Scan the zeta array to find matched patterns */ + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) + } + } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } +} + +/* Examples */ + +let str = "Hello, playground!" +str.indexesOf("ground") // [11] + +let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" +traffic.indexesOf("🚑") // [4, 21] diff --git a/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground b/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata b/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift new file mode 100644 index 000000000..c31e27c66 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -0,0 +1,32 @@ +/* Z-Algorithm based algorithm for pattern/string matching + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength: Int = pattern.characters.count + let zeta = ZetaAlgorithm(pattern + "💲" + self) + + var indexes: [Int] = [Int]() + + /* Scan the zeta array to find matched patterns */ + for index in indexes { + if index == patternLength { + indexes.append(index) + } + } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } +} From 6230a2bbc54bb08b9815764bcfc7909d471131c2 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 24 Sep 2016 14:31:50 +0200 Subject: [PATCH 0161/1275] removed directories --- .../Contents.swift | 122 ------------------ .../contents.xcplayground | 4 - .../contents.xcworkspacedata | 7 - .../timeline.xctimeline | 6 - Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 65 ---------- Z-Algorithm/ZAlgorithm.swift | 66 ---------- .../ZetaAlgorithm.playground/Contents.swift | 95 -------------- .../contents.xcplayground | 4 - .../contents.xcworkspacedata | 7 - .../timeline.xctimeline | 6 - Z-Algorithm/ZetaAlgorithm.swift | 32 ----- 11 files changed, 414 deletions(-) delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.swift delete mode 100644 Z-Algorithm/ZAlgorithm.swift delete mode 100644 Z-Algorithm/ZetaAlgorithm.playground/Contents.swift delete mode 100644 Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground delete mode 100644 Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata delete mode 100644 Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline delete mode 100644 Z-Algorithm/ZetaAlgorithm.swift diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift deleted file mode 100644 index 147477c80..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift +++ /dev/null @@ -1,122 +0,0 @@ -//: Playground - noun: a place where people can play - - -func ZetaAlgorithm(ptnr: String) -> [Int]? { - - let pattern = Array(ptnr.characters) - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) - - var left: Int = 0 - var right: Int = 0 - var k_1: Int = 0 - var betaLength: Int = 0 - var textIndex: Int = 0 - var patternIndex: Int = 0 - - for k in 1 ..< patternLength { - if k > right { - patternIndex = 0 - - while k + patternIndex < patternLength && - pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - - if zeta[k] > 0 { - left = k - right = k + zeta[k] - 1 - } - } else { - k_1 = k - left + 1 - betaLength = right - k + 1 - - if zeta[k_1 - 1] < betaLength { - zeta[k] = zeta[k_1 - 1] - } else if zeta[k_1 - 1] >= betaLength { - textIndex = betaLength - patternIndex = right + 1 - - while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - zeta[k] = patternIndex - k - left = k - right = patternIndex - 1 - } - } - } - return zeta -} - -extension String { - - func indexesOf(ptnr: String) -> [Int]? { - - let text = Array(self.characters) - let pattern = Array(ptnr.characters) - - let textLength: Int = text.count - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) - var textIndex: Int = 0 - var patternIndex: Int = 0 - var indexes: [Int] = [Int]() - - /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ - let zeta = ZetaAlgorithm(ptnr) - - for patternIndex in (1 ..< patternLength).reverse() { - textIndex = patternIndex + zeta![patternIndex] - 1 - suffixPrefix[textIndex] = zeta![patternIndex] - } - - /* Search stage: scanning the text for pattern matching */ - textIndex = 0 - patternIndex = 0 - - while textIndex + (patternLength - patternIndex - 1) < textLength { - - while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - if patternIndex == patternLength { - indexes.append(textIndex - patternIndex) - } - - if patternIndex == 0 { - textIndex = textIndex + 1 - } else { - patternIndex = suffixPrefix[patternIndex - 1] - } - } - - guard !indexes.isEmpty else { - return nil - } - return indexes - } -} - -/* Examples */ - -let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" -dna.indexesOf("CATA") // [20, 64, 130, 140, 166, 234, 255, 270] - -let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" -concert.indexesOf("🎻🎷") // [6] diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground deleted file mode 100644 index 06828af92..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift deleted file mode 100644 index 5cce1556f..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift +++ /dev/null @@ -1,65 +0,0 @@ -/* Knuth-Morris-Pratt algorithm for pattern/string matching - - The code is based on the book: - "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" - by Dan Gusfield - Cambridge University Press, 1997 -*/ - -import Foundation - -extension String { - - func indexesOf(ptnr: String) -> [Int]? { - - let text = Array(self.characters) - let pattern = Array(ptnr.characters) - - let textLength: Int = text.count - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) - var textIndex: Int = 0 - var patternIndex: Int = 0 - var indexes: [Int] = [Int]() - - /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ - let zeta = ZetaAlgorithm(ptnr) - - for patternIndex in (1 ..< patternLength).reverse() { - textIndex = patternIndex + zeta![patternIndex] - 1 - suffixPrefix[textIndex] = zeta![patternIndex] - } - - /* Search stage: scanning the text for pattern matching */ - textIndex = 0 - patternIndex = 0 - - while textIndex + (patternLength - patternIndex - 1) < textLength { - - while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - if patternIndex == patternLength { - indexes.append(textIndex - patternIndex) - } - - if patternIndex == 0 { - textIndex = textIndex + 1 - } else { - patternIndex = suffixPrefix[patternIndex - 1] - } - } - - guard !indexes.isEmpty else { - return nil - } - return indexes - } -} diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift deleted file mode 100644 index 3b6d34908..000000000 --- a/Z-Algorithm/ZAlgorithm.swift +++ /dev/null @@ -1,66 +0,0 @@ -/* Z-Algorithm for pattern/string pre-processing - - The code is based on the book: - "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" - by Dan Gusfield - Cambridge University Press, 1997 -*/ - -import Foundation - -func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) - - var left: Int = 0 - var right: Int = 0 - var k_1: Int = 0 - var betaLength: Int = 0 - var textIndex: Int = 0 - var patternIndex: Int = 0 - - for k in 1 ..< patternLength { - if k > right { - patternIndex = 0 - - while k + patternIndex < patternLength && - pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - - if zeta[k] > 0 { - left = k - right = k + zeta[k] - 1 - } - } else { - k_1 = k - left + 1 - betaLength = right - k + 1 - - if zeta[k_1 - 1] < betaLength { - zeta[k] = zeta[k_1 - 1] - } else if zeta[k_1 - 1] >= betaLength { - textIndex = betaLength - patternIndex = right + 1 - - while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - k - left = k - right = patternIndex - 1 - } - } - } - return zeta -} diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift deleted file mode 100644 index dfe24ddf6..000000000 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ /dev/null @@ -1,95 +0,0 @@ -//: Playground - noun: a place where people can play - - -func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) - - var left: Int = 0 - var right: Int = 0 - var k_1: Int = 0 - var betaLength: Int = 0 - var textIndex: Int = 0 - var patternIndex: Int = 0 - - for k in 1 ..< patternLength { - if k > right { - patternIndex = 0 - - while k + patternIndex < patternLength && - pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - - if zeta[k] > 0 { - left = k - right = k + zeta[k] - 1 - } - } else { - k_1 = k - left + 1 - betaLength = right - k + 1 - - if zeta[k_1 - 1] < betaLength { - zeta[k] = zeta[k_1 - 1] - } else if zeta[k_1 - 1] >= betaLength { - textIndex = betaLength - patternIndex = right + 1 - - while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - k - left = k - right = patternIndex - 1 - } - } - } - return zeta -} - - -extension String { - - func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(pattern + "💲" + self) - - guard zeta != nil else { - return nil - } - - var indexes: [Int] = [Int]() - - /* Scan the zeta array to find matched patterns */ - for i in 0 ..< zeta!.count { - if zeta![i] == patternLength { - indexes.append(i - patternLength - 1) - } - } - - guard !indexes.isEmpty else { - return nil - } - - return indexes - } -} - -/* Examples */ - -let str = "Hello, playground!" -str.indexesOf("ground") // [11] - -let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" -traffic.indexesOf("🚑") // [4, 21] diff --git a/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground b/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground deleted file mode 100644 index 06828af92..000000000 --- a/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata b/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift deleted file mode 100644 index c31e27c66..000000000 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ /dev/null @@ -1,32 +0,0 @@ -/* Z-Algorithm based algorithm for pattern/string matching - - The code is based on the book: - "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" - by Dan Gusfield - Cambridge University Press, 1997 -*/ - -import Foundation - -extension String { - - func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(pattern + "💲" + self) - - var indexes: [Int] = [Int]() - - /* Scan the zeta array to find matched patterns */ - for index in indexes { - if index == patternLength { - indexes.append(index) - } - } - - guard !indexes.isEmpty else { - return nil - } - - return indexes - } -} From c416818dc12878181d8c5a0e54b78be72f68c665 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 24 Sep 2016 14:41:37 +0200 Subject: [PATCH 0162/1275] first commit: added Knuth-Morris-Pratt and Z algorithms implementation --- .../Contents.swift | 122 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../timeline.xctimeline | 6 + Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 65 ++++++++++ Z-Algorithm/ZAlgorithm.swift | 66 ++++++++++ .../ZetaAlgorithm.playground/Contents.swift | 95 ++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../timeline.xctimeline | 6 + Z-Algorithm/ZetaAlgorithm.swift | 32 +++++ 11 files changed, 414 insertions(+) create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline create mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.swift create mode 100644 Z-Algorithm/ZAlgorithm.swift create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/Contents.swift create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline create mode 100644 Z-Algorithm/ZetaAlgorithm.swift diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift new file mode 100644 index 000000000..147477c80 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -0,0 +1,122 @@ +//: Playground - noun: a place where people can play + + +func ZetaAlgorithm(ptnr: String) -> [Int]? { + + let pattern = Array(ptnr.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} + +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self.characters) + let pattern = Array(ptnr.characters) + + let textLength: Int = text.count + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + var textIndex: Int = 0 + var patternIndex: Int = 0 + var indexes: [Int] = [Int]() + + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ + let zeta = ZetaAlgorithm(ptnr) + + for patternIndex in (1 ..< patternLength).reverse() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] + } + + /* Search stage: scanning the text for pattern matching */ + textIndex = 0 + patternIndex = 0 + + while textIndex + (patternLength - patternIndex - 1) < textLength { + + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + if patternIndex == patternLength { + indexes.append(textIndex - patternIndex) + } + + if patternIndex == 0 { + textIndex = textIndex + 1 + } else { + patternIndex = suffixPrefix[patternIndex - 1] + } + } + + guard !indexes.isEmpty else { + return nil + } + return indexes + } +} + +/* Examples */ + +let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" +dna.indexesOf("CATA") // [20, 64, 130, 140, 166, 234, 255, 270] + +let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" +concert.indexesOf("🎻🎷") // [6] diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift new file mode 100644 index 000000000..5cce1556f --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -0,0 +1,65 @@ +/* Knuth-Morris-Pratt algorithm for pattern/string matching + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self.characters) + let pattern = Array(ptnr.characters) + + let textLength: Int = text.count + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + var textIndex: Int = 0 + var patternIndex: Int = 0 + var indexes: [Int] = [Int]() + + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ + let zeta = ZetaAlgorithm(ptnr) + + for patternIndex in (1 ..< patternLength).reverse() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] + } + + /* Search stage: scanning the text for pattern matching */ + textIndex = 0 + patternIndex = 0 + + while textIndex + (patternLength - patternIndex - 1) < textLength { + + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + if patternIndex == patternLength { + indexes.append(textIndex - patternIndex) + } + + if patternIndex == 0 { + textIndex = textIndex + 1 + } else { + patternIndex = suffixPrefix[patternIndex - 1] + } + } + + guard !indexes.isEmpty else { + return nil + } + return indexes + } +} diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift new file mode 100644 index 000000000..3b6d34908 --- /dev/null +++ b/Z-Algorithm/ZAlgorithm.swift @@ -0,0 +1,66 @@ +/* Z-Algorithm for pattern/string pre-processing + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +func ZetaAlgorithm(ptrn: String) -> [Int]? { + + let pattern = Array(ptrn.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..dfe24ddf6 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -0,0 +1,95 @@ +//: Playground - noun: a place where people can play + + +func ZetaAlgorithm(ptrn: String) -> [Int]? { + + let pattern = Array(ptrn.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} + + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength: Int = pattern.characters.count + let zeta = ZetaAlgorithm(pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + + var indexes: [Int] = [Int]() + + /* Scan the zeta array to find matched patterns */ + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) + } + } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } +} + +/* Examples */ + +let str = "Hello, playground!" +str.indexesOf("ground") // [11] + +let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" +traffic.indexesOf("🚑") // [4, 21] diff --git a/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground b/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata b/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift new file mode 100644 index 000000000..c31e27c66 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -0,0 +1,32 @@ +/* Z-Algorithm based algorithm for pattern/string matching + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 +*/ + +import Foundation + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength: Int = pattern.characters.count + let zeta = ZetaAlgorithm(pattern + "💲" + self) + + var indexes: [Int] = [Int]() + + /* Scan the zeta array to find matched patterns */ + for index in indexes { + if index == patternLength { + indexes.append(index) + } + } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } +} From e3967dfdd69b3a04243760d4ce73fd83576fef15 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 24 Sep 2016 21:15:04 +0200 Subject: [PATCH 0163/1275] swift 3 fix --- .../Contents.swift | 12 +++---- .../timeline.xctimeline | 6 ---- Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 32 +++++++++---------- Z-Algorithm/ZAlgorithm.swift | 26 +++++++-------- .../ZetaAlgorithm.playground/Contents.swift | 8 ++--- .../timeline.xctimeline | 6 ---- Z-Algorithm/ZetaAlgorithm.swift | 22 +++++++------ 7 files changed, 52 insertions(+), 60 deletions(-) delete mode 100644 Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline delete mode 100644 Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift index 147477c80..35fb27ff8 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -10,7 +10,7 @@ func ZetaAlgorithm(ptnr: String) -> [Int]? { return nil } - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + var zeta: [Int] = [Int](repeating: 0, count: patternLength) var left: Int = 0 var right: Int = 0 @@ -71,15 +71,15 @@ extension String { return nil } - var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + var suffixPrefix: [Int] = [Int](repeating: 0, count: patternLength) var textIndex: Int = 0 var patternIndex: Int = 0 var indexes: [Int] = [Int]() /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ - let zeta = ZetaAlgorithm(ptnr) + let zeta = ZetaAlgorithm(ptnr: ptnr) - for patternIndex in (1 ..< patternLength).reverse() { + for patternIndex in (1 ..< patternLength).reversed() { textIndex = patternIndex + zeta![patternIndex] - 1 suffixPrefix[textIndex] = zeta![patternIndex] } @@ -116,7 +116,7 @@ extension String { /* Examples */ let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" -dna.indexesOf("CATA") // [20, 64, 130, 140, 166, 234, 255, 270] +dna.indexesOf(ptnr: "CATA") // [20, 64, 130, 140, 166, 234, 255, 270] let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" -concert.indexesOf("🎻🎷") // [6] +concert.indexesOf(ptnr: "🎻🎷") // [6] diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift index 5cce1556f..46a88c134 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -9,54 +9,54 @@ import Foundation extension String { - + func indexesOf(ptnr: String) -> [Int]? { - + let text = Array(self.characters) let pattern = Array(ptnr.characters) - + let textLength: Int = text.count let patternLength: Int = pattern.count - + guard patternLength > 0 else { return nil } - - var suffixPrefix: [Int] = [Int](count: patternLength, repeatedValue: 0) + + var suffixPrefix: [Int] = [Int](repeating: 0, count: patternLength) var textIndex: Int = 0 var patternIndex: Int = 0 var indexes: [Int] = [Int]() - + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ - let zeta = ZetaAlgorithm(ptnr) - - for patternIndex in (1 ..< patternLength).reverse() { + let zeta = ZetaAlgorithm(ptnr: ptnr) + + for patternIndex in (1 ..< patternLength).reversed() { textIndex = patternIndex + zeta![patternIndex] - 1 suffixPrefix[textIndex] = zeta![patternIndex] } - + /* Search stage: scanning the text for pattern matching */ textIndex = 0 patternIndex = 0 - + while textIndex + (patternLength - patternIndex - 1) < textLength { - + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { textIndex = textIndex + 1 patternIndex = patternIndex + 1 } - + if patternIndex == patternLength { indexes.append(textIndex - patternIndex) } - + if patternIndex == 0 { textIndex = textIndex + 1 } else { patternIndex = suffixPrefix[patternIndex - 1] } } - + guard !indexes.isEmpty else { return nil } diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift index 3b6d34908..c9d7de876 100644 --- a/Z-Algorithm/ZAlgorithm.swift +++ b/Z-Algorithm/ZAlgorithm.swift @@ -9,34 +9,34 @@ import Foundation func ZetaAlgorithm(ptrn: String) -> [Int]? { - + let pattern = Array(ptrn.characters) let patternLength: Int = pattern.count - + guard patternLength > 0 else { return nil } - - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) - + + var zeta: [Int] = [Int](repeating: 0, count: patternLength) + var left: Int = 0 var right: Int = 0 var k_1: Int = 0 var betaLength: Int = 0 var textIndex: Int = 0 var patternIndex: Int = 0 - + for k in 1 ..< patternLength { if k > right { patternIndex = 0 - + while k + patternIndex < patternLength && pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 + patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - + if zeta[k] > 0 { left = k right = k + zeta[k] - 1 @@ -44,18 +44,18 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { } else { k_1 = k - left + 1 betaLength = right - k + 1 - + if zeta[k_1 - 1] < betaLength { zeta[k] = zeta[k_1 - 1] } else if zeta[k_1 - 1] >= betaLength { textIndex = betaLength patternIndex = right + 1 - + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { textIndex = textIndex + 1 patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - k left = k right = patternIndex - 1 diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift index dfe24ddf6..c9d942149 100644 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -10,7 +10,7 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { return nil } - var zeta: [Int] = [Int](count: patternLength, repeatedValue: 0) + var zeta: [Int] = [Int](repeating: 0, count: patternLength) var left: Int = 0 var right: Int = 0 @@ -63,7 +63,7 @@ extension String { func indexesOf(pattern: String) -> [Int]? { let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(pattern + "💲" + self) + let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) guard zeta != nil else { return nil @@ -89,7 +89,7 @@ extension String { /* Examples */ let str = "Hello, playground!" -str.indexesOf("ground") // [11] +str.indexesOf(pattern: "ground") // [11] let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" -traffic.indexesOf("🚑") // [4, 21] +traffic.indexesOf(pattern: "🚑") // [4, 21] diff --git a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline b/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Z-Algorithm/ZetaAlgorithm.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift index c31e27c66..4d80aa665 100644 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -9,24 +9,28 @@ import Foundation extension String { - + func indexesOf(pattern: String) -> [Int]? { let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(pattern + "💲" + self) - + let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + var indexes: [Int] = [Int]() - + /* Scan the zeta array to find matched patterns */ - for index in indexes { - if index == patternLength { - indexes.append(index) + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) } } - + guard !indexes.isEmpty else { return nil } - + return indexes } } From aeaa72a741e2213cfaf3e55bb8f915fb5176f3e8 Mon Sep 17 00:00:00 2001 From: Richard Date: Sat, 24 Sep 2016 15:29:51 -0700 Subject: [PATCH 0164/1275] Updated syntax to Swift 3 --- .../Contents.swift | 30 +++++++++++-------- .../KaratsubaMultiplication.swift | 21 +++++++++---- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index bf4454956..53980ac1e 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -2,17 +2,23 @@ import Foundation -infix operator ^^ { associativity left precedence 160 } +precedencegroup ExponentiativePrecedence { + higherThan: MultiplicationPrecedence + lowerThan: BitwiseShiftPrecedence + associativity: left +} + +infix operator ^^: ExponentiativePrecedence func ^^ (radix: Int, power: Int) -> Int { return Int(pow(Double(radix), Double(power))) } // Long Multiplication - O(n^2) -func multiply(num1: Int, _ num2: Int, base: Int = 10) -> Int { - let num1Array = String(num1).characters.reverse().map{ Int(String($0))! } - let num2Array = String(num2).characters.reverse().map{ Int(String($0))! } +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))! } - var product = Array(count: num1Array.count + num2Array.count, repeatedValue: 0) + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) for i in num1Array.indices { var carry = 0 @@ -24,16 +30,16 @@ func multiply(num1: Int, _ num2: Int, base: Int = 10) -> Int { product[i + num2Array.count] += carry } - return Int(product.reverse().map{ String($0) }.reduce("", combine: +))! + return Int(product.reversed().map{ String($0) }.reduce("", +))! } // Karatsuba Multiplication - O(nlogn) -func karatsuba(num1: Int, _ num2: Int) -> Int { +func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1Array = String(num1).characters let num2Array = String(num2).characters guard num1Array.count > 1 && num2Array.count > 1 else { - return multiply(num1, num2) + return multiply(num1, by: num2) } let n = max(num1Array.count, num2Array.count) @@ -44,14 +50,12 @@ func karatsuba(num1: Int, _ num2: Int) -> Int { let c = num2 / 10^^nBy2 let d = num2 % 10^^nBy2 - let ac = karatsuba(a, c) - let bd = karatsuba(b, d) - let adPluscd = karatsuba(a+b, c+d) - ac - bd + let ac = karatsuba(a, by: c) + let bd = karatsuba(b, by: d) + let adPluscd = karatsuba(a+b, by: c+d) - ac - bd let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd return product } -print(multiply(236742342, 1231234224)) -print(karatsuba(236742342, 1231234224)) \ No newline at end of file diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index a315d7494..7837e3f3c 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -8,7 +8,18 @@ import Foundation -func karatsuba(num1: Int, _ num2: Int) -> Int { +precedencegroup ExponentiativePrecedence { + higherThan: MultiplicationPrecedence + lowerThan: BitwiseShiftPrecedence + associativity: left +} + +infix operator ^^: ExponentiativePrecedence +func ^^ (radix: Int, power: Int) -> Int { + return Int(pow(Double(radix), Double(power))) +} + +func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1Array = String(num1).characters let num2Array = String(num2).characters @@ -24,11 +35,11 @@ func karatsuba(num1: Int, _ num2: Int) -> Int { let c = num2 / 10^^nBy2 let d = num2 % 10^^nBy2 - let ac = karatsuba(a, c) - let bd = karatsuba(b, d) - let adPluscd = karatsuba(a+b, c+d) - ac - bd + let ac = karatsuba(a, by: c) + let bd = karatsuba(b, by: d) + let adPluscd = karatsuba(a+b, by: c+d) - ac - bd let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd return product -} \ No newline at end of file +} From 215ca9352840b52be84fc171954613ddde6f7a5e Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Mon, 26 Sep 2016 17:00:03 +0800 Subject: [PATCH 0165/1275] migrating dfs to swift3 --- .../Simple Example.xcplaygroundpage/Contents.swift | 2 +- .../timeline.xctimeline | 6 ------ .../DepthFirstSearch.playground/Sources/Edge.swift | 4 ++-- .../DepthFirstSearch.playground/Sources/Graph.swift | 12 ++++++------ .../DepthFirstSearch.playground/Sources/Node.swift | 8 ++++---- Depth-First Search/DepthFirstSearch.swift | 2 +- Depth-First Search/README.markdown | 2 +- 7 files changed, 15 insertions(+), 21 deletions(-) delete mode 100644 Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/timeline.xctimeline 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 770712bfb..b1d8494d6 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,4 +1,4 @@ -func depthFirstSearch(graph: Graph, source: Node) -> [String] { +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { var nodesExplored = [source.label] source.visited = true diff --git a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/timeline.xctimeline b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift index 9a58a1f96..7c841be30 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift @@ -1,11 +1,11 @@ public class Edge: Equatable { public var neighbor: Node - public init(neighbor: Node) { + public init(_ neighbor: Node) { self.neighbor = neighbor } } -public func == (lhs: Edge, rhs: Edge) -> Bool { +public func == (_ lhs: Edge, rhs: Edge) -> Bool { return lhs.neighbor == rhs.neighbor } diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift index 8cfb2a09c..87e21897c 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift @@ -5,14 +5,14 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(label: String) -> Node { - let node = Node(label: label) + public func addNode(_ label: String) -> Node { + let node = Node(label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { - let edge = Edge(neighbor: neighbor) + public func addEdge(_ source: Node, neighbor: Node) { + let edge = Edge(neighbor) source.neighbors.append(edge) } @@ -27,7 +27,7 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + public func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } @@ -50,6 +50,6 @@ public class Graph: CustomStringConvertible, Equatable { } } -public func == (lhs: Graph, rhs: Graph) -> Bool { +public func == (_ lhs: Graph, rhs: Graph) -> Bool { return lhs.nodes == rhs.nodes } diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Node.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Node.swift index 37a3b3fdf..48fc952e3 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Sources/Node.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Node.swift @@ -5,7 +5,7 @@ public class Node: CustomStringConvertible, Equatable { public var distance: Int? public var visited: Bool - public init(label: String) { + public init(_ label: String) { self.label = label neighbors = [] visited = false @@ -22,11 +22,11 @@ public class Node: CustomStringConvertible, Equatable { return distance != nil } - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + public func remove(_ edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } } -public func == (lhs: Node, rhs: Node) -> Bool { +public func == (_ lhs: Node, rhs: Node) -> Bool { return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors } diff --git a/Depth-First Search/DepthFirstSearch.swift b/Depth-First Search/DepthFirstSearch.swift index 4393ac864..04e84cb66 100644 --- a/Depth-First Search/DepthFirstSearch.swift +++ b/Depth-First Search/DepthFirstSearch.swift @@ -1,4 +1,4 @@ -func depthFirstSearch(graph: Graph, source: Node) -> [String] { +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { var nodesExplored = [source.label] source.visited = true diff --git a/Depth-First Search/README.markdown b/Depth-First Search/README.markdown index a44ae8163..9e1a5112d 100644 --- a/Depth-First Search/README.markdown +++ b/Depth-First Search/README.markdown @@ -27,7 +27,7 @@ The parent of a node is the one that "discovered" that node. The root of the tre Simple recursive implementation of depth-first search: ```swift -func depthFirstSearch(graph: Graph, source: Node) -> [String] { +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { var nodesExplored = [source.label] source.visited = true From ef081622f899131b7ba45c863637a9049f962d8d Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Mon, 26 Sep 2016 17:04:03 +0800 Subject: [PATCH 0166/1275] migrating bfs to swift3 --- .../Simple example.xcplaygroundpage/Contents.swift | 2 +- .../timeline.xctimeline | 6 ------ .../BreadthFirstSearch.playground/Sources/Edge.swift | 4 ++-- .../Sources/Graph.swift | 12 ++++++------ .../BreadthFirstSearch.playground/Sources/Node.swift | 8 ++++---- .../Sources/Queue.swift | 2 +- Breadth-First Search/BreadthFirstSearch.swift | 2 +- Breadth-First Search/README.markdown | 2 +- 8 files changed, 16 insertions(+), 22 deletions(-) delete mode 100644 Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/timeline.xctimeline 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 93aa6b337..0fb98e1c8 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,4 +1,4 @@ -func breadthFirstSearch(graph: Graph, source: Node) -> [String] { +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { var queue = Queue() queue.enqueue(source) diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/timeline.xctimeline b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift index 9a58a1f96..7c841be30 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift @@ -1,11 +1,11 @@ public class Edge: Equatable { public var neighbor: Node - public init(neighbor: Node) { + public init(_ neighbor: Node) { self.neighbor = neighbor } } -public func == (lhs: Edge, rhs: Edge) -> Bool { +public func == (_ lhs: Edge, rhs: Edge) -> Bool { return lhs.neighbor == rhs.neighbor } diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift index 8cfb2a09c..87e21897c 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift @@ -5,14 +5,14 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(label: String) -> Node { - let node = Node(label: label) + public func addNode(_ label: String) -> Node { + let node = Node(label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { - let edge = Edge(neighbor: neighbor) + public func addEdge(_ source: Node, neighbor: Node) { + let edge = Edge(neighbor) source.neighbors.append(edge) } @@ -27,7 +27,7 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + public func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } @@ -50,6 +50,6 @@ public class Graph: CustomStringConvertible, Equatable { } } -public func == (lhs: Graph, rhs: Graph) -> Bool { +public func == (_ lhs: Graph, rhs: Graph) -> Bool { return lhs.nodes == rhs.nodes } diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Node.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Node.swift index 37a3b3fdf..48fc952e3 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Node.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Node.swift @@ -5,7 +5,7 @@ public class Node: CustomStringConvertible, Equatable { public var distance: Int? public var visited: Bool - public init(label: String) { + public init(_ label: String) { self.label = label neighbors = [] visited = false @@ -22,11 +22,11 @@ public class Node: CustomStringConvertible, Equatable { return distance != nil } - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + public func remove(_ edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } } -public func == (lhs: Node, rhs: Node) -> Bool { +public func == (_ lhs: Node, rhs: Node) -> Bool { return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors } diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Queue.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Queue.swift index bf462bbdd..3d98f801c 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Queue.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Queue.swift @@ -13,7 +13,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Breadth-First Search/BreadthFirstSearch.swift b/Breadth-First Search/BreadthFirstSearch.swift index aa396ac7b..75508682a 100644 --- a/Breadth-First Search/BreadthFirstSearch.swift +++ b/Breadth-First Search/BreadthFirstSearch.swift @@ -1,4 +1,4 @@ -func breadthFirstSearch(graph: Graph, source: Node) -> [String] { +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { var queue = Queue() queue.enqueue(source) diff --git a/Breadth-First Search/README.markdown b/Breadth-First Search/README.markdown index 12e906532..23edf6da5 100644 --- a/Breadth-First Search/README.markdown +++ b/Breadth-First Search/README.markdown @@ -90,7 +90,7 @@ For an unweighted graph, this tree defines a shortest path from the starting nod Simple implementation of breadth-first search using a queue: ```swift -func breadthFirstSearch(graph: Graph, source: Node) -> [String] { +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { var queue = Queue() queue.enqueue(source) From a2bdc50e9e2307c11ad232f37acca34d944ff211 Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Mon, 26 Sep 2016 17:26:34 +0800 Subject: [PATCH 0167/1275] Migrating Brute Force String Search to Swift3 --- .../Contents.swift | 11 ++++---- .../timeline.xctimeline | 6 ---- .../BruteForceStringSearch.swift | 28 +++++++++---------- Brute-Force String Search/README.markdown | 28 +++++++++---------- 4 files changed, 34 insertions(+), 39 deletions(-) delete mode 100644 Brute-Force String Search/BruteForceStringSearch.playground/timeline.xctimeline diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift index 57f2b2090..61064c698 100644 --- a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift +++ b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift @@ -1,16 +1,17 @@ //: Playground - noun: a place where people can play extension String { - func indexOf(pattern: String) -> String.Index? { - for i in self.startIndex ..< self.endIndex { + func indexOf(_ pattern: String) -> String.Index? { + + for i in self.characters.indices { var j = i var found = true - for p in pattern.startIndex ..< pattern.endIndex { - if j == self.endIndex || self[j] != pattern[p] { + for p in pattern.characters.indices{ + if j == self.characters.endIndex || self[j] != pattern[p] { found = false break } else { - j = j.successor() + j = self.characters.index(after: j) } } if found { diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/timeline.xctimeline b/Brute-Force String Search/BruteForceStringSearch.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Brute-Force String Search/BruteForceStringSearch.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Brute-Force String Search/BruteForceStringSearch.swift b/Brute-Force String Search/BruteForceStringSearch.swift index 431677a4a..03a2dff13 100644 --- a/Brute-Force String Search/BruteForceStringSearch.swift +++ b/Brute-Force String Search/BruteForceStringSearch.swift @@ -2,21 +2,21 @@ Brute-force string search */ extension String { - func indexOf(pattern: String) -> String.Index? { - for i in self.startIndex ..< self.endIndex { - var j = i - var found = true - for p in pattern.startIndex ..< pattern.endIndex { - if j == self.endIndex || self[j] != pattern[p] { - found = false - break - } else { - j = j.successor() + func indexOf(_ pattern: String) -> String.Index? { + for i in self.characters.indices { + var j = i + var found = true + for p in pattern.characters.indices{ + if j == self.characters.endIndex || self[j] != pattern[p] { + found = false + break + } else { + j = self.characters.index(after: j) + } + } + if found { + return i } - } - if found { - return i - } } return nil } diff --git a/Brute-Force String Search/README.markdown b/Brute-Force String Search/README.markdown index 748be872f..4e967bcfb 100644 --- a/Brute-Force String Search/README.markdown +++ b/Brute-Force String Search/README.markdown @@ -28,21 +28,21 @@ Here is a brute-force solution: ```swift extension String { - func indexOf(pattern: String) -> String.Index? { - for i in self.startIndex ..< self.endIndex { - var j = i - var found = true - for p in pattern.startIndex ..< pattern.endIndex { - if j == self.endIndex || self[j] != pattern[p] { - found = false - break - } else { - j = j.successor() + func indexOf(_ pattern: String) -> String.Index? { + for i in self.characters.indices { + var j = i + var found = true + for p in pattern.characters.indices{ + if j == self.characters.endIndex || self[j] != pattern[p] { + found = false + break + } else { + j = self.characters.index(after: j) + } + } + if found { + return i } - } - if found { - return i - } } return nil } From 183cfcf5e26c35f68a2f7ec0d075c11dcf597e55 Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Tue, 27 Sep 2016 12:08:19 +0800 Subject: [PATCH 0168/1275] migrating montyhall to swift 3 --- Monty Hall Problem/MontyHall.playground/Contents.swift | 2 +- Monty Hall Problem/MontyHall.playground/timeline.xctimeline | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 Monty Hall Problem/MontyHall.playground/timeline.xctimeline diff --git a/Monty Hall Problem/MontyHall.playground/Contents.swift b/Monty Hall Problem/MontyHall.playground/Contents.swift index 930dad714..bcdafd137 100644 --- a/Monty Hall Problem/MontyHall.playground/Contents.swift +++ b/Monty Hall Problem/MontyHall.playground/Contents.swift @@ -2,7 +2,7 @@ import Foundation -func random(n: Int) -> Int { +func random(_ n: Int) -> Int { return Int(arc4random_uniform(UInt32(n))) } diff --git a/Monty Hall Problem/MontyHall.playground/timeline.xctimeline b/Monty Hall Problem/MontyHall.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Monty Hall Problem/MontyHall.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From ecbcfeaa8f41d8bc2fde76933d2bf664c958cf3c Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Tue, 27 Sep 2016 12:41:55 +0800 Subject: [PATCH 0169/1275] migrating radix-sort to swift3 --- .../Sources/RadixTree.swift | 38 +- Radix Tree/RadixTree.swift | 730 +++++++++--------- 2 files changed, 384 insertions(+), 384 deletions(-) diff --git a/Radix Tree/RadixTree.playground/Sources/RadixTree.swift b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift index 3cba5254a..1914f57bc 100644 --- a/Radix Tree/RadixTree.playground/Sources/RadixTree.swift +++ b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift @@ -85,7 +85,7 @@ public class Edge: Root { // For each child, erase it, then remove it from the children array. for _ in 0...children.count-1 { children[0].erase() - children.removeAtIndex(0) + children.remove(at: 0) } } } @@ -137,7 +137,7 @@ public class RadixTree { } // Inserts a string into the tree. - public func insert(str: String) -> Bool { + public func insert(_ str: String) -> Bool { //Account for a blank input. The empty string is already in the tree. if str == "" { return false @@ -182,9 +182,9 @@ public class RadixTree { currEdge = e var tempIndex = searchStr.startIndex for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() + tempIndex = searchStr.characters.index(after: tempIndex) } - searchStr = searchStr.substringFromIndex(tempIndex) + searchStr = searchStr.substring(from: tempIndex) found = true break } @@ -197,13 +197,13 @@ public class RadixTree { // Create index objects and move them to after the shared prefix for _ in 1...shared.characters.count { - index = index.successor() - labelIndex = labelIndex.successor() + index = searchStr.characters.index(after: index) + labelIndex = e.label.characters.index(after: labelIndex) } // Substring both the search string and the label from the shared prefix - searchStr = searchStr.substringFromIndex(index) - e.label = e.label.substringFromIndex(labelIndex) + searchStr = searchStr.substring(from: index) + e.label = e.label.substring(from: labelIndex) // Create 2 new edges and update parent/children values let newEdge = Edge(e.label) @@ -236,7 +236,7 @@ public class RadixTree { } // Tells you if a string is in the tree - public func find(str: String) -> Bool { + public func find(_ str: String) -> Bool { // A radix tree always contains the empty string if str == "" { return true @@ -267,9 +267,9 @@ public class RadixTree { currEdge = c var tempIndex = searchStr.startIndex for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() + tempIndex = searchStr.characters.index(after: tempIndex) } - searchStr = searchStr.substringFromIndex(tempIndex) + searchStr = searchStr.substring(from: tempIndex) found = true break } @@ -300,12 +300,12 @@ public class RadixTree { } // Removes a string from the tree - public func remove(str: String) -> Bool { + public func remove(_ str: String) -> Bool { // Removing the empty string removes everything in the tree if str == "" { for c in root.children { c.erase() - root.children.removeAtIndex(0) + root.children.remove(at: 0) } return true } @@ -329,7 +329,7 @@ public class RadixTree { // and everything below it in the tree if currEdge.children[c].label == searchStr { currEdge.children[c].erase() - currEdge.children.removeAtIndex(c) + currEdge.children.remove(at: c) return true } @@ -341,9 +341,9 @@ public class RadixTree { currEdge = currEdge.children[c] var tempIndex = searchStr.startIndex for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() + tempIndex = searchStr.characters.index(after: tempIndex) } - searchStr = searchStr.substringFromIndex(tempIndex) + searchStr = searchStr.substring(from: tempIndex) found = true break } @@ -364,15 +364,15 @@ public class RadixTree { // Returns the prefix that is shared between the two input strings // i.e. sharedPrefix("court", "coral") -> "co" -public func sharedPrefix(str1: String, _ str2: String) -> String { +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) { if str1[c1] == str2[c2] { temp.append( str1[c1] ) - c1 = c1.successor() - c2 = c2.successor() + c1 = str1.characters.index(after:c1) + c2 = str2.characters.index(after:c2) } else { return temp } diff --git a/Radix Tree/RadixTree.swift b/Radix Tree/RadixTree.swift index 3cba5254a..5badf0810 100644 --- a/Radix Tree/RadixTree.swift +++ b/Radix Tree/RadixTree.swift @@ -2,380 +2,380 @@ import Foundation // The root is the top of the Radix Tree public class Root { - var children: [Edge] - - public init() { - children = [Edge]() - } - - // Returns the length (in number of edges) of the longest traversal down the tree. - public func height() -> Int { - // Base case: no children: the tree has a height of 1 - if children.count == 0 { - return 1 - } - // Recursion: find the max height of a root's child and return 1 + that max - else { - var max = 1 - for c in children { - if c.height() > max { - max = c.height() - } - } - return 1 + max - } - } - - // Returns how far down in the tree a Root/Edge is. - // A root's level is always 0. - public func level() -> Int { - return 0 - } - - // Prints the tree for debugging/visualization purposes. - public func printRoot() { - // Print the first half of the children - if children.count > 1 { - for c in 0...children.count/2-1 { - children[c].printEdge() - print("|") - } - } else if children.count > 0 { - children[0].printEdge() - } - // Then print the root - print("ROOT") - // Print the second half of the children - if children.count > 1 { - for c in children.count/2...children.count-1 { - children[c].printEdge() - print("|") - } - } - print() - } + var children: [Edge] + + public init() { + children = [Edge]() + } + + // Returns the length (in number of edges) of the longest traversal down the tree. + public func height() -> Int { + // Base case: no children: the tree has a height of 1 + if children.count == 0 { + return 1 + } + // Recursion: find the max height of a root's child and return 1 + that max + else { + var max = 1 + for c in children { + if c.height() > max { + max = c.height() + } + } + return 1 + max + } + } + + // Returns how far down in the tree a Root/Edge is. + // A root's level is always 0. + public func level() -> Int { + return 0 + } + + // Prints the tree for debugging/visualization purposes. + public func printRoot() { + // Print the first half of the children + if children.count > 1 { + for c in 0...children.count/2-1 { + children[c].printEdge() + print("|") + } + } else if children.count > 0 { + children[0].printEdge() + } + // Then print the root + print("ROOT") + // Print the second half of the children + if children.count > 1 { + for c in children.count/2...children.count-1 { + children[c].printEdge() + print("|") + } + } + print() + } } // Edges are what actually store the Strings in the tree public class Edge: Root { - var parent: Root? - var label: String - - public init(_ label: String) { - self.label = label - super.init() - } - - public override func level() -> Int { - // Recurse up the tree incrementing level by one until the root is reached - if parent != nil { - return 1 + parent!.level() - } - // If an edge has no parent, it's level is one - // NOTE: THIS SHOULD NEVER HAPPEN AS THE ROOT IS ALWAYS THE TOP OF THE TREE - else { - return 1 - } - } - - // Erases a specific edge (and all edges below it in the tree). - public func erase() { - self.parent = nil - if children.count > 0 { - // For each child, erase it, then remove it from the children array. - for _ in 0...children.count-1 { - children[0].erase() - children.removeAtIndex(0) - } - } - } - - // Prints the tree for debugging/visualization purposes. - public func printEdge() { - // Print the first half of the edge's children - if children.count > 1 { - for c in 0...children.count/2-1 { - children[c].printEdge() - } - } else if children.count > 0 { - children[0].printEdge() - } - // Tab over once up to the edge's level - for x in 1...level() { - if x == level() { - print("|------>", terminator: "") - } else { - print("| ", terminator: "") - } - } - print(label) - // Print the second half of the edge's children - if children.count == 0 { - for _ in 1...level() { - print("| ", terminator: "") - } - print() - } - if children.count > 1 { - for c in children.count/2...children.count-1 { - children[c].printEdge() - } - } - } + var parent: Root? + var label: String + + public init(_ label: String) { + self.label = label + super.init() + } + + public override func level() -> Int { + // Recurse up the tree incrementing level by one until the root is reached + if parent != nil { + return 1 + parent!.level() + } + // If an edge has no parent, it's level is one + // NOTE: THIS SHOULD NEVER HAPPEN AS THE ROOT IS ALWAYS THE TOP OF THE TREE + else { + return 1 + } + } + + // Erases a specific edge (and all edges below it in the tree). + public func erase() { + self.parent = nil + if children.count > 0 { + // For each child, erase it, then remove it from the children array. + for _ in 0...children.count-1 { + children[0].erase() + children.remove(at: 0) + } + } + } + + // Prints the tree for debugging/visualization purposes. + public func printEdge() { + // Print the first half of the edge's children + if children.count > 1 { + for c in 0...children.count/2-1 { + children[c].printEdge() + } + } else if children.count > 0 { + children[0].printEdge() + } + // Tab over once up to the edge's level + for x in 1...level() { + if x == level() { + print("|------>", terminator: "") + } else { + print("| ", terminator: "") + } + } + print(label) + // Print the second half of the edge's children + if children.count == 0 { + for _ in 1...level() { + print("| ", terminator: "") + } + print() + } + if children.count > 1 { + for c in children.count/2...children.count-1 { + children[c].printEdge() + } + } + } } public class RadixTree { - var root: Root - - public init() { - root = Root() - } - - // Returns the height of the tree by calling the root's height function. - public func height() -> Int { - return root.height() - 1 - } - - // Inserts a string into the tree. - public func insert(str: String) -> Bool { - //Account for a blank input. The empty string is already in the tree. - if str == "" { - return false - } - - // searchStr is the parameter of the function - // it will be substringed as the function traverses down the tree - var searchStr = str - - // currEdge is the current Edge (or Root) in question - var currEdge = root - - while true { - var found = false - - // If the current Edge has no children then the remaining searchStr is - // created as a child - if currEdge.children.count == 0 { - let newEdge = Edge(searchStr) - currEdge.children.append(newEdge) - newEdge.parent = currEdge - return true - } - - // Loop through all of the children - for e in currEdge.children { - // Get the shared prefix between the child in question and the - // search string - let shared = sharedPrefix(searchStr, e.label) - var index = shared.startIndex - - // If the search string is equal to the shared string, - // the string already exists in the tree - if searchStr == shared { - return false - } - - // If the child's label is equal to the shared string, you have to - // traverse another level down the tree, so substring the search - // string, break the loop, and run it back - else if shared == e.label { - currEdge = e - var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() - } - searchStr = searchStr.substringFromIndex(tempIndex) - found = true - break - } - - // 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 - - // Create index objects and move them to after the shared prefix - for _ in 1...shared.characters.count { - index = index.successor() - labelIndex = labelIndex.successor() - } - - // Substring both the search string and the label from the shared prefix - searchStr = searchStr.substringFromIndex(index) - e.label = e.label.substringFromIndex(labelIndex) - - // Create 2 new edges and update parent/children values - let newEdge = Edge(e.label) - e.label = shared - for ec in e.children { - newEdge.children.append(ec) - } - newEdge.parent = e - e.children.removeAll() - for nec in newEdge.children { - nec.parent = newEdge - } - e.children.append(newEdge) - let newEdge2 = Edge(searchStr) - newEdge2.parent = e - e.children.append(newEdge2) - return true - } - // If they don't share a prefix, go to next child - } - - // If none of the children share a prefix, you have to create a new child - if !found { - let newEdge = Edge(searchStr) - currEdge.children.append(newEdge) - newEdge.parent = currEdge - return true - } - } - } - - // Tells you if a string is in the tree - public func find(str: String) -> Bool { - // A radix tree always contains the empty string - if str == "" { - return true - } - // If there are no children then the string cannot be in the tree - else if root.children.count == 0 { - return false - } - var searchStr = str - var currEdge = root - while true { - var found = false - // Loop through currEdge's children - for c in currEdge.children { - // First check if the search string and the child's label are equal - // if so the string is in the tree, return true - if searchStr == c.label { - return true - } - - // If that is not true, find the shared string b/t the search string - // and the label - let shared = sharedPrefix(searchStr, c.label) - - // If the shared string is equal to the label, update the curent node, - // break the loop, and run it back - if shared == c.label { - currEdge = c - var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() - } - searchStr = searchStr.substringFromIndex(tempIndex) - found = true - break - } - - // If the shared string is empty, go to the next child - else if shared.characters.count == 0 { - continue - } - - // If the shared string matches the search string, return true - else if shared == searchStr { - return true - } - - // 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 { - return false - } - } - - // If nothing was found, return false - if !found { - return false - } - } - } - - // Removes a string from the tree - public func remove(str: String) -> Bool { - // Removing the empty string removes everything in the tree - if str == "" { - for c in root.children { - c.erase() - root.children.removeAtIndex(0) - } - return true - } - // If the tree is empty, you cannot remove anything - else if root.children.count == 0 { - return false - } - - var searchStr = str - var currEdge = root - while true { - var found = false - // If currEdge has no children, then the searchStr is not in the tree - if currEdge.children.count == 0 { - return false - } - - // Loop through the children - for c in 0...currEdge.children.count-1 { - // If the child's label matches the search string, remove that child - // and everything below it in the tree - if currEdge.children[c].label == searchStr { - currEdge.children[c].erase() - currEdge.children.removeAtIndex(c) - return true - } - - // Find the shared string - let shared = sharedPrefix(searchStr, currEdge.children[c].label) - - // If the shared string is equal to the child's string, go down a level - if shared == currEdge.children[c].label { - currEdge = currEdge.children[c] - var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = tempIndex.successor() - } - searchStr = searchStr.substringFromIndex(tempIndex) - found = true - break - } - } - - // If there is no match, then the searchStr is not in the tree - if !found { - return false - } - } - } - - // Prints the tree by calling the root's print function - public func printTree() { - root.printRoot() - } + var root: Root + + public init() { + root = Root() + } + + // Returns the height of the tree by calling the root's height function. + public func height() -> Int { + return root.height() - 1 + } + + // Inserts a string into the tree. + public func insert(_ str: String) -> Bool { + //Account for a blank input. The empty string is already in the tree. + if str == "" { + return false + } + + // searchStr is the parameter of the function + // it will be substringed as the function traverses down the tree + var searchStr = str + + // currEdge is the current Edge (or Root) in question + var currEdge = root + + while true { + var found = false + + // If the current Edge has no children then the remaining searchStr is + // created as a child + if currEdge.children.count == 0 { + let newEdge = Edge(searchStr) + currEdge.children.append(newEdge) + newEdge.parent = currEdge + return true + } + + // Loop through all of the children + for e in currEdge.children { + // Get the shared prefix between the child in question and the + // search string + let shared = sharedPrefix(searchStr, e.label) + var index = shared.startIndex + + // If the search string is equal to the shared string, + // the string already exists in the tree + if searchStr == shared { + return false + } + + // If the child's label is equal to the shared string, you have to + // traverse another level down the tree, so substring the search + // string, break the loop, and run it back + else if shared == e.label { + currEdge = e + var tempIndex = searchStr.startIndex + for _ in 1...shared.characters.count { + tempIndex = searchStr.characters.index(after: tempIndex) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break + } + + // 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 + + // 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) + } + + // Substring both the search string and the label from the shared prefix + searchStr = searchStr.substring(from: index) + e.label = e.label.substring(from: labelIndex) + + // Create 2 new edges and update parent/children values + let newEdge = Edge(e.label) + e.label = shared + for ec in e.children { + newEdge.children.append(ec) + } + newEdge.parent = e + e.children.removeAll() + for nec in newEdge.children { + nec.parent = newEdge + } + e.children.append(newEdge) + let newEdge2 = Edge(searchStr) + newEdge2.parent = e + e.children.append(newEdge2) + return true + } + // If they don't share a prefix, go to next child + } + + // If none of the children share a prefix, you have to create a new child + if !found { + let newEdge = Edge(searchStr) + currEdge.children.append(newEdge) + newEdge.parent = currEdge + return true + } + } + } + + // Tells you if a string is in the tree + public func find(_ str: String) -> Bool { + // A radix tree always contains the empty string + if str == "" { + return true + } + // If there are no children then the string cannot be in the tree + else if root.children.count == 0 { + return false + } + var searchStr = str + var currEdge = root + while true { + var found = false + // Loop through currEdge's children + for c in currEdge.children { + // First check if the search string and the child's label are equal + // if so the string is in the tree, return true + if searchStr == c.label { + return true + } + + // If that is not true, find the shared string b/t the search string + // and the label + let shared = sharedPrefix(searchStr, c.label) + + // If the shared string is equal to the label, update the curent node, + // break the loop, and run it back + if shared == c.label { + currEdge = c + var tempIndex = searchStr.startIndex + for _ in 1...shared.characters.count { + tempIndex = searchStr.characters.index(after: tempIndex) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break + } + + // If the shared string is empty, go to the next child + else if shared.characters.count == 0 { + continue + } + + // If the shared string matches the search string, return true + else if shared == searchStr { + return true + } + + // 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 { + return false + } + } + + // If nothing was found, return false + if !found { + return false + } + } + } + + // Removes a string from the tree + public func remove(_ str: String) -> Bool { + // Removing the empty string removes everything in the tree + if str == "" { + for c in root.children { + c.erase() + root.children.remove(at: 0) + } + return true + } + // If the tree is empty, you cannot remove anything + else if root.children.count == 0 { + return false + } + + var searchStr = str + var currEdge = root + while true { + var found = false + // If currEdge has no children, then the searchStr is not in the tree + if currEdge.children.count == 0 { + return false + } + + // Loop through the children + for c in 0...currEdge.children.count-1 { + // If the child's label matches the search string, remove that child + // and everything below it in the tree + if currEdge.children[c].label == searchStr { + currEdge.children[c].erase() + currEdge.children.remove(at: c) + return true + } + + // Find the shared string + let shared = sharedPrefix(searchStr, currEdge.children[c].label) + + // If the shared string is equal to the child's string, go down a level + 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) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break + } + } + + // If there is no match, then the searchStr is not in the tree + if !found { + return false + } + } + } + + // Prints the tree by calling the root's print function + public func printTree() { + root.printRoot() + } } // Returns the prefix that is shared between the two input strings // 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) { - if str1[c1] == str2[c2] { - temp.append( str1[c1] ) - c1 = c1.successor() - c2 = c2.successor() - } else { - return temp - } - } - return temp +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) { + if str1[c1] == str2[c2] { + temp.append( str1[c1] ) + c1 = str1.characters.index(after:c1) + c2 = str2.characters.index(after:c2) + } else { + return temp + } + } + return temp } From b2c302faf26a78e0eafceaf0496cd7262b9305b2 Mon Sep 17 00:00:00 2001 From: Hai Nguyen Date: Tue, 27 Sep 2016 21:10:24 -0700 Subject: [PATCH 0170/1275] Migrate LCS to Swift 3.0 --- .travis.yml | 2 +- .../Contents.swift | 18 ++++---- .../contents.xcplayground | 2 +- .../LongestCommonSubsequence.swift | 19 +++++---- Longest Common Subsequence/README.markdown | 31 +++++++------- .../Tests/Tests.xcodeproj/project.pbxproj | 41 ++++++++++++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 7 files changed, 77 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index a04a2e742..949fc759f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ script: - 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 ./Longest\ Common\ Subsequence/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 diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift index bb6fa7c2a..0fc9ec325 100644 --- a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift @@ -1,11 +1,11 @@ extension String { - public func longestCommonSubsequence(other: String) -> String { + public func longestCommonSubsequence(_ other: String) -> String { - func lcsLength(other: String) -> [[Int]] { - var matrix = [[Int]](count: self.characters.count+1, repeatedValue: [Int](count: other.characters.count+1, repeatedValue: 0)) + func lcsLength(_ other: String) -> [[Int]] { + var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.characters.count+1), count: self.characters.count+1) - for (i, selfChar) in self.characters.enumerate() { - for (j, otherChar) in other.characters.enumerate() { + for (i, selfChar) in self.characters.enumerated() { + for (j, otherChar) in other.characters.enumerated() { if otherChar == selfChar { matrix[i+1][j+1] = matrix[i][j] + 1 } else { @@ -16,7 +16,7 @@ extension String { return matrix } - func backtrack(matrix: [[Int]]) -> String { + func backtrack(_ matrix: [[Int]]) -> String { var i = self.characters.count var j = other.characters.count var charInSequence = self.endIndex @@ -28,15 +28,15 @@ extension String { j -= 1 } else if matrix[i][j] == matrix[i - 1][j] { i -= 1 - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) } else { i -= 1 j -= 1 - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) lcs.append(self[charInSequence]) } } - return String(lcs.characters.reverse()) + return String(lcs.characters.reversed()) } return backtrack(lcsLength(other)) diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground index 5da2641c9..9f5f2f40c 100644 --- a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Longest Common Subsequence/LongestCommonSubsequence.swift b/Longest Common Subsequence/LongestCommonSubsequence.swift index 23d191102..b6834279d 100644 --- a/Longest Common Subsequence/LongestCommonSubsequence.swift +++ b/Longest Common Subsequence/LongestCommonSubsequence.swift @@ -1,17 +1,17 @@ extension String { - public func longestCommonSubsequence(other: String) -> String { + public func longestCommonSubsequence(_ other: String) -> String { // Computes the length of the lcs using dynamic programming. // Output is a matrix of size (n+1)x(m+1), where matrix[x][y] is the length // of lcs between substring (0, x-1) of self and substring (0, y-1) of other. - func lcsLength(other: String) -> [[Int]] { + func lcsLength(_ other: String) -> [[Int]] { // Create matrix of size (n+1)x(m+1). The algorithm needs first row and // first column to be filled with 0. - var matrix = [[Int]](count: self.characters.count+1, repeatedValue: [Int](count: other.characters.count+1, repeatedValue: 0)) + var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.characters.count+1), count: self.characters.count+1) - for (i, selfChar) in self.characters.enumerate() { - for (j, otherChar) in other.characters.enumerate() { + for (i, selfChar) in self.characters.enumerated() { + for (j, otherChar) in other.characters.enumerated() { if otherChar == selfChar { // Common char found, add 1 to highest lcs found so far. matrix[i+1][j+1] = matrix[i][j] + 1 @@ -28,7 +28,7 @@ extension String { // Backtracks from matrix[n][m] to matrix[1][1] looking for chars that are // common to both strings. - func backtrack(matrix: [[Int]]) -> String { + func backtrack(_ matrix: [[Int]]) -> String { var i = self.characters.count var j = other.characters.count @@ -46,21 +46,22 @@ extension String { else if matrix[i][j] == matrix[i - 1][j] { i -= 1 // As i was decremented, move back charInSequence. - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) } // Value on the left and above are different than current cell. // This means 1 was added to lcs length (line 17). else { i -= 1 j -= 1 - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) + lcs.append(self[charInSequence]) } } // Due to backtrack, chars were added in reverse order: reverse it back. // Append and reverse is faster than inserting at index 0. - return String(lcs.characters.reverse()) + return String(lcs.characters.reversed()) } // Combine dynamic programming approach with backtrack to find the lcs. diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown index 64d3988c6..ba514728a 100644 --- a/Longest Common Subsequence/README.markdown +++ b/Longest Common Subsequence/README.markdown @@ -18,9 +18,9 @@ To determine the length of the LCS between all combinations of substrings of `a` > **Note:** During the following explanation, `n` is the length of string `a`, and `m` is the length of string `b`. -To find the lengths of all possible subsequences, we use a helper function, `lcsLength()`. This creates a matrix of size `(n+1)` by `(m+1)`, where `matrix[x][y]` is the length of the LCS between the substrings `a[0...x-1]` and `b[0...y-1]`. +To find the lengths of all possible subsequences, we use a helper function, `lcsLength(_:)`. This creates a matrix of size `(n+1)` by `(m+1)`, where `matrix[x][y]` is the length of the LCS between the substrings `a[0...x-1]` and `b[0...y-1]`. -Given strings `"ABCBX"` and `"ABDCAB"`, the output matrix of `lcsLength()` is the following: +Given strings `"ABCBX"` and `"ABDCAB"`, the output matrix of `lcsLength(_:)` is the following: ``` | | Ø | A | B | D | C | A | B | @@ -34,16 +34,15 @@ Given strings `"ABCBX"` and `"ABDCAB"`, the output matrix of `lcsLength()` is th In this example, if we look at `matrix[3][4]` we find the value `3`. This means the length of the LCS between `a[0...2]` and `b[0...3]`, or between `"ABC"` and `"ABDC"`, is 3. That is correct, because these two substrings have the subsequence `ABC` in common. (Note: the first row and column of the matrix are always filled with zeros.) -Here is the source code for `lcsLength()`; this lives in an extension on `String`: +Here is the source code for `lcsLength(_:)`; this lives in an extension on `String`: ```swift -func lcsLength(other: String) -> [[Int]] { +func lcsLength(_ other: String) -> [[Int]] { - var matrix = [[Int]](count: self.characters.count+1, - repeatedValue: [Int](count: other.characters.count+1, repeatedValue: 0)) + var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.characters.count+1), count: self.characters.count+1) - for (i, selfChar) in self.characters.enumerate() { - for (j, otherChar) in other.characters.enumerate() { + for (i, selfChar) in self.characters.enumerated() { + for (j, otherChar) in other.characters.enumerated() { if otherChar == selfChar { // Common char found, add 1 to highest lcs found so far. matrix[i+1][j+1] = matrix[i][j] + 1 @@ -96,7 +95,7 @@ Now we compare `C` with `C`. These are equal, and we increment the length to `3` | X | 0 | | | | | | | ``` -And so on... this is how `lcsLength()` fills in the entire matrix. +And so on... this is how `lcsLength(_:)` fills in the entire matrix. ## Backtracking to find the actual subsequence @@ -125,7 +124,7 @@ One thing to notice is, as it's running backwards, the LCS is built in reverse o Here is the backtracking code: ```swift -func backtrack(matrix: [[Int]]) -> String { +func backtrack(_ matrix: [[Int]]) -> String { var i = self.characters.count var j = other.characters.count @@ -141,14 +140,14 @@ func backtrack(matrix: [[Int]]) -> String { // Indicates propagation without change: no new char was added to lcs. else if matrix[i][j] == matrix[i - 1][j] { i -= 1 - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) } // Value on the left and above are different than current cell. // This means 1 was added to lcs length. else { i -= 1 j -= 1 - charInSequence = charInSequence.predecessor() + charInSequence = self.index(before: charInSequence) lcs.append(self[charInSequence]) } } @@ -165,17 +164,17 @@ Due to backtracking, characters are added in reverse order, so at the end of the ## Putting it all together -To find the LCS between two strings, we first call `lcsLength()` and then `backtrack()`: +To find the LCS between two strings, we first call `lcsLength(_:)` and then `backtrack(_:)`: ```swift extension String { - public func longestCommonSubsequence(other: String) -> String { + public func longestCommonSubsequence(_ other: String) -> String { - func lcsLength(other: String) -> [[Int]] { + func lcsLength(_ other: String) -> [[Int]] { ... } - func backtrack(matrix: [[Int]]) -> String { + func backtrack(_ matrix: [[Int]]) -> String { ... } diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj index abf3084dd..bf9c18fd3 100644 --- a/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; TargetAttributes = { 4716C7A61C93750500F6C1C0 = { CreatedOnToolsVersion = 7.2.1; @@ -132,12 +132,49 @@ 4716C7861C936DCB00F6C1C0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; 4716C7871C936DCB00F6C1C0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -187,6 +224,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -228,6 +266,7 @@ PRODUCT_BUNDLE_IDENTIFIER = me.pedrovereza.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 3d7f342b3..0b0682c43 100644 --- a/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 28 Sep 2016 14:14:24 +0200 Subject: [PATCH 0171/1275] added Z-Algorithm README --- Z-Algorithm/README.markdown | 176 ++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 Z-Algorithm/README.markdown diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown new file mode 100644 index 000000000..7fbb9b48b --- /dev/null +++ b/Z-Algorithm/README.markdown @@ -0,0 +1,176 @@ +# Z-Algorithm String Search + +Goal: Write a simple linear-time string matching algorithm in Swift that returns the indexes of all the occurrencies of a given pattern. + +In other words, we want to implement an `indexesOf(pattern: String)` extension on `String` that returns an array `[Int]` of integers, representing all occurrences' indexes of the search pattern, or `nil` if the pattern could not be found inside the string. + +For example: + +```swift +let str = "Hello, playground!" +str.indexesOf(pattern: "ground") // Output: [11] + +let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" +traffic.indexesOf(pattern: "🚑") // Output: [4, 21] +``` + +Many string search algorithms use a pre-processing function to compute a table that will be used in successive stage. This table can save some time during the pattern search stage because it allows to avoid un-needed characters comparisons. The [Z-Algorithm]() is one of these functions. It borns as a pattern pre-processing function (this is its role in the [Knuth-Morris-Pratt algorithm](../Knuth-Morris-Pratt/) and others) but, just like we will show here, it can be used also as a single string search algorithm. + +### Z-Algorithm as pattern pre-processor + +As we said, the Z-Algorithm is foremost an algorithm that process a pattern in order to calculate a skip-comparisons-table. +The computation of the Z-Algorithm over a pattern `P` produces an array (called `Z` in the literature) of integers in which each element, call it `Z[i]`, represents the length of the longest substring of `P` that starts at `i` and matches a prefix of `P`. In simpler words, `Z[i]` records the longest prefix of `P[i...|P|]` that matches a prefix of `P`. As an example, let's consider `P = "ffgtrhghhffgtggfredg"`. We have that `Z[5] = 0 (f...h...)`, `Z[9] = 4 (ffgtr...ffgtg...)` and `Z[15] = 1 (ff...fr...)`. + +But how do we compute `Z`? Before we describe the algorithm we must indroduce the concept of Z-box. A Z-box is a pair `(left, right)` used during the computation that records the substring of maximal length that occurs also as a prefix of `P`. The two indices `left` and `right` represent, respectively, the left-end index and the right-end index of this substring. +The definition of the Z-Algorithm is inductive and it computes the elements of the array for every position `k` in the pattern, starting from `k = 1`. The following values (`Z[k + 1]`, `Z[k + 2]`, ...) are computed after `Z[k]`. The idea behind the algorithm is that previously computed values can speed up the calculus of `Z[k + 1]`, avoiding some character comparisons that were already done before. Consider this example: suppose we are at iteration `k = 100`, so we are analyzing position `100` of the pattern. All the values between `Z[1]` and `Z[99]` were correctly computed and `left = 70` and `right = 120`. This means that there is a substring of length `51` starting at position `70` and ending at position `120` that matches the prefix of the pattern/string we are considering. Reasoning on it a little bit we can say that the substring of length `21` starting at position `100` matches the substring of length `21` starting at position `30` of the pattern (because we are inside a substring that matches a prefix of the pattern). So we can use `Z[30]` to compute `Z[100]` without additional character comparisons. +This a simple description of the idea that is behind this algorithm. There are a few cases to manage when the use of pre-computed values cannot be directly applied and some comparisons are to be made. + +Here is the code of the function that computes the Z-array: +``` +swift +func ZetaAlgorithm(ptrn: String) -> [Int]? { + + let pattern = Array(ptrn.characters) + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta: [Int] = [Int](repeating: 0, count: patternLength) + + var left: Int = 0 + var right: Int = 0 + var k_1: Int = 0 + var betaLength: Int = 0 + var textIndex: Int = 0 + var patternIndex: Int = 0 + + for k in 1 ..< patternLength { + if k > right { // Outside a Z-box: compare the characters until mismatch + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { // Inside a Z-box + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { // Entirely inside a Z-box: we can use the values computed before + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { // Not entirely inside a Z-box: we must proceed with comparisons too + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } + } + } + return zeta +} +``` + +Let's make an example reasoning with the code above. Let's consider the string `P = “abababab"`. The algorithm begins with `k = 1`, `left = right = 0`. So, no Z-box is "active" and thus, because `k > right` we start with the character comparisons beetwen `P[1]` and `P[0]`. + + + 01234567 + k: x + abababbb + x + Z: 00000000 + left: 0 + right: 0 + +We have a mismatch at the first comparison and so the substring starting at `P[1]` does not match a prefix of `P`. So, we put `Z[1] = 0` and let `left` and `right` untouched. We begin another iteration with `k = 2`, we have `2 > 0` and again we start comparing characters `P[2]` with `P[0]`. This time the characters match and so we continue the comparisons until a mismatch occurs. It happens at position `6`. The characters matched are `4`, so we put `Z[2] = 4` and set `left = k = 2` and `right = k + Z[k] - 1 = 5`. We have our first Z-box that is the substring `"abab"` (notice that it matches a prefix of `P`) starting at position `left = 2`. + + 01234567 + k: x + abababbb + x + Z: 00400000 + left: 2 + right: 5 + +We then proceed with `k = 3`. We have `3 <= 5`. We are inside the Z-box previously found and inside a prefix of `P`. So we can look for a position that has a previously computed value. We calculate `k_1 = k - left = 1` that is the index of the prefix's character equal to `P[k]`. We check `Z[1] = 0` and `0 < (right - k + 1 = 3)` and we find that we are exactly inside the Z-box. We can use the previously computed value, so we put `Z[3] = Z[1] = 0`, `left` and `right` remain unchanged. +At iteration `k = 4` we initially execute the `else` branch of the outer `if`. Then in the inner `if` we have that `k_1 = 2` and `(Z[2] = 4) >= 5 - 4 + 1`. So, the substring `P[k...r]` matches for `right - k + 1 = 2` chars the prefix of `P` but it could not for the following characters. We must then compare the characters starting at `r + 1 = 6` with those starting at `right - k + 1 = 2`. We have `P[6] != P[2]` and so we have to set `Z[k] = 6 - 4 = 2`, `left = 4` and `right = 5`. + + 01234567 + k: x + abababbb + x + Z: 00402000 + left: 4 + right: 5 + +With iteration `k = 5` we have `k <= right` and then `(Z[k_1] = 0) < (right - k + 1 = 1)` and so we set `z[k] = 0`. In iteration `6` and `7` we execute the first branch of the outer `if` but we only have mismatches, so the algorithms terminates returning the Z-array as `Z = [0, 0, 4, 0, 2, 0, 0, 0]`. + +The Z-Algorithm runs in linear time. More specifically, the Z-Algorithm for a string `P` of size `n` has a running time of `O(n)`. + +The implementation of Z-Algorithm as string pre-processor is contained in the [ZAlgorithm.swift](./ZAlgorithm.swift) file. + +### Z-Algorithm as string search algorithm + +The Z-Algorithm discussed above leads to the simplest linear-time string matching algorithm. To obtain it, we have to simply concatenate the pattern `P` and text `T` in a string `S = P$T` where `$` is a character that does not appear neither in `P` nor `T`. Then we run the algorithm on `S` obtaining the Z-array. All we have to do now is scan the Z-array looking for elements equal to `n` (which is the pattern length). When we find such value we can report an occurrence. + +```swift +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength: Int = pattern.characters.count + /* Let's calculate the Z-Algorithm on the concatenation of pattern and text */ + let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + + var indexes: [Int] = [Int]() + + /* Scan the zeta array to find matched patterns */ + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) + } + } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } +} +``` + +Let's make an example. Let `P = “CATA“` and `T = "GAGAACATACATGACCAT"` be the pattern and the text. Let's concatenate them with the character `$`. We have the string `S = "CATA$GAGAACATACATGACCAT"`. After computing the Z-Algorithm on `S` we obtain: + + 1 2 + 01234567890123456789012 + CATA$GAGAACATACATGACCAT + Z 00000000004000300001300 + ^ + +We scan the Z-array and at position `10` we find `Z[10] = 4 = n`. So we can report a match occuring at text position `10 - n - 1 = 5`. + +As said before, the complexity of this algorithm is linear. Defining `n` and `m` as pattern and text lengths, the final complexity we obtain is `O(n + m + 1) = O(n + m)`. + + +Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"]() by Dan Gusfield, Cambridge University Press, 1997. + +*Written for Swift Algorithm Club by Matteo Dunnhofer* From 41712e0275fbc50e63f32580d402ca12d1648888 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Wed, 28 Sep 2016 14:20:58 +0200 Subject: [PATCH 0172/1275] edited Z-Algorithm README --- Z-Algorithm/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown index 7fbb9b48b..c6c50a23b 100644 --- a/Z-Algorithm/README.markdown +++ b/Z-Algorithm/README.markdown @@ -86,7 +86,7 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { } ``` -Let's make an example reasoning with the code above. Let's consider the string `P = “abababab"`. The algorithm begins with `k = 1`, `left = right = 0`. So, no Z-box is "active" and thus, because `k > right` we start with the character comparisons beetwen `P[1]` and `P[0]`. +Let's make an example reasoning with the code above. Let's consider the string `P = “abababbb"`. The algorithm begins with `k = 1`, `left = right = 0`. So, no Z-box is "active" and thus, because `k > right` we start with the character comparisons beetwen `P[1]` and `P[0]`. 01234567 @@ -171,6 +171,6 @@ We scan the Z-array and at position `10` we find `Z[10] = 4 = n`. So we can repo As said before, the complexity of this algorithm is linear. Defining `n` and `m` as pattern and text lengths, the final complexity we obtain is `O(n + m + 1) = O(n + m)`. -Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"]() by Dan Gusfield, Cambridge University Press, 1997. +Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"](https://books.google.it/books/about/Algorithms_on_Strings_Trees_and_Sequence.html?id=Ofw5w1yuD8kC&redir_esc=y) by Dan Gusfield, Cambridge University Press, 1997. *Written for Swift Algorithm Club by Matteo Dunnhofer* From 72ee49b05218ce4ca627caabaa9b2960154a9dde Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Wed, 28 Sep 2016 16:32:15 +0200 Subject: [PATCH 0173/1275] edited Z-Algorithm README --- Z-Algorithm/README.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown index c6c50a23b..8b84c28bf 100644 --- a/Z-Algorithm/README.markdown +++ b/Z-Algorithm/README.markdown @@ -26,8 +26,7 @@ The definition of the Z-Algorithm is inductive and it computes the elements of t This a simple description of the idea that is behind this algorithm. There are a few cases to manage when the use of pre-computed values cannot be directly applied and some comparisons are to be made. Here is the code of the function that computes the Z-array: -``` -swift +```swift func ZetaAlgorithm(ptrn: String) -> [Int]? { let pattern = Array(ptrn.characters) From 69758422a5fade80fda9c550818ad0056dc0634b Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 28 Sep 2016 16:49:22 -0700 Subject: [PATCH 0174/1275] Fixed a typo in the Karatsuba algorithm --- .../KaratsubaMultiplication.playground/Contents.swift | 4 ++-- Karatsuba Multiplication/KaratsubaMultiplication.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 53980ac1e..95a498322 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -52,9 +52,9 @@ func karatsuba(_ num1: Int, by num2: Int) -> Int { let ac = karatsuba(a, by: c) let bd = karatsuba(b, by: d) - let adPluscd = karatsuba(a+b, by: c+d) - ac - bd + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd - let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd return product } diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index 7837e3f3c..fb20a667d 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -37,9 +37,9 @@ func karatsuba(_ num1: Int, by num2: Int) -> Int { let ac = karatsuba(a, by: c) let bd = karatsuba(b, by: d) - let adPluscd = karatsuba(a+b, by: c+d) - ac - bd + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd - let product = ac * 10^^(2 * nBy2) + adPluscd * 10^^nBy2 + bd + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd return product } From ab2949e77658260df2153e95f32f525bff68b785 Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 28 Sep 2016 16:50:12 -0700 Subject: [PATCH 0175/1275] Added an explanation and examples to the README --- Karatsuba Multiplication/README.markdown | 123 ++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index 0afd91b0c..af3392612 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -1,8 +1,129 @@ # Karatsuba Multiplication -TODO: Explanation/Examples +Goal: To quickly multiply two numbers together +## Long Multiplication +In grade school we all learned how to multiply two numbers together via Long Multiplication. So let's try that first! +Example 1: Multiply 1234 by 5678 using Long Multiplication + + 5678 + *1234 + ------ + 22712 + 17034- + 11356-- + 5678--- + -------- + 7006652 + +So what's the problem with long multiplication? Speed. Long Multiplication runs in **O(n^2)**. + +You can see where the **O(n^2)** comes from in the implementation for Long Multiplication: + +```swift +// Long Multiplication +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))! } + + 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("", +))! +} +``` + +The double for loop is the culprit! So Long Multiplication might not be the best algorithm after all. Can we do better? + +## Karatsuba Multiplication + +The Karatsuba Algorithm was discovered by Anatoly Karatsuba and published in 1962. Karatsuba discovered that you could compute the product of two large numbers using three smaller products and some addition and subtraction. + +For two numbers x, y, where m <= n: + + x = a*10^m + b + y = c*10^m + d + +Now, we can say: + + x*y = a*c*10^(2m) + (a*d + b*c)*10^(m) + b*d + +We can compute this function recursively, and that's what makes Karatsuba Multiplication fast. + +```swift +let ac = karatsuba(a, by: c) +let bd = karatsuba(b, by: d) +let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd +``` + +The last recursion is interesting. Normally, you'd think we would have to run four recursions to find the product `x*y` (`a*c`, `a*d`, `b*c`, `b*d`). However, Karatsuba realized that you only need three recursions, and some addition and subtraction. Here's the math: + + (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c + = (a*d + b*c) + +Pretty cool, huh? + +Here's the full implementation + +```swift +// Karatsuba Multiplication +func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1Array = String(num1).characters + let num2Array = String(num2).characters + + guard num1Array.count > 1 && num2Array.count > 1 else { + return num1*num2 + } + + let n = max(num1Array.count, num2Array.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 +} +``` + +The run time for this algorithm is about **O(n^1.56)** which is better than the **O(n^2)** for Long Multiplication. + +Example 2: Multiply 1234 by 5678 using Karatsuba Multiplication + + m = 2 + x = 1234 = a*10^2 + b = 12*10^2 + 34 + y = 5678 = c*10^2 + d = 56*10^2 + 78 + + a*c = 672 + b*d = 2652 + (a*d + b*c) = 2840 + + x*y = 672*10^4 + 2840*10^2 + 2652 + = 6720000 + 284000 + 2652 + = 7006652 + +## Resources + +[Wikipedia] (https://en.wikipedia.org/wiki/Karatsuba_algorithm) + +[WolframMathWorld] (http://mathworld.wolfram.com/KaratsubaMultiplication.html) *Written for Swift Algorithm Club by Richard Ash* From b8ea4fd9b63ac20c3ae521d3a1ff018500a587d3 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 1 Oct 2016 23:02:12 +0200 Subject: [PATCH 0176/1275] added Knuth-Morris-Pratt README --- Knuth-Morris-Pratt/README.markdown | 157 +++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 Knuth-Morris-Pratt/README.markdown diff --git a/Knuth-Morris-Pratt/README.markdown b/Knuth-Morris-Pratt/README.markdown new file mode 100644 index 000000000..ab8e78cdc --- /dev/null +++ b/Knuth-Morris-Pratt/README.markdown @@ -0,0 +1,157 @@ +# Knuth-Morris-Pratt String Search + +Goal: Write a linear-time string matching algorithm in Swift that returns the indexes of all the occurrencies of a given pattern. + +In other words, we want to implement an `indexesOf(pattern: String)` extension on `String` that returns an array `[Int]` of integers, representing all occurrences' indexes of the search pattern, or `nil` if the pattern could not be found inside the string. + +For example: + +```swift +let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" +dna.indexesOf(ptnr: "CATA") // Output: [20, 64, 130, 140, 166, 234, 255, 270] + +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 idea behind the algorithm is not too different from the [naive string search](../Brute-Force String Search/) 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. + +The pre-processing stage produces an array (called `suffixPrefix` in the code) of integers in which every element `suffixPrefix[i]` records the length of the longest proper suffix of `P[0...i]` (where `P` is the pattern) that matches a prefix of `P`. In other words, `suffixPrefix[i]` is the longest proper substring of `P` that ends at position `i` and that is a prefix of `P`. Just a quick example. Consider `P = "abadfryaabsabadffg", then `suffixPrefix[4] = 0`, `suffixPrefix[9] = 2`, `suffixPrefix[14] = 4`. +There are different ways to obtain the values of `SuffixPrefix` array. We will use the method based on the [Z-Algorithm](../Z-Algorithm/). This function takes in input the pattern and produces an array of integers. Each element represents the length of the longest substring starting at position `i` of `P` and that matches a prefix of `P`. You can notice that the two arrays are similar, they record the same informations but on the different places. We only have to find a method to map `Z[i]` to `suffixPrefix[j]`. It is not that difficult and this is the code that will do for us: + +```swift +for patternIndex in (1 ..< patternLength).reversed() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] +} +``` + +We are simply computing the index of the end of the substring starting at position `i` (as we know matches a prefix of `P`). The element of `suffixPrefix` at that index then it will be set with the length of the substring. + +Once the shift-array `suffixPrefix` is ready we can begin with pattern search stage. The algorithm first attempts to compare the characters of the text with those of the pattern. If it succeeds, it goes on until a mismatch occurs. When it happens, it checks if an occurrence of the pattern is present (and reports it). Otherwise, if no comparisons are made then the text cursor is moved forward, else the pattern is shifted to the right. The shift's amount is based on the `suffixPrefix` array, and it guarantees that the prefix `P[0...suffixPrefix[i]]` will match its opposing substring in the text. In this way, shifts of more than one character are often made and lot of comparisons can be avoided, saving a lot of time. + +Here is the code of the Knuth-Morris-Pratt algorithm: + +```swift +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self.characters) + let pattern = Array(ptnr.characters) + + let textLength: Int = text.count + let patternLength: Int = pattern.count + + guard patternLength > 0 else { + return nil + } + + var suffixPrefix: [Int] = [Int](repeating: 0, count: patternLength) + var textIndex: Int = 0 + var patternIndex: Int = 0 + var indexes: [Int] = [Int]() + + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ + let zeta = ZetaAlgorithm(ptnr: ptnr) + + for patternIndex in (1 ..< patternLength).reversed() { + textIndex = patternIndex + zeta![patternIndex] - 1 + suffixPrefix[textIndex] = zeta![patternIndex] + } + + /* Search stage: scanning the text for pattern matching */ + textIndex = 0 + patternIndex = 0 + + while textIndex + (patternLength - patternIndex - 1) < textLength { + + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 + } + + if patternIndex == patternLength { + indexes.append(textIndex - patternIndex) + } + + if patternIndex == 0 { + textIndex = textIndex + 1 + } else { + patternIndex = suffixPrefix[patternIndex - 1] + } + } + + guard !indexes.isEmpty else { + return nil + } + return indexes + } +} +``` + +Let's make an example reasoning with the code above. Let's consider the string `P = ACTGACTA"`, the consequentially obtained `suffixPrefix` array equal to `[0, 0, 0, 0, 0, 0, 3, 1]`, and the text `T = "GCACTGACTGACTGACTAG"`. The algorithm begins with the text and the pattern aligned like below. We have to compare `T[0]` with `P[0]`. + + 1 + 0123456789012345678 + text: GCACTGACTGACTGACTAG + textIndex: ^ + pattern: ACTGACTA + patternIndex: ^ + x + suffixPrefix: 00000031 + +We have a mismatch and we move on comparing `T[1]` and `P[0]`. We have to check if a pattern occurrence is present but there is not. So, we have to shift the pattern right and by doing so we have to check `suffixPrefix[1 - 1]`. Its value is `0` and we restart by comparing `T[1]` with `P[0]`. Again a mismath occurs, so we go on with `T[2]` and `P[0]`. + + 1 + 0123456789012345678 + text: GCACTGACTGACTGACTAG + textIndex: ^ + pattern: ACTGACTA + patternIndex: ^ + suffixPrefix: 00000031 + +This time we have a match. And it continues until position `8`. Unfortunately the length of the match is not equal to the pattern length, we cannot report an occurrence. But we are still lucky because we can use the values computed in the `suffixPrefix` array now. In fact, the length of the match is `7`, and if we look at the element `suffixPrefix[7 - 1]` we discover that is `3`. This information tell us that that the prefix of `P` matches the suffix of the susbtring `T[0...8]`. So the `suffixPrefix` array guarantees us that the two substring match and that we do not have to compare their characters, so we can shift right the pattern for more than one character! +The comparisons restart from `T[9]` and `P[3]`. + + 1 + 0123456789012345678 + text: GCACTGACTGACTGACTAG + textIndex: ^ + pattern: ACTGACTA + patternIndex: ^ + suffixPrefix: 00000031 + +They match so we continue the compares until position `13` where a misatch occurs beetwen charcter `G` and `A`. Just like before, we are lucky and we can use the `suffixPrefix` array to shift right the pattern. + + 1 + 0123456789012345678 + text: GCACTGACTGACTGACTAG + textIndex: ^ + pattern: ACTGACTA + patternIndex: ^ + suffixPrefix: 00000031 + +Again, we have to compare. But this time the comparisons finally take us to an occurrence, at position `17 - 7 = 10`. + + 1 + 0123456789012345678 + text: GCACTGACTGACTGACTAG + textIndex: ^ + pattern: ACTGACTA + patternIndex: ^ + suffixPrefix: 00000031 + +The algorithm than tries to compare `T[18]` with `P[1]` (because we used the element `suffixPrefix[8 - 1] = 1`) but it fails and at the next iteration it ends its work. + + +The pre-processing stage involves only the pattern. The running time of the Z-Algorithm is linear and takes `O(n)`, where `n` is the length of the pattern `P`. After that, the search stage does not "overshoot" the length of the text `T` (call it `m`). It can be be proved that number of comparisons of the search stage is bounded by `2 * m`. The final running time of the Knuth-Morris-Pratt algorithm is `O(n + m)`. + + +> **Note:** To execute the code in the [KnuthMorrisPratt.swift](./KnuthMorrisPratt.swift) you have to copy the [ZAlgorithm.swift](../Z-Algorithm/ZAlgorithm.swift) file contained in the [Z-Algorithm](../Z-Algorithm/) folder. The [KnuthMorrisPratt.playground](./KnuthMorrisPratt.playground) already includes the definition of the `Zeta` function. + +Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"](https://books.google.it/books/about/Algorithms_on_Strings_Trees_and_Sequence.html?id=Ofw5w1yuD8kC&redir_esc=y) by Dan Gusfield, Cambridge University Press, 1997. + +*Written for Swift Algorithm Club by Matteo Dunnhofer* From 5423763065c6844d2c573b76435623662670b947 Mon Sep 17 00:00:00 2001 From: dontfollowmeimcrazy Date: Sat, 1 Oct 2016 23:05:50 +0200 Subject: [PATCH 0177/1275] edited Knuth-Morris-Pratt README --- 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 ab8e78cdc..f01b87b3d 100644 --- a/Knuth-Morris-Pratt/README.markdown +++ b/Knuth-Morris-Pratt/README.markdown @@ -18,7 +18,7 @@ The [Knuth-Morris-Pratt algorithm](https://en.wikipedia.org/wiki/Knuth–Morris The idea behind the algorithm is not too different from the [naive string search](../Brute-Force String Search/) 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. -The pre-processing stage produces an array (called `suffixPrefix` in the code) of integers in which every element `suffixPrefix[i]` records the length of the longest proper suffix of `P[0...i]` (where `P` is the pattern) that matches a prefix of `P`. In other words, `suffixPrefix[i]` is the longest proper substring of `P` that ends at position `i` and that is a prefix of `P`. Just a quick example. Consider `P = "abadfryaabsabadffg", then `suffixPrefix[4] = 0`, `suffixPrefix[9] = 2`, `suffixPrefix[14] = 4`. +The pre-processing stage produces an array (called `suffixPrefix` in the code) of integers in which every element `suffixPrefix[i]` records the length of the longest proper suffix of `P[0...i]` (where `P` is the pattern) that matches a prefix of `P`. In other words, `suffixPrefix[i]` is the longest proper substring of `P` that ends at position `i` and that is a prefix of `P`. Just a quick example. Consider `P = "abadfryaabsabadffg"`, then `suffixPrefix[4] = 0`, `suffixPrefix[9] = 2`, `suffixPrefix[14] = 4`. There are different ways to obtain the values of `SuffixPrefix` array. We will use the method based on the [Z-Algorithm](../Z-Algorithm/). This function takes in input the pattern and produces an array of integers. Each element represents the length of the longest substring starting at position `i` of `P` and that matches a prefix of `P`. You can notice that the two arrays are similar, they record the same informations but on the different places. We only have to find a method to map `Z[i]` to `suffixPrefix[j]`. It is not that difficult and this is the code that will do for us: ```swift From f4dc41feb8b66fe9c02d78627d2caafd3bd4f1fa Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Tue, 4 Oct 2016 22:21:13 -0500 Subject: [PATCH 0178/1275] began convert to swift3 --- .../BoyerMoore.playground/Contents.swift | 18 +++++++++--------- .../BoyerMoore.playground/timeline.xctimeline | 6 ------ 2 files changed, 9 insertions(+), 15 deletions(-) delete mode 100644 Boyer-Moore/BoyerMoore.playground/timeline.xctimeline diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 433935133..631b0d43a 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -7,20 +7,20 @@ extension String { assert(patternLength <= self.characters.count) var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerate() { + for (i, c) in pattern.characters.enumerated() { skipTable[c] = patternLength - i - 1 } - let p = pattern.endIndex.predecessor() + let p = pattern.index(before: endIndex) let lastChar = pattern[p] - var i = self.startIndex.advancedBy(patternLength - 1) + var i = self.index(startIndex, offsetBy: patternLength - 1) func backwards() -> String.Index? { var q = p var j = i while q > pattern.startIndex { - j = j.predecessor() - q = q.predecessor() + j = index(before: j) + q = index(before: q) if self[j] != pattern[q] { return nil } } return j @@ -30,9 +30,9 @@ extension String { let c = self[i] if c == lastChar { if let k = backwards() { return k } - i = i.successor() + i = index(after: i) } else { - i = i.advancedBy(skipTable[c] ?? patternLength) + i = index(i, offsetBy: skipTable[c] ?? patternLength) } } return nil @@ -44,7 +44,7 @@ extension String { // A few simple tests let s = "Hello, World" -s.indexOf("World") // 7 +s.indexOf(pattern: "World") // 7 let animals = "🐶🐔🐷🐮🐱" -animals.indexOf("🐮") // 6 +animals.indexOf(pattern: "🐮") // 6 diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From c79d699b5e31206341ee623b642c7181943e7928 Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Tue, 4 Oct 2016 22:39:54 -0500 Subject: [PATCH 0179/1275] fixed bug with end index --- .../BoyerMoore.playground/Contents.swift | 6 ++---- .../BoyerMoore.playground/timeline.xctimeline | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 Boyer-Moore/BoyerMoore.playground/timeline.xctimeline diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 631b0d43a..59cc85b86 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -11,7 +11,7 @@ extension String { skipTable[c] = patternLength - i - 1 } - let p = pattern.index(before: endIndex) + let p = pattern.index(before: pattern.endIndex) let lastChar = pattern[p] var i = self.index(startIndex, offsetBy: patternLength - 1) @@ -39,12 +39,10 @@ extension String { } } - - // A few simple tests let s = "Hello, World" s.indexOf(pattern: "World") // 7 let animals = "🐶🐔🐷🐮🐱" -animals.indexOf(pattern: "🐮") // 6 +//animals.indexOf(pattern: "🐮") // 6 diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline new file mode 100644 index 000000000..623552dab --- /dev/null +++ b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + From e53faf4fced5aa86e0bfb3f97bc98b1bd76557d2 Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Tue, 4 Oct 2016 22:53:37 -0500 Subject: [PATCH 0180/1275] uncomment test --- Boyer-Moore/BoyerMoore.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 59cc85b86..6203d36e7 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -45,4 +45,4 @@ let s = "Hello, World" s.indexOf(pattern: "World") // 7 let animals = "🐶🐔🐷🐮🐱" -//animals.indexOf(pattern: "🐮") // 6 +animals.indexOf(pattern: "🐮") // 6 From df1cc1e4d16e488ff3ed35d3c0b5b1df3d59d4fe Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Tue, 4 Oct 2016 22:56:33 -0500 Subject: [PATCH 0181/1275] formatting --- Boyer-Moore/BoyerMoore.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 6203d36e7..9a3d619dc 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -30,7 +30,7 @@ extension String { let c = self[i] if c == lastChar { if let k = backwards() { return k } - i = index(after: i) + i = index(after: i) } else { i = index(i, offsetBy: skipTable[c] ?? patternLength) } From 2e9e887c07f42306d80ac1d102e0253ecc1a9f06 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Wed, 5 Oct 2016 21:40:45 +1300 Subject: [PATCH 0182/1275] LCS - Restoring executeOnSourceChanges to default --- .../LongestCommonSubsequence.playground/contents.xcplayground | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground index 9f5f2f40c..fc5b4ab70 100644 --- a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + - \ No newline at end of file + From bf9ba314510af9a5dd15eaa0eb8d0f1dc789eb60 Mon Sep 17 00:00:00 2001 From: Chris Pilcher Date: Wed, 5 Oct 2016 21:55:24 +1300 Subject: [PATCH 0183/1275] Radix tree re-indent to use two spaces --- Radix Tree/RadixTree.swift | 684 ++++++++++++++++++------------------- 1 file changed, 342 insertions(+), 342 deletions(-) diff --git a/Radix Tree/RadixTree.swift b/Radix Tree/RadixTree.swift index 5badf0810..958ffb4e6 100644 --- a/Radix Tree/RadixTree.swift +++ b/Radix Tree/RadixTree.swift @@ -2,380 +2,380 @@ import Foundation // The root is the top of the Radix Tree public class Root { - var children: [Edge] - - public init() { - children = [Edge]() + var children: [Edge] + + public init() { + children = [Edge]() + } + + // Returns the length (in number of edges) of the longest traversal down the tree. + public func height() -> Int { + // Base case: no children: the tree has a height of 1 + if children.count == 0 { + return 1 } - - // Returns the length (in number of edges) of the longest traversal down the tree. - public func height() -> Int { - // Base case: no children: the tree has a height of 1 - if children.count == 0 { - return 1 - } - // Recursion: find the max height of a root's child and return 1 + that max - else { - var max = 1 - for c in children { - if c.height() > max { - max = c.height() - } - } - return 1 + max + // Recursion: find the max height of a root's child and return 1 + that max + else { + var max = 1 + for c in children { + if c.height() > max { + max = c.height() } + } + return 1 + max } - - // Returns how far down in the tree a Root/Edge is. - // A root's level is always 0. - public func level() -> Int { - return 0 + } + + // Returns how far down in the tree a Root/Edge is. + // A root's level is always 0. + public func level() -> Int { + return 0 + } + + // Prints the tree for debugging/visualization purposes. + public func printRoot() { + // Print the first half of the children + if children.count > 1 { + for c in 0...children.count/2-1 { + children[c].printEdge() + print("|") + } + } else if children.count > 0 { + children[0].printEdge() } - - // Prints the tree for debugging/visualization purposes. - public func printRoot() { - // Print the first half of the children - if children.count > 1 { - for c in 0...children.count/2-1 { - children[c].printEdge() - print("|") - } - } else if children.count > 0 { - children[0].printEdge() - } - // Then print the root - print("ROOT") - // Print the second half of the children - if children.count > 1 { - for c in children.count/2...children.count-1 { - children[c].printEdge() - print("|") - } - } - print() + // Then print the root + print("ROOT") + // Print the second half of the children + if children.count > 1 { + for c in children.count/2...children.count-1 { + children[c].printEdge() + print("|") + } } + print() + } } // Edges are what actually store the Strings in the tree public class Edge: Root { - var parent: Root? - var label: String - - public init(_ label: String) { - self.label = label - super.init() + var parent: Root? + var label: String + + public init(_ label: String) { + self.label = label + super.init() + } + + public override func level() -> Int { + // Recurse up the tree incrementing level by one until the root is reached + if parent != nil { + return 1 + parent!.level() } - - public override func level() -> Int { - // Recurse up the tree incrementing level by one until the root is reached - if parent != nil { - return 1 + parent!.level() - } - // If an edge has no parent, it's level is one - // NOTE: THIS SHOULD NEVER HAPPEN AS THE ROOT IS ALWAYS THE TOP OF THE TREE - else { - return 1 - } + // If an edge has no parent, it's level is one + // NOTE: THIS SHOULD NEVER HAPPEN AS THE ROOT IS ALWAYS THE TOP OF THE TREE + else { + return 1 } - - // Erases a specific edge (and all edges below it in the tree). - public func erase() { - self.parent = nil - if children.count > 0 { - // For each child, erase it, then remove it from the children array. - for _ in 0...children.count-1 { - children[0].erase() - children.remove(at: 0) - } - } + } + + // Erases a specific edge (and all edges below it in the tree). + public func erase() { + self.parent = nil + if children.count > 0 { + // For each child, erase it, then remove it from the children array. + for _ in 0...children.count-1 { + children[0].erase() + children.remove(at: 0) + } } - - // Prints the tree for debugging/visualization purposes. - public func printEdge() { - // Print the first half of the edge's children - if children.count > 1 { - for c in 0...children.count/2-1 { - children[c].printEdge() - } - } else if children.count > 0 { - children[0].printEdge() - } - // Tab over once up to the edge's level - for x in 1...level() { - if x == level() { - print("|------>", terminator: "") - } else { - print("| ", terminator: "") - } + } + + // Prints the tree for debugging/visualization purposes. + public func printEdge() { + // Print the first half of the edge's children + if children.count > 1 { + for c in 0...children.count/2-1 { + children[c].printEdge() + } + } else if children.count > 0 { + children[0].printEdge() + } + // Tab over once up to the edge's level + for x in 1...level() { + if x == level() { + print("|------>", terminator: "") + } else { + print("| ", terminator: "") + } + } + print(label) + // Print the second half of the edge's children + if children.count == 0 { + for _ in 1...level() { + print("| ", terminator: "") + } + print() + } + if children.count > 1 { + for c in children.count/2...children.count-1 { + children[c].printEdge() + } + } + } +} + +public class RadixTree { + var root: Root + + public init() { + root = Root() + } + + // Returns the height of the tree by calling the root's height function. + public func height() -> Int { + return root.height() - 1 + } + + // Inserts a string into the tree. + public func insert(_ str: String) -> Bool { + //Account for a blank input. The empty string is already in the tree. + if str == "" { + return false + } + + // searchStr is the parameter of the function + // it will be substringed as the function traverses down the tree + var searchStr = str + + // currEdge is the current Edge (or Root) in question + var currEdge = root + + while true { + var found = false + + // If the current Edge has no children then the remaining searchStr is + // created as a child + if currEdge.children.count == 0 { + let newEdge = Edge(searchStr) + currEdge.children.append(newEdge) + newEdge.parent = currEdge + return true + } + + // Loop through all of the children + for e in currEdge.children { + // Get the shared prefix between the child in question and the + // search string + let shared = sharedPrefix(searchStr, e.label) + var index = shared.startIndex + + // If the search string is equal to the shared string, + // the string already exists in the tree + if searchStr == shared { + return false } - print(label) - // Print the second half of the edge's children - if children.count == 0 { - for _ in 1...level() { - print("| ", terminator: "") - } - print() + + // If the child's label is equal to the shared string, you have to + // traverse another level down the tree, so substring the search + // string, break the loop, and run it back + else if shared == e.label { + currEdge = e + var tempIndex = searchStr.startIndex + for _ in 1...shared.characters.count { + tempIndex = searchStr.characters.index(after: tempIndex) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break } - if children.count > 1 { - for c in children.count/2...children.count-1 { - children[c].printEdge() - } + + // 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 + + // 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) + } + + // Substring both the search string and the label from the shared prefix + searchStr = searchStr.substring(from: index) + e.label = e.label.substring(from: labelIndex) + + // Create 2 new edges and update parent/children values + let newEdge = Edge(e.label) + e.label = shared + for ec in e.children { + newEdge.children.append(ec) + } + newEdge.parent = e + e.children.removeAll() + for nec in newEdge.children { + nec.parent = newEdge + } + e.children.append(newEdge) + let newEdge2 = Edge(searchStr) + newEdge2.parent = e + e.children.append(newEdge2) + return true } + // If they don't share a prefix, go to next child + } + + // If none of the children share a prefix, you have to create a new child + if !found { + let newEdge = Edge(searchStr) + currEdge.children.append(newEdge) + newEdge.parent = currEdge + return true + } } -} + } -public class RadixTree { - var root: Root - - public init() { - root = Root() + // Tells you if a string is in the tree + public func find(_ str: String) -> Bool { + // A radix tree always contains the empty string + if str == "" { + return true } - - // Returns the height of the tree by calling the root's height function. - public func height() -> Int { - return root.height() - 1 + // If there are no children then the string cannot be in the tree + else if root.children.count == 0 { + return false } - - // Inserts a string into the tree. - public func insert(_ str: String) -> Bool { - //Account for a blank input. The empty string is already in the tree. - if str == "" { - return false + var searchStr = str + var currEdge = root + while true { + var found = false + // Loop through currEdge's children + for c in currEdge.children { + // First check if the search string and the child's label are equal + // if so the string is in the tree, return true + if searchStr == c.label { + return true } - - // searchStr is the parameter of the function - // it will be substringed as the function traverses down the tree - var searchStr = str - - // currEdge is the current Edge (or Root) in question - var currEdge = root - - while true { - var found = false - - // If the current Edge has no children then the remaining searchStr is - // created as a child - if currEdge.children.count == 0 { - let newEdge = Edge(searchStr) - currEdge.children.append(newEdge) - newEdge.parent = currEdge - return true - } - - // Loop through all of the children - for e in currEdge.children { - // Get the shared prefix between the child in question and the - // search string - let shared = sharedPrefix(searchStr, e.label) - var index = shared.startIndex - - // If the search string is equal to the shared string, - // the string already exists in the tree - if searchStr == shared { - return false - } - - // If the child's label is equal to the shared string, you have to - // traverse another level down the tree, so substring the search - // string, break the loop, and run it back - else if shared == e.label { - currEdge = e - var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) - } - searchStr = searchStr.substring(from: tempIndex) - found = true - break - } - - // 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 - - // 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) - } - - // Substring both the search string and the label from the shared prefix - searchStr = searchStr.substring(from: index) - e.label = e.label.substring(from: labelIndex) - - // Create 2 new edges and update parent/children values - let newEdge = Edge(e.label) - e.label = shared - for ec in e.children { - newEdge.children.append(ec) - } - newEdge.parent = e - e.children.removeAll() - for nec in newEdge.children { - nec.parent = newEdge - } - e.children.append(newEdge) - let newEdge2 = Edge(searchStr) - newEdge2.parent = e - e.children.append(newEdge2) - return true - } - // If they don't share a prefix, go to next child - } - - // If none of the children share a prefix, you have to create a new child - if !found { - let newEdge = Edge(searchStr) - currEdge.children.append(newEdge) - newEdge.parent = currEdge - return true - } + + // If that is not true, find the shared string b/t the search string + // and the label + let shared = sharedPrefix(searchStr, c.label) + + // If the shared string is equal to the label, update the curent node, + // break the loop, and run it back + if shared == c.label { + currEdge = c + var tempIndex = searchStr.startIndex + for _ in 1...shared.characters.count { + tempIndex = searchStr.characters.index(after: tempIndex) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break } - } - - // Tells you if a string is in the tree - public func find(_ str: String) -> Bool { - // A radix tree always contains the empty string - if str == "" { - return true + + // If the shared string is empty, go to the next child + else if shared.characters.count == 0 { + continue } - // If there are no children then the string cannot be in the tree - else if root.children.count == 0 { - return false + + // If the shared string matches the search string, return true + else if shared == searchStr { + return true } - var searchStr = str - var currEdge = root - while true { - var found = false - // Loop through currEdge's children - for c in currEdge.children { - // First check if the search string and the child's label are equal - // if so the string is in the tree, return true - if searchStr == c.label { - return true - } - - // If that is not true, find the shared string b/t the search string - // and the label - let shared = sharedPrefix(searchStr, c.label) - - // If the shared string is equal to the label, update the curent node, - // break the loop, and run it back - if shared == c.label { - currEdge = c - var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) - } - searchStr = searchStr.substring(from: tempIndex) - found = true - break - } - - // If the shared string is empty, go to the next child - else if shared.characters.count == 0 { - continue - } - - // If the shared string matches the search string, return true - else if shared == searchStr { - return true - } - - // 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 { - return false - } - } - - // If nothing was found, return false - if !found { - return false - } + + // 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 { + return false } + } + + // If nothing was found, return false + if !found { + return false + } } - - // Removes a string from the tree - public func remove(_ str: String) -> Bool { - // Removing the empty string removes everything in the tree - if str == "" { - for c in root.children { - c.erase() - root.children.remove(at: 0) - } - return true - } - // If the tree is empty, you cannot remove anything - else if root.children.count == 0 { - return false + } + + // Removes a string from the tree + public func remove(_ str: String) -> Bool { + // Removing the empty string removes everything in the tree + if str == "" { + for c in root.children { + c.erase() + root.children.remove(at: 0) + } + return true + } + // If the tree is empty, you cannot remove anything + else if root.children.count == 0 { + return false + } + + var searchStr = str + var currEdge = root + while true { + var found = false + // If currEdge has no children, then the searchStr is not in the tree + if currEdge.children.count == 0 { + return false + } + + // Loop through the children + for c in 0...currEdge.children.count-1 { + // If the child's label matches the search string, remove that child + // and everything below it in the tree + if currEdge.children[c].label == searchStr { + currEdge.children[c].erase() + currEdge.children.remove(at: c) + return true } - - var searchStr = str - var currEdge = root - while true { - var found = false - // If currEdge has no children, then the searchStr is not in the tree - if currEdge.children.count == 0 { - return false - } - - // Loop through the children - for c in 0...currEdge.children.count-1 { - // If the child's label matches the search string, remove that child - // and everything below it in the tree - if currEdge.children[c].label == searchStr { - currEdge.children[c].erase() - currEdge.children.remove(at: c) - return true - } - - // Find the shared string - let shared = sharedPrefix(searchStr, currEdge.children[c].label) - - // If the shared string is equal to the child's string, go down a level - 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) - } - searchStr = searchStr.substring(from: tempIndex) - found = true - break - } - } - - // If there is no match, then the searchStr is not in the tree - if !found { - return false - } + + // Find the shared string + let shared = sharedPrefix(searchStr, currEdge.children[c].label) + + // If the shared string is equal to the child's string, go down a level + 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) + } + searchStr = searchStr.substring(from: tempIndex) + found = true + break } + } + + // If there is no match, then the searchStr is not in the tree + if !found { + return false + } } - - // Prints the tree by calling the root's print function - public func printTree() { - root.printRoot() - } + } + + // Prints the tree by calling the root's print function + public func printTree() { + root.printRoot() + } } // Returns the prefix that is shared between the two input strings // 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) { - if str1[c1] == str2[c2] { - temp.append( str1[c1] ) - c1 = str1.characters.index(after:c1) - c2 = str2.characters.index(after:c2) - } else { - return temp - } + var temp = "" + var c1 = str1.characters.startIndex + var c2 = str2.characters.startIndex + for _ in 0...min(str1.characters.count-1, str2.characters.count-1) { + if str1[c1] == str2[c2] { + temp.append( str1[c1] ) + c1 = str1.characters.index(after:c1) + c2 = str2.characters.index(after:c2) + } else { + return temp } - return temp + } + return temp } From 00c6b720b984928f3ea3d3ab9f679c0d49cf8087 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 6 Oct 2016 22:19:50 -0700 Subject: [PATCH 0184/1275] Updated README --- Karatsuba Multiplication/README.markdown | 35 ++++++++++-------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index af3392612..d4c99ec2d 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -4,9 +4,9 @@ Goal: To quickly multiply two numbers together ## Long Multiplication -In grade school we all learned how to multiply two numbers together via Long Multiplication. So let's try that first! +In grade school we learned how to multiply two numbers together via Long Multiplication. Let's try that first! -Example 1: Multiply 1234 by 5678 using Long Multiplication +### Example 1: Multiply 1234 by 5678 using Long Multiplication 5678 *1234 @@ -18,9 +18,9 @@ Example 1: Multiply 1234 by 5678 using Long Multiplication -------- 7006652 -So what's the problem with long multiplication? Speed. Long Multiplication runs in **O(n^2)**. +So what's the problem with Long Multiplication? Well remember the first part of our goal. To *quickly* multiply two numbers together. Long Multiplication is slow! (**O(n^2)**) -You can see where the **O(n^2)** comes from in the implementation for Long Multiplication: +You can see where the **O(n^2)** comes from in the implementation of Long Multiplication: ```swift // Long Multiplication @@ -44,7 +44,7 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { } ``` -The double for loop is the culprit! So Long Multiplication might not be the best algorithm after all. Can we do better? +The double for loop is the culprit! By comparing each of the digits (as is necessary!) we set ourselves up for an **O(n^2)** running time. So Long Multiplication might not be the best algorithm after all. Can we do better? ## Karatsuba Multiplication @@ -57,24 +57,17 @@ For two numbers x, y, where m <= n: Now, we can say: - x*y = a*c*10^(2m) + (a*d + b*c)*10^(m) + b*d + x*y = (a*10^m + b) * (c*10^m + d) + = a*c*10^(2m) + (a*d + b*c)*10^(m) + b*d -We can compute this function recursively, and that's what makes Karatsuba Multiplication fast. +This had been know since the 19th century. The problem is that the method requires 4 multiplications (`a*c`, `a*d`, `b*c`, `b*d`). Karatsuba's insight was that you only need three! (`a*c`, `b*d`, `(a+b)*(c+d)`). Now a perfectly valid question right now would be "How is that possible!?!" Here's the math: -```swift -let ac = karatsuba(a, by: c) -let bd = karatsuba(b, by: d) -let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd -``` - -The last recursion is interesting. Normally, you'd think we would have to run four recursions to find the product `x*y` (`a*c`, `a*d`, `b*c`, `b*d`). However, Karatsuba realized that you only need three recursions, and some addition and subtraction. Here's the math: - - (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c - = (a*d + b*c) + (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c + = (a*d + b*c) Pretty cool, huh? -Here's the full implementation +Here's the full implementation. Note that the recursive algorithm is most efficient at m = n/2. ```swift // Karatsuba Multiplication @@ -104,9 +97,9 @@ func karatsuba(_ num1: Int, by num2: Int) -> Int { } ``` -The run time for this algorithm is about **O(n^1.56)** which is better than the **O(n^2)** for Long Multiplication. +What about the running time of this algorithm? Is all this extra work worth it? We can use the Master Theorem to answer this question. This leads us to `T(n) = 3*T(n/2) + c*n + d` where c & d are some constants. It follows (because 3 > 2^1) that the running time is **O(n^log2(3))** which is roughly **O(n^1.56)**. Much better! -Example 2: Multiply 1234 by 5678 using Karatsuba Multiplication +### Example 2: Multiply 1234 by 5678 using Karatsuba Multiplication m = 2 x = 1234 = a*10^2 + b = 12*10^2 + 34 @@ -126,4 +119,6 @@ Example 2: Multiply 1234 by 5678 using Karatsuba Multiplication [WolframMathWorld] (http://mathworld.wolfram.com/KaratsubaMultiplication.html) +[Master Theorem] (https://en.wikipedia.org/wiki/Master_theorem) + *Written for Swift Algorithm Club by Richard Ash* From d0da5de44f445e2d651e9e08eeb8854b16c52a99 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 6 Oct 2016 23:03:27 -0700 Subject: [PATCH 0185/1275] Fixed a typo --- .../KaratsubaMultiplication.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 95a498322..075f75098 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -33,7 +33,7 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { return Int(product.reversed().map{ String($0) }.reduce("", +))! } -// Karatsuba Multiplication - O(nlogn) +// Karatsuba Multiplication - O(n^log2(3)) func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1Array = String(num1).characters let num2Array = String(num2).characters From 3d26e9258de7d82a494806019919f93150bc9e8d Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Fri, 7 Oct 2016 20:18:22 -0500 Subject: [PATCH 0186/1275] updated readme --- .../BoyerMoore.playground/Contents.swift | 3 + .../BoyerMoore.playground/timeline.xctimeline | 6 +- Boyer-Moore/README.markdown | 81 ++++++++++--------- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 9a3d619dc..4b2bad42c 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -46,3 +46,6 @@ s.indexOf(pattern: "World") // 7 let animals = "🐶🐔🐷🐮🐱" animals.indexOf(pattern: "🐮") // 6 + + + diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline index 623552dab..59d8c8667 100644 --- a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline +++ b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index ad1d3bc73..4d98f5a28 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -9,14 +9,14 @@ For example: ```swift // Input: let s = "Hello, World" -s.indexOf("World") +s.indexOf(pattern: "World") // Output: 7 // Input: let animals = "🐶🐔🐷🐮🐱" -animals.indexOf("🐮") +animals.indexOf(pattern: "🐮") // Output: 6 @@ -32,67 +32,68 @@ Here's how you could write it in Swift: ```swift extension String { - func indexOf(pattern: String) -> 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. +func indexOf(pattern: String) -> 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.count) + assert(patternLength > 0) + assert(patternLength <= self.characters.count) - // Make the skip table. This table determines how far we skip ahead - // when a character from the pattern is found. +// 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.enumerate() { - skipTable[c] = patternLength - i - 1 + skipTable[c] = patternLength - i - 1 } - // This points at the last character in the pattern. +// This points at the last character in the pattern. let p = pattern.endIndex.predecessor() let lastChar = pattern[p] - // The pattern is scanned right-to-left, so skip ahead in the string by - // the length of the pattern. (Minus 1 because startIndex already points - // at the first character in the source string.) +// The pattern is scanned right-to-left, so skip ahead in the string by +// the length of the pattern. (Minus 1 because startIndex already points +// at the first character in the source string.) var i = self.startIndex.advancedBy(patternLength - 1) - // This is a helper function that steps backwards through both strings - // until we find a character that doesn’t match, or until we’ve reached - // the beginning of the pattern. +// This is a helper function that steps backwards through both strings +// until we find a character that doesn’t match, or until we’ve reached +// the beginning of the pattern. func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = j.predecessor() - q = q.predecessor() - if self[j] != pattern[q] { return nil } - } - return j + var q = p + var j = i + while q > pattern.startIndex { + j = j.predecessor() + q = q.predecessor() + if self[j] != pattern[q] { return nil } + } + return j } - // The main loop. Keep going until the end of the string is reached. +// The main loop. Keep going until the end of the string is reached. while i < self.endIndex { - let c = self[i] + let c = self[i] - // Does the current character match the last character from the pattern? - if c == lastChar { +// Does the current character match the last character from the pattern? + if c == lastChar { - // There is a possible match. Do a brute-force search backwards. +// There is a possible match. Do a brute-force search backwards. if let k = backwards() { return k } - // If no match, we can only safely skip one character ahead. +// If no match, we can only safely skip one character ahead. i = i.successor() - } else { - // The characters are not equal, so skip ahead. The amount to skip is - // determined by the skip table. If the character is not present in the - // pattern, we can skip ahead by the full pattern length. However, if - // the character *is* present in the pattern, there may be a match up - // ahead and we can't skip as far. + } else { +// The characters are not equal, so skip ahead. The amount to skip is +// determined by the skip table. If the character is not present in the +// pattern, we can skip ahead by the full pattern length. However, if +// the character *is* present in the pattern, there may be a match up +// ahead and we can't skip as far. i = i.advancedBy(skipTable[c] ?? patternLength) - } + } } - return nil - } + return nil + } } + ``` The algorithm works as follows. You line up the search pattern with the source string and see what character from the string matches the *last* character of the search pattern: From a2892beff7f3769087ecc20c00a868e6b99f5628 Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Fri, 7 Oct 2016 20:36:43 -0500 Subject: [PATCH 0187/1275] formatting --- .../BoyerMoore.playground/Contents.swift | 1 + .../BoyerMoore.playground/timeline.xctimeline | 6 +- Boyer-Moore/README.markdown | 92 +++++++++---------- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 4b2bad42c..14447f495 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -39,6 +39,7 @@ extension String { } } + // A few simple tests let s = "Hello, World" diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline index 59d8c8667..7e38effd2 100644 --- a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline +++ b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index 4d98f5a28..dc40413ec 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -33,65 +33,65 @@ Here's how you could write it in Swift: ```swift extension String { func indexOf(pattern: String) -> 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. + // 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.count) + assert(patternLength > 0) + assert(patternLength <= self.characters.count) -// Make the skip table. This table determines how far we skip ahead -// when a character from the pattern is found. + // 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.enumerate() { - skipTable[c] = patternLength - i - 1 + for (i, c) in pattern.characters.enumerated() { + skipTable[c] = patternLength - i - 1 } -// This points at the last character in the pattern. - let p = pattern.endIndex.predecessor() + // This points at the last character in the pattern. + let p = index(before: pattern.endIndex) let lastChar = pattern[p] -// The pattern is scanned right-to-left, so skip ahead in the string by -// the length of the pattern. (Minus 1 because startIndex already points -// at the first character in the source string.) - var i = self.startIndex.advancedBy(patternLength - 1) + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = index(self.startIndex, offsetBy: patternLength - 1) -// This is a helper function that steps backwards through both strings -// until we find a character that doesn’t match, or until we’ve reached -// the beginning of the pattern. + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = j.predecessor() - q = q.predecessor() - if self[j] != pattern[q] { return nil } - } - return j + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j } -// The main loop. Keep going until the end of the string is reached. + // The main loop. Keep going until the end of the string is reached. while i < self.endIndex { - let c = self[i] - -// Does the current character match the last character from the pattern? - if c == lastChar { - -// There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } - -// If no match, we can only safely skip one character ahead. - i = i.successor() - } else { -// The characters are not equal, so skip ahead. The amount to skip is -// determined by the skip table. If the character is not present in the -// pattern, we can skip ahead by the full pattern length. However, if -// the character *is* present in the pattern, there may be a match up -// ahead and we can't skip as far. - i = i.advancedBy(skipTable[c] ?? patternLength) - } + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = index(i, offsetBy: skipTable[c] ?? patternLength) + } + } + return nil } - return nil - } } ``` From f09b42be3e59052a5ec5937fc645f71467aa0677 Mon Sep 17 00:00:00 2001 From: Kevin Taniguchi Date: Fri, 7 Oct 2016 21:16:05 -0500 Subject: [PATCH 0188/1275] updated readme --- .../BoyerMoore.playground/Contents.swift | 4 -- .../BoyerMoore.playground/timeline.xctimeline | 6 +-- Boyer-Moore/README.markdown | 42 +++++++++++-------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 14447f495..9a3d619dc 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -39,7 +39,6 @@ extension String { } } - // A few simple tests let s = "Hello, World" @@ -47,6 +46,3 @@ s.indexOf(pattern: "World") // 7 let animals = "🐶🐔🐷🐮🐱" animals.indexOf(pattern: "🐮") // 6 - - - diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline index 7e38effd2..a15b8d6e0 100644 --- a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline +++ b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index dc40413ec..4acc1ffb3 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -150,34 +150,42 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm: ```swift extension String { - public func indexOf(pattern: String) -> String.Index? { + func indexOf(pattern: String) -> String.Index? { let patternLength = pattern.characters.count assert(patternLength > 0) assert(patternLength <= self.characters.count) var skipTable = [Character: Int]() - for (i, c) in pattern.characters.dropLast().enumerate() { - skipTable[c] = patternLength - i - 1 + for (i, c) in pattern.characters.enumerated() { + skipTable[c] = patternLength - i - 1 } - var index = self.startIndex.advancedBy(patternLength - 1) - - while index < self.endIndex { - var i = index - var p = pattern.endIndex.predecessor() - - while self[i] == pattern[p] { - if p == pattern.startIndex { return i } - i = i.predecessor() - p = p.predecessor() - } + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + var i = self.index(startIndex, offsetBy: patternLength - 1) - let advance = skipTable[self[index]] ?? patternLength - index = index.advancedBy(advance) + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j } + while i < self.endIndex { + let c = self[i] + if c == lastChar { + if let k = backwards() { return k } + i = index(after: i) + } else { + i = index(i, offsetBy: skipTable[c] ?? patternLength) + } + } return nil - } + } } ``` From 0fa26236edb993696d77e00e47e7eebec07fe2d0 Mon Sep 17 00:00:00 2001 From: Peter Ivanics Date: Sat, 8 Oct 2016 22:31:46 +0300 Subject: [PATCH 0189/1275] Migrate Linked List to Swift 3.0 --- .../LinkedList.playground/Contents.swift | 39 ++++---- Linked List/LinkedList.swift | 97 +++++++++---------- Linked List/Tests/LinkedListTests.swift | 32 +++--- 3 files changed, 80 insertions(+), 88 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 72dcffe02..e73f89518 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -47,7 +47,7 @@ public class LinkedList { } } - public func nodeAt(_ index: Int) -> Node? { + public func node(atIndex index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -61,12 +61,12 @@ public class LinkedList { } public subscript(index: Int) -> T { - let node = nodeAt(index) + let node = self.node(atIndex: index) assert(node != nil) return node!.value } - public func append(value: T) { + public func append(_ value: T) { let newNode = Node(value: value) if let lastNode = last { newNode.previous = lastNode @@ -93,7 +93,7 @@ public class LinkedList { return (prev, next) } - public func insert(value: T, atIndex index: Int) { + public func insert(_ value: T, atIndex index: Int) { let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = Node(value: value) @@ -132,8 +132,8 @@ public class LinkedList { return remove(node: last!) } - public func removeAt(_ index: Int) -> T { - let node = nodeAt(index) + public func remove(atIndex index: Int) -> T { + let node = self.node(atIndex: index) assert(node != nil) return remove(node: node!) } @@ -168,7 +168,7 @@ extension LinkedList { let result = LinkedList() var node = head while node != nil { - result.append(value: transform(node!.value)) + result.append(transform(node!.value)) node = node!.next } return result @@ -179,7 +179,7 @@ extension LinkedList { var node = head while node != nil { if predicate(node!.value) { - result.append(value: node!.value) + result.append(node!.value) } node = node!.next } @@ -187,21 +187,18 @@ extension LinkedList { } } - - - let list = LinkedList() list.isEmpty // true list.first // nil list.last // nil -list.append(value: "Hello") +list.append("Hello") list.isEmpty list.first!.value // "Hello" list.last!.value // "Hello" list.count // 1 -list.append(value: "World") +list.append("World") list.first!.value // "Hello" list.last!.value // "World" list.count // 2 @@ -211,15 +208,15 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.nodeAt(0)!.value // "Hello" -list.nodeAt(1)!.value // "World" -list.nodeAt(2) // nil +list.node(atIndex: 0)!.value // "Hello" +list.node(atIndex: 1)!.value // "World" +list.node(atIndex: 2) // nil list[0] // "Hello" list[1] // "World" //list[2] // crash! -list.insert(value: "Swift", atIndex: 1) +list.insert("Swift", atIndex: 1) list[0] list[1] list[2] @@ -227,8 +224,8 @@ print(list) list.reverse() // [World, Swift, Hello] -list.nodeAt(0)!.value = "Universe" -list.nodeAt(1)!.value = "Swifty" +list.node(atIndex: 0)!.value = "Universe" +list.node(atIndex: 1)!.value = "Swifty" let m = list.map { s in s.characters.count } m // [8, 6, 5] let f = list.filter { s in s.characters.count > 5 } @@ -237,7 +234,7 @@ f // [Universe, Swifty] //list.removeAll() //list.isEmpty -list.remove(node: list.first!) // "Hello" +list.remove(node: list.first!) // "Hello" list.count // 2 list[0] // "Swift" list[1] // "World" @@ -246,5 +243,5 @@ list.removeLast() // "World" list.count // 1 list[0] // "Swift" -list.removeAt(0) // "Swift" +list.remove(atIndex: 0) // "Swift" list.count // 0 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 306743354..49f1c0915 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,32 +1,27 @@ -/* - Doubly-linked list - - Most operations on the linked list have complexity O(n). -*/ -open class LinkedListNode { +public class LinkedListNode { var value: T var next: LinkedListNode? weak var previous: LinkedListNode? - + public init(value: T) { self.value = value } } -open class LinkedList { +public class LinkedList { public typealias Node = LinkedListNode - + fileprivate var head: Node? - - open var isEmpty: Bool { + + public var isEmpty: Bool { return head == nil } - - open var first: Node? { + + public var first: Node? { return head } - - open var last: Node? { + + public var last: Node? { if var node = head { while case let next? = node.next { node = next @@ -36,8 +31,8 @@ open class LinkedList { return nil } } - - open var count: Int { + + public var count: Int { if var node = head { var c = 1 while case let next? = node.next { @@ -49,8 +44,8 @@ open class LinkedList { return 0 } } - - open func nodeAt(_ index: Int) -> Node? { + + public func node(atIndex index: Int) -> Node? { if index >= 0 { var node = head var i = index @@ -62,14 +57,14 @@ open class LinkedList { } return nil } - - open subscript(index: Int) -> T { - let node = nodeAt(index) + + public subscript(index: Int) -> T { + let node = self.node(atIndex: index) assert(node != nil) return node!.value } - - open func append(_ value: T) { + + public func append(_ value: T) { let newNode = Node(value: value) if let lastNode = last { newNode.previous = lastNode @@ -78,67 +73,67 @@ open class LinkedList { head = newNode } } - - fileprivate func nodesBeforeAndAfter(_ index: Int) -> (Node?, Node?) { + + 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) } - - open func insert(_ value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index) - + + public func insert(_ value: T, atIndex index: Int) { + let (prev, next) = nodesBeforeAndAfter(index: index) + let newNode = Node(value: value) newNode.previous = prev newNode.next = next prev?.next = newNode next?.previous = newNode - + if prev == nil { head = newNode } } - - open func removeAll() { + + public func removeAll() { head = nil } - - open func remove(_ node: Node) -> T { + + 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 } - - open func removeLast() -> T { + + public func removeLast() -> T { assert(!isEmpty) - return remove(last!) + return remove(node: last!) } - - open func removeAt(_ index: Int) -> T { - let node = nodeAt(index) + + public func remove(atIndex index: Int) -> T { + let node = self.node(atIndex: index) assert(node != nil) - return remove(node!) + return remove(node: node!) } } @@ -167,17 +162,17 @@ extension LinkedList { } extension LinkedList { - public func map(_ transform: (T)-> U) -> LinkedList { + public func map(transform: (T) -> U) -> LinkedList { let result = LinkedList() var node = head while node != nil { - result.append(transform(node!.value)) + result.append(transform(node!.value)) node = node!.next } return result } - - public func filter(_ predicate: (T)-> Bool) -> LinkedList { + + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head while node != nil { diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index beba84299..367ec8c6b 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -88,7 +88,7 @@ class LinkedListTest: XCTestCase { func testNodeAtIndexInEmptyList() { let list = LinkedList() - let node = list.nodeAt(0) + let node = list.node(atIndex: 0) XCTAssertNil(node) } @@ -96,7 +96,7 @@ class LinkedListTest: XCTestCase { let list = LinkedList() list.append(123) - let node = list.nodeAt(0) + let node = list.node(atIndex: 0) XCTAssertNotNil(node) XCTAssertEqual(node!.value, 123) XCTAssertTrue(node === list.first) @@ -108,21 +108,21 @@ class LinkedListTest: XCTestCase { let nodeCount = list.count XCTAssertEqual(nodeCount, numbers.count) - XCTAssertNil(list.nodeAt(-1)) - XCTAssertNil(list.nodeAt(nodeCount)) + XCTAssertNil(list.node(atIndex: -1)) + XCTAssertNil(list.node(atIndex: nodeCount)) - let first = list.nodeAt(0) + let first = list.node(atIndex: 0) XCTAssertNotNil(first) XCTAssertTrue(first === list.first) XCTAssertEqual(first!.value, numbers[0]) - let last = list.nodeAt(nodeCount - 1) + let last = list.node(atIndex: nodeCount - 1) XCTAssertNotNil(last) XCTAssertTrue(last === list.last) XCTAssertEqual(last!.value, numbers[nodeCount - 1]) for i in 0..() list.append(123) - let value = list.removeAt(0) + let value = list.remove(atIndex: 0) XCTAssertEqual(value, 123) XCTAssertTrue(list.isEmpty) @@ -181,16 +181,16 @@ class LinkedListTest: XCTestCase { func testRemoveAtIndex() { let list = buildList() - let prev = list.nodeAt(2) - let next = list.nodeAt(3) + let prev = list.node(atIndex: 2) + let next = list.node(atIndex: 3) let nodeCount = list.count list.insert(444, atIndex: 3) - let value = list.removeAt(3) + let value = list.remove(atIndex: 3) XCTAssertEqual(value, 444) - let node = list.nodeAt(3) + let node = list.node(atIndex: 3) XCTAssertTrue(next === node) XCTAssertTrue(prev!.next === node) XCTAssertTrue(node!.previous === prev) From 4f5565d15ef94ba1cc2a6f2f08c2cebc96baa058 Mon Sep 17 00:00:00 2001 From: Artur Date: Sat, 8 Oct 2016 23:58:07 +0300 Subject: [PATCH 0190/1275] Migrate treap to swift 3 --- .travis.yml | 1 + Treap/Treap.swift | 253 ++++--- Treap/Treap/Treap.xcodeproj/project.pbxproj | 162 +---- .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Tests.xcscheme | 33 +- .../xcshareddata/xcschemes/Treap.xcscheme | 101 --- Treap/Treap/Treap/AppDelegate.swift | 43 -- .../AppIcon.appiconset/Contents.json | 58 -- Treap/Treap/Treap/Base.lproj/MainMenu.xib | 681 ------------------ Treap/Treap/TreapTests/TreapTests.swift | 83 ++- Treap/TreapCollectionType.swift | 138 ++-- Treap/TreapMergeSplit.swift | 156 ++-- 12 files changed, 375 insertions(+), 1342 deletions(-) create mode 100644 Treap/Treap/Treap.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Treap.xcscheme delete mode 100644 Treap/Treap/Treap/AppDelegate.swift delete mode 100644 Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Treap/Treap/Treap/Base.lproj/MainMenu.xib diff --git a/.travis.yml b/.travis.yml index 949fc759f..35bcf6199 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,3 +39,4 @@ script: # - 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 diff --git a/Treap/Treap.swift b/Treap/Treap.swift index e1d1d4892..478f248df 100644 --- a/Treap/Treap.swift +++ b/Treap/Treap.swift @@ -25,146 +25,145 @@ THE SOFTWARE.*/ import Foundation public indirect enum Treap { - case Empty - case Node(key: Key, val: Element, p: Int, left: Treap, right: Treap) - - public init() { - self = .Empty - } - - internal func get(key: Key) -> Element? { - switch self { - case .Empty: - return nil - case let .Node(treeKey, val, _, _, _) where treeKey == key: - return val - case let .Node(treeKey, _, _, left, _) where key < treeKey: - return left.get(key) - case let .Node(treeKey, _, _, _, right) where key > treeKey: - return right.get(key) - default: - return nil - } + case empty + case node(key: Key, val: Element, p: Int, left: Treap, right: Treap) + + public init() { + self = .empty + } + + internal func get(_ key: Key) -> Element? { + switch self { + case .empty: + return nil + case let .node(treeKey, val, _, _, _) where treeKey == key: + return val + case let .node(treeKey, _, _, left, _) where key < treeKey: + return left.get(key) + case let .node(treeKey, _, _, _, right) where key > treeKey: + return right.get(key) + default: + return nil } - - public func contains(key: Key) -> Bool { - switch self { - case .Empty: - return false - case let .Node(treeKey, _, _, _, _) where treeKey == key: - return true - case let .Node(treeKey, _, _, left, _) where key < treeKey: - return left.contains(key) - case let .Node(treeKey, _, _, _, right) where key > treeKey: - return right.contains(key) - default: - return false - } + } + + public func contains(_ key: Key) -> Bool { + switch self { + case .empty: + return false + case let .node(treeKey, _, _, _, _) where treeKey == key: + return true + case let .node(treeKey, _, _, left, _) where key < treeKey: + return left.contains(key) + case let .node(treeKey, _, _, _, right) where key > treeKey: + return right.contains(key) + default: + return false } - - public var depth: Int { - get { - switch self { - case .Empty: - return 0 - case let .Node(_, _, _, left, .Empty): - return 1 + left.depth - case let .Node(_, _, _, .Empty, right): - return 1 + right.depth - case let .Node(_, _, _, left, right): - let leftDepth = left.depth - let rightDepth = right.depth - return 1 + max(leftDepth, rightDepth) - } - - } + } + + public var depth: Int { + get { + switch self { + case .empty: + return 0 + case let .node(_, _, _, left, .empty): + return 1 + left.depth + case let .node(_, _, _, .empty, right): + return 1 + right.depth + case let .node(_, _, _, left, right): + let leftDepth = left.depth + let rightDepth = right.depth + return 1 + leftDepth > rightDepth ? leftDepth : rightDepth + } + } - - public var count: Int { - get { - return Treap.countHelper(self) - } + } + + public var count: Int { + get { + return Treap.countHelper(self) } - - private static func countHelper(treap: Treap) -> Int { - if case let .Node(_, _, _, left, right) = treap { - return countHelper(left) + 1 + countHelper(right) - } - - return 0 + } + + fileprivate static func countHelper(_ treap: Treap) -> Int { + if case let .node(_, _, _, left, right) = treap { + return countHelper(left) + 1 + countHelper(right) } + + return 0 + } } -internal func leftRotate(tree: Treap) -> Treap { - if case let .Node(key, val, p, .Node(leftKey, leftVal, leftP, leftLeft, leftRight), right) = tree { - return .Node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, - right: Treap.Node(key: key, val: val, p: p, left: leftRight, right: right)) - } else { - return .Empty - } +internal func leftRotate(_ tree: Treap) -> Treap { + if case let .node(key, val, p, .node(leftKey, leftVal, leftP, leftLeft, leftRight), right) = tree { + return .node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, + right: Treap.node(key: key, val: val, p: p, left: leftRight, right: right)) + } else { + return .empty + } } -internal func rightRotate(tree: Treap) -> Treap { - if case let .Node(key, val, p, left, .Node(rightKey, rightVal, rightP, rightLeft, rightRight)) = tree { - return .Node(key: rightKey, val: rightVal, p: rightP, - left: Treap.Node(key: key, val: val, p: p, left: left, right: rightLeft), right: rightRight) - } else { - return .Empty - } +internal func rightRotate(_ tree: Treap) -> Treap { + if case let .node(key, val, p, left, .node(rightKey, rightVal, rightP, rightLeft, rightRight)) = tree { + return .node(key: rightKey, val: rightVal, p: rightP, + left: Treap.node(key: key, val: val, p: p, left: left, right: rightLeft), right: rightRight) + } else { + return .empty + } } public extension Treap { - internal func set(key: Key, val: Element, p: Int = Int(arc4random())) -> Treap { - switch self { - case .Empty: - return .Node(key: key, val: val, p: p, left: .Empty, right: .Empty) - case let .Node(nodeKey, nodeVal, nodeP, left, right) where key != nodeKey: - return insertAndBalance(nodeKey, nodeVal, nodeP, left, right, key, val, p) - case let .Node(nodeKey, _, nodeP, left, right) where key == nodeKey: - return .Node(key: key, val: val, p: nodeP, left: left, right: right) - default: // should never happen - return .Empty - } - + internal func set(key: Key, val: Element, p: Int = Int(arc4random())) -> Treap { + switch self { + case .empty: + return .node(key: key, val: val, p: p, left: .empty, right: .empty) + case let .node(nodeKey, nodeVal, nodeP, left, right) where key != nodeKey: + return insertAndBalance(nodeKey, nodeVal, nodeP, left, right, key, val, p) + case let .node(nodeKey, _, nodeP, left, right) where key == nodeKey: + return .node(key: key, val: val, p: nodeP, left: left, right: right) + default: // should never happen + return .empty } - - private func insertAndBalance(nodeKey: Key, _ nodeVal: Element, _ nodeP: Int, _ left: Treap, - _ right: Treap, _ key: Key, _ val: Element, _ p: Int) -> Treap { - let newChild: Treap - let newNode: Treap - let rotate: (Treap) -> Treap - if key < nodeKey { - newChild = left.set(key, val: val, p: p) - newNode = .Node(key: nodeKey, val: nodeVal, p: nodeP, left: newChild, right: right) - rotate = leftRotate - } else if key > nodeKey { - newChild = right.set(key, val: val, p: p) - newNode = .Node(key: nodeKey, val: nodeVal, p: nodeP, left: left, right: newChild) - rotate = rightRotate - } else { - // It should be impossible to reach here - newChild = .Empty - newNode = .Empty - return newNode - } - - if case let .Node(_, _, newChildP, _, _) = newChild where newChildP < nodeP { - return rotate(newNode) - } else { - return newNode - } + } + + fileprivate func insertAndBalance(_ nodeKey: Key, _ nodeVal: Element, _ nodeP: Int, _ left: Treap, + _ right: Treap, _ key: Key, _ val: Element, _ p: Int) -> Treap { + let newChild: Treap + let newNode: Treap + let rotate: (Treap) -> Treap + if key < nodeKey { + newChild = left.set(key: key, val: val, p: p) + newNode = .node(key: nodeKey, val: nodeVal, p: nodeP, left: newChild, right: right) + rotate = leftRotate + } else if key > nodeKey { + newChild = right.set(key: key, val: val, p: p) + newNode = .node(key: nodeKey, val: nodeVal, p: nodeP, left: left, right: newChild) + rotate = rightRotate + } else { + // It should be impossible to reach here + newChild = .empty + newNode = .empty + return newNode } - - internal func delete(key: Key) throws -> Treap { - switch self { - case .Empty: - throw NSError(domain: "com.wta.treap.errorDomain", code: -1, userInfo: nil) - case let .Node(nodeKey, val, p, left, right) where key < nodeKey: - return try Treap.Node(key: nodeKey, val: val, p: p, left: left.delete(key), right: right) - case let .Node(nodeKey, val, p, left, right) where key > nodeKey: - return try Treap.Node(key: nodeKey, val: val, p: p, left: left, right: right.delete(key)) - case let .Node(_, _, _, left, right): - return merge(left, right: right) - } + + if case let .node(_, _, newChildP, _, _) = newChild , newChildP < nodeP { + return rotate(newNode) + } else { + return newNode + } + } + + internal func delete(key: Key) throws -> Treap { + switch self { + case .empty: + throw NSError(domain: "com.wta.treap.errorDomain", code: -1, userInfo: nil) + case let .node(nodeKey, val, p, left, right) where key < nodeKey: + return try Treap.node(key: nodeKey, val: val, p: p, left: left.delete(key: key), right: right) + case let .node(nodeKey, val, p, left, right) where key > nodeKey: + return try Treap.node(key: nodeKey, val: val, p: p, left: left, right: right.delete(key: key)) + case let .node(_, _, _, left, right): + return merge(left, right: right) } + } } diff --git a/Treap/Treap/Treap.xcodeproj/project.pbxproj b/Treap/Treap/Treap.xcodeproj/project.pbxproj index 319a22f37..df9a0d6ee 100644 --- a/Treap/Treap/Treap.xcodeproj/project.pbxproj +++ b/Treap/Treap/Treap.xcodeproj/project.pbxproj @@ -7,32 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - E1E34DC71C7670240023AF4D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DC61C7670240023AF4D /* AppDelegate.swift */; }; - E1E34DC91C7670240023AF4D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E1E34DC81C7670240023AF4D /* Assets.xcassets */; }; - E1E34DCC1C7670240023AF4D /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = E1E34DCA1C7670240023AF4D /* MainMenu.xib */; }; + 750439C01DA9924E0045C660 /* Treap.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE11C7670350023AF4D /* Treap.swift */; }; + 750439C11DA992510045C660 /* TreapMergeSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */; }; + 750439C21DA992530045C660 /* TreapCollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */; }; E1E34DD71C7670250023AF4D /* TreapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DD61C7670250023AF4D /* TreapTests.swift */; }; - E1E34DE31C7670350023AF4D /* Treap.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE11C7670350023AF4D /* Treap.swift */; }; - E1E34DE41C7670350023AF4D /* TreapMergeSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */; }; - E1E34DEA1C7671200023AF4D /* TreapCollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - E1E34DD31C7670250023AF4D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E1E34DBB1C7670240023AF4D /* Project object */; - proxyType = 1; - remoteGlobalIDString = E1E34DC21C7670240023AF4D; - remoteInfo = Treap; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ - E1E34DC31C7670240023AF4D /* Treap.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Treap.app; sourceTree = BUILT_PRODUCTS_DIR; }; - E1E34DC61C7670240023AF4D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - E1E34DC81C7670240023AF4D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - E1E34DCB1C7670240023AF4D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; E1E34DCD1C7670240023AF4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E1E34DD21C7670250023AF4D /* TreapTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TreapTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + E1E34DD21C7670250023AF4D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E1E34DD61C7670250023AF4D /* TreapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreapTests.swift; sourceTree = ""; }; E1E34DD81C7670250023AF4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E1E34DE11C7670350023AF4D /* Treap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Treap.swift; path = ../../Treap.swift; sourceTree = ""; }; @@ -41,13 +24,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - E1E34DC01C7670240023AF4D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; E1E34DCF1C7670250023AF4D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -70,8 +46,7 @@ E1E34DC41C7670240023AF4D /* Products */ = { isa = PBXGroup; children = ( - E1E34DC31C7670240023AF4D /* Treap.app */, - E1E34DD21C7670250023AF4D /* TreapTests.xctest */, + E1E34DD21C7670250023AF4D /* Tests.xctest */, ); name = Products; sourceTree = ""; @@ -79,9 +54,6 @@ E1E34DC51C7670240023AF4D /* Treap */ = { isa = PBXGroup; children = ( - E1E34DC61C7670240023AF4D /* AppDelegate.swift */, - E1E34DC81C7670240023AF4D /* Assets.xcassets */, - E1E34DCA1C7670240023AF4D /* MainMenu.xib */, E1E34DE11C7670350023AF4D /* Treap.swift */, E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */, E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */, @@ -102,26 +74,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - E1E34DC21C7670240023AF4D /* Treap */ = { + E1E34DD11C7670250023AF4D /* Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = E1E34DDB1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Treap" */; - buildPhases = ( - E1E34DBF1C7670240023AF4D /* Sources */, - E1E34DC01C7670240023AF4D /* Frameworks */, - E1E34DC11C7670240023AF4D /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Treap; - productName = Treap; - productReference = E1E34DC31C7670240023AF4D /* Treap.app */; - productType = "com.apple.product-type.application"; - }; - E1E34DD11C7670250023AF4D /* TreapTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "TreapTests" */; + buildConfigurationList = E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Tests" */; buildPhases = ( E1E34DCE1C7670250023AF4D /* Sources */, E1E34DCF1C7670250023AF4D /* Frameworks */, @@ -130,11 +85,10 @@ buildRules = ( ); dependencies = ( - E1E34DD41C7670250023AF4D /* PBXTargetDependency */, ); - name = TreapTests; + name = Tests; productName = TreapTests; - productReference = E1E34DD21C7670250023AF4D /* TreapTests.xctest */; + productReference = E1E34DD21C7670250023AF4D /* Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -144,15 +98,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "WillowTree, Inc."; TargetAttributes = { - E1E34DC21C7670240023AF4D = { - CreatedOnToolsVersion = 7.2.1; - }; E1E34DD11C7670250023AF4D = { CreatedOnToolsVersion = 7.2.1; - TestTargetID = E1E34DC21C7670240023AF4D; + LastSwiftMigration = 0800; }; }; }; @@ -169,22 +120,12 @@ projectDirPath = ""; projectRoot = ""; targets = ( - E1E34DC21C7670240023AF4D /* Treap */, - E1E34DD11C7670250023AF4D /* TreapTests */, + E1E34DD11C7670250023AF4D /* Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - E1E34DC11C7670240023AF4D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E1E34DC91C7670240023AF4D /* Assets.xcassets in Resources */, - E1E34DCC1C7670240023AF4D /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E1E34DD01C7670250023AF4D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -195,46 +136,19 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - E1E34DBF1C7670240023AF4D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E1E34DEA1C7671200023AF4D /* TreapCollectionType.swift in Sources */, - E1E34DE31C7670350023AF4D /* Treap.swift in Sources */, - E1E34DC71C7670240023AF4D /* AppDelegate.swift in Sources */, - E1E34DE41C7670350023AF4D /* TreapMergeSplit.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E1E34DCE1C7670250023AF4D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 750439C01DA9924E0045C660 /* Treap.swift in Sources */, E1E34DD71C7670250023AF4D /* TreapTests.swift in Sources */, + 750439C21DA992530045C660 /* TreapCollectionType.swift in Sources */, + 750439C11DA992510045C660 /* TreapMergeSplit.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - E1E34DD41C7670250023AF4D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E1E34DC21C7670240023AF4D /* Treap */; - targetProxy = E1E34DD31C7670250023AF4D /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - E1E34DCA1C7670240023AF4D /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - E1E34DCB1C7670240023AF4D /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ E1E34DD91C7670250023AF4D /* Debug */ = { isa = XCBuildConfiguration; @@ -249,8 +163,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -293,8 +209,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -313,56 +231,31 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - }; - name = Release; - }; - E1E34DDC1C7670250023AF4D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Treap/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.Treap; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E1E34DDD1C7670250023AF4D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Treap/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.Treap; - PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; E1E34DDF1C7670250023AF4D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = TreapTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.TreapTests; PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Treap.app/Contents/MacOS/Treap"; + SWIFT_VERSION = 3.0; }; name = Debug; }; E1E34DE01C7670250023AF4D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = TreapTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.TreapTests; PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Treap.app/Contents/MacOS/Treap"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -378,21 +271,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - E1E34DDB1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Treap" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E1E34DDC1C7670250023AF4D /* Debug */, - E1E34DDD1C7670250023AF4D /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; - E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "TreapTests" */ = { + E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( E1E34DDF1C7670250023AF4D /* Debug */, E1E34DE01C7670250023AF4D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Treap/Treap/Treap.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Treap/Treap/Treap.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Treap/Treap/Treap.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 3eb165e19..fa2508008 100644 --- a/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "0800" + version = "1.7"> @@ -15,8 +15,8 @@ @@ -33,12 +33,25 @@ + + + + + + @@ -56,8 +69,8 @@ @@ -74,8 +87,8 @@ diff --git a/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Treap.xcscheme b/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Treap.xcscheme deleted file mode 100644 index 566c370e1..000000000 --- a/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Treap.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Treap/Treap/Treap/AppDelegate.swift b/Treap/Treap/Treap/AppDelegate.swift deleted file mode 100644 index a6a68a40c..000000000 --- a/Treap/Treap/Treap/AppDelegate.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// AppDelegate.swift -// Treap -// -// Created by Robert Thompson on 2/18/16. -// Copyright © 2016 Robert Thompson -/* 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.*/ -// - -import Cocoa - -@NSApplicationMain -class AppDelegate: NSObject, NSApplicationDelegate { - - @IBOutlet weak var window: NSWindow! - - - func applicationDidFinishLaunching(aNotification: NSNotification) { - // Insert code here to initialize your application - } - - func applicationWillTerminate(aNotification: NSNotification) { - // Insert code here to tear down your application - } - - -} diff --git a/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json b/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Treap/Treap/Treap/Base.lproj/MainMenu.xib b/Treap/Treap/Treap/Base.lproj/MainMenu.xib deleted file mode 100644 index 8955ad822..000000000 --- a/Treap/Treap/Treap/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,681 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Treap/Treap/TreapTests/TreapTests.swift b/Treap/Treap/TreapTests/TreapTests.swift index 5f43a376f..f349e6ab8 100644 --- a/Treap/Treap/TreapTests/TreapTests.swift +++ b/Treap/Treap/TreapTests/TreapTests.swift @@ -25,50 +25,49 @@ THE SOFTWARE.*/ // swiftlint:disable force_try import XCTest -@testable import Treap class TreapTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testSanity() { + var treap = Treap.empty + treap = treap.set(key: 5, val: "a").set(key: 7, val: "b") + XCTAssert(treap.get(5) == "a") + XCTAssert(treap.get(7) == "b") + treap = treap.set(key: 2, val: "c") + XCTAssert(treap.get(2) == "c") + treap = treap.set(key: 2, val: "d") + XCTAssert(treap.get(2) == "d") + treap = try! treap.delete(key: 5) + XCTAssert(!treap.contains(5)) + XCTAssert(treap.contains(7)) + } + + func testFairlyBalanced() { + var treap = Treap.empty + for i in 0..<1000 { + treap = treap.set(key: i, val: nil) } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() + let depth = treap.depth + XCTAssert(depth < 30, "treap.depth was \(depth)") + } + + func testFairlyBalancedCollection() { + var treap = Treap() + for i in 0..<1000 { + treap[i] = Optional.none } - - func testSanity() { - var treap = Treap.Empty - treap = treap.set(5, val: "a").set(7, val: "b") - XCTAssert(treap.get(5) == "a") - XCTAssert(treap.get(7) == "b") - treap = treap.set(2, val: "c") - XCTAssert(treap.get(2) == "c") - treap = treap.set(2, val: "d") - XCTAssert(treap.get(2) == "d") - treap = try! treap.delete(5) - XCTAssert(!treap.contains(5)) - XCTAssert(treap.contains(7)) - } - - func testFairlyBalanced() { - var treap = Treap.Empty - for i in 0..<1000 { - treap = treap.set(i, val: nil) - } - let depth = treap.depth - XCTAssert(depth < 30, "treap.depth was \(depth)") - } - - func testFairlyBalancedCollection() { - var treap = Treap() - for i in 0..<1000 { - treap[i] = Optional.None - } - let depth = treap.depth - XCTAssert(depth > 0 && depth < 30) - } - + let depth = treap.depth + XCTAssert(depth > 0 && depth < 30) + } + } diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index 36d02eaac..de40464d1 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -24,78 +24,88 @@ THE SOFTWARE.*/ import Foundation -extension Treap: MutableCollectionType { - public typealias Index = TreapIndex - - public subscript(index: TreapIndex) -> Element { - get { - guard let result = self.get(index.keys[index.keyIndex]) else { - fatalError("Invalid index!") - } - - return result - } - - mutating set { - let key = index.keys[index.keyIndex] - self = self.set(key, val: newValue) - } +extension Treap: MutableCollection { + + public typealias Index = TreapIndex + + public subscript(index: TreapIndex) -> Element { + get { + guard let result = self.get(index.keys[index.keyIndex]) else { + fatalError("Invalid index!") + } + + return result } - - public subscript(key: Key) -> Element? { - get { - return self.get(key) - } - - mutating set { - guard let value = newValue else { - let _ = try? self.delete(key) - return - } - - self = self.set(key, val: value) - } + + mutating set { + let key = index.keys[index.keyIndex] + self = self.set(key: key, val: newValue) } - - public var startIndex: TreapIndex { - return TreapIndex(keys: keys, keyIndex: 0) + } + + public subscript(key: Key) -> Element? { + get { + return self.get(key) } - - public var endIndex: TreapIndex { - let keys = self.keys - return TreapIndex(keys: keys, keyIndex: keys.count) + + mutating set { + guard let value = newValue else { + let _ = try? self.delete(key: key) + return + } + + self = self.set(key: key, val: value) } - - private var keys: [Key] { - var results: [Key] = [] - if case let .Node(key, _, _, left, right) = self { - results.appendContentsOf(left.keys) - results.append(key) - results.appendContentsOf(right.keys) - } - - return results + } + + public var startIndex: TreapIndex { + return TreapIndex(keys: keys, keyIndex: 0) + } + + public var endIndex: TreapIndex { + let keys = self.keys + return TreapIndex(keys: keys, keyIndex: keys.count) + } + + public func index(after i: TreapIndex) -> TreapIndex { + return i.successor() + } + + fileprivate var keys: [Key] { + var results: [Key] = [] + if case let .node(key, _, _, left, right) = self { + results.append(contentsOf: left.keys) + results.append(key) + results.append(contentsOf: right.keys) } + + return results + } } -public struct TreapIndex: BidirectionalIndexType { - private let keys: [Key] - private let keyIndex: Int - - public func successor() -> TreapIndex { - return TreapIndex(keys: keys, keyIndex: keyIndex + 1) - } - - public func predecessor() -> TreapIndex { - return TreapIndex(keys: keys, keyIndex: keyIndex - 1) - } - - private init(keys: [Key] = [], keyIndex: Int = 0) { - self.keys = keys - self.keyIndex = keyIndex - } +public struct TreapIndex: Comparable { + + public static func <(lhs: TreapIndex, rhs: TreapIndex) -> Bool { + return lhs.keyIndex < rhs.keyIndex + } + + fileprivate let keys: [Key] + fileprivate let keyIndex: Int + + public func successor() -> TreapIndex { + return TreapIndex(keys: keys, keyIndex: keyIndex + 1) + } + + public func predecessor() -> TreapIndex { + return TreapIndex(keys: keys, keyIndex: keyIndex - 1) + } + + fileprivate init(keys: [Key] = [], keyIndex: Int = 0) { + self.keys = keys + self.keyIndex = keyIndex + } } public func ==(lhs: TreapIndex, rhs: TreapIndex) -> Bool { - return lhs.keys == rhs.keys && lhs.keyIndex == rhs.keyIndex + return lhs.keys == rhs.keys && lhs.keyIndex == rhs.keyIndex } diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift index 277cb40b7..660bd4932 100644 --- a/Treap/TreapMergeSplit.swift +++ b/Treap/TreapMergeSplit.swift @@ -24,93 +24,93 @@ THE SOFTWARE.*/ import Foundation public extension Treap { - internal func split(key: Key) -> (left: Treap, right: Treap) { - var current = self - let val: Element - if let newVal = self.get(key) { - // swiftlint:disable force_try - current = try! current.delete(key) - // swiftlint:enable force_try - val = newVal - } else if case let .Node(_, newVal, _, _, _) = self { - val = newVal - } else { - fatalError("No values in treap") - } - - switch self { - case .Node: - if case let .Node(_, _, _, left, right) = current.set(key, val: val, p: -1) { - return (left: left, right: right) - } else { - return (left: .Empty, right: .Empty) - } - default: - return (left: .Empty, right: .Empty) - } + internal func split(_ key: Key) -> (left: Treap, right: Treap) { + var current = self + let val: Element + if let newVal = self.get(key) { + // swiftlint:disable force_try + current = try! current.delete(key: key) + // swiftlint:enable force_try + val = newVal + } else if case let .node(_, newVal, _, _, _) = self { + val = newVal + } else { + fatalError("No values in treap") } - - internal var leastKey: Key? { - switch self { - case .Empty: - return nil - case let .Node(key, _, _, .Empty, _): - return key - case let .Node(_, _, _, left, _): - return left.leastKey - } + + switch self { + case .node: + if case let .node(_, _, _, left, right) = current.set(key: key, val: val, p: -1) { + return (left: left, right: right) + } else { + return (left: .empty, right: .empty) + } + default: + return (left: .empty, right: .empty) } - - internal var mostKey: Key? { - switch self { - case .Empty: - return nil - case let .Node(key, _, _, _, .Empty): - return key - case let .Node(_, _, _, _, right): - return right.mostKey - } + } + + internal var leastKey: Key? { + switch self { + case .empty: + return nil + case let .node(key, _, _, .empty, _): + return key + case let .node(_, _, _, left, _): + return left.leastKey + } + } + + internal var mostKey: Key? { + switch self { + case .empty: + return nil + case let .node(key, _, _, _, .empty): + return key + case let .node(_, _, _, _, right): + return right.mostKey } + } } -internal func merge(left: Treap, right: Treap) -> Treap { - switch (left, right) { - case (.Empty, _): - return right - case (_, .Empty): - return left - - case let (.Node(leftKey, leftVal, leftP, leftLeft, leftRight), .Node(rightKey, rightVal, rightP, rightLeft, rightRight)): - if leftP < rightP { - return .Node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, right: merge(leftRight, right: right)) - } else { - return .Node(key: rightKey, val: rightVal, p: rightP, left: merge(rightLeft, right: left), right: rightRight) - } - default: - break +internal func merge(_ left: Treap, right: Treap) -> Treap { + switch (left, right) { + case (.empty, _): + return right + case (_, .empty): + return left + + case let (.node(leftKey, leftVal, leftP, leftLeft, leftRight), .node(rightKey, rightVal, rightP, rightLeft, rightRight)): + if leftP < rightP { + return .node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, right: merge(leftRight, right: right)) + } else { + return .node(key: rightKey, val: rightVal, p: rightP, left: merge(rightLeft, right: left), right: rightRight) } - return .Empty + default: + break + } + return .empty } extension Treap: CustomStringConvertible { - public var description: String { - get { - return Treap.descHelper(self, indent: 0) - } + public var description: String { + get { + return Treap.descHelper(self, indent: 0) } - - private static func descHelper(treap: Treap, indent: Int) -> String { - if case let .Node(key, value, priority, left, right) = treap { - var result = "" - let tabs = String(count: indent, repeatedValue: Character("\t")) - - result += descHelper(left, indent: indent + 1) - result += "\n" + tabs + "\(key), \(value), \(priority)\n" - result += descHelper(right, indent: indent + 1) - - return result - } else { - return "" - } + } + + fileprivate static func descHelper(_ treap: Treap, indent: Int) -> String { + if case let .node(key, value, priority, left, right) = treap { + var result = "" + let tabs = String(repeating: "\t", count: indent) + + result += descHelper(left, indent: indent + 1) + result += "\n" + tabs + "\(key), \(value), \(priority)\n" + result += descHelper(right, indent: indent + 1) + + return result + } else { + return "" } + } } From 18c33157976e6d2f010460004ed2a8866243b4f6 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 11 Oct 2016 23:21:10 +0200 Subject: [PATCH 0191/1275] Haversine Distance --- .../Contents.swift | 31 +++++++++++++++++++ .../contents.xcplayground | 4 +++ .../contents.xcworkspacedata | 7 +++++ HaversineDistance/README.md | 23 ++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 HaversineDistance/HaversineDistance.playground/Contents.swift create mode 100644 HaversineDistance/HaversineDistance.playground/contents.xcplayground create mode 100644 HaversineDistance/HaversineDistance.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 HaversineDistance/README.md diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift new file mode 100644 index 000000000..f46d7c394 --- /dev/null +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -0,0 +1,31 @@ + +import UIKit + +func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { + + let haversin = { (angle: Double) -> Double in + return (1 - cos(angle))/2 + } + + let ahaversin = { (angle: Double) -> Double in + return 2*asin(sqrt(angle)) + } + + // Converts from degrees to radians + let dToR = { (angle: Double) -> Double in + return (angle / 360) * 2 * M_PI + } + + let lat1 = dToR(la1) + let lon1 = dToR(lo1) + let lat2 = dToR(la2) + let lon2 = dToR(lo2) + + return radius * ahaversin(haversin(lat2 - lat1) + cos(lat1) * cos(lat2) * haversin(lon2 - lon1)) +} + +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) diff --git a/HaversineDistance/HaversineDistance.playground/contents.xcplayground b/HaversineDistance/HaversineDistance.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/HaversineDistance/HaversineDistance.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/HaversineDistance/HaversineDistance.playground/playground.xcworkspace/contents.xcworkspacedata b/HaversineDistance/HaversineDistance.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/HaversineDistance/HaversineDistance.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/HaversineDistance/README.md b/HaversineDistance/README.md new file mode 100644 index 000000000..84030cbff --- /dev/null +++ b/HaversineDistance/README.md @@ -0,0 +1,23 @@ +# Haversine Distance + +Calculates the distance on a sphere between two points given in latitude and longitude using the haversine formula. + +The haversine formula can be found on [Wikipedia](https://en.wikipedia.org/wiki/Haversine_formula) + +The Haversine Distance is implemented as a function as a class would be kind of overkill. + +`haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double` + +- `la1` is the latitude of point 1 in degrees. +- `lo1` is the longitude of point 1 in degrees. +- `la2` is the latitude of point 2 in degrees. +- `lo2` is the longitude of point 2 in degrees. +- `radius` is the radius of the sphere considered in meters, which defaults to the mean radius of the earth (from [WolframAlpha](http://www.wolframalpha.com/input/?i=earth+radius)). + +The function contains 3 closures in order to make the code more readable and comparable to the Haversine formula given by the Wikipedia page mentioned above. + +1. `haversine` implements the haversine, a trigonometric function. +2. `ahaversine` the inverse function of the haversine. +3. `dToR` a closure converting degrees to radians. + +The result of `haversineDistance` is returned in meters. From 08b9778deb23187d71c7221f04d57a4ba4a1a61d Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 11 Oct 2016 23:23:56 +0200 Subject: [PATCH 0192/1275] update readme --- HaversineDistance/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HaversineDistance/README.md b/HaversineDistance/README.md index 84030cbff..4d5f20e6a 100644 --- a/HaversineDistance/README.md +++ b/HaversineDistance/README.md @@ -21,3 +21,5 @@ The function contains 3 closures in order to make the code more readable and com 3. `dToR` a closure converting degrees to radians. The result of `haversineDistance` is returned in meters. + +*Written for Swift Algorithm Club by Jaap Wijnen.* From 5dc980eec227665710b452013dee0599e278d248 Mon Sep 17 00:00:00 2001 From: Michael Vilabrera Date: Thu, 13 Oct 2016 23:24:39 -0400 Subject: [PATCH 0193/1275] Added Swift Structures to repository list --- README.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 28a56dfd3..6b9f15a6c 100644 --- a/README.markdown +++ b/README.markdown @@ -10,7 +10,7 @@ The goal of this project is to **explain how algorithms work**. The focus is on All code is compatible with **Xcode 7.3** and **Swift 2.2**. We'll keep this updated with the latest version of Swift. -This is a work in progress. More algorithms will be added soon. :-) +This is a work in progress. More algorithms will be added soon. :-) :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: @@ -26,7 +26,7 @@ This is a work in progress. More algorithms will be added soon. :-) [How to contribute](How to Contribute.markdown). Report an issue to leave feedback, or submit a pull request. -[Under construction](Under Construction.markdown). Algorithms that are under construction. +[Under construction](Under Construction.markdown). Algorithms that are under construction. ## Where to start? @@ -210,6 +210,7 @@ Other algorithm repositories: - [@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) ## Credits From d15c1b824ebdbe33b0d415b72ef193b337fbc01a Mon Sep 17 00:00:00 2001 From: Keita Ito Date: Fri, 14 Oct 2016 11:59:41 -0700 Subject: [PATCH 0194/1275] Fix method name from reverse() to reversed() in README.markdown --- Longest Common Subsequence/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown index ba514728a..4cd2c2fcb 100644 --- a/Longest Common Subsequence/README.markdown +++ b/Longest Common Subsequence/README.markdown @@ -152,7 +152,7 @@ func backtrack(_ matrix: [[Int]]) -> String { } } - return String(lcs.characters.reverse()) + return String(lcs.characters.reversed()) } ``` @@ -160,7 +160,7 @@ This backtracks from `matrix[n+1][m+1]` (bottom-right corner) to `matrix[1][1]` 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.) -Due to backtracking, characters are added in reverse order, so at the end of the function we call `reverse()` to put the string in the right order. (Appending new characters to the end of the string and then reversing it once is faster than always inserting the characters at the front of the string.) +Due to backtracking, characters are added in reverse order, so at the end of the function we call `reversed()` to put the string in the right order. (Appending new characters to the end of the string and then reversing it once is faster than always inserting the characters at the front of the string.) ## Putting it all together From 67a2659ac972779ff7d410bcb0783375699cc5d9 Mon Sep 17 00:00:00 2001 From: Eric Yulianto Date: Sun, 16 Oct 2016 01:58:14 +0800 Subject: [PATCH 0195/1275] Migrated Topological Sort to Swift 3 --- .travis.yml | 2 +- Topological Sort/Graph.swift | 2 +- Topological Sort/Tests/Tests.xcodeproj/project.pbxproj | 10 +++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Topological Sort/Tests/TopologicalSortTests.swift | 10 +++++----- .../Topological Sort.playground/Sources/Graph.swift | 2 +- .../Sources/TopologicalSort1.swift | 4 ++-- .../Sources/TopologicalSort3.swift | 8 ++++---- Topological Sort/TopologicalSort1.swift | 4 ++-- Topological Sort/TopologicalSort3.swift | 8 ++++---- 10 files changed, 30 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 949fc759f..a495ecde6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,4 +38,4 @@ script: # - 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 ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests diff --git a/Topological Sort/Graph.swift b/Topological Sort/Graph.swift index 173676537..1e1be6919 100644 --- a/Topological Sort/Graph.swift +++ b/Topological Sort/Graph.swift @@ -7,7 +7,7 @@ public class Graph: CustomStringConvertible { adjacencyLists = [Node : [Node]]() } - public func addNode(value: Node) -> Node { + public func addNode(_ value: Node) -> Node { adjacencyLists[value] = [] return value } diff --git a/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj b/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj index 83c59dbab..f97ffdc69 100644 --- a/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -92,11 +92,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -157,8 +158,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -201,8 +204,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -221,6 +226,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -232,6 +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; }; name = Debug; }; @@ -243,6 +250,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; }; name = Release; }; diff --git a/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..14f27f777 100644 --- a/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Node { + public func addNode(_ value: Node) -> Node { adjacencyLists[value] = [] return value } diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift index 7f1aca5e7..0f9566f6a 100644 --- a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift @@ -1,10 +1,10 @@ extension Graph { - private func depthFirstSearch(source: Node, inout visited: [Node : Bool]) -> [Node] { + private func depthFirstSearch(_ source: Node, visited: inout [Node : Bool]) -> [Node] { var result = [Node]() if let adjacencyList = adjacencyList(forNode: source) { for nodeInAdjacencyList in adjacencyList { - if let seen = visited[nodeInAdjacencyList] where !seen { + if let seen = visited[nodeInAdjacencyList], !seen { result = depthFirstSearch(nodeInAdjacencyList, visited: &visited) + result } } diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift index cdc479b41..3d4a2bbbc 100644 --- a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift @@ -12,10 +12,10 @@ extension Graph { visited[node] = false } - func depthFirstSearch(source: Node) { + func depthFirstSearch(_ source: Node) { if let adjacencyList = adjacencyList(forNode: source) { for neighbor in adjacencyList { - if let seen = visited[neighbor] where !seen { + if let seen = visited[neighbor], !seen { depthFirstSearch(neighbor) } } @@ -25,11 +25,11 @@ extension Graph { } for (node, _) in visited { - if let seen = visited[node] where !seen { + if let seen = visited[node], !seen { depthFirstSearch(node) } } - return stack.reverse() + return stack.reversed() } } diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift index 7f1aca5e7..0f9566f6a 100644 --- a/Topological Sort/TopologicalSort1.swift +++ b/Topological Sort/TopologicalSort1.swift @@ -1,10 +1,10 @@ extension Graph { - private func depthFirstSearch(source: Node, inout visited: [Node : Bool]) -> [Node] { + private func depthFirstSearch(_ source: Node, visited: inout [Node : Bool]) -> [Node] { var result = [Node]() if let adjacencyList = adjacencyList(forNode: source) { for nodeInAdjacencyList in adjacencyList { - if let seen = visited[nodeInAdjacencyList] where !seen { + if let seen = visited[nodeInAdjacencyList], !seen { result = depthFirstSearch(nodeInAdjacencyList, visited: &visited) + result } } diff --git a/Topological Sort/TopologicalSort3.swift b/Topological Sort/TopologicalSort3.swift index cdc479b41..3d4a2bbbc 100644 --- a/Topological Sort/TopologicalSort3.swift +++ b/Topological Sort/TopologicalSort3.swift @@ -12,10 +12,10 @@ extension Graph { visited[node] = false } - func depthFirstSearch(source: Node) { + func depthFirstSearch(_ source: Node) { if let adjacencyList = adjacencyList(forNode: source) { for neighbor in adjacencyList { - if let seen = visited[neighbor] where !seen { + if let seen = visited[neighbor], !seen { depthFirstSearch(neighbor) } } @@ -25,11 +25,11 @@ extension Graph { } for (node, _) in visited { - if let seen = visited[node] where !seen { + if let seen = visited[node], !seen { depthFirstSearch(node) } } - return stack.reverse() + return stack.reversed() } } From dc2b5ba3c19d9733efa3f97eb450d86fc9fea4ca Mon Sep 17 00:00:00 2001 From: Steven Chen Date: Mon, 17 Oct 2016 15:03:11 -0500 Subject: [PATCH 0196/1275] Update to Swift 3.0 --- Shell Sort/Tests/Tests.xcodeproj/project.pbxproj | 3 +++ Shell Sort/shellsort.swift | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj b/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj index 9f7f4391e..1de1c7213 100644 --- a/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; }; }; @@ -224,6 +225,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; }; name = Debug; }; @@ -235,6 +237,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; }; name = Release; }; diff --git a/Shell Sort/shellsort.swift b/Shell Sort/shellsort.swift index 489a92ebc..0740272fc 100644 --- a/Shell Sort/shellsort.swift +++ b/Shell Sort/shellsort.swift @@ -20,8 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -public func insertionSort(inout list: [Int], start: Int, gap: Int) { - for i in (start + gap).stride(to: list.count, by: gap) { +public func insertionSort(_ list: inout [Int], start: Int, gap: Int) { + for i in stride(from: (start + gap), to: list.count, by: gap) { let currentValue = list[i] var pos = i while pos >= gap && list[pos - gap] > currentValue { @@ -32,7 +32,7 @@ public func insertionSort(inout list: [Int], start: Int, gap: Int) { } } -public func shellSort(inout list: [Int]) { +public func shellSort(_ list: inout [Int]) { var sublistCount = list.count / 2 while sublistCount > 0 { for pos in 0.. Date: Mon, 17 Oct 2016 19:58:29 -0500 Subject: [PATCH 0197/1275] Added public init and array init I added a public init so this can be used in a Playground. I also added an extension to create a linked list from an array of values. --- Linked List/LinkedList.playground/Contents.swift | 10 ++++++++++ Linked List/LinkedList.swift | 14 +++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index e73f89518..a90b7180c 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -187,6 +187,16 @@ extension LinkedList { } } +extension LinkedList { + convenience init(array: Array) { + self.init() + + for element in array { + self.append(element) + } + } +} + let list = LinkedList() list.isEmpty // true list.first // nil diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 49f1c0915..86d2bca9b 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -12,7 +12,9 @@ public class LinkedList { public typealias Node = LinkedListNode fileprivate var head: Node? - + + public init() {} + public var isEmpty: Bool { return head == nil } @@ -184,3 +186,13 @@ extension LinkedList { return result } } + +extension LinkedList { + convenience init(array: Array) { + self.init() + + for element in array { + self.append(element) + } + } +} From 133f2d85b0fa188da954c837381570efd263a5ec Mon Sep 17 00:00:00 2001 From: Sahn Cha Date: Tue, 18 Oct 2016 23:35:15 +0900 Subject: [PATCH 0198/1275] Miller-Rabin primality test: probabilistic version --- Miller-Rabin Primality Test/MRPrimality.swift | 61 +++++++++++++++++++ .../contents.xcworkspacedata | 7 +++ 2 files changed, 68 insertions(+) create mode 100644 Miller-Rabin Primality Test/MRPrimality.swift diff --git a/Miller-Rabin Primality Test/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.swift new file mode 100644 index 000000000..8be5ab00d --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -0,0 +1,61 @@ +// +// MRPrimality.swift +// +// +// Created by Sahn Cha on 2016. 10. 18.. +// +// + +import Foundation + +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 = modpow64(r, d, n) + if x == 1 || x == n - 1 { continue } + + for _ in 1 ... s - 1 { + x = modpow64(x, 2, n) + if x == 1 { return false } + if x == n - 1 { break } + } + + if x != n - 1 { return false } + } + return true +} + +private func modpow64(_ 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 = (result * b) % m + } + e >>= 1 + b = (b * b) % m + } + return result +} diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index e7288f299..fb2aeda4b 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -25,6 +25,13 @@ + + + + From 902e6f6a4a9ec8780029e1c9f8277f9b86841948 Mon Sep 17 00:00:00 2001 From: Sahn Cha Date: Thu, 20 Oct 2016 02:09:45 +0900 Subject: [PATCH 0199/1275] Now with playground, comments and pesticide --- .../MRPrimality.playground/Contents.swift | 24 ++++ .../Sources/MRPrimality.swift | 111 ++++++++++++++++++ .../contents.xcplayground | 4 + Miller-Rabin Primality Test/MRPrimality.swift | 66 +++++++++-- .../contents.xcworkspacedata | 3 + 5 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/contents.xcplayground diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift new file mode 100644 index 000000000..8d97dc409 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -0,0 +1,24 @@ +//: Playground - noun: a place where people can play + +// 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) \ No newline at end of file diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift new file mode 100644 index 000000000..9dca23996 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift @@ -0,0 +1,111 @@ +// +// 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/contents.xcplayground b/Miller-Rabin Primality Test/MRPrimality.playground/contents.xcplayground new file mode 100644 index 000000000..63b6dd8df --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Miller-Rabin Primality Test/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.swift index 8be5ab00d..9dca23996 100644 --- a/Miller-Rabin Primality Test/MRPrimality.swift +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -8,6 +8,19 @@ 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 } @@ -21,7 +34,6 @@ public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { let range = UInt64.max - UInt64.max % (n - 2) var r: UInt64 = 0 - repeat { arc4random_buf(&r, MemoryLayout.size(ofValue: r)) } while r >= range @@ -29,21 +41,35 @@ public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { r = r % (n - 2) + 2 for _ in 1 ... k { - var x = modpow64(r, d, n) + var x = powmod64(r, d, n) if x == 1 || x == n - 1 { continue } + if s == 1 { s = 2 } + for _ in 1 ... s - 1 { - x = modpow64(x, 2, n) + x = powmod64(x, 2, n) if x == 1 { return false } if x == n - 1 { break } } if x != n - 1 { return false } } + return true } -private func modpow64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { +/* + 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 @@ -51,11 +77,35 @@ private func modpow64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { var e = exp while e > 0 { - if e % 2 == 1 { - result = (result * b) % m - } + if e % 2 == 1 { result = mulmod64(result, b, m) } + b = mulmod64(b, b, m) e >>= 1 - b = (b * b) % m } + + 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/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index fb2aeda4b..dd0c6b668 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -31,6 +31,9 @@ + + Date: Thu, 20 Oct 2016 10:03:44 -0400 Subject: [PATCH 0200/1275] Switched to Double to handle large prime multiplier --- README.markdown | 2 +- Rabin-Karp/README.markdown | 79 ++++++++++++++ .../Rabin-Karp.playground/Contents.swift | 85 +++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 ++ Rabin-Karp/rabin-karp.swift | 103 ++++++++++++++++++ 6 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 Rabin-Karp/README.markdown create mode 100644 Rabin-Karp/Rabin-Karp.playground/Contents.swift create mode 100644 Rabin-Karp/Rabin-Karp.playground/contents.xcplayground create mode 100644 Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Rabin-Karp/rabin-karp.swift diff --git a/README.markdown b/README.markdown index 28a56dfd3..1bf9e7e6a 100644 --- a/README.markdown +++ b/README.markdown @@ -56,7 +56,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [Brute-Force String Search](Brute-Force String Search/). A naive method. - [Boyer-Moore](Boyer-Moore/). A fast method to search for substrings. It skips ahead based on a look-up table, to avoid looking at every character in the text. - Knuth-Morris-Pratt -- Rabin-Karp +- [Rabin-Karp](Rabin-Karp/) Faster search by using hashing. - [Longest Common Subsequence](Longest Common Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. ### Sorting diff --git a/Rabin-Karp/README.markdown b/Rabin-Karp/README.markdown new file mode 100644 index 000000000..0c3d0b1be --- /dev/null +++ b/Rabin-Karp/README.markdown @@ -0,0 +1,79 @@ +# Rabin-Karp string search algorithm + +The Rabin-Karp string search alogrithm is used to search text for a pattern. + +Algorithms that check for palindromes are a common programming interview question. + +## Example + +Given a text of "The big dog jumped over the fox" and a search pattern of "ump" this will return 13. +It starts by hashing "ump" then hashing "The". If hashed don't match then it slides the window a character +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 +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 code + +The major search method is next. More implementation details are in rabin-karp.swift + +```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 } + + if textArray.count < patternArray.count { + return -1 + } + + let patternHash = hash(array: patternArray) + var endIdx = patternArray.count - 1 + let firstChars = Array(textArray[0...endIdx]) + let firstHash = hash(array: firstChars) + + if (patternHash == firstHash) { + // Verify this was not a hash collison + if firstChars == patternArray { + return 0 + } + } + + var prevHash = firstHash + // Now slide the window across the text to be searched + for idx in 1...(textArray.count - patternArray.count) { + endIdx = idx + (patternArray.count - 1) + let window = Array(textArray[idx...endIdx]) + let windowHash = nextHash(prevHash: prevHash, dropped: textArray[idx - 1], added: textArray[endIdx], patternSize: patternArray.count - 1) + + if windowHash == patternHash { + if patternArray == window { + return idx + } + } + + prevHash = windowHash + } + + return -1 +} +``` + +This code can be tested in a playground using the following: + +```swift + search(text: "The big dog jumped"", "ump") +``` + +This will return 13 since ump is in the 13 position of the zero based string. + +## Additional Resources + +[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 diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift new file mode 100644 index 000000000..f9c8c1919 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -0,0 +1,85 @@ +//: Taking our rabin-karp algorithm for a walk + +import UIKit + +struct Constants { + static let hashMultiplier = 69069 +} + +precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } +infix operator ** : PowerPrecedence +func ** (radix: Int, power: Int) -> Int { + return Int(pow(Double(radix), Double(power))) +} +func ** (radix: Double, power: Int) -> Double { + return pow(radix, Double(power)) +} + +extension Character { + var asInt:Int { + let s = String(self).unicodeScalars + return Int(s[s.startIndex].value) + } +} + +// 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 } + + if textArray.count < patternArray.count { + return -1 + } + + let patternHash = hash(array: patternArray) + var endIdx = patternArray.count - 1 + let firstChars = Array(textArray[0...endIdx]) + let firstHash = hash(array: firstChars) + + if (patternHash == firstHash) { + // Verify this was not a hash collison + if firstChars == patternArray { + return 0 + } + } + + var prevHash = firstHash + // Now slide the window across the text to be searched + for idx in 1...(textArray.count - patternArray.count) { + endIdx = idx + (patternArray.count - 1) + let window = Array(textArray[idx...endIdx]) + let windowHash = nextHash(prevHash: prevHash, dropped: textArray[idx - 1], added: textArray[endIdx], patternSize: patternArray.count - 1) + + if windowHash == patternHash { + if patternArray == window { + return idx + } + } + + prevHash = windowHash + } + + return -1 +} + +public func hash(array: Array) -> Double { + var total : Double = 0 + var exponent = array.count - 1 + for i in array { + total += Double(i) * (Double(Constants.hashMultiplier) ** exponent) + exponent -= 1 + } + + return Double(total) +} + +public func nextHash(prevHash: Double, dropped: Int, added: Int, patternSize: Int) -> Double { + let oldHash = prevHash - (Double(dropped) * (Double(Constants.hashMultiplier) ** patternSize)) + return Double(Constants.hashMultiplier) * oldHash + Double(added) +} + +// TESTS +assert(search(text:"The big dog jumped over the fox", pattern:"ump") == 13, "Invalid index returned") +assert(search(text:"The big dog jumped over the fox", pattern:"missed") == Int(-1), "Invalid index returned") +assert(search(text:"The big dog jumped over the fox", pattern:"T") == 0, "Invalid index returned") diff --git a/Rabin-Karp/Rabin-Karp.playground/contents.xcplayground b/Rabin-Karp/Rabin-Karp.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/contents.xcworkspacedata b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Rabin-Karp/rabin-karp.swift b/Rabin-Karp/rabin-karp.swift new file mode 100644 index 000000000..54ef24fce --- /dev/null +++ b/Rabin-Karp/rabin-karp.swift @@ -0,0 +1,103 @@ +// The MIT License (MIT) + +// Copyright (c) 2016 Bill Barbour (brbatwork[at]gmail.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. + +struct Constants { + static let hashMultiplier = 69069 +} + +precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } +infix operator ** : PowerPrecedence +func ** (radix: Int, power: Int) -> Int { + return Int(pow(Double(radix), Double(power))) +} +func ** (radix: Double, power: Int) -> Double { + return pow(radix, Double(power)) +} + +extension Character { + var asInt:Int { + let s = String(self).unicodeScalars + return Int(s[s.startIndex].value) + } +} + +// 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 } + + if textArray.count < patternArray.count { + return -1 + } + + let patternHash = hash(array: patternArray) + var endIdx = patternArray.count - 1 + let firstChars = Array(textArray[0...endIdx]) + let firstHash = hash(array: firstChars) + + if (patternHash == firstHash) { + // Verify this was not a hash collison + if firstChars == patternArray { + return 0 + } + } + + var prevHash = firstHash + // Now slide the window across the text to be searched + for idx in 1...(textArray.count - patternArray.count) { + endIdx = idx + (patternArray.count - 1) + let window = Array(textArray[idx...endIdx]) + let windowHash = nextHash(prevHash: prevHash, dropped: textArray[idx - 1], added: textArray[endIdx], patternSize: patternArray.count - 1) + + if windowHash == patternHash { + if patternArray == window { + return idx + } + } + + prevHash = windowHash + } + + return -1 +} + +public func hash(array: Array) -> Double { + var total : Double = 0 + var exponent = array.count - 1 + for i in array { + total += Double(i) * (Double(Constants.hashMultiplier) ** exponent) + exponent -= 1 + } + + return Double(total) +} + +public func nextHash(prevHash: Double, dropped: Int, added: Int, patternSize: Int) -> Double { + let oldHash = prevHash - (Double(dropped) * (Double(Constants.hashMultiplier) ** patternSize)) + return Double(Constants.hashMultiplier) * oldHash + Double(added) +} + +// TESTS +assert(search(text:"The big dog jumped over the fox", pattern:"ump") == 13, "Invalid index returned") +assert(search(text:"The big dog jumped over the fox", pattern:"missed") == -1, "Invalid index returned") +assert(search(text:"The big dog jumped over the fox", pattern:"T") == 0, "Invalid index returned") \ No newline at end of file From 4813ee12dcd26489ab10176694829a6c1d98c669 Mon Sep 17 00:00:00 2001 From: billbarbour Date: Thu, 20 Oct 2016 11:27:13 -0400 Subject: [PATCH 0201/1275] Corrected copy pasta --- Rabin-Karp/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rabin-Karp/README.markdown b/Rabin-Karp/README.markdown index 0c3d0b1be..79699caa8 100644 --- a/Rabin-Karp/README.markdown +++ b/Rabin-Karp/README.markdown @@ -2,7 +2,7 @@ The Rabin-Karp string search alogrithm is used to search text for a pattern. -Algorithms that check for palindromes are a common programming interview question. +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. ## Example From 663f902de3b1066c9c8bfc93bdbc05836d05fb02 Mon Sep 17 00:00:00 2001 From: billbarbour Date: Thu, 20 Oct 2016 11:56:09 -0400 Subject: [PATCH 0202/1275] linter cleanup --- .../Rabin-Karp.playground/Contents.swift | 45 ++++++++++++------- Rabin-Karp/rabin-karp.swift | 29 ++++++++---- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift index f9c8c1919..4956fabe3 100644 --- a/Rabin-Karp/Rabin-Karp.playground/Contents.swift +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -16,70 +16,81 @@ func ** (radix: Double, power: Int) -> Double { } extension Character { - var asInt:Int { + var asInt: Int { let s = String(self).unicodeScalars return Int(s[s.startIndex].value) } } // Find first position of pattern in the text using Rabin Karp algorithm -public func search(text: String , pattern: String) -> Int { +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 } - + if textArray.count < patternArray.count { return -1 } - + let patternHash = hash(array: patternArray) var endIdx = patternArray.count - 1 let firstChars = Array(textArray[0...endIdx]) let firstHash = hash(array: firstChars) - - if (patternHash == firstHash) { + + if patternHash == firstHash { // Verify this was not a hash collison if firstChars == patternArray { return 0 } } - + var prevHash = firstHash // Now slide the window across the text to be searched for idx in 1...(textArray.count - patternArray.count) { endIdx = idx + (patternArray.count - 1) let window = Array(textArray[idx...endIdx]) - let windowHash = nextHash(prevHash: prevHash, dropped: textArray[idx - 1], added: textArray[endIdx], patternSize: patternArray.count - 1) - + let windowHash = nextHash( + prevHash: prevHash, + dropped: textArray[idx - 1], + added: textArray[endIdx], + patternSize: patternArray.count - 1 + ) + if windowHash == patternHash { if patternArray == window { return idx } } - + prevHash = windowHash } - + return -1 } public func hash(array: Array) -> Double { - var total : Double = 0 + var total: Double = 0 var exponent = array.count - 1 for i in array { total += Double(i) * (Double(Constants.hashMultiplier) ** exponent) exponent -= 1 } - + return Double(total) } public func nextHash(prevHash: Double, dropped: Int, added: Int, patternSize: Int) -> Double { - let oldHash = prevHash - (Double(dropped) * (Double(Constants.hashMultiplier) ** patternSize)) + let oldHash = prevHash - (Double(dropped) * + (Double(Constants.hashMultiplier) ** patternSize)) return Double(Constants.hashMultiplier) * oldHash + Double(added) } // TESTS -assert(search(text:"The big dog jumped over the fox", pattern:"ump") == 13, "Invalid index returned") -assert(search(text:"The big dog jumped over the fox", pattern:"missed") == Int(-1), "Invalid index returned") -assert(search(text:"The big dog jumped over the fox", pattern:"T") == 0, "Invalid index returned") +assert(search(text:"The big dog jumped over the fox", + pattern:"ump") == 13, "Invalid index returned") + +assert(search(text:"The big dog jumped over the fox", + pattern:"missed") == -1, "Invalid index returned") + +assert(search(text:"The big dog jumped over the fox", + pattern:"T") == 0, "Invalid index returned") diff --git a/Rabin-Karp/rabin-karp.swift b/Rabin-Karp/rabin-karp.swift index 54ef24fce..c337de1a7 100644 --- a/Rabin-Karp/rabin-karp.swift +++ b/Rabin-Karp/rabin-karp.swift @@ -34,14 +34,14 @@ func ** (radix: Double, power: Int) -> Double { } extension Character { - var asInt:Int { + var asInt: Int { let s = String(self).unicodeScalars return Int(s[s.startIndex].value) } } // Find first position of pattern in the text using Rabin Karp algorithm -public func search(text: String , pattern: String) -> Int { +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 } @@ -55,7 +55,7 @@ public func search(text: String , pattern: String) -> Int { let firstChars = Array(textArray[0...endIdx]) let firstHash = hash(array: firstChars) - if (patternHash == firstHash) { + if patternHash == firstHash { // Verify this was not a hash collison if firstChars == patternArray { return 0 @@ -67,7 +67,12 @@ public func search(text: String , pattern: String) -> Int { for idx in 1...(textArray.count - patternArray.count) { endIdx = idx + (patternArray.count - 1) let window = Array(textArray[idx...endIdx]) - let windowHash = nextHash(prevHash: prevHash, dropped: textArray[idx - 1], added: textArray[endIdx], patternSize: patternArray.count - 1) + let windowHash = nextHash( + prevHash: prevHash, + dropped: textArray[idx - 1], + added: textArray[endIdx], + patternSize: patternArray.count - 1 + ) if windowHash == patternHash { if patternArray == window { @@ -82,7 +87,7 @@ public func search(text: String , pattern: String) -> Int { } public func hash(array: Array) -> Double { - var total : Double = 0 + var total: Double = 0 var exponent = array.count - 1 for i in array { total += Double(i) * (Double(Constants.hashMultiplier) ** exponent) @@ -93,11 +98,17 @@ public func hash(array: Array) -> Double { } public func nextHash(prevHash: Double, dropped: Int, added: Int, patternSize: Int) -> Double { - let oldHash = prevHash - (Double(dropped) * (Double(Constants.hashMultiplier) ** patternSize)) + let oldHash = prevHash - (Double(dropped) * + (Double(Constants.hashMultiplier) ** patternSize)) return Double(Constants.hashMultiplier) * oldHash + Double(added) } // TESTS -assert(search(text:"The big dog jumped over the fox", pattern:"ump") == 13, "Invalid index returned") -assert(search(text:"The big dog jumped over the fox", pattern:"missed") == -1, "Invalid index returned") -assert(search(text:"The big dog jumped over the fox", pattern:"T") == 0, "Invalid index returned") \ No newline at end of file +assert(search(text:"The big dog jumped over the fox", + pattern:"ump") == 13, "Invalid index returned") + +assert(search(text:"The big dog jumped over the fox", + pattern:"missed") == -1, "Invalid index returned") + +assert(search(text:"The big dog jumped over the fox", + pattern:"T") == 0, "Invalid index returned") From 182e51b1434ea3b8ecc3e94a1c6b5a7d2f21d0fe Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 21 Oct 2016 01:11:51 -0700 Subject: [PATCH 0203/1275] Updated README to show Slow sort, Karatsuba Manipulation, and Haversine Distance. --- .../KaratsubaMultiplication.playground/Contents.swift | 1 - README.markdown | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 075f75098..bde8fd9f9 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -58,4 +58,3 @@ func karatsuba(_ num1: Int, by num2: Int) -> Int { return product } - diff --git a/README.markdown b/README.markdown index 28a56dfd3..2acedd0fa 100644 --- a/README.markdown +++ b/README.markdown @@ -84,6 +84,7 @@ Special-purpose sorts: Bad sorting algorithms (don't use these!): - [Bubble Sort](Bubble Sort/) +- [Slow Sort](Slow Sort/) ### Compression @@ -101,6 +102,7 @@ Bad sorting algorithms (don't use these!): - [Permutations and Combinations](Combinatorics/). Get your combinatorics on! - [Shunting Yard Algorithm](Shunting Yard/). Convert infix expressions to postfix. - Statistics +- [Karatsuba Multiplication](Karatsuba Multiplication/). Another take on elementary multiplication. ### Machine learning From 3947c6bff451b6d8724739ec9d3e157e481249bd Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 21 Oct 2016 13:38:55 +0200 Subject: [PATCH 0204/1275] migrate ring buffer to swift 3 --- Ring Buffer/RingBuffer.playground/Contents.swift | 14 +++++++------- .../RingBuffer.playground/timeline.xctimeline | 6 ------ 2 files changed, 7 insertions(+), 13 deletions(-) delete mode 100644 Ring Buffer/RingBuffer.playground/timeline.xctimeline diff --git a/Ring Buffer/RingBuffer.playground/Contents.swift b/Ring Buffer/RingBuffer.playground/Contents.swift index a7522c366..29b9917a0 100644 --- a/Ring Buffer/RingBuffer.playground/Contents.swift +++ b/Ring Buffer/RingBuffer.playground/Contents.swift @@ -1,15 +1,15 @@ //: Playground - noun: a place where people can play public struct RingBuffer { - private var array: [T?] - private var readIndex = 0 - private var writeIndex = 0 + fileprivate var array: [T?] + fileprivate var readIndex = 0 + fileprivate var writeIndex = 0 public init(count: Int) { - array = [T?](count: count, repeatedValue: nil) + array = [T?](repeating: nil, count: count) } - public mutating func write(element: T) -> Bool { + public mutating func write(_ element: T) -> Bool { if !isFull { array[writeIndex % array.count] = element writeIndex += 1 @@ -29,7 +29,7 @@ public struct RingBuffer { } } - private var availableSpaceForReading: Int { + fileprivate var availableSpaceForReading: Int { return writeIndex - readIndex } @@ -37,7 +37,7 @@ public struct RingBuffer { return availableSpaceForReading == 0 } - private var availableSpaceForWriting: Int { + fileprivate var availableSpaceForWriting: Int { return array.count - availableSpaceForReading } diff --git a/Ring Buffer/RingBuffer.playground/timeline.xctimeline b/Ring Buffer/RingBuffer.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Ring Buffer/RingBuffer.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From 8cb4917968ad3e70bf7f67aca78908f22ecc97cd Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 21 Oct 2016 13:45:33 +0200 Subject: [PATCH 0205/1275] migrate two sum problem to swift 3 --- Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift | 2 +- .../Solution 1/2Sum.playground/timeline.xctimeline | 6 ------ Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift | 6 +++--- 3 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 Two-Sum Problem/Solution 1/2Sum.playground/timeline.xctimeline diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift index 11c95b96c..00ce05136 100644 --- a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { +func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var map = [Int: Int]() for i in 0 ..< a.count { diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/timeline.xctimeline b/Two-Sum Problem/Solution 1/2Sum.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Two-Sum Problem/Solution 1/2Sum.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift index 1d6b0a9c8..9a555f0eb 100644 --- a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift @@ -1,6 +1,6 @@ //: Playground - noun: a place where people can play -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { +func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var i = 0 var j = a.count - 1 @@ -9,9 +9,9 @@ func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { if sum == k { return (i, j) } else if sum < k { - ++i + i += 1 } else { - --j + j -= 1 } } return nil From 56a5fa6f0273efd3959292977db3d092f0d42524 Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 21 Oct 2016 13:46:43 +0200 Subject: [PATCH 0206/1275] Removed duplicate swift files as these were already in the playground itself --- Two-Sum Problem/Solution 1/2Sum.swift | 22 ---------------------- Two-Sum Problem/Solution 2/2Sum.swift | 21 --------------------- 2 files changed, 43 deletions(-) delete mode 100644 Two-Sum Problem/Solution 1/2Sum.swift delete mode 100644 Two-Sum Problem/Solution 2/2Sum.swift diff --git a/Two-Sum Problem/Solution 1/2Sum.swift b/Two-Sum Problem/Solution 1/2Sum.swift deleted file mode 100644 index b3ef54790..000000000 --- a/Two-Sum Problem/Solution 1/2Sum.swift +++ /dev/null @@ -1,22 +0,0 @@ -/* - Determines if there are any entries a[i] + a[j] == k in the array. - Returns a tuple with the indices of the first pair of elements that sum to k. - - Uses a dictionary to store differences between the target and each element. - If any value in the dictionary equals an element in the array, they sum to k. - - This is an O(n) solution. -*/ -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { - var map = [Int: Int]() - - for i in 0 ..< a.count { - if let newK = map[a[i]] { - return (newK, i) - } else { - map[k - a[i]] = i - } - } - - return nil // if empty array or no entries sum to target k -} diff --git a/Two-Sum Problem/Solution 2/2Sum.swift b/Two-Sum Problem/Solution 2/2Sum.swift deleted file mode 100644 index 184e23800..000000000 --- a/Two-Sum Problem/Solution 2/2Sum.swift +++ /dev/null @@ -1,21 +0,0 @@ -/* - Determines if there are any entries a[i] + a[j] == k in the array. - This is an O(n) solution. - The array must be sorted for this to work! -*/ -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { - var i = 0 - var j = a.count - 1 - - while i < j { - let sum = a[i] + a[j] - if sum == k { - return (i, j) - } else if sum < k { - ++i - } else { - --j - } - } - return nil -} From 0227ee1a5ffaec264238cfb1ae21d0779ec12f57 Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 21 Oct 2016 13:49:11 +0200 Subject: [PATCH 0207/1275] update readme --- Two-Sum Problem/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Two-Sum Problem/README.markdown b/Two-Sum Problem/README.markdown index e2e15d4c0..a20666efd 100644 --- a/Two-Sum Problem/README.markdown +++ b/Two-Sum Problem/README.markdown @@ -8,10 +8,10 @@ There are a variety of solutions to this problem (some better than others). The This solution uses a dictionary to store differences between each element in the array and the sum `k` that we're looking for. The dictionary also stores the indices of each element. -With this approach, each key in the dictionary corresponds to a new target value. If one of the successive numbers from the array is equal to one of the dictionary's keys, then we know there exist two numbers that sum to `k`. +With this approach, each key in the dictionary corresponds to a new target value. If one of the successive numbers from the array is equal to one of the dictionary's keys, then we know there exist two numbers that sum to `k`. ```swift -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { +func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var dict = [Int: Int]() for i in 0 ..< a.count { @@ -69,7 +69,7 @@ The running time of this algorithm is **O(n)** because it potentially may need t Here is the code in Swift: ```swift -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { +func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var i = 0 var j = a.count - 1 @@ -78,9 +78,9 @@ func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { if sum == k { return (i, j) } else if sum < k { - ++i + i += 1 } else { - --j + j -= 1 } } return nil From 6e281b957a2cee068ee55390dc7baad1f38779c5 Mon Sep 17 00:00:00 2001 From: Jaap Date: Fri, 21 Oct 2016 14:34:50 +0200 Subject: [PATCH 0208/1275] Migrate Graph to Swift3 --- Graph/Graph.playground/Contents.swift | 8 ++--- Graph/Graph.playground/timeline.xctimeline | 11 ++++++ Graph/Graph.xcodeproj/project.pbxproj | 12 ++++++- .../xcshareddata/xcschemes/Graph.xcscheme | 2 +- .../xcschemes/GraphTests.xcscheme | 2 +- Graph/Graph/AdjacencyListGraph.swift | 36 ++++++++++--------- Graph/Graph/AdjacencyMatrixGraph.swift | 26 +++++++------- Graph/Graph/Edge.swift | 4 +-- Graph/Graph/Graph.swift | 18 +++++----- Graph/Graph/Vertex.swift | 2 +- 10 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 Graph/Graph.playground/timeline.xctimeline diff --git a/Graph/Graph.playground/Contents.swift b/Graph/Graph.playground/Contents.swift index 4e6d98a11..77de8484b 100644 --- a/Graph/Graph.playground/Contents.swift +++ b/Graph/Graph.playground/Contents.swift @@ -1,11 +1,7 @@ import Graph -// Create the vertices -var adjacencyMatrixGraph = AdjacencyMatrixGraph() -var adjacencyListGraph = AdjacencyListGraph() - -for graph in [ adjacencyMatrixGraph, adjacencyListGraph ] { - +for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { + let v1 = graph.createVertex(1) let v2 = graph.createVertex(2) let v3 = graph.createVertex(3) diff --git a/Graph/Graph.playground/timeline.xctimeline b/Graph/Graph.playground/timeline.xctimeline new file mode 100644 index 000000000..688276d32 --- /dev/null +++ b/Graph/Graph.playground/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Graph/Graph.xcodeproj/project.pbxproj b/Graph/Graph.xcodeproj/project.pbxproj index 0157eb377..82a5f2377 100644 --- a/Graph/Graph.xcodeproj/project.pbxproj +++ b/Graph/Graph.xcodeproj/project.pbxproj @@ -158,11 +158,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 49BFA2FC1CDF886B00522D66 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; 49BFA3061CDF886B00522D66 = { CreatedOnToolsVersion = 7.3; @@ -250,8 +251,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -298,8 +301,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -319,6 +324,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -328,6 +334,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -341,6 +348,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -348,6 +356,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -360,6 +369,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.Graph"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme index a8ce1124d..c4750d846 100644 --- a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -1,6 +1,6 @@ { + + +private class EdgeList where T: Equatable, T: Hashable { var vertex: Vertex var edges: [Edge]? = nil @@ -16,15 +18,15 @@ private class EdgeList { self.vertex = vertex } - func addEdge(edge: Edge) { + func addEdge(_ edge: Edge) { edges?.append(edge) } } -public class AdjacencyListGraph: AbstractGraph { +open class AdjacencyListGraph: AbstractGraph where T: Equatable, T: Hashable { - private var adjacencyList: [EdgeList] = [] + fileprivate var adjacencyList: [EdgeList] = [] public required init() { super.init() @@ -34,7 +36,7 @@ public class AdjacencyListGraph: AbstractGrap super.init(fromGraph: graph) } - public override var vertices: [Vertex] { + open override var vertices: [Vertex] { get { var vertices = [Vertex]() for edgeList in adjacencyList { @@ -44,7 +46,7 @@ public class AdjacencyListGraph: AbstractGrap } } - public override var edges: [Edge] { + open override var edges: [Edge] { get { var allEdges = Set>() for edgeList in adjacencyList { @@ -60,7 +62,7 @@ public class AdjacencyListGraph: AbstractGrap } } - public override func createVertex(data: T) -> Vertex { + open override func createVertex(_ data: T) -> Vertex { // check if the vertex already exists let matchingVertices = vertices.filter() { vertex in return vertex.data == data @@ -76,24 +78,24 @@ public class AdjacencyListGraph: AbstractGrap return vertex } - public override func addDirectedEdge(from: Vertex, to: Vertex, withWeight weight: Double?) { + open override func addDirectedEdge(_ from: Vertex, to: Vertex, withWeight weight: Double?) { // works let edge = Edge(from: from, to: to, weight: weight) let edgeList = adjacencyList[from.index] - if edgeList.edges?.count > 0 { - edgeList.addEdge(edge) + if let _ = edgeList.edges { + edgeList.addEdge(edge) } else { - edgeList.edges = [edge] + edgeList.edges = [edge] } } - public override func addUndirectedEdge(vertices: (Vertex, Vertex), withWeight weight: Double?) { + open override func addUndirectedEdge(_ vertices: (Vertex, Vertex), withWeight weight: Double?) { addDirectedEdge(vertices.0, to: vertices.1, withWeight: weight) addDirectedEdge(vertices.1, to: vertices.0, withWeight: weight) } - public override func weightFrom(sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + open override func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { guard let edges = adjacencyList[sourceVertex.index].edges else { return nil } @@ -107,11 +109,11 @@ public class AdjacencyListGraph: AbstractGrap return nil } - public override func edgesFrom(sourceVertex: Vertex) -> [Edge] { + open override func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { return adjacencyList[sourceVertex.index].edges ?? [] } - public override var description: String { + open override var description: String { get { var rows = [String]() for edgeList in adjacencyList { @@ -129,10 +131,10 @@ public class AdjacencyListGraph: AbstractGrap row.append(value) } - rows.append("\(edgeList.vertex.data) -> [\(row.joinWithSeparator(", "))]") + rows.append("\(edgeList.vertex.data) -> [\(row.joined(separator: ", "))]") } - return rows.joinWithSeparator("\n") + return rows.joined(separator: "\n") } } } diff --git a/Graph/Graph/AdjacencyMatrixGraph.swift b/Graph/Graph/AdjacencyMatrixGraph.swift index 6b19bcfcc..8f357bc8c 100644 --- a/Graph/Graph/AdjacencyMatrixGraph.swift +++ b/Graph/Graph/AdjacencyMatrixGraph.swift @@ -7,12 +7,12 @@ import Foundation -public class AdjacencyMatrixGraph: AbstractGraph { +open class AdjacencyMatrixGraph: AbstractGraph where T: Equatable, T: Hashable { // If adjacencyMatrix[i][j] is not nil, then there is an edge from // vertex i to vertex j. - private var adjacencyMatrix: [[Double?]] = [] - private var _vertices: [Vertex] = [] + fileprivate var adjacencyMatrix: [[Double?]] = [] + fileprivate var _vertices: [Vertex] = [] public required init() { super.init() @@ -22,13 +22,13 @@ public class AdjacencyMatrixGraph: AbstractGr super.init(fromGraph: graph) } - public override var vertices: [Vertex] { + open override var vertices: [Vertex] { get { return _vertices } } - public override var edges: [Edge] { + open override var edges: [Edge] { get { var edges = [Edge]() for row in 0 ..< adjacencyMatrix.count { @@ -44,7 +44,7 @@ public class AdjacencyMatrixGraph: AbstractGr // Adds a new vertex to the matrix. // Performance: possibly O(n^2) because of the resizing of the matrix. - public override func createVertex(data: T) -> Vertex { + open override func createVertex(_ data: T) -> Vertex { // check if the vertex already exists let matchingVertices = vertices.filter() { vertex in return vertex.data == data @@ -63,7 +63,7 @@ public class AdjacencyMatrixGraph: AbstractGr } // Add one new row at the bottom. - let newRow = [Double?](count: adjacencyMatrix.count + 1, repeatedValue: nil) + let newRow = [Double?](repeating: nil, count: adjacencyMatrix.count + 1) adjacencyMatrix.append(newRow) _vertices.append(vertex) @@ -71,20 +71,20 @@ public class AdjacencyMatrixGraph: AbstractGr return vertex } - public override func addDirectedEdge(from: Vertex, to: Vertex, withWeight weight: Double?) { + open override func addDirectedEdge(_ from: Vertex, to: Vertex, withWeight weight: Double?) { adjacencyMatrix[from.index][to.index] = weight } - public override func addUndirectedEdge(vertices: (Vertex, Vertex), withWeight weight: Double?) { + open override func addUndirectedEdge(_ vertices: (Vertex, Vertex), withWeight weight: Double?) { addDirectedEdge(vertices.0, to: vertices.1, withWeight: weight) addDirectedEdge(vertices.1, to: vertices.0, withWeight: weight) } - public override func weightFrom(sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + open override func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { return adjacencyMatrix[sourceVertex.index][destinationVertex.index] } - public override func edgesFrom(sourceVertex: Vertex) -> [Edge] { + open override func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { var outEdges = [Edge]() let fromIndex = sourceVertex.index for column in 0..: AbstractGr return outEdges } - public override var description: String { + open override var description: String { get { var grid = [String]() let n = self.adjacencyMatrix.count @@ -111,7 +111,7 @@ public class AdjacencyMatrixGraph: AbstractGr } grid.append(row) } - return (grid as NSArray).componentsJoinedByString("\n") + return (grid as NSArray).componentsJoined(by: "\n") } } diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index a867e164a..03518da83 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -7,7 +7,7 @@ import Foundation -public struct Edge: Equatable { +public struct Edge: Equatable where T: Equatable, T: Hashable { public let from: Vertex public let to: Vertex @@ -35,7 +35,7 @@ extension Edge: Hashable { get { var string = "\(from.description)\(to.description)" if weight != nil { - string.appendContentsOf("\(weight!)") + string.append("\(weight!)") } return string.hashValue } diff --git a/Graph/Graph/Graph.swift b/Graph/Graph/Graph.swift index 75b4bddec..2ad91608b 100644 --- a/Graph/Graph/Graph.swift +++ b/Graph/Graph/Graph.swift @@ -7,7 +7,7 @@ import Foundation -public class AbstractGraph: CustomStringConvertible { +open class AbstractGraph: CustomStringConvertible where T: Equatable, T: Hashable { public required init() {} @@ -20,19 +20,19 @@ public class AbstractGraph: CustomStringConve } } - public var description: String { + open var description: String { get { fatalError("abstract property accessed") } } - public var vertices: [Vertex] { + open var vertices: [Vertex] { get { fatalError("abstract property accessed") } } - public var edges: [Edge] { + open var edges: [Edge] { get { fatalError("abstract property accessed") } @@ -40,23 +40,23 @@ public class AbstractGraph: CustomStringConve // Adds a new vertex to the matrix. // Performance: possibly O(n^2) because of the resizing of the matrix. - public func createVertex(data: T) -> Vertex { + open func createVertex(_ data: T) -> Vertex { fatalError("abstract function called") } - public func addDirectedEdge(from: Vertex, to: Vertex, withWeight weight: Double?) { + open func addDirectedEdge(_ from: Vertex, to: Vertex, withWeight weight: Double?) { fatalError("abstract function called") } - public func addUndirectedEdge(vertices: (Vertex, Vertex), withWeight weight: Double?) { + open func addUndirectedEdge(_ vertices: (Vertex, Vertex), withWeight weight: Double?) { fatalError("abstract function called") } - public func weightFrom(sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + open func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { fatalError("abstract function called") } - public func edgesFrom(sourceVertex: Vertex) -> [Edge] { + open func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { fatalError("abstract function called") } } diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 1223eb116..43cabcd1f 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -7,7 +7,7 @@ import Foundation -public struct Vertex: Equatable { +public struct Vertex: Equatable where T: Equatable, T: Hashable { public var data: T public let index: Int From 263faef2847eb2249e650138984df56dcb5cb702 Mon Sep 17 00:00:00 2001 From: Sahn Cha Date: Fri, 21 Oct 2016 23:18:42 +0900 Subject: [PATCH 0209/1275] README ready. --- .../Images/img_pseudo.png | Bin 0 -> 149885 bytes Miller-Rabin Primality Test/README.markdown | 43 ++++++++++++++++++ .../contents.xcworkspacedata | 12 ++++- 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Miller-Rabin Primality Test/Images/img_pseudo.png create mode 100644 Miller-Rabin Primality Test/README.markdown diff --git a/Miller-Rabin Primality Test/Images/img_pseudo.png b/Miller-Rabin Primality Test/Images/img_pseudo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a06d151aa90ae0d81fd6c413426357f907d2ae1 GIT binary patch literal 149885 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 a^d, a^(2·d), a^(4·d), ... , a^((2^(s-1))·d), a^((2^s)·d) = a^(n-1) + +And we say the number `n` passes the test, *probably prime*, if 1) `a^d` is congruence to `1` in modulo `n`, or 2) `a^((2^k)·d)` is congruence to `-1` for some `k = 1, 2, ..., s-1`. + +### Pseudo Code + +The following pseudo code is excerpted from Wikipedia[3]: + +![Image of Pseudocode](./Images/img_pseudo.png) + +## Usage + +```swift +mrPrimalityTest(7) // test if 7 is prime. (default iteration = 1) +mrPrimalityTest(7, iteration: 10) // test if 7 is prime & iterate 10 times. +``` + +## Reference +1. G. L. Miller, "Riemann's Hypothesis and Tests for Primality". *J. Comput. System Sci.* 13 (1976), 300-317. +2. M. O. Rabin, "Probabilistic algorithm for testing primality". *Journal of Number Theory.* 12 (1980), 128-138. +3. Miller–Rabin primality test - Wikipedia, the free encyclopedia + +*Written for Swift Algorithm Club by **Sahn Cha**, @scha00* + +[1]: https://cs.uwaterloo.ca/research/tr/1975/CS-75-27.pdf +[2]: http://www.sciencedirect.com/science/article/pii/0022314X80900840 +[3]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index dd0c6b668..75a941c3f 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -28,11 +28,21 @@ + + + + + + + location = "group:README.markdown"> Date: Fri, 21 Oct 2016 23:25:01 +0900 Subject: [PATCH 0210/1275] Update README.markdown --- Miller-Rabin Primality Test/README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Miller-Rabin Primality Test/README.markdown b/Miller-Rabin Primality Test/README.markdown index 9fa849836..84020a9ec 100644 --- a/Miller-Rabin Primality Test/README.markdown +++ b/Miller-Rabin Primality Test/README.markdown @@ -4,9 +4,9 @@ In 1976, Gray Miller introduced an algorithm, through his ph.d thesis[1], which ## Probabilistic -The result of the test is simply a boolean. However, `true` does not implicate *the number is prime*. In fact, it means *the number is **probably** prime*. But `false` does mean *the number is composite*. +The result of the test is simply a boolean. However, `true` does not implicate _the number is prime_. In fact, it means _the number is **probably** prime_. But `false` does mean _the number is composite_. -In order to increase the accuracy of the test, it needs to be iterated few times. If it returns `true` in every single iteration, than we can say with confidence that *the number is pro......bably prime*. +In order to increase the accuracy of the test, it needs to be iterated few times. If it returns `true` in every single iteration, than we can say with confidence that _the number is pro......bably prime_. ## Algorithm @@ -16,7 +16,7 @@ Now make a sequence, in modulo `n`, as following: > a^d, a^(2·d), a^(4·d), ... , a^((2^(s-1))·d), a^((2^s)·d) = a^(n-1) -And we say the number `n` passes the test, *probably prime*, if 1) `a^d` is congruence to `1` in modulo `n`, or 2) `a^((2^k)·d)` is congruence to `-1` for some `k = 1, 2, ..., s-1`. +And we say the number `n` passes the test, _probably prime_, if 1) `a^d` is congruence to `1` in modulo `n`, or 2) `a^((2^k)·d)` is congruence to `-1` for some `k = 1, 2, ..., s-1`. ### Pseudo Code @@ -32,11 +32,11 @@ mrPrimalityTest(7, iteration: 10) // test if 7 is prime & iterate 10 times ``` ## Reference -1. G. L. Miller, "Riemann's Hypothesis and Tests for Primality". *J. Comput. System Sci.* 13 (1976), 300-317. -2. M. O. Rabin, "Probabilistic algorithm for testing primality". *Journal of Number Theory.* 12 (1980), 128-138. +1. G. L. Miller, "Riemann's Hypothesis and Tests for Primality". _J. Comput. System Sci._ 13 (1976), 300-317. +2. M. O. Rabin, "Probabilistic algorithm for testing primality". _Journal of Number Theory._ 12 (1980), 128-138. 3. Miller–Rabin primality test - Wikipedia, the free encyclopedia -*Written for Swift Algorithm Club by **Sahn Cha**, @scha00* +_Written for Swift Algorithm Club by **Sahn Cha**, @scha00_ [1]: https://cs.uwaterloo.ca/research/tr/1975/CS-75-27.pdf [2]: http://www.sciencedirect.com/science/article/pii/0022314X80900840 From a2fa24d380496152dc83eb81c8ec6a10b600878c Mon Sep 17 00:00:00 2001 From: Sahn Cha Date: Fri, 21 Oct 2016 23:34:08 +0900 Subject: [PATCH 0211/1275] typo. --- Miller-Rabin Primality Test/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Miller-Rabin Primality Test/README.markdown b/Miller-Rabin Primality Test/README.markdown index 84020a9ec..07acb9e18 100644 --- a/Miller-Rabin Primality Test/README.markdown +++ b/Miller-Rabin Primality Test/README.markdown @@ -6,11 +6,11 @@ In 1976, Gray Miller introduced an algorithm, through his ph.d thesis[1], which The result of the test is simply a boolean. However, `true` does not implicate _the number is prime_. In fact, it means _the number is **probably** prime_. But `false` does mean _the number is composite_. -In order to increase the accuracy of the test, it needs to be iterated few times. If it returns `true` in every single iteration, than we can say with confidence that _the number is pro......bably prime_. +In order to increase the accuracy of the test, it needs to be iterated few times. If it returns `true` in every single iteration, then we can say with confidence that _the number is pro......bably prime_. ## Algorithm -Let `n` be the given number, and write `n-1` as `2^s·d`, where d is odd. And choose a random number `a` within the range from `2` to `n - 1`. +Let `n` be the given number, and write `n-1` as `2^s·d`, where `d` is odd. And choose a random number `a` within the range from `2` to `n - 1`. Now make a sequence, in modulo `n`, as following: @@ -28,7 +28,7 @@ The following pseudo code is excerpted from Wikipedia[3]: ```swift mrPrimalityTest(7) // test if 7 is prime. (default iteration = 1) -mrPrimalityTest(7, iteration: 10) // test if 7 is prime & iterate 10 times. +mrPrimalityTest(7, iteration: 10) // test if 7 is prime && iterate 10 times. ``` ## Reference From 4c19e5f9091112090b3ec6ce10a0376e1b41abf3 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Sat, 22 Oct 2016 10:43:38 +0200 Subject: [PATCH 0212/1275] Clean up --- Skip-List/SkipList.swift | 78 ++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index 31b4e9144..5fc61bf8e 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -26,7 +26,7 @@ import Foundation // Stack from : https://github.com/raywenderlich/swift-algorithm-club/tree/master/Stack public struct Stack { - fileprivate var array = [T]() + fileprivate var array: [T] = [] public var isEmpty: Bool { return array.isEmpty @@ -62,53 +62,48 @@ extension Stack: Sequence { private func coinFlip() -> Bool { #if os(Linux) - return random() % 2 == 0 + return random() % 2 == 0 #elseif os(OSX) - return arc4random_uniform(2) == 1 + return arc4random_uniform(2) == 1 #endif } -// MARK: - Node - public class DataNode { public typealias Node = DataNode var data : Payload? fileprivate var key : Key? - internal var next : Node? - internal var down : Node? + var next : Node? + var down : Node? public init(key: Key, data: Payload) { self.key = key self.data = data } - public init(asHead head: Bool){ - } + public init(asHead head: Bool){} } -// MARK: - Skip List - open class SkipList { public typealias Node = DataNode fileprivate(set) var head: Node? - public init() { } + public init() {} } -// MARK: - Searching +// MARK: - Search lanes for a node with a given key extension SkipList { - internal func findNode(key: Key) -> Node? { - var currentNode : Node? = self.head + func findNode(key: Key) -> Node? { + var currentNode : Node? = head var isFound : Bool = false while !isFound { @@ -117,7 +112,7 @@ extension SkipList { switch node.next { case .none: - currentNode = node.down + currentNode = node.down case .some(let value) where value.key != nil: if value.key == key { @@ -149,26 +144,26 @@ extension SkipList { } - internal func search(key: Key) -> Payload? { - guard let node = self.findNode(key: key) else { + func search(key: Key) -> Payload? { + guard let node = findNode(key: key) else { return nil } return node.next!.data } - + } -// MARK: - Inserting +// MARK: - Insert a node into lanes depending on skip list status ( bootstrap base-layer if head is empty / start insertion from current head ). extension SkipList { - private func bootstrapBaseLayer(key: Key, data: Payload) -> Void { - self.head = Node(asHead: true) - var node = Node(key: key, data: data) + private func bootstrapBaseLayer(key: Key, data: Payload) { + head = Node(asHead: true) + var node = Node(key: key, data: data) - self.head!.next = node + head!.next = node var currentTopNode = node @@ -177,17 +172,17 @@ extension SkipList { node = Node(key: key, data: data) node.down = currentTopNode newHead.next = node - newHead.down = self.head - self.head = newHead + newHead.down = head + head = newHead currentTopNode = node } } - private func insertItem(key: Key, data: Payload) -> Void { + private func insertItem(key: Key, data: Payload) { var stack = Stack() - var currentNode: Node? = self.head + var currentNode: Node? = head while currentNode != nil { @@ -219,8 +214,8 @@ extension SkipList { node = Node(key: key, data: data) node.down = currentTopNode newHead.next = node - newHead.down = self.head - self.head = newHead + newHead.down = head + head = newHead currentTopNode = node } else { @@ -236,32 +231,32 @@ extension SkipList { } - internal func insert(key: Key, data: Payload) { - if self.head != nil { - if let node = self.findNode(key: key) { - // replace in case key already exists + func insert(key: Key, data: Payload) { + if head != nil { + if let node = findNode(key: key) { + // replace, in case of key already exists. var currentNode = node.next while currentNode != nil && currentNode!.key == key { currentNode!.data = data currentNode = currentNode!.down } } else { - self.insertItem(key: key, data: data) + insertItem(key: key, data: data) } } else { - self.bootstrapBaseLayer(key: key, data: data) + bootstrapBaseLayer(key: key, data: data) } } } -// MARK: - Removing +// MARK: - Remove a node with a given key. First, find its position in layers at the top, then remove it from each lane by traversing down to the base layer. extension SkipList { - public func remove(key: Key) -> Void { - guard let item = self.findNode(key: key) else { + public func remove(key: Key) { + guard let item = findNode(key: key) else { return } @@ -285,9 +280,12 @@ extension SkipList { } } + +// MARK: - Get associated payload from a node with a given key. + extension SkipList { public func get(key:Key) -> Payload?{ - return self.search(key: key) + return search(key: key) } } From 1de177535f8facdd188464df0c98e50cc5148504 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 24 Oct 2016 18:33:25 -0700 Subject: [PATCH 0213/1275] Init & claim of Strassen's Matrix Multiplication Algorithm --- Strassen Matrix Multiplication/README.markdown | 1 + 1 file changed, 1 insertion(+) create mode 100644 Strassen Matrix Multiplication/README.markdown diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown new file mode 100644 index 000000000..d07004bad --- /dev/null +++ b/Strassen Matrix Multiplication/README.markdown @@ -0,0 +1 @@ +## TODO: Examples & Explanation From 95069fd26cd6c0f5c60f9c980411df72c61ce379 Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 26 Oct 2016 14:12:39 -0700 Subject: [PATCH 0214/1275] Implementation for Strassen Matrix Multiplication Algorithm --- .../Contents.swift | 316 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + 3 files changed, 327 insertions(+) create mode 100644 Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift create mode 100644 Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/contents.xcplayground create mode 100644 Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift new file mode 100644 index 000000000..d4b4d8330 --- /dev/null +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -0,0 +1,316 @@ +//: Playground - noun: a place where people can play +// Reference - http://mathworld.wolfram.com/StrassenFormulas.html + + +import UIKit + +enum RowOrColumn { + case row, column +} + +protocol Number: Multipliable, Addable { + static var zero: Self { get } +} + +protocol Addable { + static func +(lhs: Self, rhs: Self) -> Self + static func -(lhs: Self, rhs: Self) -> Self +} + +protocol Multipliable { + static func *(lhs: Self, rhs: Self) -> Self +} + +extension Int: Number { + static var zero: Int { + return 0 + } +} + +extension Double: Number { + static var zero: Double { + return 0.0 + } +} + +extension Float: Number { + static var zero: Float { + return 0.0 + } +} + + +extension Array where Element: Number { + func dot(_ b: Array) -> Element { + let a = self + assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") + let c = a.indices.map{ a[$0] * b[$0] } + return c.reduce(Element.zero, { $0 + $1 }) + } +} + +struct MatrixSize: Equatable { + let rows: Int + let columns: Int + + func forEach(_ body: (Int, Int) throws -> Void) rethrows { + for row in 0.. Bool { + return lhs.columns == rhs.columns && lhs.rows == rhs.rows +} + + +struct Matrix { + + // MARK: - Variables + + let rows: Int, columns: Int + var grid: [T] + + var isSquare: Bool { + return rows == columns + } + + var size: MatrixSize { + return MatrixSize(rows: rows, columns: columns) + } + + // MARK: - Init + + init(rows: Int, columns: Int, initialValue: T = T.zero) { + self.rows = rows + self.columns = columns + self.grid = Array(repeating: initialValue, count: rows * columns) + } + + init(size: Int, initialValue: T = T.zero) { + self.rows = size + self.columns = size + self.grid = Array(repeating: initialValue, count: rows * columns) + } + + // MARK: - Subscript + + subscript(row: Int, column: Int) -> T { + get { + assert(indexIsValid(row: row, column: column), "Index out of range") + return grid[(row * columns) + column] + } + set { + assert(indexIsValid(row: row, column: column), "Index out of range") + grid[(row * columns) + column] = newValue + } + } + + subscript(type: RowOrColumn, value: Int) -> [T] { + get { + switch type { + case .row: + assert(indexIsValid(row: value, column: 0), "Index out of range") + return Array(grid[(value * columns)..<(value * columns) + columns]) + case .column: + assert(indexIsValid(row: 0, column: value), "Index out of range") + var columns: [T] = [] + for row in 0.. Bool { + return row >= 0 && row < rows && column >= 0 && column < columns + } + + private func strassenR(by B: Matrix) -> Matrix { + let A = self + assert(A.isSquare && B.isSquare, "This function requires square matricies!") + guard A.rows > 1 && B.rows > 1 else { return A * B } + + let n = A.rows + let nBy2 = n / 2 + + var a11 = Matrix(size: nBy2) + var a12 = Matrix(size: nBy2) + var a21 = Matrix(size: nBy2) + var a22 = Matrix(size: nBy2) + var b11 = Matrix(size: nBy2) + var b12 = Matrix(size: nBy2) + var b21 = Matrix(size: nBy2) + var b22 = Matrix(size: nBy2) + + for i in 0.. Int { + return Int(pow(2, ceil(log2(Double(n))))) + } + + // MARK: - Functions + + func strassenMatrixMultiply(by B: Matrix) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + let n = max(A.rows, A.columns, B.rows, B.columns) + let m = nextPowerOfTwo(of: n) + + var APrep = Matrix(size: m) + var BPrep = Matrix(size: m) + + A.size.forEach { (i, j) in + APrep[i,j] = A[i,j] + } + + B.size.forEach { (i, j) in + BPrep[i,j] = B[i,j] + } + + let CPrep = APrep.strassenR(by: BPrep) + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term multiply matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0.. + + + \ No newline at end of file diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 87c23249e572ed9b32191df58cf93d549072463e Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 27 Oct 2016 10:47:09 +0200 Subject: [PATCH 0215/1275] update readme --- Ring Buffer/README.markdown | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Ring Buffer/README.markdown b/Ring Buffer/README.markdown index 70e0ad108..0652ff548 100644 --- a/Ring Buffer/README.markdown +++ b/Ring Buffer/README.markdown @@ -17,7 +17,7 @@ Initially, the array is empty and the read (`r`) and write (`w`) pointers are at Let's add some data to this array. We'll write, or "enqueue", the number `123`: [ 123, , , , ] - r + r ---> w Each time we add data, the write pointer moves one step forward. Let's add a few more elements: @@ -46,7 +46,7 @@ Whoops, the write pointer has reached the end of the array, so there is no more [ 555, 456, 789, 666, 333 ] ---> w r -We can now read the remaining three items, `666`, `333`, and `555`. +We can now read the remaining three items, `666`, `333`, and `555`. [ 555, 456, 789, 666, 333 ] w --------> r @@ -63,16 +63,15 @@ Here is a very basic implementation in Swift: ```swift public struct RingBuffer { - private var array: [T?] - private var readIndex = 0 - private var writeIndex = 0 - + fileprivate var array: [T?] + fileprivate var readIndex = 0 + fileprivate var writeIndex = 0 + public init(count: Int) { - array = [T?](count: count, repeatedValue: nil) + array = [T?](repeating: nil, count: count) } - - /* Returns false if out of space. */ - public mutating func write(element: T) -> Bool { + + public mutating func write(_ element: T) -> Bool { if !isFull { array[writeIndex % array.count] = element writeIndex += 1 @@ -81,8 +80,7 @@ public struct RingBuffer { return false } } - - /* Returns nil if the buffer is empty. */ + public mutating func read() -> T? { if !isEmpty { let element = array[readIndex % array.count] @@ -92,19 +90,19 @@ public struct RingBuffer { return nil } } - - private var availableSpaceForReading: Int { + + fileprivate var availableSpaceForReading: Int { return writeIndex - readIndex } - + public var isEmpty: Bool { return availableSpaceForReading == 0 } - - private var availableSpaceForWriting: Int { + + fileprivate var availableSpaceForWriting: Int { return array.count - availableSpaceForReading } - + public var isFull: Bool { return availableSpaceForWriting == 0 } @@ -130,7 +128,7 @@ In other words, we take the modulo (or the remainder) of the read index and writ The reason this is a bit controversial is that `writeIndex` and `readIndex` always increment, so in theory these values could become too large to fit into an integer and the app will crash. However, a quick back-of-the-napkin calculation should take away those fears. Both `writeIndex` and `readIndex` are 64-bit integers. If we assume that they are incremented 1000 times per second, which is a lot, then doing this continuously for one year requires `ceil(log_2(365 * 24 * 60 * 60 * 1000)) = 35` bits. That leaves 28 bits to spare, so that should give you about 2^28 years before running into problems. That's a long time. :-) - + To play with this ring buffer, copy the code to a playground and do the following to mimic the example above: ```swift From e0547e96c4e11f436b1a4f2a9c6c9cbe2de1fbb5 Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 27 Oct 2016 10:55:53 +0200 Subject: [PATCH 0216/1275] update readme --- Graph/README.markdown | 94 +++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/Graph/README.markdown b/Graph/README.markdown index 349add81a..1ff1a82ac 100644 --- a/Graph/README.markdown +++ b/Graph/README.markdown @@ -42,7 +42,7 @@ Like a tree this does not have any cycles in it (no matter where you start, ther Maybe you're shrugging your shoulders and thinking, what's the big deal? Well, it turns out that graphs are an extremely useful data structure. -If you have some programming problem where you can represent some of your data as vertices and some of it as edges between those vertices, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First Search/) or [depth-first search](../Depth-First Search) to find a solution. +If you have some programming problem where you can represent some of your data as vertices and some of it as edges between those vertices, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First Search/) or [depth-first search](../Depth-First Search) to find a solution. For example, let's say you have a list of tasks where some tasks have to wait on others before they can begin. You can model this using an acyclic directed graph: @@ -110,12 +110,13 @@ We'll show you sample implementations of both adjacency list and adjacency matri The adjacency list for each vertex consists of `Edge` objects: ```swift -public struct Edge: Equatable { - +public struct Edge: Equatable where T: Equatable, T: Hashable { + public let from: Vertex public let to: Vertex public let weight: Double? + } ``` @@ -124,7 +125,7 @@ This struct describes the "from" and "to" vertices and a weight value. Note that The `Vertex` looks like this: ```swift -public struct Vertex: Equatable { +public struct Vertex: Equatable where T: Equatable, T: Hashable { public var data: T public let index: Int @@ -147,10 +148,7 @@ We can represent it as an adjacency matrix or adjacency list. The classes implem Let's create some directed, weighted graphs, using each representation, to store the example: ```swift -var adjacencyMatrixGraph = AdjacencyMatrixGraph() -var adjacencyListGraph = AdjacencyListGraph() - -for graph in [ adjacencyMatrixGraph, adjacencyListGraph ] { +for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { let v1 = graph.createVertex(1) let v2 = graph.createVertex(2) @@ -163,8 +161,8 @@ for graph in [ adjacencyMatrixGraph, adjacencyListGraph ] { graph.addDirectedEdge(v3, to: v4, withWeight: 4.5) graph.addDirectedEdge(v4, to: v1, withWeight: 2.8) graph.addDirectedEdge(v2, to: v5, withWeight: 3.2) -} +} ``` As mentioned earlier, to create an undirected edge you need to make two directed edges. If we wanted undirected graphs, we'd call this method instead, which takes care of that work for us: @@ -184,7 +182,7 @@ We could provide `nil` as the values for the `withWeight` parameter in either ca To maintain the adjacency list, there is a class that maps a list of edges to a vertex. The graph simply maintains an array of such objects and modifies them as necessary. ```swift -private class EdgeList { +private class EdgeList where T: Equatable, T: Hashable { var vertex: Vertex var edges: [Edge]? = nil @@ -193,34 +191,34 @@ private class EdgeList { self.vertex = vertex } - func addEdge(edge: Edge) { + func addEdge(_ edge: Edge) { edges?.append(edge) } } -``` +``` They are implemented as a class as opposed to structs so we can modify them by reference, in place, like when adding an edge to a new vertex, where the source vertex already has an edge list: ```swift - public override func createVertex(data: T) -> Vertex { - // check if the vertex already exists - let matchingVertices = vertices.filter() { vertex in - return vertex.data == data - } - - if matchingVertices.count > 0 { - return matchingVertices.last! - } - - // if the vertex doesn't exist, create a new one - let vertex = Vertex(data: data, index: adjacencyList.count) - adjacencyList.append(EdgeList(vertex: vertex)) - return vertex +open override func createVertex(_ data: T) -> Vertex { + // check if the vertex already exists + let matchingVertices = vertices.filter() { vertex in + return vertex.data == data + } + + if matchingVertices.count > 0 { + return matchingVertices.last! } + + // if the vertex doesn't exist, create a new one + let vertex = Vertex(data: data, index: adjacencyList.count) + adjacencyList.append(EdgeList(vertex: vertex)) + return vertex +} ``` -The adjacency list for the example looks like this: +The adjacency list for the example looks like this: ``` v1 -> [(v2: 1.0)] @@ -238,32 +236,32 @@ We'll keep track of the adjacency matrix in a two-dimensional `[[Double?]]` arra To index into the matrix using vertices, we use the `index` property in `Vertex`, which is assigned when creating the vertex through the graph object. When creating a new vertex, the graph must resize the matrix: ```swift - public override func createVertex(data: T) -> Vertex { - // check if the vertex already exists - let matchingVertices = vertices.filter() { vertex in - return vertex.data == data - } +open override func createVertex(_ data: T) -> Vertex { + // check if the vertex already exists + let matchingVertices = vertices.filter() { vertex in + return vertex.data == data + } - if matchingVertices.count > 0 { - return matchingVertices.last! - } + if matchingVertices.count > 0 { + return matchingVertices.last! + } - // if the vertex doesn't exist, create a new one - let vertex = Vertex(data: data, index: adjacencyMatrix.count) + // if the vertex doesn't exist, create a new one + let vertex = Vertex(data: data, index: adjacencyMatrix.count) - // Expand each existing row to the right one column. - for i in 0 ..< adjacencyMatrix.count { - adjacencyMatrix[i].append(nil) - } + // Expand each existing row to the right one column. + for i in 0 ..< adjacencyMatrix.count { + adjacencyMatrix[i].append(nil) + } - // Add one new row at the bottom. - let newRow = [Double?](count: adjacencyMatrix.count + 1, repeatedValue: nil) - adjacencyMatrix.append(newRow) + // Add one new row at the bottom. + let newRow = [Double?](repeating: nil, count: adjacencyMatrix.count + 1) + adjacencyMatrix.append(newRow) - _vertices.append(vertex) + _vertices.append(vertex) - return vertex - } + return vertex +} ``` Then the adjacency matrix looks like this: @@ -273,7 +271,7 @@ Then the adjacency matrix looks like this: [nil, nil, nil, 4.5, nil] v3 [2.8, nil, nil, nil, nil] v4 [nil, nil, nil, nil, nil]] v5 - + v1 v2 v3 v4 v5 From 2b64b05087ab0b2014fd0a30fa8bda42f3b32a64 Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 27 Oct 2016 16:15:44 +0200 Subject: [PATCH 0217/1275] migrate combinatorics to swift3 --- .../Combinatorics.playground/Contents.swift | 32 ++--- .../timeline.xctimeline | 6 + Combinatorics/Combinatorics.swift | 121 ------------------ Combinatorics/README.markdown | 36 +++--- 4 files changed, 40 insertions(+), 155 deletions(-) create mode 100644 Combinatorics/Combinatorics.playground/timeline.xctimeline delete mode 100644 Combinatorics/Combinatorics.swift diff --git a/Combinatorics/Combinatorics.playground/Contents.swift b/Combinatorics/Combinatorics.playground/Contents.swift index 5cb91967e..94951810f 100644 --- a/Combinatorics/Combinatorics.playground/Contents.swift +++ b/Combinatorics/Combinatorics.playground/Contents.swift @@ -1,7 +1,7 @@ //: Playground - noun: a place where people can play /* Calculates n! */ -func factorial(n: Int) -> Int { +func factorial(_ n: Int) -> Int { var n = n var result = 1 while n > 1 { @@ -20,7 +20,7 @@ factorial(20) Calculates P(n, k), the number of permutations of n distinct symbols in groups of size k. */ -func permutations(n: Int, _ k: Int) -> Int { +func permutations(_ n: Int, _ k: Int) -> Int { var n = n var answer = n for _ in 1..(a: [T], _ n: Int) { +func permuteWirth(_ a: [T], _ n: Int) { if n == 0 { print(a) // display the current permutation } else { @@ -75,7 +75,7 @@ permuteWirth(xyz, 2) Original algorithm by Robert Sedgewick. See also Dr.Dobb's Magazine June 1993, Algorithm Alley */ -func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) { +func permuteSedgewick(_ a: [Int], _ n: Int, _ pos: inout Int) { var a = a pos += 1 a[n] = pos @@ -103,16 +103,16 @@ permuteSedgewick(numbers, 0, &pos) Calculates C(n, k), or "n-choose-k", i.e. how many different selections of size k out of a total number of distinct elements (n) you can make. */ -func combinations(n: Int, _ k: Int) -> Int { +func combinations(_ n: Int, choose k: Int) -> Int { return permutations(n, k) / factorial(k) } -combinations(3, 2) -combinations(28, 5) +combinations(3, choose: 2) +combinations(28, choose: 5) print("\nCombinations:") for i in 1...20 { - print("\(20)-choose-\(i) = \(combinations(20, i))") + print("\(20)-choose-\(i) = \(combinations(20, choose: i))") } @@ -121,7 +121,7 @@ for i in 1...20 { Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose k things out of n possibilities. */ -func quickBinomialCoefficient(n: Int, _ k: Int) -> Int { +func quickBinomialCoefficient(_ n: Int, choose k: Int) -> Int { var result = 1 for i in 0.. Int { return result } -quickBinomialCoefficient(8, 2) -quickBinomialCoefficient(30, 15) +quickBinomialCoefficient(8, choose: 2) +quickBinomialCoefficient(30, choose: 15) @@ -145,7 +145,7 @@ struct Array2D { init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = .init(count: rows*columns, repeatedValue: initialValue) + array = Array(repeating: initialValue, count: rows*columns) } subscript(column: Int, row: Int) -> T { @@ -163,8 +163,8 @@ struct Array2D { space for the cached values. */ -func binomialCoefficient(n: Int, _ k: Int) -> Int { - var bc = Array(count: n + 1, repeatedValue: Array(count: n + 1, repeatedValue: 0)) +func binomialCoefficient(_ n: Int, choose k: Int) -> Int { + var bc = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1) for i in 0...n { bc[i][0] = 1 @@ -182,5 +182,5 @@ func binomialCoefficient(n: Int, _ k: Int) -> Int { return bc[n][k] } -binomialCoefficient(30, 15) -binomialCoefficient(66, 33) +binomialCoefficient(30, choose: 15) +binomialCoefficient(66, choose: 33) diff --git a/Combinatorics/Combinatorics.playground/timeline.xctimeline b/Combinatorics/Combinatorics.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Combinatorics/Combinatorics.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Combinatorics/Combinatorics.swift b/Combinatorics/Combinatorics.swift deleted file mode 100644 index 04ef98765..000000000 --- a/Combinatorics/Combinatorics.swift +++ /dev/null @@ -1,121 +0,0 @@ -/* Calculates n! */ -func factorial(n: Int) -> Int { - var n = n - var result = 1 - while n > 1 { - result *= n - n -= 1 - } - return result -} - -/* - Calculates P(n, k), the number of permutations of n distinct symbols - in groups of size k. - */ -func permutations(n: Int, _ k: Int) -> Int { - var n = n - var answer = n - for _ in 1..(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.. Int { - return permutations(n, k) / factorial(k) -} - -/* - Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose - k things out of n possibilities. - */ -func quickBinomialCoefficient(n: Int, _ k: Int) -> Int { - var result = 1 - - for i in 0.. Int { - var bc = Array(count: n + 1, repeatedValue: Array(count: n + 1, repeatedValue: 0)) - - for i in 0...n { - bc[i][0] = 1 - bc[i][i] = 1 - } - - if n > 0 { - for i in 1...n { - for j in 1.. Int { +func factorial(_ n: Int) -> Int { var n = n var result = 1 while n > 1 { @@ -62,7 +62,7 @@ You could implement this in terms of the `factorial()` function from earlier, bu Here is an algorithm that can deal with larger numbers: ```swift -func permutations(n: Int, _ k: Int) -> Int { +func permutations(_ n: Int, _ k: Int) -> Int { var n = n var answer = n for _ in 1..(a: [T], _ n: Int) { +func permuteWirth(_ a: [T], _ n: Int) { if n == 0 { print(a) // display the current permutation } else { @@ -216,7 +216,7 @@ If the above is still not entirely clear, then I suggest you give it a go in the For fun, here is an alternative algorithm, by Robert Sedgewick: ```swift -func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) { +func permuteSedgewick(_ a: [Int], _ n: Int, _ pos: inout Int) { var a = a pos += 1 a[n] = pos @@ -282,7 +282,7 @@ The formula for `C(n, k)` is: As you can see, you can derive it from the formula for `P(n, k)`. There are always more permutations than combinations. You divide the number of permutations by `k!` because a total of `k!` of these permutations give the same combination. -Above I showed that the number of permutations of `k` `l` `m` is 6, but if you pick only two of those letters the number of combinations is 3. If we use the formula we should get the same answer. We want to calculate `C(3, 2)` because we choose 2 letters out of a collection of 3. +Above I showed that the number of permutations of `k` `l` `m` is 6, but if you pick only two of those letters the number of combinations is 3. If we use the formula we should get the same answer. We want to calculate `C(3, 2)` because we choose 2 letters out of a collection of 3. 3 * 2 * 1 6 C(3, 2) = --------- = --- = 3 @@ -291,7 +291,7 @@ Above I showed that the number of permutations of `k` `l` `m` is 6, but if you p Here's a simple function to calculate `C(n, k)`: ```swift -func combinations(n: Int, _ k: Int) -> Int { +func combinations(_ n: Int, choose k: Int) -> Int { return permutations(n, k) / factorial(k) } ``` @@ -299,7 +299,7 @@ func combinations(n: Int, _ k: Int) -> Int { Use it like this: ```swift -combinations(28, 5) // prints 98280 +combinations(28, choose: 5) // prints 98280 ``` Because this uses the `permutations()` and `factorial()` functions under the hood, you're still limited by how large these numbers can get. For example, `combinations(30, 15)` is "only" `155,117,520` but because the intermediate results don't fit into a 64-bit integer, you can't calculate it with the given function. @@ -319,7 +319,7 @@ After the reduction of fractions, we get the following formula: We can implement this formula as follows: ```swift -func quickBinomialCoefficient(n: Int, _ k: Int) -> Int { +func quickBinomialCoefficient(_ n: Int, choose k: Int) -> Int { var result = 1 for i in 0.. Int { - var bc = Array(count: n + 1, repeatedValue: Array(count: n + 1, repeatedValue: 0)) +func binomialCoefficient(_ n: Int, choose k: Int) -> Int { + var bc = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1) for i in 0...n { bc[i][0] = 1 @@ -390,7 +390,7 @@ The algorithm itself is quite simple: the first loop fills in the 1s at the oute Now you can calculate `C(66, 33)` without any problems: ```swift -binomialCoefficient(66, 33) // prints a very large number +binomialCoefficient(66, choose: 33) // prints a very large number ``` You may wonder what the point is in calculating these permutations and combinations, but many algorithm problems are really combinatorics problems in disguise. Often you may need to look at all possible combinations of your data to see which one gives the right solution. If that means you need to search through `n!` potential solutions, you may want to consider a different approach -- as you've seen, these numbers become huge very quickly! From b15b38396a262291bee0b5db407d09eba3833148 Mon Sep 17 00:00:00 2001 From: Jaap Date: Thu, 27 Oct 2016 16:38:11 +0200 Subject: [PATCH 0218/1275] migrate fixedsizearray to swift3 --- .../FixedSizeArray.playground/Contents.swift | 56 ++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 ++ .../timeline.xctimeline | 16 ++++ Fixed Size Array/FixedSizeArray.swift | 46 ----------- Fixed Size Array/README.markdown | 77 ++++++++++--------- 6 files changed, 125 insertions(+), 81 deletions(-) create mode 100644 Fixed Size Array/FixedSizeArray.playground/Contents.swift create mode 100644 Fixed Size Array/FixedSizeArray.playground/contents.xcplayground create mode 100644 Fixed Size Array/FixedSizeArray.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline delete mode 100644 Fixed Size Array/FixedSizeArray.swift diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift new file mode 100644 index 000000000..663050d31 --- /dev/null +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -0,0 +1,56 @@ +//: Playground - noun: a place where people can play + +/* + An unordered array with a maximum size. + + Performance is always O(1). + */ +struct FixedSizeArray { + private var maxSize: Int + private var defaultValue: T + private var array: [T] + private (set) var count = 0 + + init(maxSize: Int, defaultValue: T) { + self.maxSize = maxSize + self.defaultValue = defaultValue + self.array = [T](repeating: defaultValue, count: maxSize) + } + + subscript(index: Int) -> T { + assert(index >= 0) + assert(index < count) + return array[index] + } + + mutating func append(newElement: T) { + assert(count < maxSize) + array[count] = newElement + count += 1 + } + + mutating func removeAtIndex(index: Int) -> T { + assert(index >= 0) + assert(index < count) + count -= 1 + let result = array[index] + array[index] = array[count] + array[count] = defaultValue + return result + } + + mutating func removeAll() { + for i in 0.. + + + \ No newline at end of file diff --git a/Fixed Size Array/FixedSizeArray.playground/playground.xcworkspace/contents.xcworkspacedata b/Fixed Size Array/FixedSizeArray.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Fixed Size Array/FixedSizeArray.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline b/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline new file mode 100644 index 000000000..def6161e4 --- /dev/null +++ b/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Fixed Size Array/FixedSizeArray.swift b/Fixed Size Array/FixedSizeArray.swift deleted file mode 100644 index 270222230..000000000 --- a/Fixed Size Array/FixedSizeArray.swift +++ /dev/null @@ -1,46 +0,0 @@ -/* - An unordered array with a maximum size. - - Performance is always O(1). -*/ -struct FixedSizeArray { - private var maxSize: Int - private var defaultValue: T - private var array: [T] - private (set) var count = 0 - - init(maxSize: Int, defaultValue: T) { - self.maxSize = maxSize - self.defaultValue = defaultValue - self.array = [T](count: maxSize, repeatedValue: defaultValue) - } - - subscript(index: Int) -> T { - assert(index >= 0) - assert(index < count) - return array[index] - } - - mutating func append(newElement: T) { - assert(count < maxSize) - array[count] = newElement - count += 1 - } - - mutating func removeAtIndex(index: Int) -> T { - assert(index >= 0) - assert(index < count) - count -= 1 - let result = array[index] - array[index] = array[count] - array[count] = defaultValue - return result - } - - mutating func removeAll() { - for i in 0.. { - private var maxSize: Int - private var defaultValue: T - private var array: [T] - private (set) var count = 0 - - init(maxSize: Int, defaultValue: T) { - self.maxSize = maxSize - self.defaultValue = defaultValue - self.array = [T](count: maxSize, repeatedValue: defaultValue) - } - - subscript(index: Int) -> T { - assert(index >= 0) - assert(index < count) - return array[index] - } - - mutating func append(newElement: T) { - assert(count < maxSize) - array[count] = newElement - count += 1 - } - - mutating func removeAtIndex(index: Int) -> T { - assert(index >= 0) - assert(index < count) - count -= 1 - let result = array[index] - array[index] = array[count] - array[count] = defaultValue - return result - } + private var maxSize: Int + private var defaultValue: T + private var array: [T] + private (set) var count = 0 + + init(maxSize: Int, defaultValue: T) { + self.maxSize = maxSize + self.defaultValue = defaultValue + self.array = [T](repeating: defaultValue, count: maxSize) + } + + subscript(index: Int) -> T { + assert(index >= 0) + assert(index < count) + return array[index] + } + + mutating func append(newElement: T) { + assert(count < maxSize) + array[count] = newElement + count += 1 + } + + mutating func removeAtIndex(index: Int) -> T { + assert(index >= 0) + assert(index < count) + count -= 1 + let result = array[index] + array[index] = array[count] + array[count] = defaultValue + return result + } + + mutating func removeAll() { + for i in 0.. Date: Fri, 28 Oct 2016 12:44:05 -0700 Subject: [PATCH 0219/1275] Added File implementations --- Strassen Matrix Multiplication/Matrix.swift | 9 +++++++++ Strassen Matrix Multiplication/MatrixSize.swift | 9 +++++++++ Strassen Matrix Multiplication/Number.swift | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100644 Strassen Matrix Multiplication/Matrix.swift create mode 100644 Strassen Matrix Multiplication/MatrixSize.swift create mode 100644 Strassen Matrix Multiplication/Number.swift diff --git a/Strassen Matrix Multiplication/Matrix.swift b/Strassen Matrix Multiplication/Matrix.swift new file mode 100644 index 000000000..493e27e06 --- /dev/null +++ b/Strassen Matrix Multiplication/Matrix.swift @@ -0,0 +1,9 @@ +// +// Matrix.swift +// +// +// Created by Richard Ash on 10/28/16. +// +// + +import Foundation diff --git a/Strassen Matrix Multiplication/MatrixSize.swift b/Strassen Matrix Multiplication/MatrixSize.swift new file mode 100644 index 000000000..a01123f3c --- /dev/null +++ b/Strassen Matrix Multiplication/MatrixSize.swift @@ -0,0 +1,9 @@ +// +// MatrixSize.swift +// +// +// Created by Richard Ash on 10/28/16. +// +// + +import Foundation diff --git a/Strassen Matrix Multiplication/Number.swift b/Strassen Matrix Multiplication/Number.swift new file mode 100644 index 000000000..1bd6cf634 --- /dev/null +++ b/Strassen Matrix Multiplication/Number.swift @@ -0,0 +1,9 @@ +// +// Number.swift +// +// +// Created by Richard Ash on 10/28/16. +// +// + +import Foundation From bf24ad0267c3cc6371f61450a9ada56aee1076cc Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Fri, 28 Oct 2016 23:33:46 -0700 Subject: [PATCH 0220/1275] fix for Swift 3 --- Shuffle/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index e0be6c1e4..ced138572 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -12,7 +12,7 @@ extension Array { var temp = [Element]() while !isEmpty { let i = random(count) - let obj = removeAtIndex(i) + let obj = remove(at: i) temp.append(obj) } self = temp @@ -44,7 +44,7 @@ Here is a much improved version of the shuffle algorithm: ```swift extension Array { public mutating func shuffle() { - for i in (count - 1).stride(through: 1, by: -1) { + for i in stride(from: count - 1, through: 1, by: -1) { let j = random(i + 1) if i != j { swap(&self[i], &self[j]) @@ -96,8 +96,8 @@ There is a slight variation on this algorithm that is useful for when you want t Here is the code: ```swift -public func shuffledArray(n: Int) -> [Int] { - var a = [Int](count: n, repeatedValue: 0) +public func shuffledArray(_ n: Int) -> [Int] { + var a = [Int](repeating: 0, count: n) for i in 0.. Date: Fri, 28 Oct 2016 23:38:01 -0700 Subject: [PATCH 0221/1275] fix for Swift 3 --- Shuffle/Shuffle.playground/Contents.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Shuffle/Shuffle.playground/Contents.swift b/Shuffle/Shuffle.playground/Contents.swift index a12086548..e6d4f000d 100644 --- a/Shuffle/Shuffle.playground/Contents.swift +++ b/Shuffle/Shuffle.playground/Contents.swift @@ -3,7 +3,7 @@ import Foundation /* Returns a random integer between 0 and n-1. */ -public func random(n: Int) -> Int { +public func random(_ n: Int) -> Int { return Int(arc4random_uniform(UInt32(n))) } @@ -12,7 +12,7 @@ public func random(n: Int) -> Int { /* Fisher-Yates / Knuth shuffle */ extension Array { public mutating func shuffle() { - for i in (count - 1).stride(through: 1, by: -1) { + for i in stride(from: count - 1, through: 1, by: -1) { let j = random(i + 1) if i != j { swap(&self[i], &self[j]) @@ -29,8 +29,8 @@ list.shuffle() /* Create a new array of numbers that is already shuffled. */ -public func shuffledArray(n: Int) -> [Int] { - var a = [Int](count: n, repeatedValue: 0) +public func shuffledArray(_ n: Int) -> [Int] { + var a = [Int](repeating: 0, count: n) for i in 0.. Date: Mon, 31 Oct 2016 00:29:56 -0700 Subject: [PATCH 0222/1275] Added HaversineDistance to front page. --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 2acedd0fa..bc0dbf21d 100644 --- a/README.markdown +++ b/README.markdown @@ -103,6 +103,7 @@ Bad sorting algorithms (don't use these!): - [Shunting Yard Algorithm](Shunting Yard/). Convert infix expressions to postfix. - Statistics - [Karatsuba Multiplication](Karatsuba Multiplication/). Another take on elementary multiplication. +- [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. ### Machine learning From 8328491307b7850c1fd6eb6d50a279fc195ed075 Mon Sep 17 00:00:00 2001 From: Jaap Date: Mon, 31 Oct 2016 20:34:34 +0100 Subject: [PATCH 0223/1275] migratehashsetswift3 --- Hash Set/HashSet.playground/Contents.swift | 72 ------------ .../HashSet.playground/Sources/HashSet.swift | 76 +++++++++++++ Hash Set/README.markdown | 104 +++++++++--------- 3 files changed, 130 insertions(+), 122 deletions(-) create mode 100644 Hash Set/HashSet.playground/Sources/HashSet.swift diff --git a/Hash Set/HashSet.playground/Contents.swift b/Hash Set/HashSet.playground/Contents.swift index 636d4d925..551c6dc86 100644 --- a/Hash Set/HashSet.playground/Contents.swift +++ b/Hash Set/HashSet.playground/Contents.swift @@ -1,33 +1,5 @@ //: Playground - noun: a place where people can play -public struct HashSet { - private var dictionary = Dictionary() - - public mutating func insert(element: T) { - dictionary[element] = true - } - - public mutating func remove(element: T) { - dictionary[element] = nil - } - - public func contains(element: T) -> Bool { - return dictionary[element] != nil - } - - public func allElements() -> [T] { - return Array(dictionary.keys) - } - - public var count: Int { - return dictionary.count - } - - public var isEmpty: Bool { - return dictionary.isEmpty - } -} - var set = HashSet() set.insert("one") @@ -43,24 +15,8 @@ set.remove("one") set.allElements() set.contains("one") - - /* Union */ -extension HashSet { - public func union(otherSet: HashSet) -> HashSet { - var combined = HashSet() - for obj in dictionary.keys { - combined.insert(obj) - } - for obj in otherSet.dictionary.keys { - combined.insert(obj) - } - return combined - } -} - - var setA = HashSet() setA.insert(1) setA.insert(2) @@ -76,41 +32,13 @@ setB.insert(6) let union = setA.union(setB) union.allElements() // [5, 6, 2, 3, 1, 4] - - /* Intersection */ -extension HashSet { - public func intersect(otherSet: HashSet) -> HashSet { - var common = HashSet() - for obj in dictionary.keys { - if otherSet.contains(obj) { - common.insert(obj) - } - } - return common - } -} - let intersection = setA.intersect(setB) intersection.allElements() // [3, 4] - - /* Difference */ -extension HashSet { - public func difference(otherSet: HashSet) -> HashSet { - var diff = HashSet() - for obj in dictionary.keys { - if !otherSet.contains(obj) { - diff.insert(obj) - } - } - return diff - } -} - let difference1 = setA.difference(setB) difference1.allElements() // [2, 1] diff --git a/Hash Set/HashSet.playground/Sources/HashSet.swift b/Hash Set/HashSet.playground/Sources/HashSet.swift new file mode 100644 index 000000000..c3365110b --- /dev/null +++ b/Hash Set/HashSet.playground/Sources/HashSet.swift @@ -0,0 +1,76 @@ +//: Playground - noun: a place where people can play + +public struct HashSet { + fileprivate var dictionary = Dictionary() + + public init() { + + } + + public mutating func insert(_ element: T) { + dictionary[element] = true + } + + public mutating func remove(_ element: T) { + dictionary[element] = nil + } + + public func contains(_ element: T) -> Bool { + return dictionary[element] != nil + } + + public func allElements() -> [T] { + return Array(dictionary.keys) + } + + public var count: Int { + return dictionary.count + } + + public var isEmpty: Bool { + return dictionary.isEmpty + } +} + +/* Union */ + +extension HashSet { + public func union(_ otherSet: HashSet) -> HashSet { + var combined = HashSet() + for obj in self.dictionary.keys { + combined.insert(obj) + } + for obj in otherSet.dictionary.keys { + combined.insert(obj) + } + return combined + } +} + +/* Intersection */ + +extension HashSet { + public func intersect(_ otherSet: HashSet) -> HashSet { + var common = HashSet() + for obj in dictionary.keys { + if otherSet.contains(obj) { + common.insert(obj) + } + } + return common + } +} + +/* Difference */ + +extension HashSet { + public func difference(_ otherSet: HashSet) -> HashSet { + var diff = HashSet() + for obj in dictionary.keys { + if !otherSet.contains(obj) { + diff.insert(obj) + } + } + return diff + } +} diff --git a/Hash Set/README.markdown b/Hash Set/README.markdown index c6616fb42..368920a1c 100644 --- a/Hash Set/README.markdown +++ b/Hash Set/README.markdown @@ -38,31 +38,35 @@ Here are the beginnings of `HashSet` in Swift: ```swift public struct HashSet { - private var dictionary = Dictionary() - - public mutating func insert(element: T) { - dictionary[element] = true - } - - public mutating func remove(element: T) { - dictionary[element] = nil - } - - public func contains(element: T) -> Bool { - return dictionary[element] != nil - } - - public func allElements() -> [T] { - return Array(dictionary.keys) - } - - public var count: Int { - return dictionary.count - } - - public var isEmpty: Bool { - return dictionary.isEmpty - } + fileprivate var dictionary = Dictionary() + + public init() { + + } + + public mutating func insert(_ element: T) { + dictionary[element] = true + } + + public mutating func remove(_ element: T) { + dictionary[element] = nil + } + + public func contains(_ element: T) -> Bool { + return dictionary[element] != nil + } + + public func allElements() -> [T] { + return Array(dictionary.keys) + } + + public var count: Int { + return dictionary.count + } + + public var isEmpty: Bool { + return dictionary.isEmpty + } } ``` @@ -101,16 +105,16 @@ Here is the code for the union operation: ```swift extension HashSet { - public func union(otherSet: HashSet) -> HashSet { - var combined = HashSet() - for obj in dictionary.keys { - combined.insert(obj) - } - for obj in otherSet.dictionary.keys { - combined.insert(obj) + public func union(_ otherSet: HashSet) -> HashSet { + var combined = HashSet() + for obj in self.dictionary.keys { + combined.insert(obj) + } + for obj in otherSet.dictionary.keys { + combined.insert(obj) + } + return combined } - return combined - } } ``` @@ -141,15 +145,15 @@ The *intersection* of two sets contains only the elements that they have in comm ```swift extension HashSet { - public func intersect(otherSet: HashSet) -> HashSet { - var common = HashSet() - for obj in dictionary.keys { - if otherSet.contains(obj) { - common.insert(obj) - } + public func intersect(_ otherSet: HashSet) -> HashSet { + var common = HashSet() + for obj in dictionary.keys { + if otherSet.contains(obj) { + common.insert(obj) + } + } + return common } - return common - } } ``` @@ -166,15 +170,15 @@ Finally, the *difference* between two sets removes the elements they have in com ```swift extension HashSet { - public func difference(otherSet: HashSet) -> HashSet { - var diff = HashSet() - for obj in dictionary.keys { - if !otherSet.contains(obj) { - diff.insert(obj) - } + public func difference(_ otherSet: HashSet) -> HashSet { + var diff = HashSet() + for obj in dictionary.keys { + if !otherSet.contains(obj) { + diff.insert(obj) + } + } + return diff } - return diff - } } ``` From 3fe357f6fd4123fc063f39d5eec8607529a1f617 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 1 Nov 2016 04:06:30 -0700 Subject: [PATCH 0224/1275] Removed an argument label for the append method in an effort to keep consistent with native collection types. Changed a method name to be more Swift like. --- .../FixedSizeArray.playground/Contents.swift | 10 +++++----- .../FixedSizeArray.playground/timeline.xctimeline | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index 663050d31..afe666a31 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -23,13 +23,13 @@ struct FixedSizeArray { return array[index] } - mutating func append(newElement: T) { + mutating func append(_ newElement: T) { assert(count < maxSize) array[count] = newElement count += 1 } - mutating func removeAtIndex(index: Int) -> T { + mutating func removeAt(index: Int) -> T { assert(index >= 0) assert(index < count) count -= 1 @@ -48,9 +48,9 @@ struct FixedSizeArray { } var array = FixedSizeArray(maxSize: 5, defaultValue: 0) -array.append(newElement: 4) -array.append(newElement: 2) +array.append(4) +array.append(2) array[1] -array.removeAtIndex(index: 0) +array.removeAt(index: 0) array.removeAll() diff --git a/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline b/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline index def6161e4..d95db1553 100644 --- a/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline +++ b/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline @@ -3,12 +3,12 @@ version = "3.0"> From b2bc31b7e8e1764f7431d07cbfacccccf7733518 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 1 Nov 2016 04:10:58 -0700 Subject: [PATCH 0225/1275] Changed tabs from 4 spaces to 2 spaces. Updated README file to reflect the updated syntax. --- .../FixedSizeArray.playground/Contents.swift | 76 ++++++++--------- .../timeline.xctimeline | 4 +- Fixed Size Array/README.markdown | 84 +++++++++---------- 3 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index afe666a31..f1bc63315 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -6,45 +6,45 @@ Performance is always O(1). */ struct FixedSizeArray { - private var maxSize: Int - private var defaultValue: T - private var array: [T] - private (set) var count = 0 - - init(maxSize: Int, defaultValue: T) { - self.maxSize = maxSize - self.defaultValue = defaultValue - self.array = [T](repeating: defaultValue, count: maxSize) - } - - subscript(index: Int) -> T { - assert(index >= 0) - assert(index < count) - return array[index] - } - - mutating func append(_ newElement: T) { - assert(count < maxSize) - array[count] = newElement - count += 1 - } - - mutating func removeAt(index: Int) -> T { - assert(index >= 0) - assert(index < count) - count -= 1 - let result = array[index] - array[index] = array[count] - array[count] = defaultValue - return result - } - - mutating func removeAll() { - for i in 0.. T { + assert(index >= 0) + assert(index < count) + return array[index] + } + + mutating func append(_ newElement: T) { + assert(count < maxSize) + array[count] = newElement + count += 1 + } + + mutating func removeAt(index: Int) -> T { + assert(index >= 0) + assert(index < count) + count -= 1 + let result = array[index] + array[index] = array[count] + array[count] = defaultValue + return result + } + + mutating func removeAll() { + for i in 0.. diff --git a/Fixed Size Array/README.markdown b/Fixed Size Array/README.markdown index efacda710..e9eade140 100644 --- a/Fixed Size Array/README.markdown +++ b/Fixed Size Array/README.markdown @@ -55,12 +55,12 @@ Fixed-size arrays are a good solution when: 1. You know beforehand the maximum number of elements you'll need. In a game this could be the number of sprites that can be active at a time. It's not unreasonable to put a limit on this. (For games it's a good idea to allocate all the objects you need in advance anyway.) 2. It is not necessary to have a sorted version of the array, i.e. the order of the elements does not matter. -If the array does not need to be sorted, then an `insertAtIndex()` operation is not needed. You can simply append any new elements to the end, until the array is full. +If the array does not need to be sorted, then an `insertAt(index)` operation is not needed. You can simply append any new elements to the end, until the array is full. The code for adding an element becomes: ```swift -func append(newElement) { +func append(_ newElement: T) { if count < maxSize { array[count] = newElement count += 1 @@ -75,7 +75,7 @@ Determining the number of elements in the array is just a matter of reading the The code for removing an element is equally simple: ```swift -func removeAtIndex(index) { +func removeAt(index: Int) { count -= 1 array[index] = array[count] } @@ -95,45 +95,45 @@ Here is an implementation in Swift: ```swift struct FixedSizeArray { - private var maxSize: Int - private var defaultValue: T - private var array: [T] - private (set) var count = 0 - - init(maxSize: Int, defaultValue: T) { - self.maxSize = maxSize - self.defaultValue = defaultValue - self.array = [T](repeating: defaultValue, count: maxSize) - } - - subscript(index: Int) -> T { - assert(index >= 0) - assert(index < count) - return array[index] - } - - mutating func append(newElement: T) { - assert(count < maxSize) - array[count] = newElement - count += 1 - } - - mutating func removeAtIndex(index: Int) -> T { - assert(index >= 0) - assert(index < count) - count -= 1 - let result = array[index] - array[index] = array[count] - array[count] = defaultValue - return result - } - - mutating func removeAll() { - for i in 0.. T { + assert(index >= 0) + assert(index < count) + return array[index] + } + + mutating func append(_ newElement: T) { + assert(count < maxSize) + array[count] = newElement + count += 1 + } + + mutating func removeAt(index: Int) -> T { + assert(index >= 0) + assert(index < count) + count -= 1 + let result = array[index] + array[index] = array[count] + array[count] = defaultValue + return result + } + + mutating func removeAll() { + for i in 0.. Date: Tue, 1 Nov 2016 18:54:39 -0500 Subject: [PATCH 0226/1275] took off an extra min --- .../SelectionSampling.playground/Contents.swift | 3 +-- .../SelectionSampling.playground/timeline.xctimeline | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 Selection Sampling/SelectionSampling.playground/timeline.xctimeline diff --git a/Selection Sampling/SelectionSampling.playground/Contents.swift b/Selection Sampling/SelectionSampling.playground/Contents.swift index f6032137b..df1bb2e32 100644 --- a/Selection Sampling/SelectionSampling.playground/Contents.swift +++ b/Selection Sampling/SelectionSampling.playground/Contents.swift @@ -3,7 +3,7 @@ import Foundation /* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { +public func random(min: Int, max: Int) -> Int { assert(min < max) return min + Int(arc4random_uniform(UInt32(max - min + 1))) } @@ -45,7 +45,6 @@ func select(from a: [T], count requested: Int) -> [T] { } - let poem = [ "there", "once", "was", "a", "man", "from", "nantucket", "who", "kept", "all", "of", "his", "cash", "in", "a", "bucket", diff --git a/Selection Sampling/SelectionSampling.playground/timeline.xctimeline b/Selection Sampling/SelectionSampling.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Selection Sampling/SelectionSampling.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From f0c17d5aeedf8d78c5449fa326e91152dc3cc5dc Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Wed, 2 Nov 2016 12:12:45 +0000 Subject: [PATCH 0227/1275] Dining Philosophers Problem Algorithm --- .../project.pbxproj | 250 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcschemes/DiningPhilosophers.xcscheme | 71 +++++ .../xcschemes/xcschememanagement.plist | 12 + DiningPhilosophers/LICENSE | 201 ++++++++++++++ DiningPhilosophers/Package.swift | 5 + DiningPhilosophers/README.md | 13 + DiningPhilosophers/Sources/main.swift | 107 ++++++++ 8 files changed, 666 insertions(+) create mode 100755 DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj create mode 100755 DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/DiningPhilosophers.xcscheme create mode 100755 DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist create mode 100755 DiningPhilosophers/LICENSE create mode 100755 DiningPhilosophers/Package.swift create mode 100755 DiningPhilosophers/README.md create mode 100755 DiningPhilosophers/Sources/main.swift diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj new file mode 100755 index 000000000..9743ff7d1 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -0,0 +1,250 @@ +// !$*UTF8*$! +{ + archiveVersion = "1"; + objectVersion = "46"; + objects = { + OBJ_1 = { + isa = "PBXProject"; + attributes = { + LastUpgradeCheck = "9999"; + }; + buildConfigurationList = OBJ_2; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = "English"; + hasScannedForEncodings = "0"; + knownRegions = ( + "en", + ); + mainGroup = OBJ_5; + productRefGroup = OBJ_11; + projectDirPath = "."; + targets = ( + OBJ_13, + ); + }; + OBJ_10 = { + isa = "PBXGroup"; + children = ( + ); + path = "Tests"; + sourceTree = ""; + }; + OBJ_11 = { + isa = "PBXGroup"; + children = ( + OBJ_12, + ); + name = "Products"; + path = ""; + sourceTree = "BUILT_PRODUCTS_DIR"; + }; + OBJ_12 = { + isa = "PBXFileReference"; + path = "DiningPhilosophers"; + sourceTree = "BUILT_PRODUCTS_DIR"; + }; + OBJ_13 = { + isa = "PBXNativeTarget"; + buildConfigurationList = OBJ_14; + buildPhases = ( + OBJ_17, + OBJ_19, + ); + dependencies = ( + ); + name = "DiningPhilosophers"; + productName = "DiningPhilosophers"; + productReference = OBJ_12; + productType = "com.apple.product-type.tool"; + }; + OBJ_14 = { + isa = "XCConfigurationList"; + buildConfigurations = ( + OBJ_15, + OBJ_16, + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Debug"; + }; + OBJ_15 = { + isa = "XCBuildConfiguration"; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + ); + INFOPLIST_FILE = "DiningPhilosophers.xcodeproj/DiningPhilosophers_Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", + "@executable_path", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)", + ); + SUPPORTED_PLATFORMS = ( + "macosx", + ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SWIFT_PACKAGE"; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = "YES"; + SWIFT_FORCE_STATIC_LINK_STDLIB = "NO"; + SWIFT_VERSION = "3.0"; + TARGET_NAME = "DiningPhilosophers"; + }; + name = "Debug"; + }; + OBJ_16 = { + isa = "XCBuildConfiguration"; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + ); + INFOPLIST_FILE = "DiningPhilosophers.xcodeproj/DiningPhilosophers_Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", + "@executable_path", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)", + ); + SUPPORTED_PLATFORMS = ( + "macosx", + ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SWIFT_PACKAGE"; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = "YES"; + SWIFT_FORCE_STATIC_LINK_STDLIB = "NO"; + SWIFT_VERSION = "3.0"; + TARGET_NAME = "DiningPhilosophers"; + }; + name = "Release"; + }; + OBJ_17 = { + isa = "PBXSourcesBuildPhase"; + files = ( + OBJ_18, + ); + }; + OBJ_18 = { + isa = "PBXBuildFile"; + fileRef = OBJ_9; + }; + OBJ_19 = { + isa = "PBXFrameworksBuildPhase"; + files = ( + ); + }; + OBJ_2 = { + isa = "XCConfigurationList"; + buildConfigurations = ( + OBJ_3, + OBJ_4, + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Debug"; + }; + OBJ_3 = { + isa = "XCBuildConfiguration"; + buildSettings = { + COMBINE_HIDPI_IMAGES = "YES"; + COPY_PHASE_STRIP = "NO"; + DEBUG_INFORMATION_FORMAT = "dwarf"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = "YES"; + GCC_OPTIMIZATION_LEVEL = "0"; + MACOSX_DEPLOYMENT_TARGET = "10.10"; + ONLY_ACTIVE_ARCH = "YES"; + OTHER_SWIFT_FLAGS = ( + "-DXcode", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = ( + "macosx", + "iphoneos", + "iphonesimulator", + "appletvos", + "appletvsimulator", + "watchos", + "watchsimulator", + ); + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + USE_HEADERMAP = "NO"; + }; + name = "Debug"; + }; + OBJ_4 = { + isa = "XCBuildConfiguration"; + buildSettings = { + COMBINE_HIDPI_IMAGES = "YES"; + COPY_PHASE_STRIP = "YES"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = "s"; + MACOSX_DEPLOYMENT_TARGET = "10.10"; + OTHER_SWIFT_FLAGS = ( + "-DXcode", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = ( + "macosx", + "iphoneos", + "iphonesimulator", + "appletvos", + "appletvsimulator", + "watchos", + "watchsimulator", + ); + SWIFT_OPTIMIZATION_LEVEL = "-O"; + USE_HEADERMAP = "NO"; + }; + name = "Release"; + }; + OBJ_5 = { + isa = "PBXGroup"; + children = ( + OBJ_6, + OBJ_7, + OBJ_10, + OBJ_11, + ); + path = ""; + sourceTree = ""; + }; + OBJ_6 = { + isa = "PBXFileReference"; + explicitFileType = "sourcecode.swift"; + path = "Package.swift"; + sourceTree = ""; + }; + OBJ_7 = { + isa = "PBXGroup"; + children = ( + OBJ_8, + ); + path = "Sources"; + sourceTree = ""; + }; + OBJ_8 = { + isa = "PBXGroup"; + children = ( + OBJ_9, + ); + name = "DiningPhilosophers"; + path = "Sources"; + sourceTree = "SOURCE_ROOT"; + }; + OBJ_9 = { + isa = "PBXFileReference"; + path = "main.swift"; + sourceTree = ""; + }; + }; + rootObject = OBJ_1; +} diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000..919434a62 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/DiningPhilosophers.xcscheme b/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/DiningPhilosophers.xcscheme new file mode 100755 index 000000000..3c17791b7 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/DiningPhilosophers.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist b/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist new file mode 100755 index 000000000..4cd3e1d66 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist @@ -0,0 +1,12 @@ + + + + SchemeUserState + + DiningPhilosophers.xcscheme + + + SuppressBuildableAutocreation + + + diff --git a/DiningPhilosophers/LICENSE b/DiningPhilosophers/LICENSE new file mode 100755 index 000000000..8dada3eda --- /dev/null +++ b/DiningPhilosophers/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/DiningPhilosophers/Package.swift b/DiningPhilosophers/Package.swift new file mode 100755 index 000000000..c7e5efd4f --- /dev/null +++ b/DiningPhilosophers/Package.swift @@ -0,0 +1,5 @@ +import PackageDescription + +let package = Package( + name: "DiningPhilosophers" +) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md new file mode 100755 index 000000000..06302cf2a --- /dev/null +++ b/DiningPhilosophers/README.md @@ -0,0 +1,13 @@ +# SwiftDiningPhilosophers +Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using GCD and Semaphore in Swift) + +Written by Jacopo Mangiavacchi + + +# from https://en.wikipedia.org/wiki/Dining_philosophers_problem + +In computer science, the dining philosophers problem is an example problem often used in concurrent algorithm design to illustrate synchronization issues and techniques for resolving them. + +It was originally formulated in 1965 by Edsger Dijkstra as a student exam exercise, presented in terms of computers competing for access to tape drive peripherals. Soon after, Tony Hoare gave the problem its present formulation. + +This Swift implementation is based on the Chandy/Misra solution and it use GCD Dispatch and Semaphone on Swift cross platform diff --git a/DiningPhilosophers/Sources/main.swift b/DiningPhilosophers/Sources/main.swift new file mode 100755 index 000000000..dfde40773 --- /dev/null +++ b/DiningPhilosophers/Sources/main.swift @@ -0,0 +1,107 @@ +// +// Swift Dining philosophers problem Algorithm +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +// +// Created by Jacopo Mangiavacchi on 11/02/16. +// +// + + +import Foundation +import Dispatch + +let numberOfPhilosophers = 4 + +class ForkPair { + static let forksSemaphore:[DispatchSemaphore] = Array(repeating: DispatchSemaphore(value: 1), count: numberOfPhilosophers) + + let leftFork: DispatchSemaphore + let rightFork: DispatchSemaphore + + init(leftIndex: Int, rightIndex: Int) { + //Order forks by index to prevent deadlock + if leftIndex > rightIndex { + leftFork = ForkPair.forksSemaphore[leftIndex] + rightFork = ForkPair.forksSemaphore[rightIndex] + } + else { + leftFork = ForkPair.forksSemaphore[rightIndex] + rightFork = ForkPair.forksSemaphore[leftIndex] + } + } + + func pickUp() { + //Acquire by starting with the lower index + leftFork.wait() + rightFork.wait() + } + + func putDown() { + //The order does not matter here + leftFork.signal() + rightFork.signal() + } +} + + +class Philosophers { + let forkPair: ForkPair + let philosopherIndex: Int + + var leftIndex = -1 + var rightIndex = -1 + + init(philosopherIndex: Int) { + leftIndex = philosopherIndex + rightIndex = philosopherIndex - 1 + + if rightIndex < 0 { + rightIndex += numberOfPhilosophers + } + + self.forkPair = ForkPair(leftIndex: leftIndex, rightIndex: rightIndex) + self.philosopherIndex = philosopherIndex + + print("Philosopher: \(philosopherIndex) left: \(leftIndex) right: \(rightIndex)") + } + + func run() { + while true { + print("Acquiring lock for Philosofer: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + forkPair.pickUp() + print("Start Eating Philosopher: \(philosopherIndex)") + //sleep(1000) + print("Releasing lock for Philosofer: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + forkPair.putDown() + } + } +} + + +// Layout of the table (P = philosopher, f = fork) for 4 Philosopher +// P0 +// f3 f0 +// P3 P1 +// f2 f1 +// P2 + +let globalSem = DispatchSemaphore(value: 0) + +for i in 0.. Date: Wed, 2 Nov 2016 15:23:31 +0100 Subject: [PATCH 0228/1275] Fix a bug in SegmentTree --- .../SegmentTree.playground/Contents.swift | 46 +++++++++---------- Segment Tree/SegmentTree.swift | 10 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Segment Tree/SegmentTree.playground/Contents.swift b/Segment Tree/SegmentTree.playground/Contents.swift index 6b33b2f44..5bba56cc0 100644 --- a/Segment Tree/SegmentTree.playground/Contents.swift +++ b/Segment Tree/SegmentTree.playground/Contents.swift @@ -28,7 +28,7 @@ public class SegmentTree { self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) } - public func query(withLeftBound: Int, rightBound: Int) -> T { + public func query(leftBound: Int, rightBound: Int) -> T { if self.leftBound == leftBound && self.rightBound == rightBound { return self.value } @@ -37,12 +37,12 @@ public class SegmentTree { guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } if leftChild.rightBound < leftBound { - return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) + return rightChild.query(leftBound: leftBound, rightBound: rightBound) } else if rightChild.leftBound > rightBound { - return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) + return leftChild.query(leftBound: leftBound, rightBound: rightBound) } else { - let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) - let rightResult = rightChild.query(withLeftBound:rightChild.leftBound, rightBound: rightBound) + let leftResult = leftChild.query(leftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(leftBound:rightChild.leftBound, rightBound: rightBound) return function(leftResult, rightResult) } } @@ -68,14 +68,14 @@ let array = [1, 2, 3, 4] let sumSegmentTree = SegmentTree(array: array, function: +) -print(sumSegmentTree.query(withLeftBound: 0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10 -print(sumSegmentTree.query(withLeftBound: 1, rightBound: 2)) // 2 + 3 = 5 -print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 1 = 1 +print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10 +print(sumSegmentTree.query(leftBound: 1, rightBound: 2)) // 2 + 3 = 5 +print(sumSegmentTree.query(leftBound: 0, rightBound: 0)) // 1 = 1 sumSegmentTree.replaceItem(at: 0, withItem: 2) //our array now is [2, 2, 3, 4] -print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 2 = 2 -print(sumSegmentTree.query(withLeftBound: 0, rightBound: 1)) // 2 + 2 = 4 +print(sumSegmentTree.query(leftBound: 0, rightBound: 0)) // 2 = 2 +print(sumSegmentTree.query(leftBound: 0, rightBound: 1)) // 2 + 2 = 4 //you can use any associative function (i.e (a+b)+c == a+(b+c)) as function for segment tree @@ -96,14 +96,14 @@ let gcdArray = [2, 4, 6, 3, 5] let gcdSegmentTree = SegmentTree(array: gcdArray, function: gcd) -print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 1)) // gcd(2, 4) = 2 -print(gcdSegmentTree.query(withLeftBound: 2, rightBound: 3)) // gcd(6, 3) = 3 -print(gcdSegmentTree.query(withLeftBound: 1, rightBound: 3)) // gcd(4, 6, 3) = 1 -print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1 +print(gcdSegmentTree.query(leftBound: 0, rightBound: 1)) // gcd(2, 4) = 2 +print(gcdSegmentTree.query(leftBound: 2, rightBound: 3)) // gcd(6, 3) = 3 +print(gcdSegmentTree.query(leftBound: 1, rightBound: 3)) // gcd(4, 6, 3) = 1 +print(gcdSegmentTree.query(leftBound: 0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1 gcdSegmentTree.replaceItem(at: 3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5] -print(gcdSegmentTree.query(withLeftBound: 3, rightBound: 4)) // gcd(10, 5) = 5 +print(gcdSegmentTree.query(leftBound: 3, rightBound: 4)) // gcd(10, 5) = 5 //example of segment tree which finds minimum on given range @@ -111,12 +111,12 @@ let minArray = [2, 4, 1, 5, 3] let minSegmentTree = SegmentTree(array: minArray, function: min) -print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1 -print(minSegmentTree.query(withLeftBound: 0, rightBound: 1)) // min(2, 4) = 2 +print(minSegmentTree.query(leftBound: 0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1 +print(minSegmentTree.query(leftBound: 0, rightBound: 1)) // min(2, 4) = 2 minSegmentTree.replaceItem(at: 2, withItem: 10) // minArray now is [2, 4, 10, 5, 3] -print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2 +print(minSegmentTree.query(leftBound: 0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2 //type of elements in array can be any type which has some associative function @@ -124,10 +124,10 @@ let stringArray = ["a", "b", "c", "A", "B", "C"] let stringSegmentTree = SegmentTree(array: stringArray, function: +) -print(stringSegmentTree.query(withLeftBound: 0, rightBound: 1)) // "a"+"b" = "ab" -print(stringSegmentTree.query(withLeftBound: 2, rightBound: 3)) // "c"+"A" = "cA" -print(stringSegmentTree.query(withLeftBound: 1, rightBound: 3)) // "b"+"c"+"A" = "bcA" -print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC" +print(stringSegmentTree.query(leftBound: 0, rightBound: 1)) // "a"+"b" = "ab" +print(stringSegmentTree.query(leftBound: 2, rightBound: 3)) // "c"+"A" = "cA" +print(stringSegmentTree.query(leftBound: 1, rightBound: 3)) // "b"+"c"+"A" = "bcA" +print(stringSegmentTree.query(leftBound: 0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC" stringSegmentTree.replaceItem(at: 0, withItem: "I") stringSegmentTree.replaceItem(at: 1, withItem: " like") @@ -136,4 +136,4 @@ stringSegmentTree.replaceItem(at: 3, withItem: " and") stringSegmentTree.replaceItem(at: 4, withItem: " swift") stringSegmentTree.replaceItem(at: 5, withItem: "!") -print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5)) +print(stringSegmentTree.query(leftBound: 0, rightBound: 5)) diff --git a/Segment Tree/SegmentTree.swift b/Segment Tree/SegmentTree.swift index b360d409a..a3ec8b1bf 100644 --- a/Segment Tree/SegmentTree.swift +++ b/Segment Tree/SegmentTree.swift @@ -35,7 +35,7 @@ public class SegmentTree { self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) } - public func query(withLeftBound: Int, rightBound: Int) -> T { + public func query(leftBound: Int, rightBound: Int) -> T { if self.leftBound == leftBound && self.rightBound == rightBound { return self.value } @@ -44,12 +44,12 @@ public class SegmentTree { guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } if leftChild.rightBound < leftBound { - return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) + return rightChild.query(leftBound: leftBound, rightBound: rightBound) } else if rightChild.leftBound > rightBound { - return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) + return leftChild.query(leftBound: leftBound, rightBound: rightBound) } else { - let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) - let rightResult = rightChild.query(withLeftBound:rightChild.leftBound, rightBound: rightBound) + let leftResult = leftChild.query(leftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(leftBound:rightChild.leftBound, rightBound: rightBound) return function(leftResult, rightResult) } } From ea634305e542a2d9601ca560ced4d4b84796f8cd Mon Sep 17 00:00:00 2001 From: Chris Amanse Date: Fri, 4 Nov 2016 23:37:20 -0700 Subject: [PATCH 0229/1275] Fix memory leak in Tree implementation - caused by retain cycle between parent and child (parent has a strong reference to child, and child has a strong reference to parent) --- Tree/Tree.playground/Contents.swift | 2 +- Tree/Tree.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index 7b3c97005..77e8fd22e 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -3,7 +3,7 @@ public class TreeNode { public var value: T - public var parent: TreeNode? + public weak var parent: TreeNode? public var children = [TreeNode]() public init(value: T) { diff --git a/Tree/Tree.swift b/Tree/Tree.swift index 00119c963..fa49f25e9 100644 --- a/Tree/Tree.swift +++ b/Tree/Tree.swift @@ -1,7 +1,7 @@ public class TreeNode { public var value: T - public var parent: TreeNode? + public weak var parent: TreeNode? public var children = [TreeNode]() public init(value: T) { From b23ad94b1758cf572dc814966b3260fbedb8a8c1 Mon Sep 17 00:00:00 2001 From: Chris Amanse Date: Fri, 4 Nov 2016 23:41:44 -0700 Subject: [PATCH 0230/1275] Fix code in Tree docs (set parent to weak) --- Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tree/README.markdown b/Tree/README.markdown index 5cf3e6beb..529a68cf1 100644 --- a/Tree/README.markdown +++ b/Tree/README.markdown @@ -26,7 +26,7 @@ Here's a basic implementation in Swift: public class TreeNode { public var value: T - public var parent: TreeNode? + public weak var parent: TreeNode? public var children = [TreeNode]() public init(value: T) { From f77809c0476c7ed1d8701cb54d0eeb01fed36198 Mon Sep 17 00:00:00 2001 From: Divyendu Singh Date: Tue, 8 Nov 2016 01:58:40 +0530 Subject: [PATCH 0231/1275] typo fix and claim commit --- Bucket Sort/README.markdown | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Bucket Sort/README.markdown b/Bucket Sort/README.markdown index f6e318c1f..f572fc9a1 100644 --- a/Bucket Sort/README.markdown +++ b/Bucket Sort/README.markdown @@ -9,16 +9,16 @@ Bucket Sort, also known as Bin Sort, is a distributed sorting algorithm, which s See the algorithm in action [here](https://www.cs.usfca.edu/~galles/visualization/BucketSort.html) and [here](http://www.algostructure.com/sorting/bucketsort.php). The performance for execution time is: - + | Case | Performance | |:-------------: |:---------------:| | Worst | O(n^2) | | Best | Omega(n + k) | -| Average | Theta(n + k) | - +| Average | Theta(n + k) | + Where **n** = the number of elements and **k** is the number of buckets. -In the *best case*, the algorithm distributes the elements uniformily between buckets, a few elements are placed on each bucket and sorting the buckets is **O(1)**. Rearranging the elements is one more run through the initial list. +In the *best case*, the algorithm distributes the elements uniformly between buckets, a few elements are placed on each bucket and sorting the buckets is **O(1)**. Rearranging the elements is one more run through the initial list. In the *worst case*, the elements are sent all to the same bucket, making the process take **O(n^2)**. @@ -63,11 +63,11 @@ So the buckets are: Now we need to choose a distribution function. `bucketNumber = (elementValue / totalNumberOfBuckets) + 1` - + Such that by applying that function we distribute all the elements in the buckets. In our example it is like the following: - + 1. Apply the distribution function to `2`. `bucketNumber = (2 / 10) + 1 = 1` 2. Apply the distribution function to `56`. `bucketNumber = (56 / 10) + 1 = 6` 3. Apply the distribution function to `4`. `bucketNumber = (4 / 10) + 1 = 1` @@ -91,12 +91,12 @@ Our buckets will be filled now: We can choose to insert the elements in every bucket in order, or sort every bucket after distributing all the elements. -### Put the elements back in the list +### Put the elements back in the list Finally we go through all the buckets and put the elements back in the list: - + `[2, 4, 26, 55, 56, 77, 98]` - + ## Swift implementation @@ -109,9 +109,9 @@ Here is a diagram that shows the functions, data structures and protocols for ou `bucketSort()` is a generic function that can apply the algorithm to any element of type `T`, as long as `T` is `Sortable`. ```swift -public func bucketSort(elements: [T], - distributor: Distributor, - sorter: Sorter, +public func bucketSort(elements: [T], + distributor: Distributor, + sorter: Sorter, buckets: [Bucket]) -> [T] { precondition(allPositiveNumbers(elements)) precondition(enoughSpaceInBuckets(buckets, elements: elements)) @@ -201,11 +201,11 @@ public struct InsertionSorter: Sorter { for i in 0 ..< results.count { var j = i while ( j > 0 && results[j-1] > results[j]) { - + let auxiliar = results[j-1] results[j-1] = results[j] results[j] = auxiliar - + j -= 1 } } @@ -236,7 +236,7 @@ public struct RangeDistributor: Distributor { public func distribute(element: T, inout buckets: [Bucket]) { let value = element.toInt() let bucketCapacity = buckets.first!.capacity - + let bucketIndex = value / bucketCapacity buckets[bucketIndex].add(element) } From 3132f5d75780fafe146258d934f4b4a5e5ff9463 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 7 Nov 2016 16:57:54 -0500 Subject: [PATCH 0232/1275] Initial commit and claim --- Rootish Array Stack/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Rootish Array Stack/README.md diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md new file mode 100644 index 000000000..e69de29bb From 6c9e3a86f9a564cff15170e5a22d088e9d381cd9 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:46:21 -0500 Subject: [PATCH 0233/1275] Update to Swift 3.0 --- .../LinearRegression.playground/Contents.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 585471487..ae2e4fc14 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -19,26 +19,26 @@ let alpha = 0.0001 for n in 1...numberOfIterations { for i in 0.. Double { - return input.reduce(0, combine: +) / Double(input.count) +func average(_ input: [Double]) -> Double { + return input.reduce(0, +) / Double(input.count) } -func multiply(input1: [Double], _ input2: [Double]) -> [Double] { - return input1.enumerate().map({ (index, element) in return element*input2[index] }) +func multiply(_ input1: [Double], _ input2: [Double]) -> [Double] { + return input1.enumerated().map({ (index, element) in return element*input2[index] }) } -func linearRegression(xVariable: [Double], _ yVariable: [Double]) -> (Double -> Double) { - let sum1 = average(multiply(xVariable, yVariable)) - average(xVariable) * average(yVariable) +func linearRegression(_ xVariable: [Double], _ yVariable: [Double]) -> ((Double) -> Double) { + let sum1 = average(multiply(yVariable, xVariable)) - average(xVariable) * average(yVariable) let sum2 = average(multiply(xVariable, xVariable)) - pow(average(xVariable), 2) let slope = sum1 / sum2 let intercept = average(yVariable) - slope * average(xVariable) From 087dc18fdf9dac0429540ee353d8696ded901b2a Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:48:35 -0500 Subject: [PATCH 0234/1275] Make multiply(_:_:) function more elegant --- Linear Regression/LinearRegression.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index ae2e4fc14..32d2cc195 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -34,7 +34,7 @@ func average(_ input: [Double]) -> Double { } func multiply(_ input1: [Double], _ input2: [Double]) -> [Double] { - return input1.enumerated().map({ (index, element) in return element*input2[index] }) + return zip(input1, input2).map { $0.0 * $0.1 } } func linearRegression(_ xVariable: [Double], _ yVariable: [Double]) -> ((Double) -> Double) { From dda0d7957da6dadc9edab569c79ccd11e1d702af Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:49:43 -0500 Subject: [PATCH 0235/1275] Make multiply(_:_:) function even more elegant --- Linear Regression/LinearRegression.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 32d2cc195..fd711849a 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -33,8 +33,8 @@ func average(_ input: [Double]) -> Double { return input.reduce(0, +) / Double(input.count) } -func multiply(_ input1: [Double], _ input2: [Double]) -> [Double] { - return zip(input1, input2).map { $0.0 * $0.1 } +func multiply(_ a: [Double], _ b: [Double]) -> [Double] { + return zip(a,b).map { $0.0 * $0.1 } } func linearRegression(_ xVariable: [Double], _ yVariable: [Double]) -> ((Double) -> Double) { From 95efaec8dc8bf00dd6d1da6702855c49d6a5fe87 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:50:52 -0500 Subject: [PATCH 0236/1275] Rename (xVariable, yVariable) -> (xs, ys) --- .../LinearRegression.playground/Contents.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index fd711849a..f50bdefbc 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -37,11 +37,11 @@ func multiply(_ a: [Double], _ b: [Double]) -> [Double] { return zip(a,b).map { $0.0 * $0.1 } } -func linearRegression(_ xVariable: [Double], _ yVariable: [Double]) -> ((Double) -> Double) { - let sum1 = average(multiply(yVariable, xVariable)) - average(xVariable) * average(yVariable) - let sum2 = average(multiply(xVariable, xVariable)) - pow(average(xVariable), 2) +func linearRegression(_ xs: [Double], _ ys: [Double]) -> ((Double) -> Double) { + let sum1 = average(multiply(ys, xs)) - average(xs) * average(ys) + let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 - let intercept = average(yVariable) - slope * average(xVariable) + let intercept = average(ys) - slope * average(xs) return { intercept + slope * $0 } } From 58a7f1c9a8aaba7a527261a67cbdca3fc6c9c9d3 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:52:54 -0500 Subject: [PATCH 0237/1275] Update multiply(_:_:) in README.md --- 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 c04e3b3dc..4c98b8995 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -113,8 +113,8 @@ We are using the ```reduce``` Swift function to sum up all the elements of the a We also need to be able to multiply each element in an array by the corresponding element in another array, to create a new array. Here is a function which will do this: ```swift -func multiply(input1: [Double], _ input2: [Double]) -> [Double] { - return input1.enumerate().map({ (index, element) in return element*input2[index] }) +func multiply(_ a: [Double], _ b: [Double]) -> [Double] { + return zip(a,b).map { $0.0 * $0.1 } } ``` From f7ec3c45d920155ea47c5c41869f5c984c98f8f9 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:54:18 -0500 Subject: [PATCH 0238/1275] Update linearRegression(_:_:) in README.md --- Linear Regression/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 4c98b8995..fde04ed2d 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -123,11 +123,11 @@ We are using the ```map``` function to multiply each element. Finally, the function which fits the line to the data: ```swift -func linearRegression(xVariable: [Double], _ yVariable: [Double]) -> (Double -> Double) { - let sum1 = average(multiply(xVariable, yVariable)) - average(xVariable) * average(yVariable) - let sum2 = average(multiply(xVariable, xVariable)) - pow(average(xVariable), 2) +func linearRegression(xs: [Double], _ ys: [Double]) -> (Double -> Double) { + let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) + let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 - let intercept = average(yVariable) - slope * average(xVariable) + let intercept = average(ys) - slope * average(xs) return { intercept + slope * $0 } } ``` From 1c09008e5a4394d0058941debef9bba2c1798570 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:55:16 -0500 Subject: [PATCH 0239/1275] Update README.md --- Linear Regression/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index fde04ed2d..9e61888ed 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -104,8 +104,8 @@ There is another way we can calculate the line of best fit, without having to do First we need some helper functions. This one calculates the average (the mean) of an array of Doubles: ```swift -func average(input: [Double]) -> Double { - return input.reduce(0, combine: +) / Double(input.count) +func average(_ input: [Double]) -> Double { + return input.reduce(0, +) / Double(input.count) } ``` We are using the ```reduce``` Swift function to sum up all the elements of the array, and then divide that by the number of elements. This gives us the mean value. @@ -123,7 +123,7 @@ We are using the ```map``` function to multiply each element. Finally, the function which fits the line to the data: ```swift -func linearRegression(xs: [Double], _ ys: [Double]) -> (Double -> Double) { +func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double -> Double) { let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 From 40d074807f83eba87d433b3b092afb7587f75660 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:56:17 -0500 Subject: [PATCH 0240/1275] Make x variable explicit in closure --- Linear Regression/LinearRegression.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index f50bdefbc..2d882314a 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -42,7 +42,7 @@ func linearRegression(_ xs: [Double], _ ys: [Double]) -> ((Double) -> Double) { let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 let intercept = average(ys) - slope * average(xs) - return { intercept + slope * $0 } + return { x in intercept + slope * x } } let result = linearRegression(carAge, carPrice)(4) From f2564ce7bf38177b1c233a258795652ff8c7dacc Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 20:56:39 -0500 Subject: [PATCH 0241/1275] Update README.md --- Linear Regression/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 9e61888ed..f50f4fd66 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -123,12 +123,12 @@ We are using the ```map``` function to multiply each element. Finally, the function which fits the line to the data: ```swift -func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double -> Double) { - let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) +func linearRegression(_ xs: [Double], _ ys: [Double]) -> ((Double) -> Double) { + let sum1 = average(multiply(ys, xs)) - average(xs) * average(ys) let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 let intercept = average(ys) - slope * average(xs) - return { intercept + slope * $0 } + return { x in intercept + slope * x } } ``` This function takes as arguments two arrays of Doubles, and returns a function which is the line of best fit. The formulas to calculate the slope and the intercept can be derived from our definition of the function J. Let's see how the output from this line fits our data: From ba0d7558187b118c390bd9cf5b475aaa9697bacf Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 21:01:40 -0500 Subject: [PATCH 0242/1275] Remove parens Xcode convinced me I needed --- Linear Regression/LinearRegression.playground/Contents.swift | 2 +- Linear Regression/README.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 2d882314a..648868971 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -37,7 +37,7 @@ func multiply(_ a: [Double], _ b: [Double]) -> [Double] { return zip(a,b).map { $0.0 * $0.1 } } -func linearRegression(_ xs: [Double], _ ys: [Double]) -> ((Double) -> Double) { +func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { let sum1 = average(multiply(ys, xs)) - average(xs) * average(ys) let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index f50f4fd66..b7a5b5ba0 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -123,7 +123,7 @@ We are using the ```map``` function to multiply each element. Finally, the function which fits the line to the data: ```swift -func linearRegression(_ xs: [Double], _ ys: [Double]) -> ((Double) -> Double) { +func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { let sum1 = average(multiply(ys, xs)) - average(xs) * average(ys) let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 From c505f184d0cde36e7372fb1bfa3cd046213d7835 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 21:03:24 -0500 Subject: [PATCH 0243/1275] Ensure README looks like code --- Linear Regression/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index b7a5b5ba0..3e132b013 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -58,12 +58,12 @@ Now for the code which will perform the iterations: ```swift let numberOfCarAdvertsWeSaw = carPrice.count -let iterations = 2000 +let numberOfIterations = 100 let alpha = 0.0001 -for n in 1...iterations { +for n in 1...numberOfIterations { for i in 0.. Date: Tue, 8 Nov 2016 21:06:21 -0500 Subject: [PATCH 0244/1275] Revert labeling of argument --- .../LinearRegression.playground/Contents.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 648868971..4f18b7add 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -7,7 +7,7 @@ let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] var intercept = 0.0 var slope = 0.0 -func predictedCarPrice(carAge: Double) -> Double { +func predictedCarPrice(_ carAge: Double) -> Double { return intercept + slope * carAge } @@ -19,13 +19,13 @@ let alpha = 0.0001 for n in 1...numberOfIterations { for i in 0.. Date: Tue, 8 Nov 2016 21:07:29 -0500 Subject: [PATCH 0245/1275] Update README --- Linear Regression/README.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 3e132b013..89f81842a 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -50,9 +50,10 @@ This is how we can represent our straight line: ```swift var intercept = 0.0 var slope = 0.0 -func predictedCarPrice(carAge: Double) -> Double { +func predictedCarPrice(_ carAge: Double) -> Double { return intercept + slope * carAge } + ``` Now for the code which will perform the iterations: @@ -63,7 +64,7 @@ let alpha = 0.0001 for n in 1...numberOfIterations { for i in 0.. Date: Tue, 8 Nov 2016 21:09:13 -0500 Subject: [PATCH 0246/1275] Add code formatting to distinguish equations --- 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 89f81842a..41af0169e 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -30,7 +30,7 @@ We can describe the straight line in terms of two variables: This is the equation for our line: -carPrice = slope * carAge + intercept +`carPrice = slope * carAge + intercept` How can we find the best values for the intercept and the slope? Let's look at two different ways to do this. @@ -75,7 +75,7 @@ for n 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 minimse 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 proprotional to ((slope.carAge+intercept) - carPrice))^2 +We want to minimse 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 proprotional 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 be2167c6c071952b05ee53e88ef4c690cf363453 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 21:13:00 -0500 Subject: [PATCH 0247/1275] Add code formatting to distinguish function name --- 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 41af0169e..94ee6aa28 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -75,7 +75,7 @@ for n 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 minimse 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 proprotional to `((slope.carAge+intercept) - carPrice))^2`. +We want to minimse 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 proprotional 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. @@ -132,7 +132,7 @@ func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { return { x in intercept + slope * x } } ``` -This function takes as arguments two arrays of Doubles, and returns a function which is the line of best fit. The formulas to calculate the slope and the intercept can be derived from our definition of the function J. Let's see how the output from this line fits our data: +This function takes as arguments two arrays of Doubles, and returns a function which is the line of best fit. The formulas to calculate the slope and the intercept can be derived from our definition of the function `J`. Let's see how the output from this line fits our data: ![graph3](Images/graph3.png) From ad9f78d936d7e2c15271d2aa854a22d9c24c7d4f Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 21:14:13 -0500 Subject: [PATCH 0248/1275] Give some breathing room --- 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 94ee6aa28..de233fae1 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -75,7 +75,7 @@ for n 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 minimse 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 proprotional to `((slope.carAge+intercept) - carPrice))^2`. +We want to minimse 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 proprotional 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 75c0102bcfb7544c4464cb8090ffa1bfa17fa5a7 Mon Sep 17 00:00:00 2001 From: jsbean Date: Tue, 8 Nov 2016 21:31:27 -0500 Subject: [PATCH 0249/1275] Put xs back before ys --- Linear Regression/LinearRegression.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 4f18b7add..f265c3c5f 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -38,7 +38,7 @@ func multiply(_ a: [Double], _ b: [Double]) -> [Double] { } func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { - let sum1 = average(multiply(ys, xs)) - average(xs) * average(ys) + let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) let slope = sum1 / sum2 let intercept = average(ys) - slope * average(xs) From 7513bc03d8df99ba5b117420922e2f90c7a1c562 Mon Sep 17 00:00:00 2001 From: jsbean Date: Wed, 9 Nov 2016 17:48:33 -0500 Subject: [PATCH 0250/1275] Make multiply(_:_:) even even more elegant --- Linear Regression/LinearRegression.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index f265c3c5f..8b579b3c1 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -34,7 +34,7 @@ func average(_ input: [Double]) -> Double { } func multiply(_ a: [Double], _ b: [Double]) -> [Double] { - return zip(a,b).map { $0.0 * $0.1 } + return zip(a,b).map(*) } func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { From b5bda5b6453e13f1eae0623d4d06b260a4fecd2c Mon Sep 17 00:00:00 2001 From: jsbean Date: Wed, 9 Nov 2016 17:49:03 -0500 Subject: [PATCH 0251/1275] Update README --- 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 de233fae1..1a1a1eb8b 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -115,7 +115,7 @@ We also need to be able to multiply each element in an array by the correspondin ```swift func multiply(_ a: [Double], _ b: [Double]) -> [Double] { - return zip(a,b).map { $0.0 * $0.1 } + return zip(a,b).map(*) } ``` @@ -146,4 +146,4 @@ Well, the line we've found doesn't fit the data perfectly. For one thing, the gr It turns out that in some of these more complicated models, the iterative approach is the only viable or efficient approach. This can also occur when the arrays of data are very large and may be sparsely populated with data values. -*Written for Swift Algorithm Club by James Harrop* \ No newline at end of file +*Written for Swift Algorithm Club by James Harrop* From 8a5c49af0b15d0e61b7606ad6ac0cad8bb5672e6 Mon Sep 17 00:00:00 2001 From: Kenny Batista Date: Fri, 11 Nov 2016 11:11:13 -0800 Subject: [PATCH 0252/1275] Update ReadMe.md --- Trie/ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 3e3dad3a6..30082a450 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -6,7 +6,7 @@ A `Trie`, (also known as a prefix tree, or radix tree in some other implementati ![A Trie](images/trie.png) -Storing the English language is a primary use case for a `Trie`. Each node in the `Trie` would representing a single character of a word. A series of nodes then make up a word. +Storing the English language is a primary use case for a `Trie`. Each node in the `Trie` would represent a single character of a word. A series of nodes then make up a word. ## Why a Trie? From b40c3d6873caa252b4b63666642f3128e74bf891 Mon Sep 17 00:00:00 2001 From: Raul Ferreira Date: Sat, 12 Nov 2016 16:37:40 +0000 Subject: [PATCH 0253/1275] Fix mistake in the formula that simplifies to (a*d + b*c) (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c should be (a+b)*(c+d) - a*c - b*d = (a*c + a*d + b*c + b*d) - a*c - b*d --- Karatsuba Multiplication/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index d4c99ec2d..c86f69831 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -62,7 +62,7 @@ Now, we can say: This had been know since the 19th century. The problem is that the method requires 4 multiplications (`a*c`, `a*d`, `b*c`, `b*d`). Karatsuba's insight was that you only need three! (`a*c`, `b*d`, `(a+b)*(c+d)`). Now a perfectly valid question right now would be "How is that possible!?!" Here's the math: - (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c + (a+b)*(c+d) - a*c - b*d = (a*c + a*d + b*c + b*d) - a*c - b*d = (a*d + b*c) Pretty cool, huh? From 16eb36c653007865a199e0d9fa1fc9cf5f2515ce Mon Sep 17 00:00:00 2001 From: Robin Malhotra Date: Thu, 17 Nov 2016 20:03:50 +0530 Subject: [PATCH 0254/1275] Update Contents.swift IMHO, making peek a computed variable feels _swiftier_ --- Queue/Queue.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index 6b771ccd1..a8be21b08 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -34,7 +34,7 @@ public struct Queue { } } - public func peek() -> T? { + public var peek: T? { return array.first } } @@ -56,7 +56,7 @@ queueOfNames.dequeue() // Return the first element in the queue. // Returns "Lisa" since "Carl" was dequeued on the previous line. -queueOfNames.peek() +queueOfNames.peek // Check to see if the queue is empty. // Returns "false" since the queue still has elements in it. From d7267e911efa8ba6d7b3c26da6c8cef59d82b9c7 Mon Sep 17 00:00:00 2001 From: jsbean Date: Wed, 23 Nov 2016 23:32:37 -0500 Subject: [PATCH 0255/1275] Update code and README for Swift 3.0 --- .../Contents.swift} | 28 ++++++++------- .../contents.xcplayground | 4 +++ .../contents.xcworkspacedata | 7 ++++ Minimum Edit Distance/README.markdown | 35 +++++++++---------- 4 files changed, 43 insertions(+), 31 deletions(-) rename Minimum Edit Distance/{MinimumEditDistance.swift => MinimumEditDistance.playground/Contents.swift} (53%) mode change 100644 => 100755 create mode 100755 Minimum Edit Distance/MinimumEditDistance.playground/contents.xcplayground create mode 100755 Minimum Edit Distance/MinimumEditDistance.playground/playground.xcworkspace/contents.xcworkspacedata mode change 100644 => 100755 Minimum Edit Distance/README.markdown diff --git a/Minimum Edit Distance/MinimumEditDistance.swift b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift old mode 100644 new mode 100755 similarity index 53% rename from Minimum Edit Distance/MinimumEditDistance.swift rename to Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift index a128b2dab..d651ddf2e --- a/Minimum Edit Distance/MinimumEditDistance.swift +++ b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift @@ -1,34 +1,36 @@ extension String { - + public func minimumEditDistance(other: String) -> Int { let m = self.characters.count let n = other.characters.count - var matrix = [[Int]](count: m+1, repeatedValue: [Int](count: n+1, repeatedValue: 0)) - - + var matrix = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) + // initialize matrix for index in 1...m { // the distance of any first string to an empty second string - matrix[index][0]=index + matrix[index][0] = index } + for index in 1...n { // the distance of any second string to an empty first string - matrix[0][index]=index + matrix[0][index] = index } - + // compute Levenshtein distance - for (i, selfChar) in self.characters.enumerate() { - for (j, otherChar) in other.characters.enumerate() { + for (i, selfChar) in self.characters.enumerated() { + for (j, otherChar) in other.characters.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 - matrix[i+1][j+1] = matrix[i][j] + matrix[i + 1][j + 1] = matrix[i][j] } else { - // minimum of the cost of insertion, deletion, or substitution added to the already computed costs in the corresponding cells - matrix[i+1][j+1] = min(matrix[i][j]+1, matrix[i+1][j]+1, matrix[i][j+1]+1) + // minimum of the cost of insertion, deletion, or substitution + // added to the already computed costs in the corresponding cells + matrix[i + 1][j + 1] = min(matrix[i][j] + 1, matrix[i + 1][j] + 1, matrix[i][j + 1] + 1) } - } } return matrix[m][n] } } + +"Door".minimumEditDistance(other: "Dolls") diff --git a/Minimum Edit Distance/MinimumEditDistance.playground/contents.xcplayground b/Minimum Edit Distance/MinimumEditDistance.playground/contents.xcplayground new file mode 100755 index 000000000..5da2641c9 --- /dev/null +++ b/Minimum Edit Distance/MinimumEditDistance.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Minimum Edit Distance/MinimumEditDistance.playground/playground.xcworkspace/contents.xcworkspacedata b/Minimum Edit Distance/MinimumEditDistance.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000..919434a62 --- /dev/null +++ b/Minimum Edit Distance/MinimumEditDistance.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Minimum Edit Distance/README.markdown b/Minimum Edit Distance/README.markdown old mode 100644 new mode 100755 index d72e0dbda..905b358ae --- a/Minimum Edit Distance/README.markdown +++ b/Minimum Edit Distance/README.markdown @@ -6,7 +6,7 @@ The minimum edit distance is a possibility to measure the similarity of two stri A common distance measure is given by the *Levenshtein distance*, which allows the following three transformation operations: -* **Inseration** (*ε→x*) of a single symbol *x* with **cost 1**, +* **Insertion** (*ε→x*) of a single symbol *x* with **cost 1**, * **Deletion** (*x→ε*) of a single symbol *x* with **cost 1**, and * **Substitution** (*x→y*) of two single symbols *x, y* with **cost 1** if *x≠y* and with **cost 0** otherwise. @@ -15,7 +15,7 @@ When transforming a string by a sequence of operations, the costs of the single To avoid exponential time complexity, the minimum edit distance of two strings in the usual is computed using *dynamic programming*. For this in a matrix ```swift -var matrix = [[Int]](count: m+1, repeatedValue: [Int](count: n+1, repeatedValue: 0)) +var matrix = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) ``` already computed minimal edit distances of prefixes of *w* and *u* (of length *m* and *n*, respectively) are used to fill the matrix. In a first step the matrix is initialized by filling the first row and the first column as follows: @@ -23,29 +23,30 @@ already computed minimal edit distances of prefixes of *w* and *u* (of length *m ```swift // initialize matrix for index in 1...m { - // the distance of any prefix of the first string to an empty second string - matrix[index][0]=index + // the distance of any first string to an empty second string + matrix[index][0] = index } + for index in 1...n { - // the distance of any prefix of the second string to an empty first string - matrix[0][index]=index + // the distance of any second string to an empty first string + matrix[0][index] = index } ``` + Then in each cell the minimum of the cost of insertion, deletion, or substitution added to the already computed costs in the corresponding cells is chosen. In this way the matrix is filled iteratively: ```swift // compute Levenshtein distance -for (i, selfChar) in self.characters.enumerate() { - for (j, otherChar) in other.characters.enumerate() { +for (i, selfChar) in self.characters.enumerated() { + for (j, otherChar) in other.characters.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 - matrix[i+1][j+1] = matrix[i][j] + matrix[i + 1][j + 1] = matrix[i][j] } else { - // minimum of the cost of insertion, deletion, or substitution added - // to the already computed costs in the corresponing cells - matrix[i+1][j+1] = min(matrix[i][j]+1, matrix[i+1][j]+1, matrix[i][j+1]+1) - } - + // minimum of the cost of insertion, deletion, or substitution + // added to the already computed costs in the corresponding cells + matrix[i + 1][j + 1] = min(matrix[i][j] + 1, matrix[i + 1][j] + 1, matrix[i][j + 1] + 1) + } } } ``` @@ -58,8 +59,6 @@ return matrix[m][n] This algorithm has a time complexity of Θ(*mn*). -### Other distance measures - -**todo** +**TODO**: Other distance measures. -*Written for Swift Algorithm Club by Luisa Herrmann* \ No newline at end of file +*Written for Swift Algorithm Club by Luisa Herrmann* From 38dc9eefedf61e5edc838fcb034657df2a22dcc6 Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 24 Nov 2016 15:36:22 +0800 Subject: [PATCH 0256/1275] update Array2D, Deque to swift3.0 update Array2D, Deque to swift3.0 --- Array2D/README.markdown | 6 +++--- Deque/Deque-Optimized.swift | 4 ++-- Deque/README.markdown | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Array2D/README.markdown b/Array2D/README.markdown index e73d453a6..51e77435e 100644 --- a/Array2D/README.markdown +++ b/Array2D/README.markdown @@ -30,14 +30,14 @@ let myCookie = cookies[3][6] Actually, you could create the array in a single line of code, like so: ```swift -var cookies = [[Int]](count: 9, repeatedValue: [Int](count: 7, repeatedValue: 0)) +var cookies = [[Int]](repeating: [Int](repeating: 0, count: 7), count: 9) ``` but that's just ugly. To be fair, you can hide the ugliness in a helper function: ```swift func dim(count: Int, _ value: T) -> [T] { - return [T](count: count, repeatedValue: value) + return [T](repeating: value, count: count) } ``` @@ -72,7 +72,7 @@ public struct Array2D { public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = .init(count: rows*columns, repeatedValue: initialValue) + array = .init(repeating: initialValue, count: rows*columns) } public subscript(column: Int, row: Int) -> T { diff --git a/Deque/Deque-Optimized.swift b/Deque/Deque-Optimized.swift index 17ff89e68..6326b457b 100644 --- a/Deque/Deque-Optimized.swift +++ b/Deque/Deque-Optimized.swift @@ -10,7 +10,7 @@ public struct Deque { public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) - array = .init(count: capacity, repeatedValue: nil) + array = [T?](repeating: nil, count: capacity) head = capacity } @@ -29,7 +29,7 @@ public struct Deque { public mutating func enqueueFront(_ element: T) { if head == 0 { capacity *= 2 - let emptySpace = [T?](count: capacity, repeatedValue: nil) + let emptySpace = [T?](repeating: nil, count: capacity) array.insertContentsOf(emptySpace, at: 0) head = capacity } diff --git a/Deque/README.markdown b/Deque/README.markdown index 7671555dc..5858f3e6d 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -122,7 +122,7 @@ public struct Deque { public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) - array = .init(count: capacity, repeatedValue: nil) + array = [T?](repeating: nil, count: capacity) head = capacity } @@ -238,8 +238,8 @@ There is one tiny problem... If you enqueue a lot of objects at the front, you'r public mutating func enqueueFront(element: T) { if head == 0 { capacity *= 2 - let emptySpace = [T?](count: capacity, repeatedValue: nil) - array.insertContentsOf(emptySpace, at: 0) + let emptySpace = [T?](repeating: nil, count: capacity) + array.insert(contentsOf: emptySpace, at: 0) head = capacity } From 653452a37c4a491e60ba66ff2d79f76b66c39014 Mon Sep 17 00:00:00 2001 From: JJ Date: Fri, 25 Nov 2016 21:33:24 -0500 Subject: [PATCH 0257/1275] Fix for #246: Invalid tree in MinimumMaximum.png and update README.markdown to match. --- Binary Search Tree/Images/MinimumMaximum.png | Bin 12151 -> 11913 bytes Binary Search Tree/README.markdown | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Binary Search Tree/Images/MinimumMaximum.png b/Binary Search Tree/Images/MinimumMaximum.png index 70fe4ea7b2cee1bd641a785981e0015815f3a594..10b4e635291d25cc899f659679dafdf8c8985b1a 100644 GIT binary patch literal 11913 zcmZ{~1z43)(=H5xbc#xMDIg$73TzPRZjhFi?gnWP1OzGR?(R+r>27JH*+}O;Yx{ox zcfS8z=Wt!X-p{jQ)~vN=?zv~e6y+tbF-R~F5D>7XB;PB8|1j{oh=v0GW^qaEfq#gO z$`bDo=LcAP!53sR5jhbAgvuz)JHyA|JGz~umLmcJCIS2x5#dJ)5$G^&p{nVmDJRQs zWNXc8Xl(n@gw@U34zxx<5OCuMAFWNC45{3#t!y0m-2`d=wcrPz;g8v9sQxu^vJ|Az zlvAVkpuVsM+vccc5y=G-+`|q(qR{{7_eo zmns&pOV?WN`rGzDDYcjLw<&@p$A26l&NF;w$KEp^+RwEu?}KZ@O=z)DMAzrk?k(Ag zo&@9j1W;!Zt?>{&`SO4NSb56${kZK`ekg@crRDOs=X$bj8$Kzw6&?h3SA8{^{y+yS zQZ1wzfxx_!8XZh37j2pgZHdI(0tzs7f`ybB36F< ziDAEATK@%;twm8LyIimJ!`c3 zG{1Q90xu{isAvjLEdts{l(#osq(%@<$o5>VSY0i5zS8^F<>eiruG6=M(~-Aoh16e& zRP<#HQDKp9kMJh*v7OsR6z4)d|US_=u!%A!$Q zXS19wd#0i9T}#Aclfnz_KmyIAiH0dfQ^^b9Ua+x>;MQk$1MXpDSL)pCD(nIQDgaKwQ$mdb@- zkBI!3I4cC~il4W>hFj8ag(MC!uZwvzj=6lTYSVSFtOPy3ri0p9J%&BDETT09cG+_< zo9)R?cGQV-+DbR1Jy01m%-K9`V8Fj$~c z>#rfU_B$G%+e4o7UwHIji?L=_dp7nJ+kLzn*ZQU?uOJkji4RVOQJupSe$)bR#pI{^ zG$nFb#(Tt3#JH}eE2KQ=Kl~-M-z&`jRk70hm9$vF7$yBtn^`DDZ#~3xbu%Dfbgt4! z*TOg+V~Aua@%l5~3JNw!Xp{3k*cny!9}rWjmc-*c`P3rmGlL8}<}1h@G(Z+J-Z~9I z)Ca!9Wz9$YCp`oT{hOpB9Bxp9@f;}vf@wk}AZ_%QXUxBbnql|HzG`8x3cmh>N2eLo zKY*Ao`zU=|YF668u`KF=us^0bo7MMi9lycvMe`jpC{nN+2}CC_HfNLKNnp{+`aMj+ z{WJ_g;BP-XT#3wogWzu-SpIHlbXp?jbI4h`^4!S`>CuPXXz0@%6KUEstfA~a zzM4`|7zh<|xFL`-52Z@H!5Z(K>5YFCp`Oa`T(UcvUpxUx0{*zu`XT6vw zy=;if694KSP0)JSL*IzCDHu-lKw-l7x%C_xt+mW1_ff#|N?l zqHp_~^_yL+OFyT8yEo7ppdfVpp5j7jCX?JN&!{hQy=GFLK)1;WzxlYW*`p87Gy*C? z#C_^mM5xxn>Ta9%Gf#GnHK+(iA*>JfgKJD|LT5y2kh)e{L*N*$Nf zji$LJqfaX}7Alo}6rKgl_r5+iyNvcL-j`BlnL^$-{rkjSU-2K%-n9wVoM_v&(m#L^ z230@Ubi&d*jV=!69WFX3QJraOhA2`3`0a0<391J55Pk=>dS1qV^ACo841|1)PP#m5 zK7I~vP0dh8KphV0)vfFPj2y$&rW?B`@9Qo~YCZR@XN4!WZP(jlm~r!{Xb|x$S_B4e z?$frrzcS;+8f^9lm3>97U0=aFp575k2kC{QbRcLyn$SV@sL(nDb{*BQ>W>)#5k`Cc z1Clew!n?PcKDt1G_=UrilFEx{4VSv9?zW&)2;l@qNA~&_;kr-uRupBs{`sp9p`4=v zDgqBz8r)u#*sJ#;Xeov&@X!9l>qB}gcOZ@HuCoP%`F0751MaUXwjh%njLd5JT-_`bS~m#)VF6=!Y?; zdntQCJ5jUbQ~CdXU*DT9PIx)TtWgHK++(^L;n0dm9W+@6mi$5UeL7cXoos@cJ>6h$ zw4a-xr<{8OC2t$#YEajj!?u_%)t)60@@l9Bo>%QtDAL8*^4>&lxbraAtY%$B(FDW| zcnXt6TvG0#s{G3$)hO2$@7YiDRk>=as>buuQgOlQl4!8);p9?ai9P@$RaIxRTqM2R z?b?VkTgBDPw5;?yUxBjNuse9>?)nsX;m8Q0*Ii66UQ~cijQX7YmpkL#pMX^~VWTuj z(jekhWKZU{R;FKLIO~E9vbAf*F{#CL?Gow?>Y@I!TvQP(77Kr_%zOv!#)W$$PRkjV z!mT9iI*ZBPPqSsIme%QC0M7aOX{zAcIRHOJG0-P_T#%^XV{TFptBz~*ybLbOnSSh4 zZJWlQb4LUyw+L1U3qSPvQ7ira5RM9*M!*4slORqtt!9BMBQ(jZ`f=>n6{q9hx^t79 z_G>|eB%KOW>Anw*yayHCo2C`%{zuW?rdEU zL^=5lim&-hNfMV)FV^`l-#LkoxE7uMkBjKM0@Y6)qm4vF{CL+xX;s5uc853T`-7gu zG2P!^s`Lom9?;6Ui}>;3ulOS(p%lbG@uk=5CFFKx^i@@Jr2PXtTW*MTQeqYrN2 zbUDy`nJ6+@phR2gbMFB+$OSQWpa-KMfmvg-bLRWchw~90xu};^(zXwG*F`;eW0z8ByrOYADD-C=QIH~yw*kfFIBp0rx6~1V%2y{TA8F+YmtNaf3IMg|vafjT zmpTw?5DGj#nd0c7jC?FXbvb8*s}@7T9VBDBAeYLordp&bW%Ins3XU_T-=QV~ z+8#>E7Wzi)&n=5lU@Uwfp4TR(U!Yl;#S4H87%opCoz*Npg$`?oNQs|-K{mR4@E?Nq zVKSuq-lZ_58ies|s`w1gG<-O|pBa^=u}HnNNY5nrC0S}0p0Byt!dvn{+YMy(4_8`x z>V?W;tqX|dFBKkR41{rGlV(1BK*He_#zEj;&FCb-l581oa<=3Xq|L2nbqcjIf?r{@oYCwD>f|%3zpq7T-6KS6n;Wjb}lB@j9t_d{l0%kW?f!eQBCTCMW;dWqErELuNoJaFop?vN=T^vj7hb^%DPm#MfAfF zK(LxXWM%qby6zj;W~@TpLcMLebCU}P(sZGUMBeA9N116CZw-EE)tG-1ko5~plZj_h zI^OAa)f6}IAm;k?{mnEHRtb#nK8#-2&@eN9&eICULdi=Qy=AQGCGN5>Kjwf;b@(Jn z2`#rq!XkBl&xJE;7X_>v^-_~!L=5vEv^JXU@40#?Z^jpDEprdk{SX+bWE~U# zUVvcWyfBqozXu+bTxRz_$U5N3hDcDj=iI!%3R|+*H9pJDv?~z~pESr%^C)uau)8}w zS?@SnFx% zcWCxG-_vnRAt#*Q#)@_XN0y;HJq zAK3_v(;og40miIh^@p>yU0pifR{3@74@}yQzEhLB3hS|fM6-P@D6--P0EjM==Fbr+ zRsbq){H@3Vu?c21O4qNXRPi85G>E0Qi(28574;g;?D~)3%_M%={gRXaTUH@97H9aH<4sW+^ra_9{v6tEPwwIGbS!@BD5O7E z>st^6K`T8rsPX;VfzuA&c2tXI-Yc!V*f)FB?0dLSyVZ(y(yNf%hBJ2` zMuAj?_Jw=V?CaCQ zbMi>ubu@xwN+bvC$yvn1Q3scuvCJYmSm3*>)5aM#>`{Z6hjDs+xEOU8xIxem5x9~l zb^lsS&iXw)wO*(}|9Uan3=NU`_gwBT7=~JQ0dm|$$?$LKXJ`TN`7B^97`{Zc@O6&U zuz=yl9^m+3DZQW3{n-QizvX6&CR*L_X8_f@*WWV7>W`oY=t2m3k0^b*%qM3J_h(8c zj%>^C)ufIFlDBcIXI$AAAa{Y|K(jNnbnGN+N|vYY+&{V!%LM$ z5{*0r;*)v|yqMAF5DCw8xAm|I)kcHPNA5Sr0N*k0BV65Y4JHu6LvsNYyII})@p&yw z2xGj^^=7QYau6ZG0vYwHp9NlE$S5?xoJHIm=htSxb-CHm7RkufVwFiaSq*P$TyPdO zFLB~L;?|p|sV)mO7Jpa8O|c>lyn3Ta*zQ9-w)9c9EXx`hrt(^4TcBN->j2osk;aiR zMsW!INpbA)L#24JkFcXnCO3L}p{&~GyX-t01`p6L1p}a-ofL7Uz#OS=ckHjUx7S+D zbDYb6(oAm!T8S5wtF~!55w{$Oq2Eh|R=J&gye<*o938RkM|KuTRphBtk8w7cOR~CA zh-Hu~0nEXNI%u(L)&Kxf*5?3@R++t-0X!L_zM20hbRG~y{l|M=jL*^neF4=|wcdCQ zx~LWkA@fC$@{EA3NaJ$<*if*H!{Xb&47( ztDhw0VN!h{_Q>5%<8#boI>DJ;{ctg%61TG7ccPOIf5^jhC^1v|4jz;LU04z&v|ck) zF`cV0+>3*G-JSF)bK1;TiN$SF91U|qSwuSd6XZH_z6CzSMjkHKYx68SsbpA>);6ME zPKXQ|gcfcAfco^}Mmp|Fq4v}Cd%y(#ggsnB)M7mKe6CF_6t=be*KhXA6Cz(uStv_N z!=z9zZh_O6gvDp9E-VFjT4bX5)tntJYD6xH7(p7ATKfBH5UNW){Z8kU1(E7(E^*u_$5e4((f0b)eT+io^DPW(11xvFc9AW{r{wm z5}=72%@PY&-KDfk#9|#5^t@1|-yJUvi0D$FU9~L56zY!<0=~GA$sYA#Xo+)nHNm%^ zI;23u1Mi@F>U#l4y<+|n=h14yQJ!9SczABcSO}A90hQ5WU80vUl5cI`h z#3H0kD27~}>|bym<*J~5=sHFw+EFam6C5wq=23#jJWG{;-yZmNbv~=FCIz))tEo@! zuYl9t#@{05^fKgA3rcx6>R{}#S@L}m#IzolN3R^0zhz1g=EDNf_o$W;+@_Qyq>|Rk zS=RF9-4rygoNv{|*I>K(>Bd3ZPXeQFw=s^kxan#DEnDSS#d`ke^0Z1Pl*Hy1*V5ZG zDoW_4fCzARUWeR))7IK3*oP@H#Or$e-pod&9A7fF93CgX4eWn1k;vRYcsaGKNrQ+) z`-b#K$?Vu0uk>MvE}EKiHh%W6%n*vbBG}XC&%cCFct{49XPuAoZeZCjTGxXJXyYuM z-EW4m)4VLB&G`lhmw)0kgyPf5&rA8P^LR=(fK9JO^XNsaj(wrekzy zkaned*qFt@&%UHE9J=NXtYVqA8wLKQvsaLeHg9|%f!|B2K6M5(B|42&9&v9Q7%yl1 zxOM?YetxT;E&jEq8yCWIiQtqeU%1$?kq5KWWZGZxxxbOZj@%6|gqU*Z{+;%n5Fy{W zcm-L7FF6~U?!KKgaVN}>tn=CXiMDmwS{i?y5+s9lK)Snx`l#U$lCw$EjBV*%wZKlW z1FWCblmB=}t%F5Z#^Ct<|AS^X&UUA@enrrRwzqx11;yta)} z`Fd2sgJ|#%IOzJ%?F;xrvn!7GEh|^6_ETI-f;?nqLHy_7r?CtX4j$cTKrOtJKj{xo zumr2yCiV~HC*!rta9WVW(7VC4RIiW!?sbvwv|2q@q{eK~iAEAHyTlyJLv4-@iF|(5 zx-s?S>A_gc$ZasGjUs(xh-Ylx+y3Q`d(r=_i89b7Jp3#r6iFNJQ;yl!ci)ODqC@(G z68$Y#CgB$yp-)aNQ#iOyK{OLz%^Ef$-%c_6W*$j4teQPfD2V^JR~ot|qos^?0_ZPqTYN?&#AX$+7V`&jEy8N=ynfwmVc>|bIC z%ituUF{(t2{hLW}z15@~q~5^>dH~^XNp9DH*k(+=P9i2IrVdbuT9{B-5M@fuz?vZDqC7!=lipS`Kc~Huu_+dq69b1=Byb!EJ4`lpg~F~<6{KeeNWr% z5i`VSjyNBtSl=U!hmuwXYXP8P;?K&_**9=HsY21s*-F#BWKlM$YG5=RS1 zL?T5A8pYU*lBvbZVMVZ^IzO57$7IA6Uw=e0i2hCN1=PBC>&Yl{RYc%0PB9XqfRntx zEKvuba5%NL@5D*Ibbek5`RY7hW%9A(GveN2u+tKtQ8@Hc1DGbyDfgbgb6)y6eJ;?jJ*FxK>BXfjmYR4F0h~QjiJ;WXc!i;;S{Cjgay({mmB?p&h4t&<(oKdtZxeqXrB{mdM#rgz3xi)x0=nNf6WbpKtC-i zJhnC-D*VmfrH?W{ccEff1H&mmDxZn1%J>>umotoY^xto+9_HsSRQ!h173b=Id&tBQ zIlTs*d@LDP-;i`Eo53+yj6@xLO077a2xvkV?xGJ9kz&k})b*jyVfJ_AK}2iuMdCBi z3j<UP9uQ$nDt0r`U--sa@FnI# zB=;L`U%?0{vp*P}Mv5Co1!lKfzxz6@k4t;^MaP0sGG-X^0*sKTmZS@Bxrl7Bs34|n z_0Tvc@iMIPdfzB;g+UTD07||%Zg`So4S7~$2>30zly(&HD{FrsURULHAKwVX9JCrL zYo`b!e9!^<#J`j$sR6C!wfU_rUnKXSLAEI)XPD&5zz#^6oWcMXys2f4n3}WAEI>Q@ zi!*^v1Bjm^oh(nup4UN+?4qtOM4f&cLh19u^#`A7?1&UGD#T`?X7@6HlJ8Z6FYMv3 z>atGa)vu2L#w#n%;rjwe*8|wvpMb~S%1jsF$**;I#1WE`22u!r9j`Y5JrF%Q5H`rH zUJ||UF+xkHXV`v!5lbBIE-$1}`$-KBXWEjqxvl1?P(R0@7AtR)JxFtR-M6 zf2R-AM2Gwc&W_~cxSKPIihI=kZFJ6eH}Uf_apuQr?Auci_ihGHedYO`I7yrCj-%{> zOCg~7DI28aWQ9;oJ3wMq(kFOQ3!h2;&iizjXA6HAP2=|B&;-kqwbR;VwZrct(Cc3` zi@#4OT$k(}q8;R8?;mcDw{FP_I;EOYYF#Jgcm}vvLrZls9dr1RSOO5OJA^MlkT%c_ z;k)5~Em1^!XKyf)!lw@CuF^>Iw;$@nm2;CSgT_48!x&kbIkiFgK<&Y9u?HhB@Ld+Q z=Hp$Trid;(tVS@RL`evfR zenVBtE35^okR~t>Pg2a3Xk|-RZ2-hp^#F2XC>#i0pvFKQn1xaR1|{Q+Lj-Hc=y?C(StU(286souhnDb@7ADNSUbD7@%;`eDUZ!} zatq)Ei+c1yd4uV*XV0!VH0`m=xSVzrL8*jo`+Z$XsUo9~FzK>=ANgKf`&j*skq?f# zAx%}6@8GL?B?+Edl%CnT;PPW$bt&&-J2k2m(U$@`B>5K3UxYoN}h5}qI_)o<5}L+%FoWlLTA zpU-9h5>yNG{0AjO-svhbPRVgEfhgQT10uO&bjEd~vlN;WvZA6ONN>}2ZThbsCdQy) z`-f#lhPTNyDZ~v{bxl1eX|-JyHcd>#RuYF+TgOK2Q0vJ(|vTtCs@C8%^SrNU`fe z&(djhD54XTNnnjjMIPnTdE4x?oArAiDAA|aHnW;S=CS(fnbUIv4p8duj&<@~1P z^V_q>ggO~|xgld($XT0|N?#K6eHw4xd&mo(t7`E~eIvX|wLzH%Nm)r;dB$&Fl8K*q zAA*90r<7h$Kc+C$Zv;Mp#E9d$){Au{B>yLs%JL)%9Vh8WpfJ_DPA?Y#MT z;k~P(nE6|$9V$J~L$2$$@G_$D5-rY3lfmcbVMAkoT7)b$!&0EJnL!4G#UF$G`rlD&fBd`I6D?QF(IV~g+?TAZ&*7yp zxRARFrtyGVcX#y+xvNrscJ^mapZ1e|9cyuSyw*iQ(lwVTA0<(zVZ3{Tpu$6rw!W%q z&b=in(smAqJ;?pGy#YZ6F2% z0CGL!i_Ss-ycokRib>O0WRoYB6179uXfXN63;qfedQXMtx+F0gAGW;n(ckxv?ojVLrSICLqX{-hJzj+2d++D4~6POuK3{&O7dU{tpk6ZWDF2=;^mNY@;jOiq*GXQlEIj2z*Wh(&qFFZmU z1@h9DDtQGl2ZpV~i94=Y(fU5uKb!W7idj5=6iHWwXgZ<@SMA@(T^=pxX51ukW-6o$ z&AiM{`FIcbs-hms-UwnNF7vUDStpybmp6#JE$h-bL6qiXBw<+9^Y0cICak{^vZ2k{ zl_=+aalSvFHH&jX>Q}c^NHuBNrCPlPR5dL@q(iyY>Ie7Gwln$#4t zTI#!W%413zwmV_kOhnJK9m7)Xdil7$02k3oPH!xJL)z4KVD23dpg+i6fGF+xQ#d3? zovjV|gjZkTzyqWKbEE_O-~dO4jq~{p&NbeyjEI>Y22v%SkAZHmRPdSNUGsk!?J;xN zW68;$r#uN^Bw89q>dl}4v*a=6bK?|rb~T1Sz942V1q7fLD2`M)M#jBdPg_bh>wjbY zryiPoWql{^V_BxzGX?SV^BkWRt0grCVuoTW$hM7+kqxi;p z;SDo^7Pnms@o0EH8Eb1Iio1Fi;_Ky;lBr{ODVGre3AfdY^jR65_jO}!Ii9rp1f9w? zY}7qdY$qfF%&g6BM{6AcqmcMW&7-}1s(4gqemhM%_uuB`{EUq26I#28SI%&jDU&Y+ zU!<=&($`&mNuLCd=GnW$C< delta 11725 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 diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 483e75a58..bacb1ffe1 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -412,7 +412,7 @@ To see how this works, take the following tree: ![Example](Images/MinimumMaximum.png) -For example, if we look at node `10`, its leftmost descendent is `6`. We get there by following all the `left` pointers until there are no more left children to look at. The leftmost descendent of the root node `7` is `1`. Therefore, `1` is the minimum value in the entire tree. +For example, if we look at node `10`, its leftmost descendent is `7`. We get there by following all the `left` pointers until there are no more left children to look at. The leftmost descendent of the root node `6` is `1`. Therefore, `1` is the minimum value in the entire tree. We won't need it for deleting, but for completeness' sake, here is the opposite of `minimum()`: @@ -426,7 +426,7 @@ We won't need it for deleting, but for completeness' sake, here is the opposite } ``` -It returns the rightmost descendent of the node. We find it by following `right` pointers until we get to the end. In the above example, the rightmost descendent of node `2` is `5`. The maximum value in the entire tree is `11`, because that is the rightmost descendent of the root node `7`. +It returns the rightmost descendent of the node. We find it by following `right` pointers until we get to the end. In the above example, the rightmost descendent of node `2` is `5`. The maximum value in the entire tree is `11`, because that is the rightmost descendent of the root node `6`. Finally, we can write the code that removes a node from the tree: @@ -500,11 +500,11 @@ if let node2 = tree.search(2) { First you find the node that you want to remove with `search()` and then you call `remove()` on that object. Before the removal, the tree printed like this: - ((1) <- 2 -> (5)) <- 7 -> ((9) <- 10) + ((1) <- 2 -> (5)) <- 6 -> ((9) <- 10) But after `remove()` you get: - ((1) <- 5) <- 7 -> ((9) <- 10) + ((1) <- 5) <- 6 -> ((9) <- 10) As you can see, node `5` has taken the place of `2`. From e9eeab8c00c7a1674ba8b0f5ac7f1b51356ef925 Mon Sep 17 00:00:00 2001 From: Divyendu Singh Date: Sun, 27 Nov 2016 18:34:47 +0530 Subject: [PATCH 0258/1275] Migration of code to swift 3 style This includes 1. Correct location for inout keyword 2. Correct function calls --- Bucket Sort/BucketSort.playground/Contents.swift | 7 ++----- .../Sources/BucketSort.swift | 15 +++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Bucket Sort/BucketSort.playground/Contents.swift b/Bucket Sort/BucketSort.playground/Contents.swift index f7383746c..c111c3961 100644 --- a/Bucket Sort/BucketSort.playground/Contents.swift +++ b/Bucket Sort/BucketSort.playground/Contents.swift @@ -20,9 +20,6 @@ // // - - - ////////////////////////////////////// // MARK: Extensions ////////////////////////////////////// @@ -38,8 +35,8 @@ extension Int: IntConvertible, Sortable { ////////////////////////////////////// let input = [1, 2, 4, 6, 10] -let buckets = [Bucket(capacity: 15), Bucket(capacity: 15), Bucket(capacity: 15)] +var buckets = [Bucket(capacity: 15), Bucket(capacity: 15), Bucket(capacity: 15)] -let sortedElements = bucketSort(input, distributor: RangeDistributor(), sorter: InsertionSorter(), buckets: buckets) +let sortedElements = bucketSort(elements: input, distributor: RangeDistributor(), sorter: InsertionSorter(), buckets: &buckets) print(sortedElements) diff --git a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift index c93b96cb2..e510e51b4 100644 --- a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift +++ b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift @@ -27,16 +27,15 @@ import Foundation ////////////////////////////////////// -public func bucketSort(elements: [T], distributor: Distributor, sorter: Sorter, buckets: [Bucket]) -> [T] { - var bucketsCopy = buckets +public func bucketSort(elements: [T], distributor: Distributor, sorter: Sorter, buckets: inout [Bucket]) -> [T] { for elem in elements { - distributor.distribute(elem, buckets: &bucketsCopy) + distributor.distribute(element: elem, buckets: &buckets) } var results = [T]() for bucket in buckets { - results += bucket.sort(sorter) + results += bucket.sort(algorithm: sorter) } return results @@ -48,7 +47,7 @@ public func bucketSort(elements: [T], distributor: Distributor, sor public protocol Distributor { - func distribute(element: T, inout buckets: [Bucket]) + func distribute(element: T, buckets: inout [Bucket]) } /* @@ -70,12 +69,12 @@ public struct RangeDistributor: Distributor { public init() {} - public func distribute(element: T, inout buckets: [Bucket]) { + public func distribute(element: T, buckets: inout [Bucket]) { let value = element.toInt() let bucketCapacity = buckets.first!.capacity let bucketIndex = value / bucketCapacity - buckets[bucketIndex].add(element) + buckets[bucketIndex].add(item: element) } } @@ -139,6 +138,6 @@ public struct Bucket { } public func sort(algorithm: Sorter) -> [T] { - return algorithm.sort(elements) + return algorithm.sort(items: elements) } } From 2245c950594c4e9d7bde2383f0890c1fa95305d5 Mon Sep 17 00:00:00 2001 From: Divyendu Singh Date: Sun, 27 Nov 2016 19:44:26 +0530 Subject: [PATCH 0259/1275] uncomment bucket sort in travis.yml file --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 45f0d4beb..17655c21e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ script: - 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 ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests From 30dd3a043e44e63a0ba11bcfda2c6be26cbf1298 Mon Sep 17 00:00:00 2001 From: Divyendu Singh Date: Sun, 27 Nov 2016 20:00:31 +0530 Subject: [PATCH 0260/1275] move the text cases to swift 3 syntax --- Bucket Sort/BucketSort.swift | 44 ++++++++++++++----- Bucket Sort/Tests/Tests.swift | 8 ++-- .../Tests/Tests.xcodeproj/project.pbxproj | 3 ++ 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift index 8363fd867..ef72c67dc 100644 --- a/Bucket Sort/BucketSort.swift +++ b/Bucket Sort/BucketSort.swift @@ -21,6 +21,30 @@ // 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 @@ -39,7 +63,7 @@ import Foundation - Returns: A new array with sorted elements */ -public func bucketSort(elements: [T], distributor: Distributor, sorter: Sorter, buckets: [Bucket]) -> [T] { +public func bucketSort(_ elements: [T], distributor: Distributor, sorter: Sorter, buckets: [Bucket]) -> [T] { precondition(allPositiveNumbers(elements)) precondition(enoughSpaceInBuckets(buckets, elements: elements)) @@ -57,12 +81,12 @@ public func bucketSort(elements: [T], distributor: Distributor, sor return results } -private func allPositiveNumbers(array: [T]) -> Bool { +private func allPositiveNumbers(_ array: [T]) -> Bool { return array.filter { $0.toInt() >= 0 }.count > 0 } -private func enoughSpaceInBuckets(buckets: [Bucket], elements: [T]) -> Bool { - let maximumValue = elements.maxElement()?.toInt() +private func enoughSpaceInBuckets(_ buckets: [Bucket], elements: [T]) -> Bool { + let maximumValue = elements.max()?.toInt() let totalCapacity = buckets.count * (buckets.first?.capacity)! return totalCapacity >= maximumValue @@ -74,7 +98,7 @@ private func enoughSpaceInBuckets(buckets: [Bucket], elements: [ public protocol Distributor { - func distribute(element: T, inout buckets: [Bucket]) + func distribute(_ element: T, buckets: inout [Bucket]) } /* @@ -96,7 +120,7 @@ public struct RangeDistributor: Distributor { public init() {} - public func distribute(element: T, inout buckets: [Bucket]) { + public func distribute(_ element: T, buckets: inout [Bucket]) { let value = element.toInt() let bucketCapacity = buckets.first!.capacity @@ -121,14 +145,14 @@ public protocol Sortable: IntConvertible, Comparable { ////////////////////////////////////// public protocol Sorter { - func sort(items: [T]) -> [T] + func sort(_ items: [T]) -> [T] } public struct InsertionSorter: Sorter { public init() {} - public func sort(items: [T]) -> [T] { + public func sort(_ items: [T]) -> [T] { var results = items for i in 0 ..< results.count { var j = i @@ -158,13 +182,13 @@ public struct Bucket { elements = [T]() } - public mutating func add(item: T) { + public mutating func add(_ item: T) { if elements.count < capacity { elements.append(item) } } - public func sort(algorithm: Sorter) -> [T] { + public func sort(_ algorithm: Sorter) -> [T] { return algorithm.sort(elements) } } diff --git a/Bucket Sort/Tests/Tests.swift b/Bucket Sort/Tests/Tests.swift index 22ac751de..b50789ed0 100644 --- a/Bucket Sort/Tests/Tests.swift +++ b/Bucket Sort/Tests/Tests.swift @@ -25,7 +25,7 @@ class TestTests: XCTestCase { largeArray = [Int]() for _ in 0.. [Int] { + fileprivate func performBucketSort(_ elements: [Int], totalBuckets: Int) -> [Int] { - let value = (elements.maxElement()?.toInt())! + 1 + let value = (elements.max()?.toInt())! + 1 let capacityRequired = Int( ceil( Double(value) / Double(totalBuckets) ) ) var buckets = [Bucket]() @@ -71,7 +71,7 @@ class TestTests: XCTestCase { return results } - func isSorted(array: [Int]) -> Bool { + func isSorted(_ array: [Int]) -> Bool { var index = 0 var sorted = true diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj index 9a42afa4b..64eb170b0 100644 --- a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0810; }; }; }; @@ -222,6 +223,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -234,6 +236,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; }; name = Release; }; From 187f9236924896710b945d879c426370bfb130d7 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 7 Nov 2016 22:38:03 -0500 Subject: [PATCH 0261/1275] Added implementation --- Rootish Array Stack/README.md | 19 +++ Rootish Array Stack/RootishArrayStack.swift | 115 ++++++++++++++++++ .../images/RootishArrayStackExample.png | Bin 0 -> 152134 bytes .../images/RootishArrayStackIntro.png | Bin 0 -> 72856 bytes .../contents.xcworkspacedata | 10 ++ 5 files changed, 144 insertions(+) create mode 100644 Rootish Array Stack/RootishArrayStack.swift create mode 100644 Rootish Array Stack/images/RootishArrayStackExample.png create mode 100644 Rootish Array Stack/images/RootishArrayStackIntro.png diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index e69de29bb..842439a0c 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -0,0 +1,19 @@ +# Rootish Array Stack + +A *Rootish Array Stack* is an ordered array based structure that minimizes wasted space (based on [Gauss's summation technique](https://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/)). A *Rootish Array Stack* consists of an array holding many fixed size arrays in ascending size. + +![Rootish Array Stack Intro](/images/RootishArrayStackIntro.png) + + +A resizable array holds references to blocks (arrays of fixed size). A block's capacity is the same as it's index in the resizable array. Blocks don't grow/shrink like regular Swift arrays. Instead, when their capacity is reached, a new slightly larger block is created. When a block is emptied the last block is freed. This is a great improvement on what a swift array does in terms of wasted space. + +![Rootish Array Stack Intro](/images/RootishArrayStackExample.png) + +Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). + +### How indices map: +| Subscript index | Indices of Blocks| +| :------------- | :------------- | +| `[0]` | `blocks[0][0]` | + +## A Mathematical Explanation diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift new file mode 100644 index 000000000..f17f9620e --- /dev/null +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -0,0 +1,115 @@ +// +// main.swift +// RootishArrayStack +// +// Created by Benjamin Emdon on 2016-11-07. +// + +import Darwin + +public struct RootishArrayStack { + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 + + public init() { } + + var count: Int { + return internalCount + } + + var capacity: Int { + return blocks.count * (blocks.count + 1) / 2 + } + + fileprivate static func toBlock(index: Int) -> Int { + let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) + return block + } + + fileprivate mutating func grow() { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } + + fileprivate mutating func shrink() { + var numberOfBlocks = blocks.count + while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { + blocks.remove(at: blocks.count - 1) + numberOfBlocks -= 1 + } + } + + public subscript(index: Int) -> T { + get { + let block = RootishArrayStack.toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + return blocks[block][blockIndex]! + } + set(newValue) { + let block = RootishArrayStack.toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + blocks[block][blockIndex] = newValue + } + } + + public mutating func insert(element: T, atIndex index: Int) { + if capacity < count + 1 { + grow() + } + internalCount += 1 + var i = count - 1 + while i > index { + self[i] = self[i - 1] + i -= 1 + } + self[index] = element + } + + public mutating func append(element: T) { + insert(element: element, atIndex: count) + } + + fileprivate mutating func makeNil(atIndex index: Int) { + let block = RootishArrayStack.toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + blocks[block][blockIndex] = nil + } + + public mutating func remove(atIndex index: Int) -> T { + let element = self[index] + for i in index..= count { + shrink() + } + return element + } + + public var memoryDescription: String { + var s = "{\n" + for i in blocks { + s += "\t[" + for j in i { + s += "\(j), " + } + s += "]\n" + } + return s + "}" + } +} + +extension RootishArrayStack: CustomStringConvertible { + public var description: String { + var s = "[" + for index in 0..jgQMsoAU^;^e| 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�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 literal 0 HcmV?d00001 diff --git a/Rootish Array Stack/images/RootishArrayStackIntro.png b/Rootish Array Stack/images/RootishArrayStackIntro.png new file mode 100644 index 0000000000000000000000000000000000000000..74802e4ba978ff729ea594a711a1d61231fae880 GIT binary patch literal 72856 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 F{{XywOS}L8 literal 0 HcmV?d00001 diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5f2c83aee..ac3a79be9 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1520,6 +1520,16 @@ + + + + + + From dbc751f344f64648c175d83444f8dc0bcb6033ca Mon Sep 17 00:00:00 2001 From: Marcio Klepacz Date: Mon, 28 Nov 2016 22:09:59 -0500 Subject: [PATCH 0262/1275] Fix link to Minimum Spanning Tree (Unweighted) --- 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 23edf6da5..084f4611a 100644 --- a/Breadth-First Search/README.markdown +++ b/Breadth-First Search/README.markdown @@ -149,6 +149,6 @@ 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 Path/) between a source node and each of the other nodes (only for unweighted graphs). -* Calculating the [minimum spanning tree](../Minimum Spanning Tree/) on an unweighted graph. +* Calculating the [minimum spanning tree](../Minimum Spanning Tree (Unweighted)/) on an unweighted graph. *Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* From e0f13280433d5fe91855d3e133a145a1eaa2446f Mon Sep 17 00:00:00 2001 From: ViktorSimko Date: Sun, 4 Dec 2016 12:51:16 +0100 Subject: [PATCH 0263/1275] fixed typos in B-Tree README --- B-Tree/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/B-Tree/README.md b/B-Tree/README.md index 493fdedfb..f6924aadc 100644 --- a/B-Tree/README.md +++ b/B-Tree/README.md @@ -123,13 +123,13 @@ If the child `c2` at index `i-1` has more keys than the order of the tree: 1. We move the key at index `i-1` from the parent node to the child `c1`'s keys array at index `0`. 2. We move the last key from `c2` to the parent's keys array at index `i-1`. -3. (If `c1` is non-leaf) We move the last children from `c1` to `c2`'s children array at index 0. +3. (If `c1` is non-leaf) We move the last child from `c2` to `c1`'s children array at index 0. Else: 1. We move the key at index `i` from the parent node to the end of child `c1`'s keys array. 2. We move the first key from `c2` to the parent's keys array at index `i`. -3. (If `c1` isn't a leaf) We move the first children from `c2` to the end of `c1`'s children array. +3. (If `c1` isn't a leaf) We move the first child from `c2` to the end of `c1`'s children array. ![Moving Key](Images/MovingKey.png) @@ -141,13 +141,13 @@ If `c1` has a left sibling `c2`: 1. We move the key from the parent at index `i-1` to the end of `c2`'s keys array. 2. We move the keys and the children(if it's a non-leaf) from `c1` to the end of `c2`'s keys and children array. -3. We remove the children at index `i` from the parent node. +3. We remove the child at index `i-1` from the parent node. Else if `c1` only has a right sibling `c2`: 1. We move the key from the parent at index `i` to the beginning of `c2`'s keys array. 2. We move the keys and the children(if it's a non-leaf) from `c1` to the beginning of `c2`'s keys and children array. -3. We remove the children at index `i` from the parent node. +3. We remove the child at index `i` from the parent node. After merging it is possible that now the parent node contains too few keys, so in the worst case merging also can go up to the root, in which case the height of the tree decreases. From 4072983c1fb4725fa21a52421897d82e3040c459 Mon Sep 17 00:00:00 2001 From: Dannel Albert Date: Wed, 7 Dec 2016 00:25:05 -0500 Subject: [PATCH 0264/1275] + methods to append, insert, remove node objects Useful for manipulating linked lists and you already have node objects --- Linked List/LinkedList.swift | 366 ++++++++++++++++++----------------- 1 file changed, 187 insertions(+), 179 deletions(-) diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 86d2bca9b..83f898f6c 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,198 +1,206 @@ public class LinkedListNode { - var value: T - var next: LinkedListNode? - weak var previous: LinkedListNode? - - public init(value: T) { - self.value = value - } + var value: T + var next: LinkedListNode? + weak var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } } public class LinkedList { - public typealias Node = LinkedListNode - - fileprivate var head: Node? - - public init() {} - - public var isEmpty: Bool { - return head == nil - } - - public var first: Node? { - return head - } - - public var last: Node? { - if var node = head { - while case let next? = node.next { - node = next - } - return node - } else { - return nil - } - } - - public var count: Int { - if var node = head { - var c = 1 - while case let next? = node.next { - node = next - c += 1 - } - return c - } 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 - } - } - return nil - } - - public subscript(index: Int) -> T { - let node = self.node(atIndex: index) - assert(node != nil) - return node!.value - } - - public func append(_ value: T) { - let newNode = Node(value: value) - if let lastNode = last { - newNode.previous = lastNode - lastNode.next = newNode - } else { - head = newNode - } - } - - 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 (prev, next) = nodesBeforeAndAfter(index: index) - - let newNode = Node(value: value) - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { - head = newNode - } - } - - public func removeAll() { - head = nil - } - - 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 - } - - public func removeLast() -> T { - assert(!isEmpty) - return remove(node: last!) - } - - public func remove(atIndex index: Int) -> T { - let node = self.node(atIndex: index) - assert(node != nil) - return remove(node: node!) - } + public typealias Node = LinkedListNode + + fileprivate var head: Node? + + public init() {} + + public var isEmpty: Bool { + return head == nil + } + + public var first: Node? { + return head + } + + public var last: Node? { + if var node = head { + while case let next? = node.next { + node = next + } + return node + } else { + return nil + } + } + + public var count: Int { + if var node = head { + var c = 1 + while case let next? = node.next { + node = next + c += 1 + } + return c + } 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 + } + } + return nil + } + + public subscript(index: Int) -> T { + let node = self.node(atIndex: index) + assert(node != nil) + return node!.value + } + + public func append(_ value: T) { + let newNode = Node(value: value) + self.append(newNode) + } + + public func append(_ newNode: Node) { + if let lastNode = last { + newNode.previous = lastNode + lastNode.next = newNode + } else { + head = newNode + } + } + + 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(_ newNode: Node, atIndex index: Int) { + let (prev, next) = nodesBeforeAndAfter(index: index) + + newNode.previous = prev + newNode.next = next + prev?.next = newNode + next?.previous = newNode + + if prev == nil { + head = newNode + } + } + + public func removeAll() { + head = nil + } + + @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 + } + + @discardableResult public func removeLast() -> T { + assert(!isEmpty) + return remove(node: last!) + } + + @discardableResult public func remove(atIndex index: Int) -> T { + let node = self.node(atIndex: index) + assert(node != nil) + return remove(node: node!) + } } 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 += ", " } - } - return s + "]" - } + public var description: String { + var s = "[" + var node = head + while node != nil { + s += "\(node!.value)" + node = node!.next + if node != nil { s += ", " } + } + return s + "]" + } } 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 + } + } } 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 - } - 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 - } - return result - } + public func map(transform: (T) -> U) -> LinkedList { + let result = LinkedList() + var node = head + while node != nil { + result.append(transform(node!.value)) + node = node!.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) + } + node = node!.next + } + return result + } } extension LinkedList { - convenience init(array: Array) { - self.init() + convenience init(array: Array) { + self.init() - for element in array { - self.append(element) + for element in array { + self.append(element) + } } - } } From cf5ca9cb198437b589f7c4ffcd47bcefe7e4b12a Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 12 Dec 2016 10:13:35 +0100 Subject: [PATCH 0265/1275] Updated to Swift 3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated to Swift 3 Syntax. The .swift file wasn’t converted yet. Additionally, I fixed a bug in there. --- .../BoyerMoore.playground/Contents.swift | 94 ++++++---- .../BoyerMoore.playground/timeline.xctimeline | 6 +- Boyer-Moore/BoyerMoore.swift | 118 ++++++------ Boyer-Moore/README.markdown | 169 +++++++++--------- 4 files changed, 209 insertions(+), 178 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 9a3d619dc..362a298f9 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -1,42 +1,66 @@ //: Playground - noun: a place where people can play extension String { - func indexOf(pattern: String) -> String.Index? { - let patternLength = pattern.characters.count - assert(patternLength > 0) - assert(patternLength <= self.characters.count) - - var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { - skipTable[c] = patternLength - i - 1 - } - - let p = pattern.index(before: pattern.endIndex) - let lastChar = pattern[p] - var i = self.index(startIndex, offsetBy: patternLength - 1) - - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = index(before: j) - q = index(before: q) - if self[j] != pattern[q] { return nil } - } - return j - } - - while i < self.endIndex { - let c = self[i] - if c == lastChar { - if let k = backwards() { return k } - i = index(after: i) - } else { - i = index(i, offsetBy: skipTable[c] ?? patternLength) - } + func indexOf(pattern: String) -> 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 + assert(patternLength > 0) + assert(patternLength <= self.characters.count) + + // 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() { + skipTable[c] = patternLength - i - 1 + } + + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = self.index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < self.endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = self.index(i, offsetBy: skipTable[c] ?? patternLength) + } + } + return nil } - return nil - } } // A few simple tests diff --git a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline index a15b8d6e0..89bc76f90 100644 --- a/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline +++ b/Boyer-Moore/BoyerMoore.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift index 12a1d86c1..4d7660ec3 100644 --- a/Boyer-Moore/BoyerMoore.swift +++ b/Boyer-Moore/BoyerMoore.swift @@ -6,64 +6,64 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func indexOf(pattern: String) -> 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.count) - - // 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.enumerate() { - skipTable[c] = patternLength - i - 1 - } - - // This points at the last character in the pattern. - let p = pattern.endIndex.predecessor() - let lastChar = pattern[p] - - // The pattern is scanned right-to-left, so skip ahead in the string by - // the length of the pattern. (Minus 1 because startIndex already points - // at the first character in the source string.) - var i = self.startIndex.advancedBy(patternLength - 1) - - // This is a helper function that steps backwards through both strings - // until we find a character that doesn’t match, or until we’ve reached - // the beginning of the pattern. - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = j.predecessor() - q = q.predecessor() - if self[j] != pattern[q] { return nil } - } - return j - } - - // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { - let c = self[i] - - // Does the current character match the last character from the pattern? - if c == lastChar { - - // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } - - // If no match, we can only safely skip one character ahead. - i = i.successor() - } else { - // The characters are not equal, so skip ahead. The amount to skip is - // determined by the skip table. If the character is not present in the - // pattern, we can skip ahead by the full pattern length. However, if - // the character *is* present in the pattern, there may be a match up - // ahead and we can't skip as far. - i = i.advancedBy(skipTable[c] ?? patternLength) - } + func indexOf(pattern: String) -> 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 + assert(patternLength > 0) + assert(patternLength <= self.characters.count) + + // 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() { + skipTable[c] = patternLength - i - 1 + } + + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = self.index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < self.endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = self.index(i, offsetBy: skipTable[c] ?? patternLength) + } + } + return nil } - return nil - } } diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index 4acc1ffb3..576f6d17b 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -1,13 +1,13 @@ # Boyer-Moore String Search -Goal: Write a string search algorithm in pure Swift without importing Foundation or using `NSString`'s `rangeOfString()` method. - +Goal: Write a string search algorithm in pure Swift without importing Foundation or using `NSString`'s `rangeOfString()` method. + In other words, we want to implement an `indexOf(pattern: String)` extension on `String` that returns the `String.Index` of the first occurrence of the search pattern, or `nil` if the pattern could not be found inside the string. - + For example: ```swift -// Input: +// Input: let s = "Hello, World" s.indexOf(pattern: "World") @@ -24,7 +24,7 @@ animals.indexOf(pattern: "🐮") > **Note:** The index of the cow is 6, not 3 as you might expect, because the string uses more storage per character for emoji. The actual value of the `String.Index` is not so important, just that it points at the right character in the string. -The [brute-force approach](../Brute-Force String Search/) works OK, but it's not very efficient, especially on large chunks of text. As it turns out, you don't need to look at *every* character from the source string -- you can often skip ahead multiple characters. +The [brute-force approach](../Brute-Force String Search/) works OK, but it's not very efficient, especially on large chunks of text. As it turns out, you don't need to look at _every_ character from the source string -- you can often skip ahead multiple characters. The skip-ahead algorithm is called [Boyer-Moore](https://en.wikipedia.org/wiki/Boyer–Moore_string_search_algorithm) and it has been around for a long time. It is considered the benchmark for all string search algorithms. @@ -32,75 +32,76 @@ Here's how you could write it in Swift: ```swift extension String { -func indexOf(pattern: String) -> 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.count) - - // 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() { - skipTable[c] = patternLength - i - 1 - } - - // This points at the last character in the pattern. - let p = index(before: pattern.endIndex) - let lastChar = pattern[p] - - // The pattern is scanned right-to-left, so skip ahead in the string by - // the length of the pattern. (Minus 1 because startIndex already points - // at the first character in the source string.) - var i = index(self.startIndex, offsetBy: patternLength - 1) - - // This is a helper function that steps backwards through both strings - // until we find a character that doesn’t match, or until we’ve reached - // the beginning of the pattern. - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = index(before: j) - q = index(before: q) - if self[j] != pattern[q] { return nil } - } - return j - } - - // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { - let c = self[i] - - // Does the current character match the last character from the pattern? - if c == lastChar { - - // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } - - // If no match, we can only safely skip one character ahead. - i = index(after: i) - } else { - // The characters are not equal, so skip ahead. The amount to skip is - // determined by the skip table. If the character is not present in the - // pattern, we can skip ahead by the full pattern length. However, if - // the character *is* present in the pattern, there may be a match up - // ahead and we can't skip as far. - i = index(i, offsetBy: skipTable[c] ?? patternLength) - } - } - return nil + func indexOf(pattern: String) -> 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 + assert(patternLength > 0) + assert(patternLength <= self.characters.count) + + // 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() { + skipTable[c] = patternLength - i - 1 + } + + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = self.index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < self.endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = self.index(i, offsetBy: skipTable[c] ?? patternLength) + } + } + return nil } } - ``` -The algorithm works as follows. You line up the search pattern with the source string and see what character from the string matches the *last* character of the search pattern: +The algorithm works as follows. You line up the search pattern with the source string and see what character from the string matches the _last_ character of the search pattern: - source string: Hello, World - search pattern: World - ^ +``` +source string: Hello, World +search pattern: World + ^ +``` There are three possibilities: @@ -112,25 +113,31 @@ There are three possibilities: In the example, the characters `o` and `d` do not match, but `o` does appear in the search pattern. That means we can skip ahead several positions: - source string: Hello, World - search pattern: World - ^ +``` +source string: Hello, World +search pattern: World + ^ +``` Note how the two `o` characters line up now. Again you compare the last character of the search pattern with the search text: `W` vs `d`. These are not equal but the `W` does appear in the pattern. So skip ahead again to line up those two `W` characters: - source string: Hello, World - search pattern: World - ^ +``` +source string: Hello, World +search pattern: World + ^ +``` This time the two characters are equal and there is a possible match. To verify the match you do a brute-force search, but backwards, from the end of the search pattern to the beginning. And that's all there is to it. The amount to skip ahead at any given time is determined by the "skip table", which is a dictionary of all the characters in the search pattern and the amount to skip by. The skip table in the example looks like: - W: 4 - o: 3 - r: 2 - l: 1 - d: 0 +``` +W: 4 +o: 3 +r: 2 +l: 1 +d: 0 +``` The closer a character is to the end of the pattern, the smaller the skip amount. If a character appears more than once in the pattern, the one nearest to the end of the pattern determines the skip value for that character. @@ -193,4 +200,4 @@ In practice, the Horspool version of the algorithm tends to perform a little bet Credits: This code is based on the paper: [R. N. Horspool (1980). "Practical fast searching in strings". Software - Practice & Experience 10 (6): 501–506.](http://www.cin.br/~paguso/courses/if767/bib/Horspool_1980.pdf) -*Written for Swift Algorithm Club by Matthijs Hollemans* +_Written for Swift Algorithm Club by Matthijs Hollemans, updated by Andreas Neusüß_ From 24fa81839a45e24a6d5600c774fce3b730eb4de1 Mon Sep 17 00:00:00 2001 From: zaccone Date: Mon, 12 Dec 2016 15:42:21 -0500 Subject: [PATCH 0266/1275] I created an Xcode project with my changes. It makes it easier to test and the playground was crashing! --- Trie/ReadMe.md | 10 + Trie/Trie/Trie.xcodeproj/project.pbxproj | 531 + .../contents.xcworkspacedata | 7 + Trie/Trie/Trie/AppDelegate.swift | 26 + .../AppIcon.appiconset/Contents.json | 58 + Trie/Trie/Trie/Base.lproj/Main.storyboard | 693 + Trie/Trie/Trie/Info.plist | 32 + Trie/Trie/Trie/Trie.swift | 207 + Trie/Trie/Trie/ViewController.swift | 27 + Trie/Trie/Trie/dictionary.txt | 162825 +++++++++++++++ Trie/Trie/TrieTests/Info.plist | 22 + Trie/Trie/TrieTests/TrieTests.swift | 162 + Trie/Trie/TrieUITests/Info.plist | 22 + Trie/Trie/TrieUITests/TrieUITests.swift | 36 + 14 files changed, 164658 insertions(+) create mode 100644 Trie/Trie/Trie.xcodeproj/project.pbxproj create mode 100644 Trie/Trie/Trie.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Trie/Trie/Trie/AppDelegate.swift create mode 100644 Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Trie/Trie/Trie/Base.lproj/Main.storyboard create mode 100644 Trie/Trie/Trie/Info.plist create mode 100644 Trie/Trie/Trie/Trie.swift create mode 100644 Trie/Trie/Trie/ViewController.swift create mode 100644 Trie/Trie/Trie/dictionary.txt create mode 100644 Trie/Trie/TrieTests/Info.plist create mode 100644 Trie/Trie/TrieTests/TrieTests.swift create mode 100644 Trie/Trie/TrieUITests/Info.plist create mode 100644 Trie/Trie/TrieUITests/TrieUITests.swift diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 30082a450..6b28dd189 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -162,3 +162,13 @@ Let n be the length of some value in the `Trie`. See also [Wikipedia entry for Trie](https://en.wikipedia.org/wiki/Trie). *Written for the Swift Algorithm Club by Christian Encarnacion. Refactored by Kelvin Lau* + +# Changes by Rick Zaccone + +* Added comments to all methods +* Refactored the `remove` method +* Renamed some variables. I have mixed feelings about the way Swift infers types. It's not always apparent what type a variable will have. To address this, I made changes such as renaming `parent` to `parentNode` to emphasize that it is a node and not the value contained within the node. +* Added a `words` property that recursively traverses the trie and constructs an array containing all of the words in the trie. +* Added a `isLeaf` property to `TrieNode` for readability. +* Implemented `count` and `isEmpty` properties for the trie. +* I tried stress testing the trie by adding 162,825 words. The playground was very slow while adding the words and eventually crashed. To fix this problem, I moved everything into a project and wrote `XCTest` tests that test the trie. There are also several performance tests. Everything passes. diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj new file mode 100644 index 000000000..70a0626da --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -0,0 +1,531 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + EB798DFE1DFEF79900F0628D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798DFD1DFEF79900F0628D /* AppDelegate.swift */; }; + EB798E001DFEF79900F0628D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798DFF1DFEF79900F0628D /* ViewController.swift */; }; + EB798E021DFEF79900F0628D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EB798E011DFEF79900F0628D /* Assets.xcassets */; }; + EB798E051DFEF79900F0628D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB798E031DFEF79900F0628D /* Main.storyboard */; }; + EB798E101DFEF79900F0628D /* TrieTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E0F1DFEF79900F0628D /* TrieTests.swift */; }; + EB798E1B1DFEF79900F0628D /* TrieUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E1A1DFEF79900F0628D /* TrieUITests.swift */; }; + EB798E291DFEF81400F0628D /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E281DFEF81400F0628D /* Trie.swift */; }; + EB798E2A1DFEF81400F0628D /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E281DFEF81400F0628D /* Trie.swift */; }; + EB798E2C1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; + EB798E2D1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + EB798E0C1DFEF79900F0628D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = EB798DF21DFEF79900F0628D /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB798DF91DFEF79900F0628D; + remoteInfo = Trie; + }; + EB798E171DFEF79900F0628D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = EB798DF21DFEF79900F0628D /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB798DF91DFEF79900F0628D; + remoteInfo = Trie; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + EB798DFA1DFEF79900F0628D /* Trie.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Trie.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EB798DFD1DFEF79900F0628D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + EB798DFF1DFEF79900F0628D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + EB798E011DFEF79900F0628D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EB798E041DFEF79900F0628D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + EB798E061DFEF79900F0628D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EB798E0B1DFEF79900F0628D /* TrieTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrieTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EB798E0F1DFEF79900F0628D /* TrieTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrieTests.swift; sourceTree = ""; }; + EB798E111DFEF79900F0628D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EB798E161DFEF79900F0628D /* TrieUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrieUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EB798E1A1DFEF79900F0628D /* TrieUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrieUITests.swift; sourceTree = ""; }; + EB798E1C1DFEF79900F0628D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EB798E281DFEF81400F0628D /* Trie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = ""; }; + EB798E2B1DFEF90B00F0628D /* dictionary.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.txt; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EB798DF71DFEF79900F0628D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E081DFEF79900F0628D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E131DFEF79900F0628D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EB798DF11DFEF79900F0628D = { + isa = PBXGroup; + children = ( + EB798DFC1DFEF79900F0628D /* Trie */, + EB798E0E1DFEF79900F0628D /* TrieTests */, + EB798E191DFEF79900F0628D /* TrieUITests */, + EB798DFB1DFEF79900F0628D /* Products */, + ); + sourceTree = ""; + }; + EB798DFB1DFEF79900F0628D /* Products */ = { + isa = PBXGroup; + children = ( + EB798DFA1DFEF79900F0628D /* Trie.app */, + EB798E0B1DFEF79900F0628D /* TrieTests.xctest */, + EB798E161DFEF79900F0628D /* TrieUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + EB798DFC1DFEF79900F0628D /* Trie */ = { + isa = PBXGroup; + children = ( + EB798DFD1DFEF79900F0628D /* AppDelegate.swift */, + EB798DFF1DFEF79900F0628D /* ViewController.swift */, + EB798E011DFEF79900F0628D /* Assets.xcassets */, + EB798E031DFEF79900F0628D /* Main.storyboard */, + EB798E061DFEF79900F0628D /* Info.plist */, + EB798E281DFEF81400F0628D /* Trie.swift */, + EB798E2B1DFEF90B00F0628D /* dictionary.txt */, + ); + path = Trie; + sourceTree = ""; + }; + EB798E0E1DFEF79900F0628D /* TrieTests */ = { + isa = PBXGroup; + children = ( + EB798E0F1DFEF79900F0628D /* TrieTests.swift */, + EB798E111DFEF79900F0628D /* Info.plist */, + ); + path = TrieTests; + sourceTree = ""; + }; + EB798E191DFEF79900F0628D /* TrieUITests */ = { + isa = PBXGroup; + children = ( + EB798E1A1DFEF79900F0628D /* TrieUITests.swift */, + EB798E1C1DFEF79900F0628D /* Info.plist */, + ); + path = TrieUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + EB798DF91DFEF79900F0628D /* Trie */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB798E1F1DFEF79900F0628D /* Build configuration list for PBXNativeTarget "Trie" */; + buildPhases = ( + EB798DF61DFEF79900F0628D /* Sources */, + EB798DF71DFEF79900F0628D /* Frameworks */, + EB798DF81DFEF79900F0628D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Trie; + productName = Trie; + productReference = EB798DFA1DFEF79900F0628D /* Trie.app */; + productType = "com.apple.product-type.application"; + }; + EB798E0A1DFEF79900F0628D /* TrieTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB798E221DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieTests" */; + buildPhases = ( + EB798E071DFEF79900F0628D /* Sources */, + EB798E081DFEF79900F0628D /* Frameworks */, + EB798E091DFEF79900F0628D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + EB798E0D1DFEF79900F0628D /* PBXTargetDependency */, + ); + name = TrieTests; + productName = TrieTests; + productReference = EB798E0B1DFEF79900F0628D /* TrieTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + EB798E151DFEF79900F0628D /* TrieUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB798E251DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieUITests" */; + buildPhases = ( + EB798E121DFEF79900F0628D /* Sources */, + EB798E131DFEF79900F0628D /* Frameworks */, + EB798E141DFEF79900F0628D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + EB798E181DFEF79900F0628D /* PBXTargetDependency */, + ); + name = TrieUITests; + productName = TrieUITests; + productReference = EB798E161DFEF79900F0628D /* TrieUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EB798DF21DFEF79900F0628D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 0810; + ORGANIZATIONNAME = "Rick Zaccone"; + TargetAttributes = { + EB798DF91DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + ProvisioningStyle = Automatic; + }; + EB798E0A1DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + ProvisioningStyle = Automatic; + TestTargetID = EB798DF91DFEF79900F0628D; + }; + EB798E151DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + ProvisioningStyle = Automatic; + TestTargetID = EB798DF91DFEF79900F0628D; + }; + }; + }; + buildConfigurationList = EB798DF51DFEF79900F0628D /* Build configuration list for PBXProject "Trie" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EB798DF11DFEF79900F0628D; + productRefGroup = EB798DFB1DFEF79900F0628D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EB798DF91DFEF79900F0628D /* Trie */, + EB798E0A1DFEF79900F0628D /* TrieTests */, + EB798E151DFEF79900F0628D /* TrieUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EB798DF81DFEF79900F0628D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB798E2C1DFEF90B00F0628D /* dictionary.txt in Resources */, + EB798E021DFEF79900F0628D /* Assets.xcassets in Resources */, + EB798E051DFEF79900F0628D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E091DFEF79900F0628D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB798E2D1DFEF90B00F0628D /* dictionary.txt in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E141DFEF79900F0628D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EB798DF61DFEF79900F0628D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB798E291DFEF81400F0628D /* Trie.swift in Sources */, + EB798E001DFEF79900F0628D /* ViewController.swift in Sources */, + EB798DFE1DFEF79900F0628D /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E071DFEF79900F0628D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB798E101DFEF79900F0628D /* TrieTests.swift in Sources */, + EB798E2A1DFEF81400F0628D /* Trie.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB798E121DFEF79900F0628D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB798E1B1DFEF79900F0628D /* TrieUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + EB798E0D1DFEF79900F0628D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB798DF91DFEF79900F0628D /* Trie */; + targetProxy = EB798E0C1DFEF79900F0628D /* PBXContainerItemProxy */; + }; + EB798E181DFEF79900F0628D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB798DF91DFEF79900F0628D /* Trie */; + targetProxy = EB798E171DFEF79900F0628D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + EB798E031DFEF79900F0628D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + EB798E041DFEF79900F0628D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + EB798E1D1DFEF79900F0628D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = 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.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + EB798E1E1DFEF79900F0628D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = 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.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + EB798E201DFEF79900F0628D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Trie/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + EB798E211DFEF79900F0628D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Trie/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + EB798E231DFEF79900F0628D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TrieTests/Info.plist; + 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; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; + }; + name = Debug; + }; + EB798E241DFEF79900F0628D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TrieTests/Info.plist; + 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; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; + }; + name = Release; + }; + EB798E261DFEF79900F0628D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TrieUITests/Info.plist; + 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; + TEST_TARGET_NAME = Trie; + }; + name = Debug; + }; + EB798E271DFEF79900F0628D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TrieUITests/Info.plist; + 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; + TEST_TARGET_NAME = Trie; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EB798DF51DFEF79900F0628D /* Build configuration list for PBXProject "Trie" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E1D1DFEF79900F0628D /* Debug */, + EB798E1E1DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB798E1F1DFEF79900F0628D /* Build configuration list for PBXNativeTarget "Trie" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E201DFEF79900F0628D /* Debug */, + EB798E211DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + EB798E221DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E231DFEF79900F0628D /* Debug */, + EB798E241DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + EB798E251DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E261DFEF79900F0628D /* Debug */, + EB798E271DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = EB798DF21DFEF79900F0628D /* Project object */; +} diff --git a/Trie/Trie/Trie.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..cd768f89b --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Trie/Trie/Trie/AppDelegate.swift b/Trie/Trie/Trie/AppDelegate.swift new file mode 100644 index 000000000..4da9dc345 --- /dev/null +++ b/Trie/Trie/Trie/AppDelegate.swift @@ -0,0 +1,26 @@ +// +// AppDelegate.swift +// Trie +// +// Created by Rick Zaccone on 2016-12-12. +// Copyright © 2016 Rick Zaccone. All rights reserved. +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + +} + diff --git a/Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json b/Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..2db2b1c7c --- /dev/null +++ b/Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Trie/Trie/Trie/Base.lproj/Main.storyboard b/Trie/Trie/Trie/Base.lproj/Main.storyboard new file mode 100644 index 000000000..64d3d90d8 --- /dev/null +++ b/Trie/Trie/Trie/Base.lproj/Main.storyboard @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Trie/Trie/Trie/Info.plist b/Trie/Trie/Trie/Info.plist new file mode 100644 index 000000000..ed3668788 --- /dev/null +++ b/Trie/Trie/Trie/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Rick Zaccone. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift new file mode 100644 index 000000000..bd1abc538 --- /dev/null +++ b/Trie/Trie/Trie/Trie.swift @@ -0,0 +1,207 @@ +// +// Trie.swift +// Trie +// +// Created by Rick Zaccone on 2016-12-12. +// Copyright © 2016 Rick Zaccone. All rights reserved. +// + +import Foundation + + +/// A node in the trie +class TrieNode { + var value: T? + weak var parentNode: TrieNode? + var children: [T: TrieNode] = [:] + var isTerminating = false + var isLeaf: Bool { + get { + return children.count == 0 + } + } + + /// Initializes a node. + /// + /// - Parameters: + /// - value: The value that goes into the node + /// - parentNode: A reference to this node's parent + init(value: T? = nil, parentNode: TrieNode? = nil) { + self.value = value + self.parentNode = parentNode + } + + /// Adds a child node to self. If the child is already present, + /// do nothing. + /// + /// - Parameter value: The item to be added to this node. + func add(value: T) { + guard children[value] == nil else { + return + } + children[value] = TrieNode(value: value, parentNode: self) + } +} + +/// A trie data structure containing words. Each node is a single +/// character of a word. +class Trie { + 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 + + /// Creats an empty trie. + init() { + root = Node() + wordCount = 0 + } +} + +// MARK: - Adds methods: insert, remove, contains +extension Trie { + + /// Inserts a word into the trie. If the word is already present, + /// there is no change. + /// + /// - Parameter word: the word to be inserted. + func insert(word: String) { + guard !word.isEmpty else { + return + } + var currentNode = root + let charactersInWord = Array(word.lowercased().characters) + var index = 0 + while index < charactersInWord.count { + let character = charactersInWord[index] + if let childNode = currentNode.children[character] { + currentNode = childNode + } else { + currentNode.add(value: character) + currentNode = currentNode.children[character]! + } + index += 1 + } + // Word already present? + guard !currentNode.isTerminating else { + return + } + self.wordCount += 1 + currentNode.isTerminating = true + } + + /// Determines whether a word is in the trie. + /// + /// - Parameter word: the word to check for + /// - Returns: true if the word is present, false otherwise. + func contains(word: String) -> Bool { + guard !word.isEmpty else { + return false + } + var currentNode = root + let charactersInWord = Array(word.lowercased().characters) + var index = 0 + while index < charactersInWord.count, let childNode = currentNode.children[charactersInWord[index]] { + index += 1 + currentNode = childNode + } + return index == charactersInWord.count && currentNode.isTerminating + } + + /// Attempts to walk to the terminating node of a word. The + /// search will fail if the word is not present. + /// + /// - Parameter word: the word in question + /// - Returns: the node where the search ended, nil if the + /// search failed. + private func findTerminalNodeOf(word: String) -> Node? { + var currentNode = root + var charactersInWord = Array(word.lowercased().characters) + var index = 0 + while index < charactersInWord.count { + let character = charactersInWord[index] + guard let childNode = currentNode.children[character] else { + return nil + } + currentNode = childNode + index += 1 + } + return currentNode.isTerminating ? currentNode : nil + } + + + /// Deletes a word from the trie by starting with the last letter + /// and moving back, deleting nodes until either a non-leaf or a + /// terminating node is found. + /// + /// - Parameter terminalNode: the node representing the last node + /// of a word + private func deleteNodesForWordEndingWith(terminalNode: Node) { + var lastNode = terminalNode + var character = lastNode.value + while lastNode.isLeaf, let parentNode = lastNode.parentNode { + lastNode = parentNode + lastNode.children[character!] = nil + character = lastNode.value + if lastNode.isTerminating { + break + } + } + } + + /// Removes a word from the trie. If the word is not present or + /// it is empty, just ignore it. If the last node is a leaf, + /// delete that node and higher nodes that are leaves until a + /// terminating node or non-leaf is found. If the last node of + /// the word has more children, the word is part of other words. + /// Mark the last node as non-terminating. + /// + /// - Parameter word: the word to be removed + func remove(word: String) { + guard !word.isEmpty else { + return + } + guard let terminalNode = findTerminalNodeOf(word: word) else { + return + } + if terminalNode.isLeaf { + deleteNodesForWordEndingWith(terminalNode: terminalNode) + } else { + terminalNode.isTerminating = false + } + self.wordCount -= 1 + } + + /// Returns an array of words in a subtrie of the trie + /// + /// - Parameters: + /// - rootNode: the root node of the subtrie + /// - partialWord: the letters collected by traversing to this node + /// - Returns: the words in the subtrie + func wordsInSubtrie(rootNode: Node, partialWord: String) -> [String] { + var subtrieWords = [String]() + var previousLetters = partialWord + if let value = rootNode.value { + previousLetters.append(value) + } + if rootNode.isTerminating { + subtrieWords.append(previousLetters) + } + for (_, childNode) in rootNode.children { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: previousLetters) + subtrieWords += childWords + } + return subtrieWords + } +} diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift new file mode 100644 index 000000000..b2e9d9105 --- /dev/null +++ b/Trie/Trie/Trie/ViewController.swift @@ -0,0 +1,27 @@ +// +// ViewController.swift +// Trie +// +// Created by Rick Zaccone on 2016-12-12. +// Copyright © 2016 Rick Zaccone. All rights reserved. +// + +import Cocoa + +class ViewController: NSViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. + } + } + + +} + diff --git a/Trie/Trie/Trie/dictionary.txt b/Trie/Trie/Trie/dictionary.txt new file mode 100644 index 000000000..4e5bcd075 --- /dev/null +++ b/Trie/Trie/Trie/dictionary.txt @@ -0,0 +1,162825 @@ +10s +10th +11th +12th +13th +14th +15th +16th +17th +1800s +1890s +18th +1900s +1910s +1920s +1930s +1940s +1950s +1960s +1970s +1980s +1990s +19th +1st +20s +20th +21st +22nd +23rd +24th +25th +26th +27th +28th +29th +2nd +30s +30th +31st +3rd +40s +4th +50s +5th +60s +6th +70s +7th +80s +8th +90s +9th +a +aachen +aah +aahed +aahing +aahs +aardvark +aardvarks +aardwolf +aardwolves +aaron +ab +aba +ababa +abaca +abaci +aback +abacterial +abacus +abacuses +abadan +abaft +abalone +abalones +abampere +abamperes +abandon +abandoned +abandonee +abandonees +abandoner +abandoners +abandoning +abandonment +abandonments +abandons +abapical +abase +abased +abasement +abasements +abases +abash +abashed +abashes +abashing +abashment +abashments +abasia +abasing +abatable +abate +abated +abatement +abatements +abater +abaters +abates +abating +abatis +abatises +abattoir +abattoirs +abaxial +abbacies +abbacy +abbatial +abbess +abbesses +abbeville +abbevillian +abbey +abbeys +abbot +abbots +abbreviate +abbreviated +abbreviates +abbreviating +abbreviation +abbreviations +abbreviator +abbreviators +abbé +abbés +abc +abcoulomb +abdicable +abdicate +abdicated +abdicates +abdicating +abdication +abdications +abdicator +abdicators +abdomen +abdomens +abdominal +abdominally +abdominous +abducens +abducent +abducentes +abduct +abducted +abducting +abduction +abductions +abductor +abductors +abducts +abeam +abecedarian +abecedarians +abed +abednego +abel +abelard +abelia +abelian +abelmosk +abelmosks +aberdare +aberdeen +aberdonian +aberdonians +aberrance +aberrancies +aberrancy +aberrant +aberrantly +aberrants +aberrated +aberration +aberrational +aberrations +abet +abetment +abetments +abets +abetted +abetter +abetters +abetting +abettor +abettors +abeyance +abeyant +abfarad +abfarads +abhenries +abhenry +abhor +abhorred +abhorrence +abhorrences +abhorrent +abhorrently +abhorrer +abhorrers +abhorring +abhors +abidance +abidances +abide +abided +abider +abiders +abides +abiding +abidingly +abidingness +abigail +abigails +abilities +ability +abiogeneses +abiogenesis +abiogenetic +abiogenetical +abiogenic +abiogenically +abiogenist +abiological +abiologically +abiosis +abiotic +abiotically +abject +abjection +abjections +abjectly +abjectness +abjuration +abjurations +abjure +abjured +abjurer +abjurers +abjures +abjuring +ablate +ablated +ablates +ablating +ablation +ablations +ablative +ablatively +ablatives +ablaut +ablaze +able +abler +ablest +abloom +abluted +ablution +ablutionary +ablutions +ably +abnegate +abnegated +abnegates +abnegating +abnegation +abnegations +abnegator +abnegators +abnormal +abnormalities +abnormality +abnormally +abnormals +aboard +abode +abodes +abohm +aboil +abolish +abolishable +abolished +abolisher +abolishers +abolishes +abolishing +abolishment +abolishments +abolition +abolitionary +abolitionism +abolitionist +abolitionists +abomasa +abomasal +abomasum +abominable +abominably +abominate +abominated +abominates +abominating +abomination +abominations +abominator +abominators +aboral +aborally +aboriginal +aboriginally +aborigine +aborigines +aborning +abort +aborted +aborter +aborters +abortifacient +aborting +abortion +abortionist +abortionists +abortions +abortive +abortively +abortiveness +aborts +abos +abound +abounded +abounding +abounds +about +above +aboveboard +aboveground +abracadabra +abrachia +abradable +abradant +abradants +abrade +abraded +abrader +abraders +abrades +abrading +abraham +abranchiate +abrash +abrasion +abrasions +abrasive +abrasively +abrasiveness +abrasives +abreact +abreacted +abreacting +abreaction +abreactions +abreacts +abreast +abridge +abridged +abridgement +abridgements +abridger +abridgers +abridges +abridging +abridgment +abridgments +abrin +abroach +abroad +abrogate +abrogated +abrogates +abrogating +abrogation +abrogations +abrupt +abruption +abruptly +abruptness +abruzzi +abruzzo +absalom +abscess +abscessed +abscesses +abscessing +abscise +abscised +abscises +abscisin +abscising +abscisins +abscissa +abscissae +abscissas +abscission +abscissions +abscond +absconded +absconder +absconders +absconding +absconds +absence +absences +absent +absented +absentee +absenteeism +absentees +absentia +absenting +absently +absentminded +absentmindedly +absentmindedness +absents +absinth +absinthe +absinthes +absinths +absolute +absolutely +absoluteness +absolutes +absolution +absolutions +absolutism +absolutisms +absolutist +absolutistic +absolutists +absolutize +absolutized +absolutizes +absolutizing +absolvable +absolve +absolved +absolver +absolvers +absolves +absolving +absorb +absorbability +absorbable +absorbance +absorbancy +absorbant +absorbants +absorbed +absorbedly +absorbedness +absorbefacient +absorbencies +absorbency +absorbent +absorbents +absorber +absorbers +absorbing +absorbingly +absorbs +absorptance +absorption +absorptions +absorptive +absorptivity +absquatulate +absquatulated +absquatulates +absquatulating +abstain +abstained +abstainer +abstainers +abstaining +abstains +abstemious +abstemiously +abstemiousness +abstention +abstentions +abstentious +abstinence +abstinent +abstinently +abstract +abstractable +abstracted +abstractedly +abstractedness +abstracter +abstracters +abstracting +abstraction +abstractional +abstractionism +abstractionist +abstractionists +abstractions +abstractive +abstractly +abstractness +abstractor +abstractors +abstracts +abstruse +abstrusely +abstruseness +abstrusities +abstrusity +absurd +absurdism +absurdist +absurdities +absurdity +absurdly +absurdness +absurdum +abu +abubble +abuilding +abulia +abulias +abulic +abundance +abundances +abundant +abundantly +abusable +abuse +abused +abuser +abusers +abuses +abusing +abusive +abusively +abusiveness +abut +abutilon +abutilons +abutment +abutments +abuts +abutted +abutter +abutters +abutting +abuzz +abvolt +abvolts +aby +abydos +abye +abyes +abying +abys +abysm +abysmal +abysmally +abysms +abyss +abyssal +abysses +abyssinia +abyssinian +abyssinians +acacia +acacias +academe +academes +academia +academic +academical +academically +academician +academicians +academicism +academics +academies +academism +academy +acantha +acanthae +acanthi +acanthocephalan +acanthoid +acanthopterygian +acanthus +acanthuses +acapnia +acapulco +acari +acariasis +acarid +acaridae +acarids +acarologist +acarology +acarophobia +acarpous +acarus +acatalectic +acaudate +acaulescent +accede +acceded +accedence +acceder +acceders +accedes +acceding +accelerando +accelerant +accelerate +accelerated +accelerates +accelerating +acceleratingly +acceleration +accelerations +accelerative +accelerator +accelerators +accelerograph +accelerometer +accelerometers +accent +accented +accenting +accentless +accents +accentual +accentually +accentuate +accentuated +accentuates +accentuating +accentuation +accept +acceptability +acceptable +acceptableness +acceptably +acceptance +acceptances +acceptant +acceptation +accepted +acceptedly +accepter +accepters +accepting +acceptingly +acceptingness +acceptive +acceptor +acceptors +accepts +access +accessaries +accessary +accessed +accesses +accessibility +accessible +accessibleness +accessibly +accessing +accession +accessional +accessioned +accessioning +accessions +accessorial +accessories +accessorily +accessoriness +accessorize +accessorized +accessorizes +accessorizing +accessory +acciaccatura +accidence +accident +accidental +accidentally +accidentalness +accidentals +accidently +accidents +accidie +accidies +accipiter +accipitrine +acclaim +acclaimed +acclaimer +acclaimers +acclaiming +acclaims +acclamation +acclamations +acclamatory +acclimate +acclimated +acclimates +acclimating +acclimation +acclimatization +acclimatize +acclimatized +acclimatizer +acclimatizers +acclimatizes +acclimatizing +acclivities +acclivitous +acclivity +accolade +accoladed +accolades +accolading +accommodate +accommodated +accommodates +accommodating +accommodatingly +accommodation +accommodational +accommodationist +accommodations +accommodative +accommodativeness +accommodator +accommodators +accompanied +accompanies +accompaniment +accompaniments +accompanist +accompanists +accompany +accompanying +accompli +accomplice +accomplices +accomplis +accomplish +accomplishable +accomplished +accomplisher +accomplishers +accomplishes +accomplishing +accomplishment +accomplishments +accord +accordance +accordances +accordant +accordantly +accorded +according +accordingly +accordion +accordionist +accordionists +accordions +accords +accost +accosted +accosting +accosts +accouchement +accouchements +account +accountabilities +accountability +accountable +accountableness +accountably +accountancies +accountancy +accountant +accountants +accountantship +accounted +accounting +accountings +accounts +accouter +accoutered +accoutering +accouterment +accouterments +accouters +accoutre +accoutred +accoutrement +accoutrements +accoutres +accoutring +accra +accredit +accreditable +accreditation +accreditations +accredited +accrediting +accredits +accrescent +accrete +accreted +accretes +accreting +accretion +accretionary +accretions +accretive +accruable +accrual +accruals +accrue +accrued +accruement +accruements +accrues +accruing +acculturate +acculturated +acculturates +acculturating +acculturation +acculturational +acculturative +accumbent +accumulable +accumulate +accumulated +accumulates +accumulating +accumulation +accumulations +accumulative +accumulatively +accumulativeness +accumulator +accumulators +accuracies +accuracy +accurate +accurately +accurateness +accurse +accursed +accursedly +accursedness +accurst +accusable +accusal +accusals +accusation +accusations +accusative +accusatively +accusatives +accusatorial +accusatorially +accusatory +accuse +accused +accuser +accusers +accuses +accusing +accusingly +accustom +accustomation +accustomed +accustomedness +accustoming +accustoms +ace +aced +acedia +acedias +aceldama +acellular +acentric +acephalous +acequia +acequias +acerate +acerated +acerb +acerbate +acerbated +acerbates +acerbating +acerbic +acerbically +acerbities +acerbity +acerola +acerolas +acerose +acervuli +acervulus +aces +acetabula +acetabular +acetabulum +acetal +acetaldehyde +acetals +acetamide +acetaminophen +acetanilide +acetate +acetates +acetic +acetification +acetified +acetifier +acetifies +acetify +acetifying +acetoaceticacetonic +acetone +acetones +acetonic +acetophenetidin +acetous +acetum +acetyl +acetylate +acetylated +acetylates +acetylating +acetylation +acetylative +acetylcholine +acetylcholinesterase +acetylene +acetylenic +acetylic +acetyls +acetylsalicylic +achaea +achaean +achaeans +achaemenid +achaemenids +achalasia +achates +ache +ached +achene +achenes +achenial +acheron +aches +acheulean +acheuleans +acheulian +acheulians +achier +achiest +achievable +achieve +achieved +achievement +achievements +achiever +achievers +achieves +achieving +achillea +achilles +achiness +aching +achingly +achira +achlamydeous +achlorhydria +achlorhydric +achlorophyllous +acholia +achondrite +achondritic +achondroplasia +achondroplastic +achromat +achromatic +achromatically +achromaticity +achromatin +achromatinic +achromatism +achromatize +achromatized +achromatizes +achromatizing +achromats +achromic +achy +acicula +aciculae +acicular +aciculas +aciculate +aciculated +acid +acidanthera +acidemia +acidhead +acidheads +acidic +acidifiable +acidification +acidified +acidifier +acidifiers +acidifies +acidify +acidifying +acidimeter +acidimeters +acidimetric +acidimetry +acidities +acidity +acidly +acidness +acidophil +acidophilic +acidophilus +acidosis +acidotic +acids +acidulate +acidulated +acidulates +acidulating +acidulation +acidulent +acidulous +aciduria +acidy +acinar +acing +acini +acinic +acinous +acinus +ackee +ackees +ackerman +acknowledge +acknowledgeable +acknowledged +acknowledgedly +acknowledgement +acknowledgements +acknowledges +acknowledging +acknowledgment +acknowledgments +acme +acmes +acne +acned +acock +acoelomate +acoelous +acold +acolyte +acolytes +aconite +aconites +acorn +acorns +acoustic +acoustical +acoustically +acoustician +acoustics +acoustoelectric +acoustoelectrically +acoustooptical +acoustooptically +acoustooptics +acquaint +acquaintance +acquaintances +acquaintanceship +acquaintanceships +acquainted +acquainting +acquaints +acquiesce +acquiesced +acquiescence +acquiescent +acquiescently +acquiesces +acquiescing +acquirable +acquire +acquired +acquirement +acquirements +acquirer +acquirers +acquires +acquiring +acquisition +acquisitional +acquisitions +acquisitive +acquisitively +acquisitiveness +acquisitor +acquit +acquits +acquittal +acquittals +acquittance +acquitted +acquitter +acquitters +acquitting +acre +acreage +acreages +acres +acrid +acridine +acridines +acridities +acridity +acridly +acridness +acriflavine +acrimonious +acrimoniously +acrimoniousness +acrimony +acrobat +acrobatic +acrobatically +acrobatics +acrobats +acrocentric +acrocephalic +acrocephaly +acrodont +acrodonts +acrolect +acrolein +acroleins +acromegalic +acromegalies +acromegaly +acromelic +acromion +acronym +acronymic +acronymically +acronymous +acronyms +acropetal +acropetally +acrophobia +acropolis +acropolises +acrosomal +acrosome +across +acrostic +acrostical +acrostically +acrostics +acrylate +acrylates +acrylic +acrylics +acrylonitrile +act +acta +actability +actable +actaeon +acte +acted +actes +actin +actinal +actinally +acting +actinia +actiniae +actinian +actinians +actinic +actinically +actinide +actinides +actinism +actinium +actinoid +actinolite +actinomere +actinometer +actinometers +actinometric +actinometrical +actinometry +actinomorphic +actinomorphous +actinomorphy +actinomyces +actinomycetal +actinomycete +actinomycetous +actinomycin +actinomycosis +actinomycotic +actinon +actinons +actinouranium +action +actionable +actionably +actionless +actions +actium +activate +activated +activates +activating +activation +activations +activator +activators +active +actively +activeness +actives +activism +activist +activistic +activists +activities +activity +actomyosin +actor +actorish +actors +actress +actresses +acts +actual +actualities +actuality +actualization +actualizations +actualize +actualized +actualizes +actualizing +actually +actuarial +actuarially +actuaries +actuary +actuate +actuated +actuates +actuating +actuation +actuations +actuator +actuators +acuity +aculeate +acumen +acuminate +acuminated +acuminates +acuminating +acumination +acupressure +acupuncture +acupunctured +acupunctures +acupuncturing +acupuncturist +acupuncturists +acute +acutely +acuteness +acuter +acutest +acyclic +acyclovir +acyl +acylate +acylated +acylates +acylating +acylation +acylations +acyls +ad +ada +adage +adages +adagio +adagios +adam +adamance +adamances +adamancies +adamancy +adamant +adamantine +adamantly +adamants +adapt +adaptability +adaptable +adaptableness +adaptation +adaptational +adaptationally +adaptations +adapted +adaptedness +adapter +adapters +adapting +adaption +adaptions +adaptive +adaptively +adaptiveness +adaptivity +adaptor +adaptors +adapts +adaxial +add +addable +addax +addaxes +added +addend +addenda +addends +addendum +adder +adders +addible +addict +addicted +addicting +addiction +addictions +addictive +addicts +adding +addis +addison +addition +additional +additionally +additions +additive +additively +additives +additivity +addle +addlebrained +addled +addlepated +addles +addling +address +addressability +addressable +addressed +addressee +addressees +addresser +addressers +addresses +addressing +adds +adduce +adduceable +adduced +adducer +adducers +adduces +adducing +adduct +adducted +adducting +adduction +adductive +adductor +adductors +adducts +adelaide +ademption +aden +adenectomy +adenine +adenines +adenitis +adenitises +adenocarcinoma +adenocarcinomatous +adenohypophyseal +adenohypophyses +adenohypophysial +adenohypophysis +adenoid +adenoidal +adenoids +adenoma +adenomas +adenomatoid +adenomatous +adenosine +adenosis +adenosyl +adenoviral +adenovirus +adenoviruses +adenyl +adept +adeptly +adeptness +adepts +adequacies +adequacy +adequate +adequately +adequateness +adhere +adhered +adherence +adherent +adherently +adherents +adheres +adhering +adhesion +adhesional +adhesions +adhesiotomies +adhesiotomy +adhesive +adhesively +adhesiveness +adhesives +adiabatic +adiabatically +adieu +adieus +adieux +adige +adios +adipic +adipocere +adipocyte +adipose +adiposeness +adiposity +adirondack +adirondacks +adit +adits +adjacencies +adjacency +adjacent +adjacently +adjectival +adjectivally +adjective +adjectively +adjectives +adjoin +adjoined +adjoining +adjoins +adjoint +adjoints +adjourn +adjourned +adjourning +adjournment +adjournments +adjourns +adjudge +adjudged +adjudges +adjudging +adjudicate +adjudicated +adjudicates +adjudicating +adjudication +adjudications +adjudicative +adjudicator +adjudicators +adjudicatory +adjunct +adjunction +adjunctive +adjunctly +adjuncts +adjuration +adjurations +adjuratory +adjure +adjured +adjurer +adjurers +adjures +adjuring +adjust +adjustability +adjustable +adjustably +adjusted +adjuster +adjusters +adjusting +adjustive +adjustment +adjustmental +adjustments +adjustor +adjustors +adjusts +adjutancy +adjutant +adjutants +adjuvant +adjuvants +adlerian +adlib +adlibbed +adlibs +adman +admass +admeasure +admeasured +admeasurement +admeasurements +admeasurer +admeasures +admeasuring +admen +admin +administer +administered +administering +administers +administrable +administrant +administrants +administrate +administrated +administrates +administrating +administration +administrational +administrations +administrative +administratively +administrator +administrators +administratra +administratrices +administratrix +admirability +admirable +admirableness +admirably +admiral +admirals +admiralties +admiralty +admiration +admirations +admire +admired +admirer +admirers +admires +admiring +admiringly +admissibility +admissible +admissibleness +admissibly +admission +admissions +admissive +admit +admits +admittance +admittances +admitted +admittedly +admitting +admix +admixed +admixes +admixing +admixture +admixtures +admonish +admonished +admonisher +admonishes +admonishing +admonishingly +admonishment +admonishments +admonition +admonitions +admonitorily +admonitory +adnate +adnation +adnations +adnexa +adnexal +adnominal +adnoun +adnouns +ado +adobe +adobes +adolescence +adolescent +adolescently +adolescents +adonais +adonis +adopt +adoptability +adoptable +adopted +adoptee +adoptees +adopter +adopters +adoptianism +adoptianist +adoptianists +adopting +adoption +adoptionism +adoptionist +adoptionists +adoptions +adoptive +adoptively +adopts +adorability +adorable +adorableness +adorably +adoral +adoration +adore +adored +adorer +adorers +adores +adoring +adoringly +adorn +adorned +adorner +adorners +adorning +adornment +adornments +adorns +adrenal +adrenalectomy +adrenalin +adrenaline +adrenalize +adrenalized +adrenalizes +adrenalizing +adrenally +adrenals +adrenergic +adrenergically +adrenochrome +adrenocortical +adrenocorticosteroid +adrenocorticotrophic +adrenocorticotrophin +adrenocorticotropic +adrenocorticotropin +adrenolytic +adriatic +adrift +adroit +adroitly +adroitness +ads +adscititious +adsorb +adsorbable +adsorbate +adsorbates +adsorbed +adsorbent +adsorbents +adsorbing +adsorbs +adsorption +adsorptive +adularia +adularias +adulate +adulated +adulates +adulating +adulation +adulations +adulator +adulators +adulatory +adult +adulterant +adulterants +adulterate +adulterated +adulterates +adulterating +adulteration +adulterations +adulterator +adulterators +adulterer +adulterers +adulteress +adulteresses +adulteries +adulterine +adulterous +adulterously +adultery +adulthood +adultlike +adultly +adultness +adults +adumbrate +adumbrated +adumbrates +adumbrating +adumbration +adumbrations +adumbrative +adumbratively +adust +advance +advanced +advancement +advancements +advancer +advancers +advances +advancing +advantage +advantaged +advantageous +advantageously +advantageousness +advantages +advantaging +advect +advected +advecting +advection +advections +advective +advects +advent +adventism +adventist +adventists +adventitia +adventitial +adventitious +adventitiously +adventitiousness +adventive +adventively +advents +adventure +adventured +adventurer +adventurers +adventures +adventuresome +adventuresomely +adventuresomeness +adventuress +adventuresses +adventuring +adventurism +adventurist +adventuristic +adventurists +adventurous +adventurously +adventurousness +adverb +adverbial +adverbially +adverbs +adversarial +adversaries +adversary +adversative +adversatively +adverse +adversely +adverseness +adversities +adversity +advert +adverted +advertence +advertences +advertencies +advertency +advertent +advertently +adverting +advertise +advertised +advertisement +advertisements +advertiser +advertisers +advertises +advertising +adverts +advice +advices +advisability +advisable +advisableness +advisably +advise +advised +advisedly +advisee +advisees +advisement +advisements +adviser +advisers +advises +advising +advisor +advisories +advisors +advisory +advocacy +advocate +advocated +advocates +advocating +advocation +advocative +advocator +advocators +advocatory +advowson +advowsons +adynamia +adynamias +adynamic +adyta +adytum +adz +adze +adzes +aechmea +aecia +aecial +aeciospore +aecium +aedes +aedilberct +aedile +aediles +aedine +aegean +aegeus +aegis +aeneas +aeneid +aeneous +aeolian +aeolians +aeolic +aeolus +aeon +aeonian +aeonic +aeons +aepyornis +aequorin +aerate +aerated +aerates +aerating +aeration +aerations +aerator +aerators +aerenchyma +aerial +aerialist +aerialists +aerially +aerials +aerie +aerier +aeries +aeriest +aerily +aero +aeroallergen +aeroballistic +aeroballistics +aerobat +aerobatic +aerobatics +aerobe +aerobes +aerobic +aerobically +aerobicize +aerobicized +aerobicizes +aerobicizing +aerobics +aerobiological +aerobiologically +aerobiology +aerobiosis +aerobiotic +aerobium +aeroculture +aerodrome +aerodromes +aerodynamic +aerodynamical +aerodynamically +aerodynamicist +aerodynamicists +aerodynamics +aerodyne +aerodynes +aeroembolism +aerofoil +aerofoils +aerogram +aerograms +aerographer +aerolite +aerolites +aerolith +aeroliths +aerolitic +aerologic +aerological +aerologist +aerologists +aerology +aeromagnetic +aeromagnetically +aeromagnetics +aeromechanical +aeromechanically +aeromechanics +aeromedical +aeromedicine +aerometeorograph +aerometer +aerometers +aeronaut +aeronautic +aeronautical +aeronautically +aeronautics +aeronauts +aeroneurosis +aeronomer +aeronomic +aeronomical +aeronomist +aeronomy +aeropause +aerophagia +aerophobia +aerophore +aerophyte +aeroplane +aeroplanes +aeroponics +aerosol +aerosolization +aerosolize +aerosolized +aerosolizes +aerosolizing +aerosols +aerospace +aerosphere +aerostat +aerostatic +aerostatical +aerostatics +aerostats +aerotactic +aerotaxis +aerothermodynamics +aery +aeschylus +aesculapian +aesculapius +aesop +aesopian +aesopic +aesthesia +aesthete +aesthetes +aesthetic +aesthetically +aesthetician +aestheticians +aestheticism +aestheticize +aestheticized +aestheticizes +aestheticizing +aesthetics +aestival +aestivate +aestivated +aestivates +aestivating +aestivation +aethelberht +aethelred +aether +aetheric +aethers +afar +afeard +afeared +afebrile +affability +affable +affably +affair +affaire +affaires +affairs +affect +affectability +affectable +affectation +affectations +affected +affectedly +affectedness +affecter +affecters +affecting +affectingly +affection +affectional +affectionally +affectionate +affectionately +affectionateness +affectioned +affectionless +affections +affective +affectively +affectivity +affectless +affectlessness +affects +affenpinscher +afferent +afferently +affiance +affianced +affiances +affiancing +affiant +affiants +afficionado +affidavit +affidavits +affiliate +affiliated +affiliates +affiliating +affiliation +affiliations +affine +affined +affinely +affinities +affinity +affirm +affirmable +affirmably +affirmance +affirmant +affirmation +affirmations +affirmative +affirmatively +affirmatives +affirmed +affirmer +affirmers +affirming +affirms +affix +affixable +affixal +affixation +affixations +affixed +affixer +affixers +affixes +affixial +affixing +affixment +afflatus +afflatuses +afflict +afflicted +afflicter +afflicting +affliction +afflictions +afflictive +afflictively +afflicts +affluence +affluency +affluent +affluently +affluents +afflux +affluxes +afford +affordability +affordable +affordably +afforded +affording +affords +afforest +afforestation +afforested +afforesting +afforests +affray +affrayed +affraying +affrays +affricate +affricates +affricative +affright +affrighted +affrighting +affrightment +affrights +affront +affronted +affronting +affronts +affusion +affusions +afghan +afghani +afghanistan +afghans +aficionada +aficionado +aficionados +afield +afire +aflame +aflatoxicosis +aflatoxin +afloat +aflutter +afoot +afore +aforementioned +aforesaid +aforethought +aforetime +aforetimes +afoul +afraid +afreet +afreets +afresh +africa +african +africanism +africanist +africanization +africanize +africanized +africanizes +africanizing +africans +africanus +afrikaans +afrikaner +afrikaners +afrit +afrits +afro +afros +aft +after +afterbirth +afterbirths +afterburner +afterburners +aftercare +afterclap +afterdamp +afterdeck +afterdecks +aftereffect +aftereffects +afterglow +afterimage +afterimages +afterlife +afterlives +aftermarket +aftermarkets +aftermath +aftermost +afternoon +afternoons +afterpains +afterpiece +afters +aftersensation +aftershave +aftershaves +aftershock +aftershocks +aftertaste +aftertastes +afterthought +afterthoughts +aftertime +aftertimes +afterward +afterwards +afterword +afterwork +afterworld +afterworlds +aftmost +agadir +again +against +agalactia +agama +agamas +agamemnon +agamete +agametes +agamic +agamically +agammaglobulinemia +agammaglobulinemic +agamogenesis +agamospermy +agapanthus +agape +agar +agaric +agarics +agars +agassiz +agate +agates +agave +agaves +agaze +age +aged +agedly +agedness +ageing +ageism +ageist +ageists +ageless +agelessly +agelessness +agelong +agencies +agency +agenda +agendaless +agendas +agendum +agendums +agenesis +agent +agential +agentries +agentry +agents +ager +ageratum +ageratums +agers +ages +aggie +aggies +aggiornamento +aggiornamentos +agglomerate +agglomerated +agglomerates +agglomerating +agglomeration +agglomerations +agglomerative +agglomerator +agglutinability +agglutinable +agglutinant +agglutinate +agglutinated +agglutinates +agglutinating +agglutination +agglutinations +agglutinative +agglutinin +agglutinins +agglutinogen +agglutinogenic +aggradation +aggradational +aggrade +aggraded +aggrades +aggrading +aggrandize +aggrandized +aggrandizement +aggrandizements +aggrandizer +aggrandizers +aggrandizes +aggrandizing +aggravate +aggravated +aggravates +aggravating +aggravatingly +aggravation +aggravations +aggravative +aggravator +aggravators +aggregate +aggregated +aggregately +aggregateness +aggregates +aggregating +aggregation +aggregational +aggregations +aggregative +aggregatively +aggregator +aggregators +aggress +aggressed +aggresses +aggressing +aggression +aggressions +aggressive +aggressively +aggressiveness +aggressivity +aggressor +aggressors +aggrieve +aggrieved +aggrievedly +aggrieves +aggrieving +agha +aghas +aghast +agile +agilely +agileness +agility +agin +agincourt +aging +agism +agist +agists +agita +agitate +agitated +agitatedly +agitates +agitating +agitation +agitational +agitative +agitato +agitator +agitators +agitprop +agitprops +aglaia +aglare +agleam +aglet +aglets +agley +aglitter +aglow +aglycon +aglycone +aglycones +aglycons +agnail +agnails +agnate +agnates +agnathan +agnatic +agnatically +agnation +agnations +agnes +agnize +agnized +agnizes +agnizing +agnomen +agnomens +agnomina +agnosia +agnostic +agnostically +agnosticism +agnostics +agnus +ago +agog +agon +agonal +agone +agones +agonic +agonies +agonist +agonistes +agonistic +agonistically +agonists +agonize +agonized +agonizes +agonizing +agonizingly +agony +agora +agorae +agoraphobia +agoraphobiac +agoraphobic +agoras +agorot +agoroth +agotis +agouti +agouties +agoutis +agra +agrafe +agrafes +agraffe +agraffes +agranulocytosis +agrapha +agraphia +agraphias +agraphic +agrarian +agrarianism +agrarianly +agrarians +agree +agreeability +agreeable +agreeableness +agreeably +agreed +agreeing +agreement +agreements +agrees +agribusiness +agricide +agricola +agricultural +agriculturalist +agriculturalists +agriculturally +agriculture +agricultures +agriculturist +agriculturists +agrigento +agrimation +agrimonies +agrimony +agrippa +agrippina +agrobiologic +agrobiological +agrobiologically +agrobiologist +agrobiology +agrochemical +agroforester +agroforesters +agroforestry +agroindustrial +agrologic +agrological +agrologically +agrologist +agrology +agronomic +agronomical +agronomically +agronomist +agronomists +agronomy +agrostologist +agrostology +aground +aguacate +ague +aguecheek +agues +aguish +aguishly +aguishness +ah +aha +ahab +ahead +ahem +ahems +ahimsa +ahimsas +ahistoric +ahistorical +ahmadabad +ahmedabad +ahold +aholds +ahoy +ahs +ai +aiblins +aid +aidan +aide +aided +aider +aiders +aides +aiding +aidman +aidmen +aids +aigret +aigrets +aigrette +aigrettes +aiguille +aiguilles +aiguillette +aikido +aikidos +ail +ailanthus +ailanthuses +ailed +aileron +ailerons +ailing +ailment +ailments +ails +ailurophile +ailurophobe +ailurophobia +aim +aimed +aiming +aimless +aimlessly +aimlessness +aims +ain +ain't +ainu +ainus +aioli +air +airbag +airbags +airbed +airbeds +airboat +airboats +airborne +airbrake +airbrakes +airbrush +airbrushed +airbrushes +airbrushing +airburst +airbursts +airbus +airbuses +aircraft +aircrew +aircrews +airdate +airdrome +airdromes +airdrop +airdropped +airdropping +airdrops +aired +airedale +airedales +airer +airers +aires +airfare +airfares +airfield +airfields +airflow +airfoil +airfoils +airforce +airforces +airframe +airframes +airfreight +airglow +airglows +airhead +airheads +airier +airiest +airily +airiness +airing +airings +airless +airlessness +airlift +airlifted +airlifting +airlifts +airline +airliner +airliners +airlines +airlock +airlocks +airmail +airmailed +airmailing +airmails +airman +airmanship +airmen +airmobile +airpark +airparks +airplane +airplanes +airplay +airport +airports +airpost +airpower +airs +airscrew +airscrews +airship +airships +airsick +airsickness +airside +airspace +airspeed +airspeeds +airstream +airstreams +airstrip +airstrips +airt +airted +airtight +airtightness +airtime +airting +airts +airwave +airwaves +airway +airways +airwoman +airwomen +airworthier +airworthiest +airworthiness +airworthy +airy +aisle +aisles +ait +aitch +aitchbone +aitches +aits +aix +ajar +ajax +ajuga +ajugas +akaryocyte +akbar +akee +akees +akhenaten +akhenaton +akimbo +akin +akinesia +akinetic +akkad +akrotiri +al +ala +alabama +alabaman +alabamans +alabamian +alabamians +alabaster +alabastrine +alack +alacritous +alacrity +aladdin +alae +alai +alameda +alamedas +alamein +alamo +alamode +alamodes +alamogordo +alamos +alanine +alanines +alanyl +alanyls +alar +alaric +alarm +alarmed +alarming +alarmingly +alarmism +alarmist +alarmists +alarms +alarum +alarums +alary +alas +alaska +alaskan +alaskans +alassio +alastor +alastors +alate +alb +albacore +albacores +alban +albania +albanian +albanians +albany +albatross +albatrosses +albedo +albedos +albeit +albert +alberta +albertus +albescent +albigenses +albigensian +albigensianism +albinism +albinistic +albino +albinos +albinotic +albion +albite +albites +albitic +albitical +albs +album +albumen +albumin +albuminoid +albuminous +albuminuria +albuminuric +albumose +albumoses +albums +albuquerque +alcaic +alcaics +alcaide +alcaides +alcalde +alcaldes +alcatraz +alcayde +alcaydes +alcazar +alcazars +alcestis +alchemic +alchemical +alchemically +alchemist +alchemistic +alchemistical +alchemists +alchemize +alchemized +alchemizes +alchemizing +alchemy +alcibiades +alcohol +alcoholic +alcoholically +alcoholicity +alcoholics +alcoholism +alcoholometer +alcoholometers +alcoholometry +alcohols +alcott +alcove +alcoves +alcuin +aldebaran +aldehyde +aldehydes +alder +alderman +aldermancy +aldermanic +aldermen +alders +alderwoman +alderwomen +aldicarb +aldis +aldol +aldolase +aldolases +aldols +aldose +aldoses +aldosterone +aldosteronism +aldrin +aldrins +ale +aleatoric +aleatory +alec +alecithal +aleck +alecks +alecky +alecs +alee +alegar +alegars +alehouse +alehouses +alembic +alembics +alençon +aleph +alephs +aleppo +alert +alerted +alerting +alertly +alertness +alerts +ales +aleuron +aleurone +aleurones +aleuronic +aleurons +aleut +aleutian +aleutians +aleuts +alevin +alevins +alewife +alewives +alex +alexander +alexandra +alexandria +alexandrian +alexandrine +alexandrines +alexandrite +alexandrites +alexia +alexin +alfa +alfalfa +alfas +alfilaria +alfonso +alforja +alforjas +alfred +alfredo +alfresco +alga +algae +algaecide +algaecides +algal +algaroba +algarobas +algarroba +algarrobas +algarve +algas +algebra +algebraic +algebraically +algebraist +algebraists +algebras +algeciras +alger +algeria +algerian +algerians +algicidal +algicide +algicides +algid +algidities +algidity +algiers +algin +alginate +alginates +algins +algoid +algol +algolagnia +algolagniac +algolagnic +algolagnist +algological +algologically +algologist +algologists +algology +algonquian +algonquians +algonquin +algonquins +algophobia +algorism +algorithm +algorithmic +algorithmically +algorithms +alhambra +ali +alia +alias +aliases +alibi +alibied +alibiing +alibis +alible +alicante +alice +alicyclic +alidad +alidade +alidades +alidads +alien +alienability +alienable +alienage +alienages +alienate +alienated +alienates +alienating +alienation +alienator +alienators +aliened +alienee +alienees +aliening +alienism +alienisms +alienist +alienists +alienly +alienness +alienor +alienors +aliens +aliesterase +aliform +alight +alighted +alighting +alightment +alights +align +aligned +aligner +aligners +aligning +alignment +alignments +aligns +alike +alikeness +aliment +alimental +alimentally +alimentary +alimentation +alimentative +alimented +alimenting +aliments +alimonies +alimony +aline +alined +alinement +alinements +alines +alining +aliphatic +aliquot +aliquots +alit +aliter +alive +aliveness +aliyah +aliyahs +alizarin +alizarine +alizarines +alizarins +alkahest +alkahestic +alkahestical +alkahests +alkalescence +alkalescent +alkali +alkalimeter +alkalimeters +alkalimetry +alkaline +alkalinity +alkalinization +alkalinize +alkalinized +alkalinizes +alkalinizing +alkalis +alkalization +alkalize +alkalized +alkalizes +alkalizing +alkaloid +alkaloidal +alkaloids +alkaloses +alkalosis +alkalotic +alkane +alkanes +alkanet +alkanets +alkene +alkenes +alkine +alkines +alkoxy +alkyd +alkyds +alkyl +alkylate +alkylated +alkylates +alkylating +alkylation +alkyls +alkyne +alkynes +all +alla +allah +allahabad +allamanda +allan +allantoic +allantoid +allantoides +allantoin +allantois +allargando +allay +allayed +allayer +allayers +allaying +allayment +allays +allegation +allegations +allege +allegeable +alleged +allegedly +alleger +allegers +alleges +alleghenies +allegheny +allegiance +allegiances +allegiant +alleging +allegoric +allegorical +allegorically +allegoricalness +allegories +allegorist +allegorists +allegorization +allegorize +allegorized +allegorizer +allegorizes +allegorizing +allegory +allegretto +allegrettos +allegro +allegros +allele +alleles +allelic +allelism +allelomorph +allelomorphic +allelomorphism +allelomorphs +allelopathic +allelopathy +alleluia +alleluias +allemande +allemandes +allen +allenby +aller +allergen +allergenic +allergenicity +allergens +allergic +allergies +allergist +allergists +allergy +allers +allethrin +alleviate +alleviated +alleviates +alleviating +alleviation +alleviations +alleviative +alleviator +alleviators +alleviatory +alley +alleyn +alleyne +alleys +alleyway +alleyways +alliaceous +alliance +alliances +allied +allies +alligator +alligatoring +alligators +allison +alliterate +alliterated +alliterates +alliterating +alliteration +alliterations +alliterative +alliteratively +alliterativeness +allium +alliums +alloantibody +alloantigen +allocable +allocatable +allocate +allocated +allocates +allocating +allocation +allocations +allocator +allocators +allochthonous +allocution +allocutions +allogamies +allogamous +allogamy +allogeneic +allogenic +allograft +allograph +allographic +allomerism +allomerous +allometric +allometry +allomorph +allomorphic +allomorphism +allomorphs +allonge +allonges +allonym +allonymous +allonymously +allonyms +allopath +allopathic +allopathically +allopathies +allopathist +allopathists +allopaths +allopathy +allopatric +allopatrically +allopatry +allophane +allophone +allophones +allophonic +allopolyploid +allopolyploidy +allopurinol +allosteric +allosterically +allostery +allot +allotetraploid +allotetraploidy +allotment +allotments +allotransplant +allotransplantation +allotransplanted +allotransplanting +allotransplants +allotrope +allotropes +allotropic +allotropical +allotropically +allotropy +allots +allotted +allottee +allottees +allotter +allotters +allotting +allotype +allotypes +allotypic +allotypically +allotypy +allover +allovers +allow +allowable +allowably +allowance +allowanced +allowances +allowancing +allowed +allowedly +allowing +allows +alloxan +alloxans +alloy +alloyed +alloying +alloys +allseed +allseeds +allspice +allude +alluded +alludes +alluding +allure +allured +allurement +allurements +allurer +allurers +allures +alluring +alluringly +allusion +allusions +allusive +allusively +allusiveness +alluvia +alluvial +alluvion +alluvium +alluviums +ally +allying +allyl +allylic +allyls +alma +almagest +almagests +almanac +almanacs +almandine +almandines +almandite +almandites +almeria +almightily +almightiness +almighty +almond +almonds +almoner +almoners +almost +alms +almsgiver +almsgivers +almsgiving +almshouse +almshouses +almsman +almsmen +alnico +alocasia +aloe +aloes +aloetic +aloft +alogical +alogically +alogicalness +aloha +aloin +aloins +alone +aloneness +along +alongshore +alongside +aloof +aloofly +aloofness +alopecia +alopecias +alopecic +aloud +alow +alp +alpaca +alpacas +alpenglow +alpenhorn +alpenhorns +alpenstock +alpenstocks +alpestrine +alpha +alphabet +alphabetic +alphabetical +alphabetically +alphabetization +alphabetizations +alphabetize +alphabetized +alphabetizer +alphabetizers +alphabetizes +alphabetizing +alphabets +alphameric +alphanumeric +alphanumerical +alphanumerically +alphanumerics +alphas +alpheus +alphorn +alphorns +alpine +alpinism +alpinist +alpinists +alps +already +alright +alsace +alsatian +alsatians +alsike +also +alstroemeria +alt +altai +altaic +altair +altamira +altar +altarpiece +altarpieces +altars +altazimuth +altazimuths +alter +alterability +alterable +alterableness +alterably +alteration +alterations +alterative +altercate +altercated +altercates +altercating +altercation +altercations +altered +alterer +alterers +altering +alternaria +alternate +alternated +alternately +alternateness +alternates +alternating +alternation +alternations +alternative +alternatively +alternativeness +alternatives +alternator +alternators +alters +althea +altho +althorn +althorns +although +altimeter +altimeters +altimetric +altimetry +altiplano +altiplanos +altitude +altitudes +altitudinal +altitudinous +altnaharra +alto +altocumuli +altocumulus +altogether +altoona +altos +altostratus +altricial +altruism +altruist +altruistic +altruistically +altruists +alts +alula +alulae +alular +alum +alumina +aluminas +aluminate +aluminiferous +aluminium +aluminize +aluminized +aluminizes +aluminizing +aluminosilicate +aluminous +aluminum +aluminums +alumna +alumnae +alumni +alumnus +alumroot +alumroots +alunite +alunites +alvarez +alveolar +alveolarly +alveolars +alveolate +alveolation +alveoli +alveolus +alway +always +alyssum +alyssums +alzheimer +alzheimer's +am +ama +amah +amahs +amain +amalfi +amalgam +amalgamate +amalgamated +amalgamates +amalgamating +amalgamation +amalgamations +amalgamative +amalgamator +amalgamators +amalgams +amanda +amandine +amanita +amanitas +amantadine +amanuenses +amanuensis +amaranth +amaranthine +amaranths +amarelle +amarelles +amaretto +amarettos +amarillo +amarna +amaryllis +amaryllises +amas +amass +amassable +amassed +amasser +amassers +amasses +amassing +amassment +amassments +amateur +amateurish +amateurishly +amateurishness +amateurism +amateurs +amative +amatively +amativeness +amatol +amatols +amatory +amaurosis +amaurotic +amaze +amazed +amazedly +amazedness +amazement +amazes +amazing +amazingly +amazon +amazonia +amazonian +amazonite +amazons +ambage +ambages +ambagious +ambarella +ambassador +ambassadorial +ambassadors +ambassadorship +ambassadorships +ambassadress +ambassadresses +ambeer +ambeers +amber +ambergris +amberjack +ambiance +ambiances +ambidexterity +ambidextrous +ambidextrously +ambience +ambiences +ambient +ambiguities +ambiguity +ambiguous +ambiguously +ambiguousness +ambipolar +ambisexual +ambisexuality +ambit +ambition +ambitionless +ambitions +ambitious +ambitiously +ambitiousness +ambits +ambivalence +ambivalent +ambivalently +ambiversion +ambivert +ambiverts +amble +ambled +ambler +amblers +ambles +ambling +amblygonite +amblyopia +amblyopic +ambo +amboina +amboinas +ambos +amboyna +amboynas +ambries +ambrose +ambrosia +ambrosial +ambrosially +ambrosian +ambrosias +ambrotype +ambry +ambsace +ambsaces +ambulacra +ambulacral +ambulacrum +ambulance +ambulances +ambulant +ambulate +ambulated +ambulates +ambulating +ambulation +ambulations +ambulatories +ambulatorily +ambulatory +ambuscade +ambuscaded +ambuscader +ambuscades +ambuscading +ambush +ambushed +ambusher +ambushers +ambushes +ambushing +ambushment +ameba +amebas +amebiasis +amebic +ameboid +ameer +ameers +ameliorate +ameliorated +ameliorates +ameliorating +amelioration +ameliorations +ameliorative +ameliorator +ameliorators +amelioratory +amen +amenability +amenable +amenableness +amenably +amend +amendable +amendatory +amended +amender +amenders +amending +amendment +amendments +amends +amenhotep +amenities +amenity +amenophis +amenorrhea +amenorrheic +amensalism +ament +amentaceous +amentia +amentias +amentiferous +aments +amerasian +amerasians +amerce +amerceable +amerced +amercement +amercements +amerces +amerciable +amercing +america +american +americana +americanism +americanisms +americanist +americanists +americanization +americanize +americanized +americanizes +americanizing +americanness +americans +americas +americium +amerind +amerindian +amerindians +amerinds +ames +ameslan +amethopterin +amethyst +amethystine +amethysts +ametropia +ametropic +amharic +amherst +ami +amiability +amiable +amiableness +amiably +amianthus +amicability +amicable +amicableness +amicably +amice +amices +amici +amicus +amid +amidase +amidases +amide +amides +amidic +amido +amidol +amidols +amidships +amidst +amiens +amigo +amigos +amine +amines +amino +aminoacidemia +aminoaciduria +aminobenzoic +aminobutyric +aminopeptidase +aminopeptidases +aminophenol +aminophylline +aminopterin +aminopyrine +aminopyrines +aminosalicylic +aminotransferase +amir +amirs +amish +amiss +amities +amitoses +amitosis +amitotic +amitotically +amitriptyline +amitrole +amitroles +amity +ammeter +ammeters +ammine +ammines +ammino +ammo +ammonia +ammoniac +ammoniacal +ammoniate +ammoniated +ammoniates +ammoniating +ammoniation +ammonification +ammonified +ammonifier +ammonifies +ammonify +ammonifying +ammonite +ammonites +ammonitic +ammonium +ammonoid +ammonoids +ammunition +ammunitions +amnesia +amnesiac +amnesiacs +amnesic +amnesics +amnestic +amnestied +amnesties +amnesty +amnestying +amnia +amniocenteses +amniocentesis +amniographies +amniography +amnion +amnions +amnioscope +amnioscopies +amnioscopy +amniote +amniotes +amniotic +amobarbital +amoeba +amoebae +amoebaean +amoebas +amoebiasis +amoebic +amoebocyte +amoeboid +amok +amoks +amole +amoles +among +amongst +amontillado +amontillados +amor +amoral +amoralism +amorality +amorally +amore +amoretti +amoretto +amorettos +amorist +amoristic +amorists +amorous +amorously +amorousness +amorphism +amorphous +amorphously +amorphousness +amort +amortizable +amortization +amortizations +amortize +amortized +amortizes +amortizing +amos +amosite +amosites +amount +amounted +amounting +amounts +amour +amours +amoxicillin +amp +amperage +amperages +ampere +amperes +ampersand +ampersands +amphetamine +amphetamines +amphiarthroses +amphiarthrosis +amphibia +amphibian +amphibians +amphibiotic +amphibious +amphibiously +amphibiousness +amphibole +amphiboles +amphibolic +amphibolite +amphibolitic +amphibologies +amphibology +amphibolous +amphibrach +amphictyonic +amphictyonies +amphictyony +amphidiploid +amphidiploidy +amphimacer +amphimictic +amphimixes +amphimixis +amphion +amphioxus +amphipathic +amphiploid +amphiploids +amphiploidy +amphipod +amphipods +amphiprostyle +amphisbaena +amphisbaenic +amphistylar +amphitheater +amphitheaters +amphitheatric +amphitheatrical +amphitheatrically +amphithecia +amphithecium +amphitrite +amphitropous +amphitryon +amphora +amphorae +amphoral +amphoras +amphoteric +ampicillin +ample +ampleness +ampler +amplest +amplexicaul +amplexus +amplidyne +amplidynes +amplification +amplifications +amplified +amplifier +amplifiers +amplifies +amplify +amplifying +amplitude +amplitudes +amply +ampoule +ampoules +amps +ampul +ampule +ampules +ampulla +ampullae +ampullar +ampuls +amputate +amputated +amputates +amputating +amputation +amputations +amputator +amputators +amputee +amputees +ampère +amreeta +amreetas +amrita +amritas +amritsar +amsterdam +amtrac +amtrack +amtracks +amtracs +amtrak +amuck +amulet +amulets +amun +amundsen +amusable +amuse +amused +amusedly +amusement +amusements +amuser +amusers +amuses +amusing +amusingly +amusingness +amusive +amygdala +amygdalae +amygdale +amygdales +amygdalin +amygdaline +amygdaloid +amygdaloidal +amygdule +amygdules +amyl +amylaceous +amylase +amylases +amyloid +amyloidosis +amyloids +amylolysis +amylolytic +amylopsin +amylose +amyloses +amyls +amylum +amylums +amyotonia +an +ana +anabaena +anabaenas +anabaptism +anabaptist +anabaptists +anabas +anabases +anabasis +anabatic +anabiosis +anabiotic +anabolic +anabolism +anachronic +anachronism +anachronisms +anachronistic +anachronistically +anachronous +anachronously +anaclisis +anaclitic +anacolutha +anacoluthic +anacoluthically +anacoluthon +anacoluthons +anaconda +anacondas +anacreon +anacreontic +anacruses +anacrusis +anadem +anadems +anadiploses +anadiplosis +anadromous +anaemia +anaemias +anaerobe +anaerobes +anaerobic +anaerobically +anaerobiosis +anaerobiotic +anaesthesia +anaesthesiology +anaesthetic +anaesthetics +anaesthetist +anaesthetists +anaesthetization +anaesthetizations +anaesthetize +anaesthetized +anaesthetizes +anaesthetizing +anagenesis +anaglyph +anaglyphic +anaglyphs +anagoge +anagoges +anagogic +anagogically +anagogies +anagogy +anagram +anagrammatic +anagrammatical +anagrammatically +anagrammatization +anagrammatize +anagrammatized +anagrammatizes +anagrammatizing +anagrams +anaheim +anal +analcime +analcimes +analcimic +analcite +analcites +analecta +analectic +analects +analemma +analemmas +analeptic +analgesia +analgesic +analgesics +analgetic +analities +anality +anally +analog +analogic +analogical +analogically +analogies +analogist +analogize +analogized +analogizes +analogizing +analogous +analogously +analogousness +analogs +analogue +analogues +analogy +analphabet +analphabetic +analphabetics +analphabetism +analphabets +analysand +analysands +analyses +analysis +analyst +analysts +analytic +analytical +analytically +analyticities +analyticity +analytics +analyzability +analyzable +analyzation +analyze +analyzed +analyzer +analyzers +analyzes +analyzing +anamneses +anamnesis +anamnestic +anamnestically +anamorphic +anamorphoses +anamorphosis +anapaest +anapaests +anapest +anapestic +anapests +anaphase +anaphases +anaphasic +anaphor +anaphora +anaphoras +anaphoric +anaphorically +anaphors +anaphrodisia +anaphrodisiac +anaphylactic +anaphylactically +anaphylactoid +anaphylaxes +anaphylaxis +anaplasia +anaplasmoses +anaplasmosis +anaplastic +anapsid +anapsids +anarch +anarchic +anarchical +anarchically +anarchies +anarchism +anarchist +anarchistic +anarchists +anarcho +anarchs +anarchy +anarthria +anarthric +anarthrous +anas +anasarca +anasarcas +anasarcous +anasazi +anastasia +anastigmat +anastigmatic +anastomose +anastomosed +anastomoses +anastomosing +anastomosis +anastomotic +anastrophe +anatase +anatases +anathema +anathemas +anathematization +anathematize +anathematized +anathematizes +anathematizing +anatolia +anatolian +anatolians +anatomic +anatomical +anatomically +anatomies +anatomist +anatomists +anatomization +anatomize +anatomized +anatomizes +anatomizing +anatomy +anatropous +anatto +anattos +anaxagoras +anaximander +ancestor +ancestors +ancestral +ancestrally +ancestress +ancestresses +ancestries +ancestry +anchor +anchorage +anchorages +anchored +anchoress +anchoresses +anchoret +anchorets +anchoring +anchorite +anchorites +anchoritic +anchoritically +anchorless +anchorman +anchormen +anchorperson +anchorpersons +anchors +anchorwoman +anchorwomen +anchovies +anchovy +ancien +anciens +ancient +anciently +ancientness +ancientry +ancients +ancilla +ancillae +ancillaries +ancillary +ancon +ancona +ancones +ancress +ancresses +ancylostomiasis +and +andalucía +andalusia +andalusian +andalusians +andalusite +andaman +andamanese +andamans +andante +andantes +andantino +andantinos +andean +andes +andesite +andesites +andesitic +andhra +andiron +andirons +andorra +andorran +andorrans +andouille +andradite +andrew +andrews +androcles +androecia +androecial +androecium +androgen +androgenic +androgenization +androgenize +androgenized +androgenizes +androgenizing +androgens +androgyne +androgynous +androgynously +androgyny +android +androids +andromache +andromeda +andronicus +androsterone +andré +ands +anecdota +anecdotage +anecdotal +anecdotalist +anecdotalists +anecdotally +anecdote +anecdotes +anecdotic +anecdotical +anecdotically +anecdotist +anecdotists +anechoic +anemia +anemias +anemic +anemically +anemics +anemochory +anemograph +anemography +anemometer +anemometers +anemometrical +anemometry +anemone +anemones +anemophilous +anencephalic +anencephalies +anencephaly +anent +aneroid +anesthesia +anesthesias +anesthesiologist +anesthesiologists +anesthesiology +anesthetic +anesthetically +anesthetics +anesthetist +anesthetists +anesthetization +anesthetize +anesthetized +anesthetizes +anesthetizing +anestrus +anestruses +aneuploid +aneuploidy +aneurism +aneurisms +aneurysm +aneurysmal +aneurysms +anew +anfractuosities +anfractuosity +anfractuous +anga +angaria +angarias +angaries +angary +angel +angela +angeleno +angelenos +angeles +angelfish +angelfishes +angelic +angelica +angelical +angelically +angelicas +angelico +angelina +angelologist +angelologists +angelology +angels +angelus +angeluses +anger +angered +angering +angerless +angers +angevin +angevins +angina +anginal +anginose +angiocardiographic +angiocardiography +angiogenesis +angiogram +angiograms +angiographic +angiography +angiology +angioma +angiomas +angiomata +angiomatous +angiopathies +angiopathy +angioplasties +angioplasty +angiosarcoma +angiosperm +angiosperms +angiotensin +angkor +angle +angled +angler +anglerfish +anglerfishes +anglers +angles +anglesite +angleworm +angleworms +anglia +anglian +anglians +anglican +anglicanism +anglicans +anglicanus +anglice +anglicism +anglicisms +anglicist +anglicization +anglicizations +anglicize +anglicized +anglicizes +anglicizing +angling +anglings +anglo +anglophil +anglophile +anglophiles +anglophilia +anglophiliac +anglophilic +anglophobe +anglophobes +anglophobia +anglophobic +anglophone +anglophonic +anglos +angola +angolan +angolans +angora +angoras +angostura +angoulême +angrier +angriest +angrily +angriness +angry +angst +angstrom +angstroms +anguilla +anguillan +anguillans +anguish +anguished +anguishes +anguishing +angular +angularities +angularity +angularly +angularness +angulate +angulated +angulately +angulates +angulating +angulation +angus +anguses +anhinga +anhingas +anhydride +anhydrides +anhydrite +anhydrous +anhydrously +ani +anil +anile +anilin +aniline +anilines +anilingus +anilins +anility +anils +anima +animadversion +animadversions +animadvert +animadverted +animadverting +animadverts +animal +animalcula +animalcule +animalcules +animalculum +animalism +animalist +animalistic +animality +animalization +animalize +animalized +animalizes +animalizing +animallike +animally +animals +animas +animate +animated +animatedly +animately +animateness +animates +animatic +animating +animation +animations +animato +animator +animators +animis +animism +animist +animistic +animists +animo +animosities +animosity +animus +animé +anion +anionic +anionically +anions +aniracetam +anis +anise +aniseed +aniseeds +aniseikonia +aniseikonic +anises +anisette +anisettes +anisogamete +anisogamic +anisogamy +anisometric +anisometropia +anisometropic +anisotropic +anisotropically +anisotropism +anisotropy +anjou +ankara +ankerite +ankerites +ankh +ankhs +ankle +anklebone +anklebones +ankles +anklet +anklets +ankylose +ankylosed +ankyloses +ankylosing +ankylosis +ankylotic +anlace +anlaces +anlage +anlagen +anlages +ann +anna +annalist +annalistic +annalists +annals +annan +annapolis +annapurna +annates +annatto +annattos +anne +anneal +annealed +annealing +anneals +annelid +annelidan +annelidans +annelids +annex +annexation +annexational +annexationism +annexationist +annexationists +annexations +annexed +annexes +annexing +annie +annihilability +annihilable +annihilate +annihilated +annihilates +annihilating +annihilation +annihilations +annihilative +annihilator +annihilators +annihilatory +anniversaries +anniversary +anno +annotate +annotated +annotates +annotating +annotation +annotations +annotative +annotator +annotators +announce +announced +announcement +announcements +announcer +announcers +announces +announcing +annoy +annoyance +annoyances +annoyed +annoyer +annoyers +annoying +annoyingly +annoys +annual +annualize +annualized +annualizes +annualizing +annually +annuals +annuitant +annuitants +annuities +annuity +annul +annular +annulate +annulated +annulation +annulet +annulets +annuli +annulled +annulling +annulment +annulments +annuls +annulus +annuluses +annum +annunciate +annunciated +annunciates +annunciating +annunciation +annunciations +annunciator +annunciators +annunciatory +annus +anoa +anoas +anodal +anodally +anode +anodes +anodic +anodically +anodization +anodize +anodized +anodizes +anodizing +anodyne +anodynes +anoint +anointed +anointer +anointers +anointing +anointment +anointments +anoints +anole +anoles +anomalies +anomalistic +anomalistical +anomalistically +anomalous +anomalously +anomalousness +anomaly +anomic +anomie +anomy +anon +anonym +anonymities +anonymity +anonymous +anonymously +anonymousness +anonyms +anopheles +anopheline +anorak +anoraks +anorectic +anorectics +anoretic +anorexia +anorexic +anorexics +anorexigenic +anorthic +anorthite +anorthitic +anorthosite +anosmia +anosmias +anosmic +anosognosia +anosognosic +anosognosics +another +anouilh +anovulant +anovulation +anovulatory +anoxemia +anoxemias +anoxemic +anoxia +anoxic +ansate +anschluss +anselm +anserine +anson +answer +answerability +answerable +answerableness +answerably +answerback +answered +answerer +answerers +answering +answers +ant +anta +antacid +antacids +antae +antaean +antagonism +antagonisms +antagonist +antagonistic +antagonistically +antagonists +antagonize +antagonized +antagonizes +antagonizing +antarctic +antarctica +antares +antas +ante +anteater +anteaters +antebellum +antecede +anteceded +antecedence +antecedent +antecedently +antecedents +antecedes +anteceding +antecessor +antecessors +antechamber +antechambers +antechoir +antechoirs +anted +antedate +antedated +antedates +antedating +antediluvian +antediluvians +anteed +antefix +antefixa +antefixal +antefixes +anteing +antelope +antelopes +antemeridian +antemortem +antenatal +antenatally +antenna +antennae +antennal +antennas +antennule +antependia +antependium +antepenult +antepenultima +antepenultimate +antepenultimates +antepenults +anterior +anteriorly +anteroom +anterooms +antes +anthelia +anthelion +anthelmintic +anthelmintics +anthem +anthemia +anthemion +anthems +anther +antheridia +antheridium +antherozoid +anthers +anthesis +anthill +anthills +anthocyanin +anthological +anthologies +anthologist +anthologists +anthologize +anthologized +anthologizer +anthologizers +anthologizes +anthologizing +anthology +anthony +anthozoan +anthozoic +anthracene +anthraces +anthracis +anthracite +anthracites +anthracitic +anthracnose +anthracosis +anthrax +anthropic +anthropical +anthropocentric +anthropocentrically +anthropocentricity +anthropocentrism +anthropogenesis +anthropogenic +anthropoid +anthropoidal +anthropoids +anthropologic +anthropological +anthropologically +anthropologist +anthropologists +anthropology +anthropometric +anthropometrical +anthropometrically +anthropometrist +anthropometry +anthropomorph +anthropomorphic +anthropomorphically +anthropomorphism +anthropomorphist +anthropomorphists +anthropomorphization +anthropomorphize +anthropomorphized +anthropomorphizes +anthropomorphizing +anthropomorphous +anthropomorphs +anthropopathism +anthropophagi +anthropophagic +anthropophagous +anthropophagus +anthropophagy +anthroposophical +anthroposophist +anthroposophy +anthurium +anti +antiabortion +antiabortionist +antiabortionists +antiacademic +antiadministration +antiaggression +antiaging +antiaircraft +antialcohol +antialcoholism +antialien +antiallergenic +antiallergic +antianemia +antianxiety +antiapartheid +antiaphrodisiac +antiaristocratic +antiarrhythmic +antiarthritic +antiarthritis +antiassimilation +antiasthma +antiatom +antiatoms +antiauthoritarian +antiauthoritarianism +antiauthority +antibacklash +antibacterial +antibaryon +antibes +antibias +antibillboard +antibioses +antibiosis +antibiotic +antibiotically +antibiotics +antiblack +antiblackism +antibodies +antibody +antiboss +antibourgeois +antiboycott +antibug +antibureaucratic +antiburglar +antiburglary +antibusiness +antibusing +antic +anticaking +antically +anticancer +anticancerous +anticapitalism +anticapitalist +anticapitalists +anticarcinogen +anticarcinogenic +anticaries +anticatalyst +anticathode +anticellulite +anticensorship +antichlor +antichloristic +anticholesterol +anticholinergic +anticholinesterase +antichrist +antichrists +antichurch +anticigarette +anticipant +anticipants +anticipatable +anticipate +anticipated +anticipates +anticipating +anticipation +anticipations +anticipative +anticipatively +anticipator +anticipators +anticipatory +anticity +anticlassical +anticlerical +anticlericalism +anticlimactic +anticlimactical +anticlimactically +anticlimax +anticlimaxes +anticlinal +anticline +anticlines +anticling +anticlockwise +anticlotting +anticoagulant +anticoagulants +anticoagulation +anticodon +anticold +anticollision +anticolonial +anticolonialism +anticolonialist +anticolonialists +anticommercial +anticommercialism +anticommunism +anticommunist +anticommunists +anticompetitive +anticonglomerate +anticonservation +anticonservationist +anticonservationists +anticonsumer +anticonventional +anticonvulsant +anticonvulsive +anticorporate +anticorrosion +anticorrosive +anticorrosives +anticorruption +anticounterfeiting +anticrack +anticreative +anticrime +anticruelty +antics +anticult +anticultural +anticyclone +anticyclones +anticyclonic +antidandruff +antidefamation +antidemocratic +antidepressant +antidepressants +antidepression +antidepressive +antiderivative +antiderivatives +antidesegregation +antidesertification +antidesiccant +antideuteron +antidevelopment +antidiabetic +antidiarrheal +antidilution +antidiscrimination +antidisestablishmentarian +antidisestablishmentarianism +antidogmatic +antidotal +antidotally +antidote +antidotes +antidraft +antidumping +antieconomic +antieducational +antiegalitarian +antielectron +antielectrons +antielite +antielitism +antielitist +antielitists +antiemetic +antientropic +antienvironmental +antienzymatic +antienzyme +antienzymic +antiepilepsy +antiepileptic +antierotic +antiestablishment +antiestrogen +antietam +antievolution +antievolutionary +antievolutionism +antievolutionist +antievolutionists +antifamily +antifascism +antifascist +antifascists +antifashion +antifashionable +antifatigue +antifebrile +antifederalism +antifederalist +antifemale +antifeminine +antifeminism +antifeminist +antifeminists +antifertility +antifilibuster +antiflu +antifluoridationist +antifoam +antifoaming +antifogging +antiforeclosure +antiforeign +antiforeigner +antiformalist +antiformalists +antifouling +antifraud +antifreeze +antifreezes +antifriction +antifundamentalist +antifundamentalists +antifungal +antifur +antigalaxy +antigambling +antigay +antigen +antigene +antigenes +antigenic +antigenically +antigenicity +antigens +antiglare +antiglobulin +antigone +antigovernment +antigravity +antigreenmail +antigrowth +antigua +antiguan +antiguans +antiguerrilla +antigun +antihelium +antihemophilic +antihero +antiheroes +antiheroic +antiheroine +antiheroism +antiherpes +antihierarchical +antihijack +antihistamine +antihistamines +antihistaminic +antihistorical +antihomosexual +antihuman +antihumanism +antihumanistic +antihumanitarian +antihunter +antihunting +antihydrogen +antihypertensive +antihypertensives +antihysteric +antijam +antijamming +antikickback +antiknock +antiknocks +antilabor +antileak +antileprosy +antilepton +antileukemic +antiliberal +antiliberalism +antilibertarian +antiliquor +antiliterate +antilitter +antilittering +antilles +antilock +antilog +antilogarithm +antilogarithmic +antilogarithms +antilogical +antilogies +antilogs +antilogy +antilynching +antimacassar +antimacassars +antimacho +antimagnetic +antimalaria +antimalarial +antimalarials +antimale +antiman +antimanagement +antimarijuana +antimarket +antimaterialism +antimaterialist +antimaterialists +antimatter +antimechanist +antimechanists +antimere +antimeres +antimerger +antimeric +antimetabolic +antimetabolite +antimetaphysical +antimicrobial +antimilitarism +antimilitarist +antimilitarists +antimilitary +antimiscegenation +antimissile +antimitotic +antimodern +antimodernist +antimodernists +antimonarchical +antimonarchist +antimonarchists +antimonial +antimonopolist +antimonopolists +antimonopoly +antimony +antimosquito +antimusical +antinarrative +antinational +antinationalist +antinationalists +antinatural +antinature +antinausea +antineoplastic +antinepotism +antineutrino +antineutrinos +antineutron +antineutrons +anting +antings +antinodal +antinode +antinodes +antinoise +antinome +antinomian +antinomianism +antinomians +antinomic +antinomies +antinomy +antinovel +antinovelist +antinuclear +antinucleon +antinucleons +antiobesity +antiobscenity +antioch +antiochus +antiorganization +antioxidant +antioxidants +antipapal +antiparasitic +antiparticle +antiparticles +antiparty +antipasti +antipasto +antipastos +antipathetic +antipathetical +antipathetically +antipathies +antipathy +antiperiodic +antipersonnel +antiperspirant +antiperspirants +antipesticide +antiphlogistic +antiphon +antiphonal +antiphonally +antiphonaries +antiphonary +antiphonies +antiphons +antiphony +antiphrases +antiphrasis +antipiracy +antiplague +antiplaque +antipleasure +antipneumococcal +antipoaching +antipodal +antipode +antipodean +antipodeans +antipodes +antipoetic +antipolice +antipolitical +antipolitics +antipollution +antipollutionist +antipope +antipopes +antipopular +antiporn +antipornographic +antipornography +antipot +antipoverty +antipredator +antipress +antiprofiteering +antiprogressive +antiprostitution +antiproton +antiprotons +antipruritic +antipsychotic +antipsychotics +antipyresis +antipyretic +antipyretics +antipyrine +antiquarian +antiquarianism +antiquarians +antiquaries +antiquark +antiquary +antiquate +antiquated +antiquatedness +antiquates +antiquating +antiquation +antique +antiqued +antiquely +antiqueness +antiquer +antiquers +antiques +antiquing +antiquities +antiquity +antirabies +antirachitic +antiracism +antiracist +antiracists +antiracketeering +antiradar +antiradical +antiradicalism +antirape +antirational +antirationalism +antirationalist +antirationalists +antirationality +antirealism +antirealist +antirealists +antirecession +antirecessionary +antired +antireductionism +antireductionist +antireductionists +antireflection +antireflective +antireform +antiregulatory +antireligion +antireligious +antirevolutionary +antirheumatic +antirheumatics +antiriot +antiritualism +antirock +antiroll +antiromantic +antiromanticism +antiroyalist +antiroyalists +antirrhinum +antirrhinums +antirust +antis +antisatellite +antischizophrenia +antischizophrenic +antiscience +antiscientific +antiscorbutic +antisecrecy +antisecretory +antisegregation +antiseizure +antisentimental +antiseparatist +antiseparatists +antisepses +antisepsis +antiseptic +antiseptically +antiseptics +antisera +antiserum +antiserums +antisex +antisexist +antisexists +antisexual +antisexuality +antishark +antiship +antishock +antishoplifting +antiskid +antislavery +antisleep +antislip +antismog +antismoke +antismoker +antismoking +antismuggling +antismut +antisnob +antisocial +antisocialist +antisocialists +antisocially +antispasmodic +antispasmodics +antispeculation +antispeculative +antispending +antistate +antistatic +antisthenes +antistick +antistory +antistress +antistrike +antistrophe +antistrophes +antistrophic +antistrophically +antistudent +antisubmarine +antisubsidy +antisubversion +antisubversive +antisuicide +antisymmetric +antisyphilitic +antitakeover +antitank +antitarnish +antitax +antitechnological +antitechnology +antiterrorism +antiterrorist +antiterrorists +antitheft +antitheoretical +antitheses +antithesis +antithetic +antithetical +antithetically +antithyroid +antitobacco +antitotalitarian +antitoxic +antitoxin +antitoxins +antitrade +antitrades +antitraditional +antitrust +antitruster +antitrusters +antitubercular +antituberculosis +antituberculous +antitumor +antitumoral +antitussive +antitype +antitypes +antityphoid +antitypical +antiulcer +antiunemployment +antiunion +antiuniversity +antiurban +antivenin +antivenins +antiviolence +antiviral +antivirus +antivitamin +antivivisection +antivivisectionist +antivivisectionists +antiwar +antiwear +antiwelfare +antiwhaling +antiwoman +antiwrinkle +antler +antlered +antlers +antoinette +antonine +antonines +antoninus +antonio +antonomasia +antony +antonym +antonymic +antonymous +antonyms +antonymy +antra +antral +antre +antres +antrim +antrorse +antrorsely +antrum +ants +antsier +antsiest +antsy +antwerp +anubis +anuran +anurans +anuresis +anuretic +anuria +anurias +anuric +anurous +anus +anuses +anvil +anvils +anxieties +anxiety +anxious +anxiously +anxiousness +any +anybody +anybody's +anyhow +anymore +anyone +anyone's +anyplace +anything +anytime +anyway +anyways +anywhere +anywise +anzio +aorist +aoristic +aoristically +aorists +aorta +aortae +aortal +aortas +aortic +aortographic +aortography +aosta +aoudad +aoudads +apace +apache +apachean +apaches +apanage +apanages +aparejo +aparejos +apart +apartheid +apartment +apartmental +apartments +apartness +apatetic +apathetic +apathetical +apathetically +apathy +apatite +apatites +ape +apeak +aped +apelike +apennine +apennines +aper +aperient +aperients +aperiodic +aperiodically +aperiodicity +aperitif +aperitifs +apertural +aperture +apertures +aperçu +aperçus +apes +apetalous +apetaly +apex +apexes +aphaereses +aphaeresis +aphaeretic +aphagia +aphagias +aphanite +aphanites +aphanitic +aphasia +aphasiac +aphasiacs +aphasias +aphasic +aphasics +aphelia +aphelion +apheresis +apheses +aphesis +aphetic +aphetically +aphid +aphides +aphidian +aphidians +aphids +aphis +aphonia +aphonias +aphonic +aphorism +aphorisms +aphorist +aphoristic +aphoristically +aphorists +aphorize +aphorized +aphorizes +aphorizing +aphotic +aphrodisiac +aphrodisiacal +aphrodisiacs +aphrodite +aphyllies +aphyllous +aphylly +apian +apiarian +apiaries +apiarist +apiarists +apiary +apical +apically +apices +apiculate +apicultural +apiculture +apiculturist +apiece +aping +apio +apios +apis +apish +apishly +apishness +apivorous +aplacental +aplanatic +aplasia +aplasias +aplastic +aplenty +aplite +aplites +aplitic +aplomb +apnea +apneas +apneic +apnoea +apnoeas +apocalypse +apocalypses +apocalyptic +apocalyptical +apocalyptically +apocalypticism +apocalyptism +apocalyptist +apocalyptists +apocarpies +apocarpous +apocarpy +apochromatic +apocope +apocopes +apocrine +apocrypha +apocryphal +apocryphally +apocryphalness +apodal +apodeictic +apodictic +apodictically +apodoses +apodosis +apodous +apoenzyme +apogamic +apogamies +apogamous +apogamy +apogean +apogee +apogees +apolitical +apolitically +apollinaris +apollo +apollonian +apollos +apollyon +apologetic +apologetically +apologetics +apologia +apologias +apologies +apologist +apologists +apologize +apologized +apologizer +apologizers +apologizes +apologizing +apologue +apologues +apology +apolune +apolunes +apomict +apomictic +apomictically +apomicts +apomixis +apomixises +apomorphine +aponeuroses +aponeurosis +aponeurotic +apophasis +apophthegm +apophthegms +apophyge +apophyges +apophyllite +apophysate +apophyseal +apophyses +apophysis +apoplectic +apoplectically +apoplexy +aport +aposematic +aposematically +aposiopeses +aposiopesis +aposiopetic +aposporous +apospory +apostasies +apostasy +apostate +apostates +apostatize +apostatized +apostatizes +apostatizing +apostle +apostlehood +apostles +apostleship +apostleships +apostolate +apostolic +apostolicity +apostrophe +apostrophes +apostrophic +apostrophize +apostrophized +apostrophizes +apostrophizing +apothecaries +apothecary +apothecia +apothecial +apothecium +apothegm +apothegmatic +apothegmatical +apothegmatically +apothegms +apothem +apothems +apotheoses +apotheosis +apotheosize +apotheosized +apotheosizes +apotheosizing +apotropaic +apotropaically +appal +appalachia +appalachian +appalachians +appall +appalled +appalling +appallingly +appalls +appaloosa +appaloosas +appals +appanage +appanages +apparat +apparatchik +apparatchiki +apparatchiks +apparats +apparatus +apparatuses +apparel +appareled +appareling +apparelled +apparelling +apparels +apparent +apparently +apparentness +apparition +apparitional +apparitions +apparitor +apparitors +appeal +appealability +appealable +appealed +appealer +appealers +appealing +appealingly +appeals +appear +appearance +appearances +appeared +appearing +appears +appeasable +appeasably +appease +appeased +appeasement +appeasements +appeaser +appeasers +appeases +appeasing +appel +appellant +appellants +appellate +appellation +appellations +appellative +appellatively +appellee +appellees +appels +append +appendage +appendages +appendant +appendectomies +appendectomy +appended +appendices +appendicitis +appendicular +appending +appendix +appendixes +appends +apperceive +apperceived +apperceives +apperceiving +apperception +apperceptive +appertain +appertained +appertaining +appertains +appestat +appestats +appetence +appetencies +appetency +appetent +appetite +appetites +appetitive +appetizer +appetizers +appetizing +appetizingly +appian +applaud +applaudable +applaudably +applauded +applauder +applauders +applauding +applauds +applause +applauses +apple +applejack +applejacks +apples +applesauce +appliance +appliances +applicability +applicable +applicably +applicant +applicants +application +applications +applicative +applicatively +applicator +applicators +applicatory +applied +applier +appliers +applies +appliqué +appliquéd +appliquéing +appliqués +apply +applying +appoggiatura +appoint +appointed +appointee +appointees +appointing +appointive +appointment +appointments +appointor +appoints +appomattox +apportion +apportioned +apportioning +apportionment +apportionments +apportions +appose +apposed +apposes +apposing +apposite +appositely +appositeness +apposition +appositional +appositionally +appositions +appositive +appositively +appositives +appraisable +appraisal +appraisals +appraise +appraised +appraisement +appraisements +appraiser +appraisers +appraises +appraising +appraisingly +appreciable +appreciably +appreciate +appreciated +appreciates +appreciating +appreciation +appreciations +appreciative +appreciatively +appreciativeness +appreciator +appreciators +appreciatory +apprehend +apprehended +apprehending +apprehends +apprehensible +apprehensibly +apprehension +apprehensions +apprehensive +apprehensively +apprehensiveness +apprentice +apprenticed +apprentices +apprenticeship +apprenticeships +apprenticing +appressed +apprise +apprised +apprises +apprising +apprize +apprized +apprizes +apprizing +approach +approachability +approachable +approached +approaches +approaching +approbate +approbated +approbates +approbating +approbation +approbations +approbative +approbatory +appropriable +appropriate +appropriated +appropriately +appropriateness +appropriates +appropriating +appropriation +appropriations +appropriative +appropriator +appropriators +approvable +approvably +approval +approvals +approve +approved +approver +approvers +approves +approving +approvingly +approximate +approximated +approximately +approximates +approximating +approximation +approximations +approximative +approximatively +appurtenance +appurtenances +appurtenant +appétit +apractic +apraxia +apraxias +apraxic +apricot +apricots +april +aprils +apriority +apron +aproned +aproning +aprons +apropos +après +apse +apses +apsidal +apsides +apsis +apt +apteral +apterous +apteryx +apteryxes +aptitude +aptitudes +aptitudinal +aptitudinally +aptly +aptness +apulia +apyrase +apyrases +apéritif +apéritifs +aqua +aquacade +aquacades +aquacultural +aquaculture +aquaculturist +aquae +aquafortis +aqualung +aqualungs +aquamarine +aquamarines +aquanaut +aquanauts +aquaplane +aquaplaned +aquaplaner +aquaplaners +aquaplanes +aquaplaning +aquarelle +aquarellist +aquaria +aquarian +aquarians +aquarist +aquarists +aquarium +aquariums +aquarius +aquas +aquatic +aquatically +aquatics +aquatint +aquatinted +aquatinter +aquatinting +aquatintist +aquatints +aquavit +aqueduct +aqueducts +aqueous +aquiculture +aquifer +aquiferous +aquifers +aquila +aquilegia +aquiline +aquilinity +aquinas +aquitaine +aquiver +arab +arabesque +arabesques +arabia +arabian +arabians +arabic +arabicize +arabicized +arabicizes +arabicizing +arability +arabinose +arabist +arabists +arabization +arabize +arabized +arabizes +arabizing +arable +arables +arabs +araby +arachne +arachnid +arachnidan +arachnidans +arachnids +arachnoid +arachnoids +arachnophobia +aragon +aragonese +aragonite +arak +araks +aralia +aramaean +aramaic +arame +aramean +arapaho +arapahoe +arapahoes +arapahos +arapaima +arapaimas +ararat +araucanian +araucaria +arawak +arawakan +arawakans +arawaks +arbalest +arbalester +arbalests +arbalist +arbalists +arbiter +arbiters +arbitrable +arbitrage +arbitraged +arbitrager +arbitragers +arbitrages +arbitrageur +arbitrageurs +arbitraging +arbitral +arbitrament +arbitraments +arbitrarily +arbitrariness +arbitrary +arbitrate +arbitrated +arbitrates +arbitrating +arbitration +arbitrational +arbitrations +arbitrative +arbitrator +arbitrators +arbor +arboreal +arboreally +arboreous +arbores +arborescence +arborescent +arboreta +arboretum +arboretums +arboricultural +arboriculture +arboricultures +arborist +arborists +arborization +arborize +arborized +arborizes +arborizing +arbors +arborvitae +arboviral +arbovirology +arbovirus +arbutus +arbutuses +arc +arcade +arcaded +arcades +arcadia +arcadian +arcadians +arcadias +arcading +arcady +arcana +arcane +arcanum +arcanums +arccosine +arced +arch +archaean +archaeans +archaeologic +archaeological +archaeologically +archaeologist +archaeologists +archaeology +archaeopteryx +archaic +archaically +archaism +archaisms +archaist +archaistic +archaists +archaize +archaized +archaizer +archaizers +archaizes +archaizing +archangel +archangelic +archangels +archbishop +archbishopric +archbishoprics +archbishops +archconservative +archconservatives +archdeacon +archdeaconate +archdeaconries +archdeaconry +archdeacons +archdeaconship +archdiocesan +archdiocese +archdioceses +archducal +archduchess +archduchesses +archduchies +archduchy +archduke +archdukes +archean +arched +archegonia +archegonial +archegoniate +archegonium +archencephalon +archenemies +archenemy +archenteric +archenteron +archeological +archeologically +archeologist +archeologists +archeology +archeozoic +archer +archerfish +archerfishes +archeries +archers +archery +arches +archetypal +archetypally +archetype +archetypes +archetypical +archetypically +archfiend +archfiends +archidiaconal +archidiaconate +archidiaconates +archiepiscopal +archiepiscopality +archiepiscopally +archiepiscopate +archiepiscopates +archil +archils +archimandrite +archimandrites +archimedean +archimedes +archine +archines +arching +archipelagic +archipelago +archipelagoes +archipelagos +architect +architectonic +architectonically +architectonics +architects +architectural +architecturally +architecture +architectures +architrave +architraves +archival +archive +archived +archives +archiving +archivist +archivists +archivolt +archivolts +archliberal +archly +archness +archon +archons +archonship +archonships +archosaur +archosaurs +archpriest +archrival +archway +archways +arciform +arcing +arcked +arcking +arco +arcs +arcsine +arctangent +arctic +arctically +arctics +arcturus +arcuate +arcuated +arcuately +arcuation +ardeb +ardebs +ardencies +ardency +ardennes +ardent +ardently +ardor +ardors +arduous +arduously +arduousness +are +area +areal +areally +areas +areaway +areaways +areca +arecas +aren +aren't +arena +arenaceous +arenas +arenicolous +areola +areolae +areolar +areolas +areolate +areolation +areole +areoles +areopagite +areopagites +areopagitic +areopagus +ares +arete +aretes +arethusa +arethusas +argali +argalis +argent +argentic +argentiferous +argentina +argentine +argentinean +argentineans +argentines +argentinian +argentinians +argentite +argentous +argents +argil +argillaceous +argillite +argils +arginase +arginases +arginine +arginines +argive +argives +argo +argol +argols +argon +argonaut +argonauts +argos +argosies +argosy +argot +argots +arguable +arguably +argue +argued +arguer +arguers +argues +argufied +argufier +argufiers +argufies +argufy +argufying +arguing +argument +argumenta +argumentation +argumentative +argumentatively +argumentativeness +argumentive +arguments +argumentum +argus +arguses +argyle +argyles +argyll +argylls +argyrol +arhat +arhats +arhatship +aria +ariadne +arian +arianism +arians +arias +ariboflavinosis +arid +aridity +aridness +ariel +ariels +aries +arietta +ariettas +ariette +ariettes +aright +arikara +arikaras +aril +ariled +arillate +arils +arimathaea +arimathea +arioso +ariosos +ariosto +arise +arisen +arises +arising +arista +aristae +aristarchus +aristas +aristate +aristides +aristocracies +aristocracy +aristocrat +aristocratic +aristocratical +aristocratically +aristocrats +aristophanes +aristophanic +aristotelean +aristotelian +aristotelianism +aristotelians +aristotle +arithmetic +arithmetical +arithmetically +arithmetician +arithmeticians +arithmetics +arizona +arizonan +arizonans +arizonian +arizonians +ark +arkansan +arkansans +arkansas +arks +arkwright +arles +arm +armada +armadas +armadillo +armadillos +armageddon +armagh +armament +armamentaria +armamentarium +armamentariums +armaments +armature +armatures +armband +armbands +armchair +armchairs +armed +armenia +armenian +armenians +armentières +armer +armers +armet +armets +armful +armfuls +armhole +armholes +armies +armiger +armigers +arming +arminian +arminianism +arminians +arminius +armistice +armistices +armless +armlet +armlets +armlike +armload +armloads +armoire +armoires +armor +armored +armorer +armorers +armorial +armorially +armorials +armories +armoring +armorless +armors +armory +armpit +armpits +armrest +armrests +arms +armsful +armstrong +army +armyworm +armyworms +arnatto +arnattos +arne +arnheim +arnhem +arnica +arnicas +arno +arnold +aroid +aroids +aroint +arointed +arointing +aroints +aroma +aromas +aromatherapies +aromatherapist +aromatherapists +aromatherapy +aromatic +aromatically +aromaticity +aromaticness +aromatics +aromatization +aromatize +aromatized +aromatizes +aromatizing +arose +around +arousal +arousals +arouse +aroused +arouses +arousing +arpanet +arpeggio +arpeggios +arpent +arpents +arquebus +arquebuses +arracacha +arrack +arracks +arraign +arraigned +arraigner +arraigning +arraignment +arraignments +arraigns +arrange +arranged +arrangement +arrangements +arranger +arrangers +arranges +arranging +arrant +arrantly +arras +array +arrayal +arrayals +arrayed +arrayer +arrayers +arraying +arrays +arrear +arrearage +arrears +arrest +arrestant +arrestants +arrested +arrestee +arrestees +arrester +arresters +arresting +arrestingly +arrestment +arrestments +arrestor +arrestors +arrests +arrhythmia +arrhythmias +arrhythmic +arrhythmically +arriba +arris +arrises +arrival +arrivals +arrive +arrived +arrivederci +arriver +arrivers +arrives +arriving +arriviste +arrière +arroba +arrobas +arrogance +arrogant +arrogantly +arrogate +arrogated +arrogates +arrogating +arrogation +arrogations +arrogative +arrogator +arrondissement +arrondissements +arrow +arrowed +arrowhead +arrowheads +arrowing +arrowroot +arrowroots +arrows +arrowwood +arrowworm +arrowworms +arrowy +arroyo +arroyos +arse +arsenal +arsenals +arsenate +arsenates +arsenic +arsenical +arsenide +arsenides +arsenious +arsenite +arsenites +arsenopyrite +arses +arshin +arshins +arsine +arsines +arsis +arson +arsonist +arsonists +arsonous +arsons +arsphenamine +art +artaxerxes +arte +artel +artels +artemis +artemisia +arterial +arterialization +arterialize +arterialized +arterializes +arterializing +arterially +arterials +arteries +arteriogram +arteriograms +arteriographic +arteriography +arteriolar +arteriole +arterioles +arterioloscleroses +arteriolosclerosis +arterioscleroses +arteriosclerosis +arteriosclerotic +arteriovenous +arteritis +artery +artesian +artful +artfully +artfulness +arthralgia +arthralgic +arthritic +arthritically +arthritics +arthritides +arthritis +arthrodesis +arthrogram +arthrograms +arthrography +arthrogryposis +arthromere +arthromeric +arthropathy +arthropod +arthropodal +arthropodous +arthropods +arthroscope +arthroscopic +arthroscopically +arthroscopies +arthroscopy +arthroses +arthrosis +arthrospore +arthrotomy +arthur +arthurian +artichoke +artichokes +article +articled +articles +articling +articulable +articulacy +articular +articularly +articulate +articulated +articulately +articulateness +articulates +articulating +articulation +articulations +articulative +articulator +articulators +articulatory +artier +artiest +artifact +artifacts +artifactual +artifice +artificer +artificers +artifices +artificial +artificialities +artificiality +artificially +artificialness +artilleries +artillerist +artillerists +artillery +artilleryman +artillerymen +artily +artiness +artiodactyl +artiodactylous +artisan +artisans +artisanship +artist +artiste +artistes +artistic +artistically +artistry +artists +artless +artlessly +artlessness +artois +arts +artwork +artworks +arty +aruba +arugula +arum +arums +arunachal +aryan +aryans +aryl +arytenoid +arytenoidal +arête +arêtes +as +asafetida +asafetidas +asafoetida +asafoetidas +asbestic +asbestine +asbestos +asbestoses +asbestosis +asbestotic +asbestus +asbestuses +ascariasis +ascarid +ascarides +ascarids +ascaris +ascend +ascendable +ascendance +ascendancy +ascendant +ascendantly +ascendants +ascended +ascendence +ascendency +ascendent +ascendents +ascender +ascenders +ascendible +ascending +ascendingly +ascends +ascension +ascensional +ascensions +ascensive +ascent +ascents +ascertain +ascertainable +ascertainableness +ascertainably +ascertained +ascertaining +ascertainment +ascertainments +ascertains +asceses +ascesis +ascetic +ascetical +ascetically +asceticism +ascetics +asci +ascidia +ascidian +ascidians +ascidiate +ascidiform +ascidium +ascii +ascites +ascitic +ascocarp +ascocarps +ascogonia +ascogonium +ascomycete +ascomycetes +ascomycetous +ascorbate +ascorbic +ascospore +ascosporic +ascosporous +ascot +ascots +ascribable +ascribe +ascribed +ascribes +ascribing +ascription +ascriptions +ascriptive +ascus +asdic +asdics +asepalous +asepses +asepsis +aseptic +aseptically +asepticism +asexual +asexuality +asexualize +asexualized +asexualizes +asexualizing +asexually +ash +ashamed +ashamedly +ashanti +ashcan +ashcans +ashed +ashen +asher +ashes +asheville +ashier +ashiest +ashiness +ashing +ashlar +ashlars +ashless +ashore +ashram +ashrams +ashton +ashtoreth +ashtray +ashtrays +ashy +asia +asian +asianization +asians +asiatic +asiatics +aside +asides +asinine +asininely +asininity +asinorum +ask +askance +askant +asked +asker +askers +askeses +askesis +askew +askewness +asking +asks +aslant +asleep +aslope +aslosh +asmodeus +asocial +asp +asparaginase +asparagine +asparagus +aspartame +aspartate +aspartic +aspartokinase +aspasia +aspect +aspects +aspectual +aspen +aspens +asperate +asperated +asperates +asperating +asperges +aspergill +aspergilla +aspergilli +aspergillosis +aspergillum +aspergillums +aspergillus +asperities +asperity +asperse +aspersed +asperses +aspersing +aspersion +aspersions +asphalt +asphalted +asphaltic +asphalting +asphaltite +asphaltites +asphalts +asphaltum +aspheric +aspherical +asphodel +asphodels +asphyxia +asphyxiant +asphyxiate +asphyxiated +asphyxiates +asphyxiating +asphyxiation +asphyxiations +asphyxiator +asphyxiators +aspic +aspics +aspidistra +aspidistras +aspirant +aspirants +aspirate +aspirated +aspirates +aspirating +aspiration +aspirations +aspirator +aspirators +aspiratory +aspire +aspired +aspirer +aspirers +aspires +aspirin +aspiring +aspiringly +aspirins +asps +asquint +ass +assagai +assagais +assai +assail +assailable +assailableness +assailant +assailants +assailed +assailer +assailers +assailing +assailment +assails +assais +assam +assassin +assassinate +assassinated +assassinates +assassinating +assassination +assassinations +assassinative +assassinator +assassins +assault +assaulted +assaulter +assaulters +assaulting +assaultive +assaultively +assaultiveness +assaults +assay +assayable +assayed +assayer +assayers +assaying +assays +assegai +assegais +assemblage +assemblages +assemblagist +assemble +assembled +assembler +assemblers +assembles +assemblies +assembling +assembly +assemblyman +assemblymen +assemblywoman +assemblywomen +assent +assentation +assented +assenter +assenters +assenting +assentingly +assentive +assentiveness +assentor +assentors +assents +assert +assertable +asserted +assertedly +asserter +asserters +assertible +asserting +assertion +assertional +assertions +assertive +assertively +assertiveness +assertor +assertors +asserts +asses +assess +assessable +assessed +assesses +assessing +assessment +assessments +assessor +assessorial +assessors +asset +assets +asseverate +asseverated +asseverates +asseverating +asseveration +asseverations +asseverative +asshole +assholes +assibilate +assibilated +assibilates +assibilating +assibilation +assiduities +assiduity +assiduous +assiduously +assiduousness +assign +assignability +assignable +assignably +assignat +assignation +assignational +assignations +assignats +assigned +assignee +assignees +assigner +assigners +assigning +assignment +assignments +assignor +assignors +assigns +assimilability +assimilable +assimilate +assimilated +assimilates +assimilating +assimilation +assimilationism +assimilationist +assimilationists +assimilations +assimilative +assimilator +assimilators +assimilatory +assiniboin +assiniboins +assisi +assist +assistance +assistant +assistants +assistantship +assistantships +assisted +assister +assisters +assisting +assists +assize +assizes +associability +associable +associableness +associate +associated +associates +associateship +associateships +associating +association +associational +associationism +associationist +associationistic +associations +associative +associatively +associativity +assoil +assoiled +assoiling +assoilment +assoils +assonance +assonances +assonant +assonantal +assonants +assort +assortative +assorted +assorter +assorters +assorting +assortment +assortments +assorts +assuage +assuaged +assuagement +assuagements +assuages +assuaging +assuasive +assumability +assumable +assumably +assume +assumed +assumedly +assumer +assumers +assumes +assuming +assumingly +assumpsit +assumption +assumptions +assumptive +assumptively +assurable +assurance +assurances +assure +assured +assuredly +assuredness +assureds +assurer +assurers +assures +assurgency +assurgent +assuring +assuror +assurors +assyria +assyrian +assyrians +assyriological +assyriologist +assyriologists +assyriology +astarboard +astarte +astasia +astasias +astatic +astatically +astaticism +astatine +astatines +aster +asteria +asterias +asteriated +asterisk +asterisked +asterisking +asteriskless +asterisks +asterism +asterismal +asterisms +astern +asternal +asteroid +asteroidal +asteroids +asters +asthenia +asthenic +asthenics +asthenopia +asthenopic +asthenosphere +asthenospheric +asthma +asthmatic +asthmatically +asthmatics +astigmatic +astigmatically +astigmatism +astigmatisms +astilbe +astir +astomatal +astomatous +astomous +astonied +astonish +astonished +astonishes +astonishing +astonishingly +astonishment +astonishments +astor +astoria +astound +astounded +astounding +astoundingly +astounds +astrachan +astrachans +astraddle +astragal +astragalar +astragali +astragals +astragalus +astrakhan +astrakhans +astral +astrally +astraphobia +astray +astrictive +astride +astringency +astringent +astringently +astringents +astrionics +astrobiological +astrobiologist +astrobiologists +astrobiology +astrochemist +astrochemistry +astrocyte +astrocytic +astrocytoma +astrocytomas +astrocytomata +astrodome +astrodomes +astrodynamic +astrodynamics +astrogate +astrogated +astrogates +astrogating +astrogation +astrogator +astrogeologist +astrogeology +astrolabe +astrolabes +astrologer +astrologers +astrologic +astrological +astrologically +astrology +astrometric +astrometrical +astrometry +astronaut +astronautic +astronautical +astronautically +astronautics +astronauts +astronavigation +astronavigator +astronomer +astronomers +astronomic +astronomical +astronomically +astronomy +astrophotographer +astrophotographers +astrophotographic +astrophotography +astrophysical +astrophysicist +astrophysicists +astrophysics +astrosphere +asturian +asturians +asturias +astute +astutely +astuteness +astyanax +astylar +asuncion +asunción +asunder +aswan +aswarm +aswirl +aswoon +asylum +asylums +asymmetric +asymmetrical +asymmetrically +asymmetries +asymmetry +asymptomatic +asymptomatically +asymptote +asymptotes +asymptotic +asymptotical +asymptotically +asynapsis +asynchronism +asynchronous +asynchronously +asynchrony +asyndetic +asyndetically +asyndeton +asyntactic +at +atalanta +ataman +atamans +atamasco +atapuerca +ataractic +ataraxia +ataraxias +ataraxic +ataraxics +ataturk +atavism +atavisms +atavist +atavistic +atavistically +atavists +ataxia +ataxias +ataxic +ataxics +ataxies +ataxy +ate +atelectasis +atelier +ateliers +atemoya +atemporal +athabascan +athabaskan +athanasian +athanasius +atheism +atheist +atheistic +atheistical +atheistically +atheists +atheling +athelings +athelstan +athena +athenaeum +athenaeums +atheneum +atheneums +athenian +athenians +athens +atheoretical +atherogenesis +atherogenic +atherogenicity +atheroma +atheromas +atheromata +atheromatosis +atheromatous +atheroscleroses +atherosclerosis +atherosclerotic +atherosclerotically +athirst +athlete +athletes +athletic +athletically +athleticism +athletics +athodyd +athodyds +athos +athwart +athwartship +atilt +atingle +ation +atlanta +atlantan +atlantes +atlantic +atlanticism +atlanticist +atlantis +atlas +atlases +atlatl +atlatls +atman +atmans +atmometer +atmometers +atmometric +atmometry +atmosphere +atmospheres +atmospheric +atmospherically +atmospherics +atmospherium +atoll +atolls +atom +atomic +atomically +atomicity +atomies +atomism +atomisms +atomist +atomistic +atomistical +atomistically +atomists +atomization +atomize +atomized +atomizer +atomizers +atomizes +atomizing +atoms +atomy +atonable +atonal +atonalism +atonalist +atonalistic +atonalities +atonality +atonally +atone +atoneable +atoned +atonement +atonements +atoner +atoners +atones +atonic +atonicity +atonics +atonies +atoning +atony +atop +atopic +atopies +atopy +atoxic +atrabilious +atrabiliousness +atrazine +atrazines +atremble +atresia +atresias +atresic +atreus +atria +atrial +atrioventricular +atrip +atrium +atriums +atrocious +atrociously +atrociousness +atrocities +atrocity +atrophic +atrophied +atrophies +atrophy +atrophying +atropine +atropines +atropins +attaboy +attach +attachable +attached +attacher +attachers +attaches +attaching +attachment +attachments +attaché +attachés +attack +attacked +attacker +attackers +attacking +attackman +attackmen +attacks +attain +attainability +attainable +attainableness +attainably +attainder +attainders +attained +attaining +attainment +attainments +attains +attaint +attainted +attainting +attaints +attar +attars +attelet +attempt +attemptable +attempted +attempter +attempters +attempting +attempts +attend +attendance +attendances +attendant +attendantly +attendants +attended +attendee +attendees +attender +attenders +attending +attends +attention +attentional +attentions +attentive +attentively +attentiveness +attenuate +attenuated +attenuates +attenuating +attenuation +attenuations +attenuator +attenuators +attest +attestant +attestation +attestations +attested +attester +attesters +attesting +attestor +attestors +attests +attic +attica +atticism +atticisms +attics +atticus +attila +attire +attired +attires +attiring +attitude +attitudes +attitudinal +attitudinize +attitudinized +attitudinizes +attitudinizing +attoampere +attoamperes +attobecquerel +attobecquerels +attocandela +attocandelas +attocoulomb +attocoulombs +attofarad +attofarads +attogram +attograms +attohenries +attohenry +attohenrys +attohertz +attojoule +attojoules +attokelvin +attokelvins +attolumen +attolumens +attolux +attometer +attometers +attomole +attomoles +attonewton +attonewtons +attoohm +attoohms +attopascal +attopascals +attoradian +attoradians +attorn +attorned +attorney +attorneys +attorneyship +attorning +attornment +attorns +attosecond +attoseconds +attosiemens +attosievert +attosieverts +attosteradian +attosteradians +attotesla +attoteslas +attovolt +attovolts +attowatt +attowatts +attoweber +attowebers +attract +attractable +attractant +attractants +attracted +attracter +attracting +attraction +attractions +attractive +attractively +attractiveness +attractor +attractors +attracts +attributable +attribute +attributed +attributer +attributers +attributes +attributing +attribution +attributional +attributions +attributive +attributively +attributiveness +attributives +attributor +attrit +attrite +attrited +attrites +attriting +attrition +attritional +attrits +attritted +attritting +attune +attuned +attunement +attunements +attunes +attuning +atwitter +atypical +atypicality +atypically +au +aubade +aubades +auberge +auberges +aubergine +aubergines +auburn +auburns +aubusson +auckland +auction +auctioned +auctioneer +auctioneered +auctioneering +auctioneers +auctioning +auctions +auctorial +aucuba +audacious +audaciously +audaciousness +audacities +audacity +auden +audi +audial +audibility +audible +audibleness +audibles +audibly +audience +audiences +audile +audiles +auding +audings +audio +audiocassette +audiogenic +audiogram +audiograms +audiological +audiologist +audiologists +audiology +audiometer +audiometers +audiometric +audiometry +audiophile +audiophiles +audios +audiotape +audiotaped +audiotapes +audiotaping +audiotyping +audiotypist +audiotypists +audiovisual +audiovisuals +audit +auditable +audited +auditing +audition +auditioned +auditioning +auditions +auditive +auditor +auditoria +auditorium +auditoriums +auditors +auditory +audits +audubon +auf +aufklarung +aufklärung +augean +augend +augends +auger +augers +aught +aughts +augite +augites +augitic +augment +augmentable +augmentation +augmentations +augmentative +augmented +augmenter +augmenters +augmenting +augmentor +augmentors +augments +augsburg +augur +augural +augured +auguries +auguring +augurs +augury +august +augusta +augustan +augustans +augustine +augustinian +augustinianism +augustinians +augustinism +augustly +augustness +augusts +augustus +auk +auklet +auklets +auks +auld +aunt +aunthood +aunthoods +auntie +aunties +auntlike +auntly +aunts +aura +aurae +aural +aurally +aurar +auras +aureate +aureately +aureateness +aurei +aurelian +aurelius +aureola +aureolas +aureole +aureoles +aureomycin +aureus +auric +auricle +auricled +auricles +auricula +auriculae +auricular +auricularly +auriculas +auriculate +auriculately +auriferous +auriform +auriga +aurochs +aurora +auroral +aurorally +auroras +aurorean +aurous +aurum +auschwitz +auscultate +auscultated +auscultates +auscultating +auscultation +auscultations +auscultative +auscultatory +ausform +ausformed +ausforming +ausforms +auslander +auspex +auspicate +auspicated +auspicates +auspicating +auspice +auspices +auspicious +auspiciously +auspiciousness +aussie +aussies +austen +austenite +austenitic +austere +austerely +austereness +austerer +austerest +austerities +austerity +austerlitz +austin +austral +australasia +australasian +australes +australia +australian +australians +australis +australoid +australopithecine +australopithecus +austria +austrian +austrians +austro +autacoid +autacoidal +autacoids +autarch +autarchic +autarchical +autarchies +autarchy +autarkic +autarkical +autarkies +autarky +autecological +autecology +auteur +auteurism +auteurist +auteurs +authentic +authentically +authenticate +authenticated +authenticates +authenticating +authentication +authentications +authenticator +authenticators +authenticity +author +authored +authoress +authoresses +authorial +authoring +authoritarian +authoritarianism +authoritarians +authoritative +authoritatively +authoritativeness +authorities +authority +authorization +authorizations +authorize +authorized +authorizer +authorizers +authorizes +authorizing +authors +authorship +autism +autist +autistic +autistically +auto +autoantibody +autobahn +autobahns +autobiographer +autobiographers +autobiographic +autobiographical +autobiographically +autobiographies +autobiography +autobus +autobuses +autobusses +autocatalyses +autocatalysis +autocatalytic +autocatalytically +autocephalous +autochthon +autochthones +autochthonism +autochthonous +autochthonously +autochthons +autochthony +autoclave +autoclaved +autoclaves +autoclaving +autocollimator +autocollimators +autocorrelation +autocracies +autocracy +autocrat +autocratic +autocratical +autocratically +autocrats +autocross +autodidact +autodidactic +autodidacts +autodyne +autodynes +autoecious +autoeciously +autoecism +autoed +autoerotic +autoeroticism +autoerotism +autofocus +autofocuses +autogamic +autogamies +autogamous +autogamy +autogeneses +autogenesis +autogenetic +autogenetically +autogenic +autogenies +autogenous +autogenously +autogeny +autogiro +autogiros +autograft +autografted +autografting +autografts +autograph +autographed +autographic +autographical +autographically +autographing +autographs +autography +autogyro +autogyros +autoharp +autohypnosis +autohypnotic +autoimmune +autoimmunities +autoimmunity +autoimmunization +autoinfection +autoinfections +autoing +autoinoculable +autoinoculation +autointoxication +autoloader +autoloaders +autoloading +autologous +autolycus +autolysate +autolysin +autolysis +autolytic +autolyze +autolyzed +autolyzes +autolyzing +automaker +automakers +automat +automata +automatable +automate +automated +automates +automatic +automatically +automaticity +automatics +automating +automation +automations +automatism +automatist +automative +automatization +automatize +automatized +automatizes +automatizing +automaton +automatons +automatous +automats +automobile +automobiles +automobilist +automobilists +automorphism +automorphisms +automotive +autonomic +autonomically +autonomies +autonomist +autonomists +autonomous +autonomously +autonomy +autopen +autophagy +autopiler +autopilot +autopilots +autoplastic +autoplastically +autoplasty +autopolyploid +autopolyploidy +autopsic +autopsical +autopsied +autopsies +autopsist +autopsy +autopsying +autoradiogram +autoradiograms +autoradiograph +autoradiographic +autoradiography +autorotate +autorotated +autorotates +autorotating +autorotation +autoroute +autos +autosensor +autosexing +autosomal +autosomally +autosome +autosomes +autostrada +autostradas +autosuggest +autosuggested +autosuggestibility +autosuggestible +autosuggesting +autosuggestion +autosuggestive +autosuggests +autotelic +autotetraploid +autotetraploids +autotetraploidy +autotomic +autotomies +autotomize +autotomized +autotomizes +autotomizing +autotomous +autotomy +autotoxemia +autotoxic +autotoxin +autotransformer +autotroph +autotrophic +autotrophically +autotrophy +autoworker +autre +autumn +autumnal +autumnally +autumns +autunite +autunites +auvergne +aux +auxesis +auxetic +auxetically +auxiliaries +auxiliary +auxin +auxinic +auxinically +auxins +auxotroph +auxotrophic +auxotrophy +avail +availability +available +availableness +availably +availed +availing +availingly +avails +avalanche +avalanched +avalanches +avalanching +avalon +avant +avarice +avaricious +avariciously +avariciousness +avascular +avascularity +avast +avatar +avatars +avaunt +ave +avellan +avellane +avenge +avenged +avenger +avengers +avenges +avenging +avengingly +avens +aventail +aventails +aventine +aventurine +avenue +avenues +aver +average +averaged +averagely +averageness +averages +averaging +averment +averments +avernus +averrable +averred +averring +avers +averse +aversely +averseness +aversion +aversions +aversive +aversively +aversiveness +avert +avertable +averted +avertible +averting +averts +aves +avesta +avgas +avgases +avgasses +avian +aviaries +aviarist +aviarists +aviary +aviate +aviated +aviates +aviating +aviation +aviator +aviators +aviatrices +aviatrix +aviatrixes +aviculture +aviculturist +avid +avidin +avidins +avidities +avidity +avidly +avidness +avifauna +avifaunal +avifaunas +avignon +avila +avion +avionic +avionics +avirulence +avirulent +avis +avises +avitaminoses +avitaminosis +avitaminotic +aviv +avo +avocado +avocadoes +avocados +avocation +avocational +avocationally +avocations +avocet +avocets +avogadro +avoid +avoidable +avoidably +avoidance +avoidances +avoided +avoider +avoiders +avoiding +avoids +avoirdupois +avon +avos +avouch +avouched +avouches +avouching +avouchment +avouchments +avow +avowable +avowably +avowal +avowals +avowed +avowedly +avower +avowers +avowing +avows +avulse +avulsed +avulses +avulsing +avulsion +avulsions +avuncular +aw +await +awaited +awaiting +awaits +awake +awaked +awaken +awakened +awakener +awakeners +awakening +awakenings +awakens +awakes +awaking +award +awardable +awarded +awardee +awardees +awarder +awarders +awarding +awards +aware +awareness +awash +away +awayness +awe +aweary +aweather +awed +aweigh +aweless +awes +awesome +awesomely +awesomeness +awestricken +awestruck +awful +awfully +awfulness +awhile +awhirl +awing +awkward +awkwardly +awkwardness +awl +awless +awls +awn +awned +awning +awninged +awnings +awnless +awns +awoke +awoken +awry +ax +axe +axed +axel +axels +axenic +axenically +axes +axial +axiality +axially +axil +axile +axilla +axillae +axillar +axillaries +axillars +axillary +axils +axing +axiological +axiologically +axiologist +axiology +axiom +axiomatic +axiomatically +axiomatization +axiomatizations +axiomatize +axiomatized +axiomatizes +axiomatizing +axioms +axis +axisymmetric +axisymmetrical +axisymmetrically +axisymmetry +axle +axles +axletree +axletrees +axman +axmen +axminster +axolotl +axolotls +axon +axonal +axone +axonemal +axoneme +axones +axonometric +axons +axoplasm +axoplasmic +axoplasms +ay +ayah +ayahs +ayatollah +ayatollahs +aye +ayers +ayes +ayin +ayins +azalea +azaleas +azathioprine +azeotrope +azeotropic +azeotropy +azerbaijan +azerbaijani +azerbaijanis +azide +azides +azido +azidothymidine +azimuth +azimuthal +azimuthally +azimuths +azine +azines +azo +azoic +azole +azoles +azonal +azonic +azorean +azores +azorian +azotemia +azotemias +azotemic +azoth +azoths +azotobacter +azoturia +azoturias +aztec +aztecan +aztecs +azure +azures +azurite +azurites +azygos +azygoses +azygous +aîné +aînée +añu +b +baa +baaed +baaing +baal +baalbek +baalim +baalism +baals +baas +baba +babar +babas +babassu +babassus +babbage +babbitt +babbittry +babbitts +babble +babbled +babblement +babbler +babblers +babbles +babbling +babcock +babe +babel +babels +babes +babesbabel +babesia +babesias +babesiosis +babied +babier +babies +babiest +babirusa +babirusas +babka +babkas +baboo +baboon +baboonery +baboonish +baboons +baboos +babu +babul +babuls +babus +babushka +babushkas +baby +babyhood +babying +babyish +babylon +babylonia +babylonian +babylonians +babysat +babysitter +babysitters +babysitting +baccalaureate +baccalaureates +baccarat +baccate +bacchanal +bacchanalia +bacchanalian +bacchanalians +bacchanalias +bacchanals +bacchant +bacchante +bacchantes +bacchantic +bacchants +bacchic +bacchus +bach +bached +bachelor +bachelor's +bachelorhood +bachelorhoods +bachelors +bachelorship +baches +baching +bacillar +bacillary +bacilli +bacillus +bacitracin +back +backache +backaches +backbeat +backbeats +backbencher +backbenchers +backbend +backbends +backbit +backbite +backbiter +backbiters +backbites +backbiting +backbitten +backboard +backboards +backbone +backboned +backbones +backbreaker +backbreakers +backbreaking +backcloth +backcountry +backcourt +backcourtman +backcourtmen +backcross +backcrossed +backcrosses +backcrossing +backdate +backdated +backdates +backdating +backdoor +backdoors +backdrop +backdrops +backed +backelordom +backer +backers +backfield +backfields +backfill +backfilled +backfilling +backfills +backfire +backfired +backfires +backfiring +backgammon +background +backgrounder +backgrounders +backgrounds +backhand +backhanded +backhandedly +backhandedness +backhander +backhanders +backhanding +backhands +backhoe +backhoes +backhouse +backhouses +backing +backings +backlash +backlashed +backlasher +backlashers +backlashes +backlashing +backless +backlight +backlighted +backlighting +backlights +backlist +backlisted +backlisting +backlists +backlit +backlog +backlogged +backlogging +backlogs +backorder +backorders +backpack +backpacked +backpacker +backpackers +backpacking +backpacks +backpedal +backpedaled +backpedaling +backpedalled +backpedalling +backpedals +backpressure +backpressures +backquote +backquotes +backrest +backrests +backroom +backrooms +backrush +backrushes +backs +backsaw +backsaws +backscatter +backscattered +backscattering +backscatters +backseat +backseats +backset +backsets +backshore +backshores +backside +backsides +backslap +backslapped +backslapper +backslappers +backslapping +backslaps +backslash +backslashes +backslid +backslidden +backslide +backslider +backsliders +backslides +backsliding +backspace +backspaced +backspaces +backspacing +backspin +backspins +backstab +backstabbed +backstabber +backstabbers +backstabbing +backstabs +backstage +backstairs +backstay +backstays +backstitch +backstitched +backstitches +backstitching +backstop +backstopped +backstopping +backstops +backstretch +backstretches +backstroke +backstrokeer +backstrokeers +backstrokes +backstroking +backswept +backswimmer +backswimmers +backswing +backswings +backsword +backswords +backtrace +backtrack +backtracked +backtracking +backtracks +backup +backups +backward +backwardly +backwardness +backwards +backwash +backwashes +backwater +backwaters +backwoods +backwoodsman +backwoodsmen +backyard +backyards +bacon +baconian +baconians +bacons +bacteremia +bacteremic +bacteremically +bacteria +bacterial +bacterially +bactericidal +bactericidally +bactericide +bactericides +bacterin +bacterins +bacteriocin +bacteriocins +bacteriogenic +bacteriologic +bacteriological +bacteriologically +bacteriologist +bacteriologists +bacteriology +bacteriolyses +bacteriolysis +bacteriolytic +bacteriophage +bacteriophages +bacteriophagic +bacteriophagy +bacteriorhodopsin +bacteriorhodopsins +bacterioscopy +bacteriostases +bacteriostasis +bacteriostat +bacteriostatic +bacteriostats +bacterium +bacteriuria +bacterization +bacterizations +bacterize +bacterized +bacterizes +bacterizing +bacteroid +bactria +bactrian +baculiform +bad +badajoz +badass +badasses +baddie +baddies +baddy +bade +baden +badge +badged +badger +badgered +badgering +badgers +badges +badging +badinage +badinages +badland +badlands +badly +badman +badmen +badminton +badmouth +badmouthed +badmouthing +badmouths +badness +baedeker +baedekers +bael +baels +baffin +baffle +baffled +bafflegabs +bafflement +bafflements +baffler +bafflers +baffles +baffling +bafflingly +bag +bagasse +bagasses +bagatelle +bagatelles +bagehot +bagel +bagels +bagful +bagfuls +baggage +bagged +bagger +baggers +baggier +baggiest +baggily +bagginess +bagging +baggings +baggy +baghdad +baglike +bagman +bagmen +bagnio +bagnios +bagpipe +bagpiper +bagpipers +bagpipes +bags +bagsful +baguette +baguettes +bagwig +bagwigs +bagworm +bagworms +bah +bahama +bahaman +bahamas +bahamian +bahamians +bahawalpur +bahrain +bahraini +bahrainis +baht +bahts +bail +bailable +bailed +bailee +bailees +bailer +bailers +bailey +baileys +bailie +bailies +bailiff +bailiffs +bailiffship +bailing +bailiwick +bailiwicks +bailment +bailments +bailor +bailors +bailout +bailouts +bails +bailsman +bailsmen +baird +bairn +bairns +bait +baited +baiter +baiters +baiting +baits +baiza +baizas +baize +baizes +bake +baked +bakelite +baker +bakeries +bakers +bakersfield +bakery +bakes +bakeshop +bakeshops +baking +baklava +baklavas +baksheesh +balaam +balaclava +balaclavas +balalaika +balalaikas +balance +balanced +balancer +balancers +balances +balancing +balas +balases +balata +balatas +balboa +balboas +balbriggan +balconies +balcony +bald +baldachin +baldachins +balder +balderdash +baldest +baldhead +baldheaded +baldheads +balding +baldish +baldly +baldness +baldpate +baldpates +baldric +baldrics +baldwin +baldwins +bale +balearic +balearics +baled +baleen +baleens +balefire +balefires +baleful +balefully +balefulness +baler +balers +bales +balfour +bali +balinese +baling +balk +balkan +balkanization +balkanize +balkanized +balkanizes +balkanizing +balkans +balked +balker +balkers +balkier +balkiest +balkiness +balking +balkline +balklines +balks +balky +ball +ballad +ballade +balladeer +balladeers +ballades +balladic +balladist +balladists +balladry +ballads +ballantyne +ballarat +ballast +ballasted +ballasting +ballasts +ballcarrier +ballcarriers +balled +ballerina +ballerinas +ballet +balletic +balletomane +balletomanes +balletomania +ballets +ballflower +ballflowers +ballgame +ballgames +balling +ballista +ballistae +ballistic +ballistically +ballistician +ballisticians +ballistics +ballistocardiogram +ballistocardiograms +ballistocardiograph +ballistocardiographs +ballistocardiography +ballon +ballonet +ballonets +ballons +balloon +ballooned +ballooning +balloonist +balloonists +balloons +ballot +balloted +balloter +balloters +balloting +ballots +ballottement +ballottements +ballpark +ballparks +ballplayer +ballplayers +ballpoint +ballpoints +ballroom +ballrooms +balls +ballsier +ballsiest +ballsy +bally +ballyhoo +ballyhooed +ballyhooing +ballyhoos +ballyrag +ballyragged +ballyragging +ballyrags +balm +balmacaan +balmacaans +balmier +balmiest +balmily +balminess +balmoral +balmorals +balms +balmy +balneal +balneology +baloney +baloneys +balsa +balsam +balsamic +balsamroot +balsamroots +balsams +balsas +balsasbalsa +balt +balthazar +baltic +baltimore +baltimorean +baltimoreans +balts +baluchi +baluchis +baluchistan +baluchithere +baluchitheres +baluster +balusters +balustrade +balustrades +balzac +bam +bamako +bambara +bambini +bambino +bambinos +bamboo +bamboos +bamboozle +bamboozled +bamboozlement +bamboozler +bamboozlers +bamboozles +bamboozling +ban +banach +banal +banalities +banality +banalize +banalized +banalizes +banalizing +banally +banana +bananas +banausic +banco +bancos +bancroft +band +banda +bandage +bandaged +bandager +bandagers +bandages +bandaging +bandana +bandanas +bandanna +bandannas +bandbox +bandboxes +bandeau +bandeaus +bandeaux +banded +bander +banderilla +banderillas +banderillero +banderilleros +banderol +banderole +banderoles +banderols +banders +bandicoot +bandicoots +bandied +bandies +banding +bandings +bandit +banditry +bandits +banditti +bandjarmasin +bandleader +bandleaders +bandmaster +bandmasters +bandog +bandogs +bandoleer +bandoleers +bandolier +bandoliers +bandoneon +bandoneonist +bandoneonists +bandoneons +bandora +bandoras +bandore +bandores +bands +bandsman +bandsmen +bandstand +bandstands +bandwagon +bandwagoning +bandwagons +bandwidth +bandwidths +bandy +bandying +bane +baneberries +baneberry +baneful +banefully +banes +bang +bangalore +banged +banger +bangers +banging +bangkok +bangkoks +bangladesh +bangladeshi +bangladeshis +bangle +bangles +bangor +bangs +bangtail +bangtails +bangui +bani +baning +banish +banished +banisher +banishers +banishes +banishing +banishment +banishments +banister +banisters +banjo +banjoes +banjoist +banjoists +banjos +bank +bankability +bankable +bankbook +bankbooks +bankcard +bankcards +banked +banker +bankerly +bankers +banking +bankings +banknote +banknotes +bankroll +bankrolled +bankroller +bankrollers +bankrolling +bankrolls +bankrupt +bankruptcies +bankruptcy +bankrupted +bankrupting +bankruptive +bankrupts +banks +banksia +banksias +bankside +banksides +banned +banner +bannered +banneret +bannerets +bannerette +bannerettes +bannering +bannerol +bannerols +banners +banning +bannister +bannisters +bannock +bannocks +banns +banquet +banqueted +banqueter +banqueters +banqueting +banquets +banquette +banquettes +banquo +bans +banshee +banshees +banshie +banshies +bantam +bantams +bantamweight +bantamweights +banter +bantered +banterer +banterers +bantering +banteringly +banters +bantling +bantlings +bantu +bantus +bantustan +bantustans +banyan +banyans +banzai +banzais +baobab +baobabs +baptisia +baptisias +baptism +baptismal +baptismally +baptisms +baptist +baptisteries +baptistery +baptistries +baptistry +baptists +baptize +baptized +baptizer +baptizers +baptizes +baptizing +bar +barabbas +barathea +baratheas +barb +barbadian +barbadians +barbados +barbara +barbarian +barbarianism +barbarians +barbaric +barbarically +barbarism +barbarisms +barbarities +barbarity +barbarization +barbarize +barbarized +barbarizes +barbarizing +barbarossa +barbarous +barbarously +barbarousness +barbary +barbasco +barbascos +barbate +barbe +barbecue +barbecued +barbecuer +barbecuers +barbecues +barbecuing +barbed +barbedness +barbel +barbell +barbellate +barbells +barbels +barber +barbered +barbering +barberries +barberry +barbers +barbershop +barbershops +barbes +barbet +barbets +barbette +barbettes +barbican +barbicans +barbicel +barbicels +barbing +barbirolli +barbital +barbitals +barbitone +barbitones +barbiturate +barbiturates +barbituric +barbizon +barbs +barbuda +barbudan +barbudans +barbule +barbules +barbwire +barbwires +barca +barcarole +barcaroles +barcas +barcelona +barclay +barcode +barcodes +bard +bardacious +barde +barded +bardes +bardic +barding +bardolino +bardolinos +bards +bare +bareback +barebacked +bared +barefaced +barefacedly +barefacedness +barefoot +barefooted +barege +bareges +barehanded +barehandedness +bareheaded +barelegged +bareleggedness +barely +bareness +barents +barer +bares +barest +barf +barfed +barfing +barflies +barfly +barfs +bargain +bargained +bargainer +bargainers +bargaining +bargains +barge +bargeboard +bargeboards +barged +bargee +bargees +bargello +bargellos +bargeman +bargemen +barges +barghest +barghests +barging +bargirl +bargirls +barhop +barhoping +barhopped +barhops +bari +bariatric +bariatrician +bariatricians +bariatrics +baric +barilla +barillas +baring +barite +barites +baritonal +baritone +baritones +barium +bark +barked +barkeep +barkeeper +barkeepers +barkeeps +barkentine +barkentines +barker +barkers +barkier +barkiest +barking +barkless +barks +barky +barley +barleycorn +barleycorns +barlow +barlows +barm +barmaid +barmaids +barman +barmecidal +barmecide +barmen +barmier +barmiest +barms +barmy +barn +barnabas +barnacle +barnacled +barnacles +barnardo +barnburner +barnburners +barns +barnstorm +barnstormed +barnstormer +barnstormers +barnstorming +barnstorms +barnum +barny +barnyard +barnyards +barogram +barograms +barograph +barographic +barographs +barolo +barolos +barometer +barometers +barometric +barometrical +barometrically +barometry +baron +baronage +baronages +baroness +baronesses +baronet +baronetage +baronetages +baronetcies +baronetcy +baronetess +baronets +barong +barongs +baronial +baronies +barons +barony +baroque +baroquely +baroques +baroreceptor +baroreceptors +barotseland +barouche +barouches +barque +barquentine +barquentines +barques +barrack +barracked +barracker +barrackers +barracking +barracks +barracoon +barracoons +barracuda +barracudas +barrage +barraged +barrages +barraging +barramunda +barramundas +barramundi +barramundis +barranca +barrancas +barranco +barrancos +barrater +barraters +barrator +barrators +barratries +barratrous +barratrously +barratry +barre +barred +barrel +barreled +barrelful +barrelfuls +barrelhead +barrelheads +barrelhouse +barrelhouses +barreling +barrelled +barrelling +barrels +barren +barrenly +barrenness +barrens +barres +barrette +barrettes +barricade +barricaded +barricader +barricaders +barricades +barricading +barrier +barriers +barring +barrio +barrios +barrister +barristers +barroom +barrooms +barrow +barrows +barry +barrymore +bars +barstool +barstools +bartend +bartended +bartender +bartenders +bartending +bartends +barter +bartered +barterer +barterers +bartering +barters +bartholomew +bartizan +bartizaned +bartizans +bartlett +bartletts +bartók +bartókian +baruch +barware +barycenter +barycenters +baryon +baryonic +baryons +barysphere +baryspheres +baryta +barytas +baryte +barytes +barytone +barytones +bas +basal +basally +basalt +basaltic +basalts +bascule +bascules +base +baseball +baseballs +baseboard +baseboards +baseborn +baseburner +baseburners +based +basel +baseless +baselessly +baseline +baselines +basely +baseman +basemen +basement +basementless +basements +baseness +basenji +basenjis +baser +baserunning +bases +basest +bash +bashaw +bashaws +bashed +basher +bashers +bashes +bashful +bashfully +bashfulness +bashing +basic +basically +basichromatic +basicities +basicity +basics +basidia +basidial +basidiocarp +basidiocarps +basidiomycete +basidiomycetes +basidiomycetous +basidiospore +basidiospores +basidiosporous +basidium +basification +basified +basifier +basifiers +basifies +basifixed +basify +basifying +basil +basilar +basilica +basilican +basilicas +basilicata +basilisk +basilisks +basils +basin +basinal +basined +basinet +basinets +basing +basins +basipetal +basipetally +basis +bask +basked +baskerville +basket +basketball +basketballs +basketful +basketfuls +basketlike +basketry +baskets +basketsful +basketwork +basking +basks +basle +basophil +basophile +basophiles +basophilia +basophilias +basophilic +basophils +basotho +basque +basques +basra +bass +basses +basset +bassets +bassett +bassi +bassinet +bassinets +bassist +bassists +basso +bassoon +bassoonist +bassoonists +bassoons +bassos +basswood +basswoods +bast +bastard +bastardies +bastardization +bastardizations +bastardize +bastardized +bastardizes +bastardizing +bastardly +bastards +bastardy +baste +basted +baster +basters +bastes +bastille +bastilles +bastinado +bastinadoed +bastinadoes +bastinadoing +basting +bastings +bastion +bastioned +bastions +bastnaesite +bastnaesites +basutoland +bat +batavia +batavian +batavians +batboy +batboys +batch +batched +batcher +batchers +batches +batching +bate +bateau +bateaux +bated +bates +batfish +batfishes +batfowl +batfowled +batfowling +batfowls +batgirl +batgirls +bath +bathe +bathed +bather +bathers +bathes +bathetic +bathetically +bathhouse +bathhouses +bathing +bathmat +bathmats +batholith +batholithic +batholiths +bathometer +bathometers +bathophobia +bathophobias +bathos +bathoses +bathrobe +bathrobes +bathroom +bathrooms +baths +bathsheba +bathtub +bathtubs +bathurst +bathwater +bathyal +bathymetric +bathymetrical +bathymetrically +bathymetry +bathypelagic +bathyscaph +bathyscaphe +bathyscaphes +bathyscaphs +bathysphere +bathyspheres +bathythermograph +bathythermographs +batik +batiks +bating +batiste +batman +batmen +baton +batons +batophobia +batrachian +batrachians +batrachotoxin +batrachotoxins +bats +batsman +batsmen +batswana +batswanas +batt +battailous +battalia +battalias +battalion +battalions +batteau +batted +battement +batten +battenbergs +battened +battening +battens +batter +battered +batterer +batterers +batterie +batteries +battering +batters +battery +battier +battiest +battiness +batting +battings +battle +battled +battledore +battledores +battlefield +battlefields +battlefront +battlefronts +battleground +battlegrounds +battlement +battlemented +battlements +battler +battlers +battles +battleship +battleships +battlewagon +battlewagons +battling +batts +battu +battue +battues +batty +batwing +batwings +bauble +baubles +baucis +baud +baudelaire +bauds +bauhaus +bauhinia +bauhinias +baum +baumé +bauxite +bauxites +bauxitic +bavaria +bavarian +bavarians +bawbee +bawbees +bawcock +bawcocks +bawd +bawdier +bawdiest +bawdily +bawdiness +bawdries +bawdry +bawds +bawdy +bawdyhouse +bawdyhouses +bawl +bawled +bawler +bawlers +bawling +bawls +bay +bayadere +bayaderes +bayberries +bayberry +bayed +bayesian +bayeux +baying +bayonet +bayoneted +bayoneting +bayonets +bayonetted +bayonetting +bayonne +bayou +bayous +bayreuth +bays +bayside +bazaar +bazaars +bazooka +bazookas +bdellium +bdelliums +be +beach +beachboy +beachboys +beachcomb +beachcombed +beachcomber +beachcombers +beachcombing +beachcombs +beached +beaches +beachfront +beachfronts +beachhead +beachheads +beaching +beachless +beachscape +beachscapes +beachside +beachwear +beachy +beacon +beaconed +beaconing +beacons +bead +beaded +beadier +beadiest +beadily +beading +beadings +beadle +beadles +beadroll +beadrolls +beads +beadsman +beadsmen +beadwork +beady +beagle +beagles +beak +beaked +beaker +beakers +beaks +beaky +beam +beamed +beamier +beamiest +beaming +beamingly +beamish +beamishly +beams +beamy +bean +beanbag +beanbags +beanball +beanballs +beaned +beaneries +beanery +beanie +beanies +beaning +beano +beanos +beanpole +beanpoles +beans +beanstalk +beanstalks +bear +bearability +bearable +bearably +bearbaiting +bearbaitings +bearberries +bearberry +bearcat +bearcats +beard +bearded +beardedness +bearding +beardless +beardlessness +beards +beardtongue +beardtongues +bearer +bearers +bearing +bearings +bearish +bearishly +bearishness +bearlike +bears +bearskin +bearskins +beast +beastie +beasties +beastings +beastlier +beastliest +beastliness +beastly +beasts +beat +beatable +beaten +beater +beaters +beatific +beatifically +beatification +beatifications +beatified +beatifies +beatify +beatifying +beating +beatings +beatitude +beatitudes +beatles +beatless +beatnik +beatniks +beatrice +beats +beau +beaucoup +beaucoups +beaufort +beaujolais +beaumont +beaune +beaus +beaut +beauteous +beauteously +beauteousness +beautician +beauticians +beauties +beautification +beautifications +beautified +beautifier +beautifiers +beautifies +beautiful +beautifully +beautifulness +beautify +beautifying +beauts +beauty +beautyberries +beautyberry +beautybush +beautybushes +beaux +beaver +beaverboard +beaverbrook +beavered +beavering +beavers +beavertail +beavertails +bebop +bebopper +beboppers +becalm +becalmed +becalming +becalms +became +because +beccafico +beccaficos +bechance +bechanced +bechances +bechancing +bechuana +bechuanaland +bechuanas +beck +becket +beckets +beckon +beckoned +beckoner +beckoners +beckoning +beckoningly +beckons +becks +becloud +beclouded +beclouding +beclouds +become +becomes +becoming +becomingly +becomingness +becquerel +becquerels +bed +bedabble +bedabbled +bedabbles +bedabbling +bedaub +bedaubed +bedaubing +bedaubs +bedazzle +bedazzled +bedazzlement +bedazzles +bedazzling +bedbug +bedbugs +bedchamber +bedchambers +bedclothes +bedcover +bedcovering +bedcovers +bedded +bedder +bedders +bedding +bede +bedeck +bedecked +bedecking +bedecks +bedevil +bedeviled +bedeviling +bedevilled +bedevilling +bedevilment +bedevils +bedew +bedewed +bedewing +bedews +bedfast +bedfellow +bedfellows +bedford +bedfordshire +bedight +bedighted +bedighting +bedights +bedim +bedimmed +bedimming +bedims +bedizen +bedizened +bedizening +bedizenment +bedizens +bedlam +bedlamite +bedlamites +bedmate +bedmates +bedouin +bedouins +bedpan +bedpans +bedplate +bedplates +bedpost +bedposts +bedraggle +bedraggled +bedraggles +bedraggling +bedrid +bedridden +bedrock +bedroll +bedrolls +bedroom +bedrooms +beds +bedside +bedsides +bedsonia +bedsoniae +bedsore +bedsores +bedspread +bedspreads +bedspring +bedsprings +bedstead +bedsteads +bedstraw +bedstraws +bedtime +bedtimes +beduin +beduins +bee +beebee +beebees +beebread +beech +beecham +beechdrops +beechen +beeches +beechnut +beechnuts +beef +beefalo +beefaloes +beefalos +beefcake +beefcakes +beefeater +beefeaters +beefed +beefier +beefiest +beefiness +beefing +beefs +beefsteak +beefsteaks +beefwood +beefwoods +beefy +beehive +beehives +beekeeper +beekeepers +beekeeping +beelike +beeline +beelines +beelzebub +been +beep +beeped +beeper +beepers +beeping +beeps +beer +beerbohm +beerhouse +beerhouses +beerier +beeriest +beers +beersheba +beery +bees +beestings +beeswax +beet +beethoven +beetle +beetled +beetles +beetleweed +beetleweeds +beetling +beetroot +beetroots +beets +beeves +befall +befallen +befalling +befalls +befell +befit +befits +befitted +befitting +befittingly +befog +befogged +befogging +befogs +befool +befooled +befooling +befools +before +beforehand +beforetime +befoul +befouled +befouling +befouls +befriend +befriended +befriending +befriends +befuddle +befuddled +befuddlement +befuddlements +befuddles +befuddling +beg +began +beget +begets +begetter +begetters +begetting +beggar +beggared +beggaries +beggaring +beggarliness +beggarly +beggars +beggary +begged +begging +begin +beginner +beginners +beginning +beginnings +begins +begird +begirded +begirding +begirds +begirt +begone +begonia +begonias +begorra +begot +begotten +begrime +begrimed +begrimes +begriming +begrudge +begrudged +begrudger +begrudgers +begrudges +begrudging +begrudgingly +begs +beguile +beguiled +beguilement +beguilements +beguiler +beguilers +beguiles +beguiling +beguilingly +beguine +beguines +begum +begums +begun +behalf +behalves +behave +behaved +behaver +behavers +behaves +behaving +behavior +behavioral +behaviorally +behaviorism +behaviorist +behavioristic +behaviorists +behaviors +behead +beheaded +beheading +beheadings +beheads +beheld +behemoth +behemoths +behest +behind +behindhand +behinds +behold +beholden +beholder +beholders +beholding +beholds +behoof +behoove +behooved +behooves +behooving +beige +beiges +beigy +beijing +being +beings +beirut +bejesus +bejewel +bejeweled +bejeweling +bejewelled +bejewels +bel +belabor +belabored +belaboring +belabors +belarus +belated +belatedly +belatedness +belaud +belauded +belauding +belauds +belay +belayed +belaying +belays +belch +belched +belches +belching +beldam +beldame +beldames +beldams +beleaguer +beleaguered +beleaguering +beleaguerment +beleaguers +belemnite +belemnites +belfast +belfried +belfries +belfry +belgae +belgian +belgians +belgic +belgium +belgrade +belgravia +belie +belied +belief +beliefs +belier +beliers +belies +believability +believable +believably +believe +believed +believer +believers +believes +believing +belike +belittle +belittled +belittlement +belittler +belittlers +belittles +belittling +belittlingly +belive +belize +belizian +belizians +bell +bella +belladonna +bellbird +bellbirds +bellboy +bellboys +belle +belled +belleek +belleeks +belles +belletrism +belletrist +belletristic +belletrists +bellflower +bellflowers +bellhop +bellhops +belli +bellicose +bellicosely +bellicoseness +bellicosity +bellied +bellies +belligerence +belligerency +belligerent +belligerently +belligerents +belling +bellini +bellman +bellmen +belloc +bellona +bellow +bellowed +bellower +bellowers +bellowing +bellows +bellpull +bellpulls +bells +bellum +bellwether +bellwethers +bellwort +bellworts +belly +bellyache +bellyached +bellyacher +bellyachers +bellyaches +bellyaching +bellyband +bellybands +bellybutton +bellybuttons +bellyful +bellyfuls +bellying +belmont +belmopan +beloit +belonephobia +belonephobias +belong +belonged +belonger +belongers +belonging +belongingness +belongings +belongs +belorussia +belorussian +belorussians +beloved +beloveds +below +belowground +bels +belsen +belshazzar +belt +beltane +belted +belting +beltings +beltless +belts +beltway +beltways +beluga +belukha +belvedere +belvederes +belying +bema +bemata +bemedaled +bemedalled +bemire +bemired +bemires +bemiring +bemoan +bemoaned +bemoaning +bemoans +bemock +bemocked +bemocking +bemocks +bemuse +bemused +bemusedly +bemusement +bemuses +bemusing +ben +benares +bench +benched +bencher +benchers +benches +benching +benchmark +benchmarked +benchmarking +benchmarks +benchwarmer +benchwarmers +bend +bendable +benday +bendayed +bendaying +bendays +bender +benders +bending +bends +bendy +bene +beneath +benedict +benedictine +benedictines +benediction +benedictions +benedictive +benedictory +benedicts +benedictus +benefaction +benefactions +benefactor +benefactors +benefactress +benefactresses +benefic +benefice +beneficed +beneficence +beneficences +beneficent +beneficently +benefices +beneficial +beneficially +beneficialness +beneficiaries +beneficiary +beneficiate +beneficiated +beneficiating +beneficiation +beneficing +benefit +benefited +benefiter +benefiters +benefiting +benefits +benefitted +benefitting +benelux +benevento +benevolence +benevolent +benevolently +benevolentness +bengal +bengalese +bengali +bengaline +bengalines +bengalis +benghazi +benidorm +benighted +benightedly +benightedness +benign +benignancies +benignancy +benignant +benignantly +benignities +benignity +benignly +benin +beninese +benison +benisons +benjamin +benne +bennet +bennets +bennies +bennington +benny +bens +bent +bentham +benthamism +benthamite +benthamites +benthic +benthonic +benthos +benthoses +bentonite +bentonites +bentonitic +bents +bentwood +bentwoods +benumb +benumbed +benumbing +benumbment +benumbs +benz +benzaldehyde +benzaldehydes +benzalkonium +benzanthracene +benzedrine +benzene +benzenes +benzidine +benzidines +benzimidazole +benzimidazoles +benzin +benzine +benzines +benzins +benzoate +benzoates +benzocaine +benzocaines +benzocarbazole +benzocarbazoles +benzodiazepine +benzodiazepines +benzoic +benzoin +benzoins +benzol +benzols +benzophenone +benzophenones +benzopyrene +benzopyrenes +benzoyl +benzoyls +benzyl +benzylic +benzyls +beowulf +bepaint +bepainted +bepainting +bepaints +bequeath +bequeathal +bequeathals +bequeathed +bequeather +bequeathers +bequeathing +bequeathment +bequeaths +bequest +bequests +berate +berated +berates +berating +berber +berberine +berberines +berbers +berceuse +berceuses +berdache +berdaches +berdachism +berea +bereave +bereaved +bereavement +bereavements +bereaver +bereavers +bereaves +bereaving +bereft +berenices +beret +berets +berg +bergamo +bergamot +bergamots +bergen +bergs +bergsonian +bergsonism +beribboned +beriberi +bering +berkeleian +berkeleianism +berkeley +berkelium +berkshire +berkshires +berlin +berline +berliner +berliners +berlioz +berm +berms +bermuda +bermudan +bermudans +bermudas +bermudian +bermudians +bern +bernadette +bernadotte +bernard +bernardine +berne +bernese +bernhardt +bernini +bernoulli +bernstein +berried +berries +berry +berrying +berrylike +berseem +berseems +berserk +berserker +berserkers +berserkly +berserks +berth +bertha +berthas +berthed +berthing +berths +beryl +berylline +beryllium +beryls +berzelius +bes +besançon +beseech +beseeched +beseecher +beseechers +beseeches +beseeching +beseechingly +beseem +beseemed +beseeming +beseems +beset +besetment +besets +besetting +beshrew +beshrewed +beshrewing +beshrews +beside +besides +besiege +besieged +besiegement +besieger +besiegers +besieges +besieging +besmear +besmeared +besmearing +besmears +besmirch +besmirched +besmircher +besmirchers +besmirches +besmirching +besmirchment +besom +besoms +besot +besots +besotted +besotting +besought +bespangle +bespangled +bespangles +bespangling +bespatter +bespattered +bespattering +bespatters +bespeak +bespeaking +bespeaks +bespectacled +bespoke +bespoken +besprent +besprinkle +besprinkled +besprinkles +besprinkling +bessarabia +bessel +bessemer +bessie +bessies +best +bestead +besteaded +besteading +besteads +bested +bestial +bestialities +bestiality +bestialize +bestialized +bestializes +bestializing +bestially +bestiaries +bestiary +besting +bestir +bestirred +bestirring +bestirs +bestow +bestowable +bestowal +bestowals +bestowed +bestowing +bestowment +bestows +bestraddle +bestraddled +bestraddles +bestraddling +bestrew +bestrewed +bestrewing +bestrewn +bestrews +bestridden +bestride +bestrides +bestriding +bestrode +bests +bestseller +bestsellerdom +bestsellers +bestselling +bet +beta +betaine +betaines +betake +betaken +betakes +betaking +betamethasone +betamethasones +betas +betatron +betatrons +betel +betelgeuse +betels +beth +bethanechol +bethanechols +bethany +bethel +bethels +bethesda +bethink +bethinking +bethinks +bethlehem +bethought +betide +betided +betides +betiding +betimes +betjeman +betoken +betokened +betokening +betokens +betonies +betony +betook +betray +betrayal +betrayals +betrayed +betrayer +betrayers +betraying +betrays +betroth +betrothal +betrothals +betrothed +betrothing +betroths +bets +betta +bettas +betted +better +bettered +bettering +betterment +betterments +betters +betterton +betting +bettor +bettors +betty +between +betweenbrain +betweenness +betweentimes +betweenwhiles +betwixt +beulah +bevel +beveled +beveling +bevelled +bevelling +bevels +beverage +beverages +beverly +bevies +bevy +bewail +bewailed +bewailer +bewailers +bewailing +bewailment +bewails +beware +bewared +bewares +bewaring +bewhiskered +bewick +bewigged +bewilder +bewildered +bewilderedly +bewilderedness +bewildering +bewilderingly +bewilderment +bewilders +bewitch +bewitched +bewitcher +bewitchers +bewitchery +bewitches +bewitching +bewitchingly +bewitchment +bewitchments +bewray +bewrayed +bewraying +bewrays +bey +beyond +beys +bezant +bezants +bezel +bezels +bezique +bezoar +bezoars +bhakti +bhaktis +bhang +bhangs +bhutan +bhutanese +bi +biafra +biafran +biafrans +bialy +bialys +biannual +biannually +biarritz +bias +biased +biases +biasing +biasness +biassed +biasses +biassing +biathlete +biathletes +biathlon +biathlons +biaxial +biaxiality +biaxially +bib +bibb +bibbed +bibber +bibbers +bibbery +bibbing +bibbs +bibcock +bibcocks +bibelot +bibelots +bible +bibles +bibless +biblical +biblically +biblicism +biblicist +biblicists +bibliofilm +bibliofilms +bibliographer +bibliographers +bibliographic +bibliographical +bibliographically +bibliographies +bibliography +bibliolater +bibliolaters +bibliolatrous +bibliolatry +bibliology +bibliomancies +bibliomancy +bibliomania +bibliomaniac +bibliomaniacal +bibliomaniacs +bibliopegic +bibliopegist +bibliopegists +bibliopegy +bibliophile +bibliophiles +bibliophilic +bibliophilism +bibliophilistic +bibliophily +bibliopole +bibliopoles +bibliopolic +bibliopolical +bibliopolist +bibliopolists +bibliotheca +bibliothecal +bibliothecas +bibliotherapies +bibliotherapy +bibliotic +bibliotics +bibliotist +bibliotists +bibs +bibulous +bibulously +bibulousness +bicameral +bicameralism +bicarb +bicarbonate +bicarbonates +bicarbs +bicaudal +bicellular +bicentenaries +bicentenary +bicentennial +bicentennials +bicentric +bicentricity +bicephalous +biceps +bicepses +bichloride +bichlorides +bichromate +bichromated +bichromates +bichrome +bicipital +bicker +bickered +bickerer +bickerers +bickering +bickers +bicoastal +bicolor +bicolored +bicolors +bicomponent +biconcave +biconcavity +biconditional +biconditionals +biconvex +biconvexity +bicorne +bicornes +bicornuate +bicultural +biculturalism +bicuspid +bicuspidate +bicuspids +bicycle +bicycled +bicycler +bicyclers +bicycles +bicyclic +bicycling +bicyclist +bicyclists +bid +bidarka +bidarkas +biddability +biddable +biddably +bidden +bidder +bidders +biddies +bidding +biddings +biddy +bide +bided +bidentate +bider +biders +bides +bidet +bidets +bidialectal +bidialectalism +bidialectalist +bidialectalists +biding +bidirectional +bidirectionally +bidonville +bidonvilles +bids +biedermeier +bien +biennia +biennial +biennially +biennials +biennium +bienniums +bier +biers +bierstadt +bifacial +biff +biffed +biffies +biffing +biffs +biffy +bifid +bifida +bifidity +bifidly +bifilar +bifilarly +biflagellate +bifocal +bifocaled +bifocalism +bifocals +bifoliolate +biform +bifunctional +bifurcate +bifurcated +bifurcately +bifurcates +bifurcating +bifurcation +bifurcations +big +bigamies +bigamist +bigamists +bigamous +bigamously +bigamy +bigarade +bigarades +bigeminal +bigeminies +bigeminy +bigeneric +bigeye +bigeyes +bigfoot +bigger +biggest +biggety +biggie +biggies +biggin +bigging +biggings +biggins +biggish +biggity +bighead +bigheaded +bigheadedness +bigheads +bighearted +bigheartedly +bigheartedness +bighorn +bighorns +bight +bights +bigly +bigmouth +bigmouthed +bigmouths +bigness +bignonia +bignonias +bigos +bigot +bigoted +bigotedly +bigotedness +bigotries +bigotry +bigots +bigtime +bigwig +bigwigs +bihar +bijection +bijections +bijective +bijou +bijous +bijouterie +bijouteries +bijoux +bijugate +bike +biked +biker +bikers +bikes +bikeway +bikeways +bikie +bikies +biking +bikini +bikinied +bikinis +bilabial +bilabially +bilabials +bilabiate +bilander +bilanders +bilateral +bilateralism +bilaterally +bilateralness +bilayer +bilayers +bilbao +bilberries +bilberry +bilbo +bilboa +bilboas +bilboes +bildungsroman +bildungsromans +bile +biles +bilge +bilged +bilges +bilging +bilgy +bilharzia +bilharzias +bilharziasis +biliary +bilimbi +bilimbis +bilinear +bilingual +bilingualism +bilingually +bilinguals +bilious +biliously +biliousness +bilirubin +bilirubins +biliverdin +biliverdins +bilk +bilked +bilker +bilkers +bilking +bilks +bill +billable +billabong +billabongs +billboard +billboarded +billboarding +billboards +billbug +billbugs +billed +biller +billers +billet +billeted +billeting +billets +billfish +billfishes +billfold +billfolds +billhead +billheads +billhook +billhooks +billiard +billiards +billies +billing +billings +billingsgate +billion +billionaire +billionaires +billionfold +billions +billionth +billionths +billon +billons +billow +billowed +billowiness +billowing +billows +billowy +billposter +billposters +billposting +bills +billy +billycock +billycocks +bilobate +bilobed +bilobular +bilocation +bilocations +bilocular +biltong +biltongs +bimanal +bimanous +bimanual +bimanually +bimaxillary +bimbo +bimbos +bimestrial +bimetal +bimetallic +bimetallism +bimetallist +bimetallistic +bimetallists +bimetals +bimillenaries +bimillenary +bimillenial +bimillenially +bimillennia +bimillennium +bimillenniums +biminis +bimodal +bimodality +bimolecular +bimolecularly +bimonthlies +bimonthly +bimorphemic +bin +binal +binaries +binary +binate +binational +binaural +binaurally +bind +binder +binderies +binders +bindery +binding +bindingly +bindingness +bindings +bindle +bindles +bindlestiff +bindlestiffs +binds +bindweed +bindweeds +bine +bines +binge +binged +bingeing +binger +bingers +binges +binging +bingo +bingoes +bingos +binnacle +binnacles +binned +binning +binocular +binocularity +binocularly +binoculars +binomial +binomially +binomials +binominal +bins +bint +bints +binturong +binturongs +binuclear +binucleate +binucleated +bio +bioaccumulation +bioaccumulations +bioaccumulative +bioacoustics +bioactive +bioactivities +bioactivity +bioagent +bioagents +bioassay +bioassays +bioastronautical +bioastronautics +bioavailability +biocatalyst +biocatalysts +biocatalytic +biocenology +biocenose +biocenoses +biocenosis +biochemical +biochemically +biochemist +biochemistries +biochemistry +biochemists +biochip +biochips +biocidal +biocide +biocides +bioclimatic +bioclimatology +biocoenoses +biocoenosis +biocompatibility +biocompatible +bioconversion +biodegradability +biodegradable +biodegradation +biodegrade +biodegraded +biodegrades +biodegrading +biodiversity +biodynamic +biodynamics +bioelectric +bioelectrical +bioelectricity +bioelectronic +bioelectronics +bioenergetic +bioenergetics +bioengineer +bioengineered +bioengineering +bioengineers +bioenvironmental +bioethical +bioethicist +bioethicists +bioethics +biofeedback +bioflavonoid +bioflavonoids +biogas +biogenesis +biogenetic +biogenetical +biogenetically +biogenetics +biogenic +biogenous +biogeochemical +biogeochemistry +biogeographer +biogeographers +biogeographic +biogeographical +biogeography +biogerontologist +biogerontologists +biogerontology +biographee +biographees +biographer +biographers +biographic +biographical +biographically +biographies +biography +biohazard +biohazards +bioinorganic +bioinstrumentation +bioinstrumentations +biologic +biological +biologically +biologicals +biologics +biologism +biologist +biologistic +biologists +biology +bioluminescence +bioluminescent +biolysis +biolytic +biomarker +biomarkers +biomass +biomasses +biomaterial +biomaterials +biomathematical +biomathematician +biomathematicians +biomathematics +biome +biomechanical +biomechanically +biomechanics +biomedical +biomedicine +biomembrane +biomembranes +biomes +biometeorology +biometric +biometrical +biometrically +biometrics +biometry +biomimesis +biomineralogist +biomineralogists +biomolecular +biomolecule +biomolecules +bionic +bionics +bionomic +bionomical +bionomically +bionomics +bioorganic +biophysical +biophysically +biophysicist +biophysicists +biophysics +biopic +biopics +biopolymer +biopolymers +bioprocess +bioprocessed +bioprocesses +bioprocessing +biopsic +biopsied +biopsies +biopsy +biopsychic +biopsychology +bioptic +bioreactor +bioreactors +bioregion +bioregional +bioregionalism +bioregionalist +bioregionalists +bioregions +bioresearch +biorhythm +biorhythmic +biorhythms +bios +biosatellite +biosatellites +bioscience +biosciences +bioscientific +bioscientist +bioscientists +bioscope +bioscopes +bioscopies +bioscopy +biosensor +biosensors +biosocial +biosocially +biosphere +biospheres +biospheric +biostatistician +biostatisticians +biostatistics +biosyntheses +biosynthesis +biosynthesize +biosynthesized +biosynthesizes +biosynthesizing +biosynthetic +biosynthetically +biosystematic +biosystematics +biosystematist +biosystematists +biota +biotas +biotech +biotechnical +biotechnological +biotechnologist +biotechnologists +biotechnology +biotelemetric +biotelemetry +biotherapies +biotherapy +biotic +biotin +biotins +biotite +biotites +biotitic +biotope +biotopes +biotransformation +biotransformations +biotron +biotrons +biotype +biotypes +biotypic +bioweapon +bioweapons +biparental +biparentally +biparous +bipartisan +bipartisanism +bipartisanship +bipartite +bipartitely +bipartition +biped +bipedal +bipedalism +bipedality +bipeds +biphenyl +biphenyls +bipinnate +bipinnately +biplane +biplanes +bipod +bipods +bipolar +bipolarity +bipolarization +bipolarize +bipolarized +bipolarizes +bipolarizing +bipotentialities +bipotentiality +bipropellant +bipropellants +biquadratic +biquadratics +biquarterly +biracial +biracialism +biradial +biramous +birch +birched +birchen +bircher +birchers +birches +birching +birchism +birchist +birchists +bird +birdbath +birdbaths +birdbrain +birdbrained +birdbrains +birdcage +birdcages +birdcall +birdcalls +birded +birder +birders +birdhouse +birdhouses +birdie +birdied +birdieing +birdies +birding +birdlike +birdlime +birdlimed +birdlimes +birdliming +birdman +birdmen +birds +birdseed +birdseeds +birdshot +birdwatcher +birdwatchers +birdying +birefringence +birefringent +bireme +biremes +biretta +birettas +birk +birkbeck +birkie +birkies +birks +birl +birled +birler +birlers +birling +birls +birmingham +biro +biros +birr +birred +birring +birrs +birth +birthday +birthdays +birthed +birthing +birthings +birthmark +birthmarks +birthplace +birthplaces +birthrate +birthrates +birthright +birthrights +birthroot +birthroots +births +birthstone +birthstones +birthwort +birthworts +biryani +biryanis +bis +biscay +biscayne +biscotti +biscotto +biscuit +biscuits +bise +bisect +bisected +bisecting +bisection +bisectional +bisectionally +bisections +bisector +bisectors +bisects +biseriate +biserrate +bises +bisexual +bisexuality +bisexually +bisexuals +bishop +bishopric +bishoprics +bishops +bislama +bismarck +bismarckian +bismuth +bismuthal +bismuthic +bison +bisons +bisque +bisques +bissau +bissextile +bissextiles +bistate +bister +bistered +bisters +bistort +bistorts +bistouries +bistoury +bistre +bistred +bistres +bistro +bistroic +bistros +bisulcate +bisulfate +bisulfates +bisulfide +bisulfides +bisulfite +bisulfites +bit +bitable +bitartrate +bitartrates +bitch +bitched +bitcheries +bitchery +bitches +bitchier +bitchiest +bitchily +bitchiness +bitching +bitchy +bite +biteable +biteplate +biteplates +biter +biters +bites +bitewing +bitewings +bithynia +bithynian +biting +bitingly +bitmap +bitmapped +bitmapping +bitmaps +bitok +bitoks +bits +bitstock +bitstocks +bitsy +bitt +bitted +bitten +bitter +bitterbrush +bitterbrushes +bittered +bitterender +bitterenders +bitterer +bitterest +bittering +bitterish +bitterly +bittern +bitterness +bitterns +bitternut +bitternuts +bitterroot +bitterroots +bitters +bittersweet +bittersweetly +bittersweetness +bittersweets +bitterweed +bittier +bittiest +bittiness +bitting +bittock +bittocks +bitts +bitty +bitumen +bitumens +bituminization +bituminize +bituminized +bituminizes +bituminizing +bituminoid +bituminous +bitwise +bivalence +bivalency +bivalent +bivalents +bivalve +bivalved +bivalves +bivariate +bivouac +bivouacked +bivouacking +bivouacks +bivouacs +biweeklies +biweekly +biyearly +biz +bizarre +bizarrely +bizarreness +bizet +bizonal +bizone +bizones +blab +blabbed +blabber +blabbered +blabbering +blabbermouth +blabbermouths +blabbers +blabbing +blabby +blabs +black +blackamoor +blackamoors +blackball +blackballed +blackballer +blackballers +blackballing +blackballs +blackbeard +blackberries +blackberry +blackbird +blackbirder +blackbirders +blackbirds +blackboard +blackboards +blackbodies +blackbody +blackbuck +blackbucks +blackcap +blackcaps +blackcock +blackcocks +blackcurrant +blackcurrants +blackdamp +blacked +blacken +blackened +blackener +blackeners +blackening +blackens +blacker +blackest +blackface +blackfaces +blackfeet +blackfish +blackfishes +blackflies +blackfly +blackfoot +blackguard +blackguarded +blackguarding +blackguardism +blackguardly +blackguards +blackhander +blackhanders +blackhead +blackheads +blackheart +blacking +blackings +blackish +blackjack +blackjacked +blackjacking +blackjacks +blackland +blackleg +blacklegs +blacklight +blacklist +blacklisted +blacklister +blacklisters +blacklisting +blacklists +blackly +blackmail +blackmailed +blackmailer +blackmailers +blackmailing +blackmails +blackness +blackout +blackouts +blackpoll +blackpolls +blacks +blacksburg +blacksmith +blacksmithing +blacksmiths +blacksnake +blacksnakes +blackstone +blackstrap +blackstraps +blacktail +blacktails +blackthorn +blackthorns +blacktop +blacktopped +blacktopping +blacktops +blackwash +blackwashed +blackwashes +blackwashing +blackwater +bladder +bladderlike +bladdernose +bladdernoses +bladdernut +bladdernuts +bladders +bladderwort +bladderworts +bladdery +blade +bladed +blades +blaff +blaffs +blagging +blagoveshchensk +blah +blahs +blain +blains +blamable +blamableness +blamably +blame +blamed +blameful +blamefully +blamefulness +blameless +blamelessly +blamelessness +blamer +blamers +blames +blameworthier +blameworthiest +blameworthiness +blameworthy +blaming +blanc +blanch +blanche +blanched +blancher +blanchers +blanches +blanching +blancmange +blancmanges +bland +blander +blandest +blandification +blandified +blandifies +blandify +blandifying +blandish +blandished +blandisher +blandishers +blandishes +blandishing +blandishment +blandishments +blandly +blandness +blank +blanked +blanker +blankest +blanket +blanketed +blanketflower +blanketflowers +blanketing +blanketlike +blankets +blanking +blankly +blankness +blanks +blare +blared +blares +blaring +blarney +blarneyed +blarneying +blarneys +blaspheme +blasphemed +blasphemer +blasphemers +blasphemes +blasphemies +blaspheming +blasphemous +blasphemously +blasphemousness +blasphemy +blast +blasted +blastema +blastemal +blastemas +blastemata +blastematic +blastemic +blaster +blasters +blastie +blasties +blasting +blastment +blastocoel +blastocoelic +blastocoels +blastocyst +blastocystic +blastocysts +blastoderm +blastodermatic +blastodermic +blastoderms +blastodisk +blastodisks +blastoff +blastoffs +blastogenesis +blastogenetic +blastogenic +blastoma +blastomas +blastomata +blastomere +blastomeres +blastomeric +blastomycete +blastomycetes +blastomycin +blastomycins +blastomycosis +blastoporal +blastopore +blastopores +blastoporic +blastosphere +blastospheres +blastospore +blastospores +blasts +blastula +blastulae +blastular +blastulas +blastulation +blasé +blat +blatancies +blatancy +blatant +blatantly +blate +blather +blathered +blatherer +blatherers +blathering +blathers +blatherskite +blatherskites +blats +blatted +blatter +blattered +blattering +blatters +blatting +blaw +blawed +blawing +blawn +blaws +blaxploitation +blaze +blazed +blazer +blazers +blazes +blazing +blazingly +blazon +blazoned +blazoner +blazoners +blazoning +blazonment +blazonries +blazonry +blazons +bleach +bleachable +bleached +bleacher +bleachers +bleaches +bleaching +bleak +bleaker +bleakest +bleakish +bleakly +bleakness +blear +bleared +blearier +bleariest +blearily +bleariness +blearing +blears +bleary +bleat +bleated +bleater +bleaters +bleating +bleats +bleb +blebby +blebs +bled +bleed +bleeder +bleeders +bleeding +bleedings +bleeds +bleep +bleeped +bleeper +bleepers +bleeping +bleeps +blemish +blemished +blemisher +blemishers +blemishes +blemishing +blench +blenched +blencher +blenchers +blenches +blenching +blend +blende +blended +blender +blenders +blendes +blending +blends +blenheim +blennies +blenny +blent +bleomycin +bleomycins +blepharitis +blepharoplast +blepharoplasts +blepharoplasty +blepharospasm +blepharospasms +blesbok +blesboks +bless +blessed +blessedly +blessedness +blesser +blessers +blesses +blessing +blessings +blest +blether +blethered +blethering +blethers +blew +bligh +blight +blighted +blighter +blighters +blighting +blights +blimp +blimpish +blimpishly +blimpishness +blimps +blin +blind +blinded +blinder +blinders +blindest +blindfish +blindfishes +blindfold +blindfolded +blindfolding +blindfolds +blinding +blindingly +blindly +blindman +blindman's +blindness +blinds +blindworm +blindworms +blini +blinis +blink +blinked +blinker +blinkered +blinkering +blinkers +blinking +blinks +blintz +blintze +blintzes +blip +blipped +blipping +blips +bliss +blissful +blissfully +blissfulness +blister +blistered +blistering +blisteringly +blisters +blistery +blithe +blithely +blitheness +blither +blithered +blithering +blithers +blithesome +blithesomely +blithest +blithsomeness +blitz +blitzed +blitzes +blitzing +blitzkrieg +blitzkriegs +blivit +blivits +blizzard +blizzards +blizzardy +bloat +bloated +bloater +bloaters +bloating +bloats +blob +blobbed +blobbing +blobs +bloc +block +blockade +blockaded +blockader +blockaders +blockades +blockading +blockage +blockages +blockbuster +blockbusters +blockbusting +blocked +blocker +blockers +blockhead +blockheadedness +blockheads +blockhouse +blockhouses +blockier +blockiest +blocking +blockish +blockishly +blockishness +blocks +blocky +blocs +bloemfontein +blois +bloke +blokes +blond +blonde +blonder +blondes +blondest +blondish +blondness +blonds +blood +bloodbath +bloodbaths +bloodcurdling +bloodcurdlingly +blooded +bloodedness +bloodguilt +bloodguiltiness +bloodguilty +bloodhound +bloodhounds +bloodied +bloodier +bloodies +bloodiest +bloodily +bloodiness +blooding +bloodless +bloodlessly +bloodlessness +bloodletter +bloodletters +bloodletting +bloodlettings +bloodline +bloodlines +bloodlust +bloodmobile +bloodmobiles +bloodred +bloodroot +bloodroots +bloods +bloodshed +bloodshot +bloodstain +bloodstained +bloodstaining +bloodstains +bloodstock +bloodstone +bloodstones +bloodstream +bloodstreams +bloodsucker +bloodsuckers +bloodsucking +bloodthirstily +bloodthirstiness +bloodthirsty +bloodworm +bloodworms +bloody +bloodying +bloom +bloomed +bloomer +bloomers +blooming +blooms +bloomy +bloop +blooped +blooper +bloopers +blooping +bloops +blossom +blossomed +blossoming +blossoms +blossomy +blot +blotch +blotched +blotches +blotchily +blotchiness +blotching +blotchy +blots +blotted +blotter +blotters +blotting +blotto +blouse +bloused +blouses +blousing +blouson +blousons +blousy +blow +blowback +blowbacks +blowby +blowbys +blower +blowers +blowfish +blowfishes +blowflies +blowfly +blowgun +blowguns +blowhard +blowhards +blowhole +blowholes +blowier +blowiest +blowing +blowjob +blowjobs +blown +blowoff +blowoffs +blowout +blowouts +blowpipe +blowpipes +blows +blowsier +blowsiest +blowsy +blowtorch +blowtorches +blowup +blowups +blowy +blowzier +blowziest +blowzily +blowziness +blowzy +blub +blubbed +blubber +blubbered +blubberer +blubberers +blubbering +blubberingly +blubbers +blubbery +blubbing +blubs +blucher +bluchers +bludgeon +bludgeoned +bludgeoneers +bludgeoner +bludgeoners +bludgeoning +bludgeons +blue +bluebeard +bluebeards +bluebell +bluebells +blueberries +blueberry +bluebill +bluebills +bluebird +bluebirds +bluebonnet +bluebonnets +bluebook +bluebooks +bluebottle +bluebottles +bluecoat +bluecoated +bluecoats +bluecurls +blued +bluefin +bluefish +bluefishes +bluegill +bluegills +bluegrass +blueing +blueings +bluejacket +bluejackets +bluely +blueness +bluenose +bluenosed +bluenoses +bluepoint +bluepoints +blueprint +blueprinted +blueprinting +blueprints +bluer +blues +blueshift +bluesman +bluesmen +bluest +bluestem +bluestems +bluestocking +bluestockings +bluestone +bluestones +bluesy +bluet +bluetongue +bluetongues +bluets +blueweed +blueweeds +bluey +blueys +bluff +bluffable +bluffed +bluffer +bluffers +bluffest +bluffing +bluffly +bluffness +bluffs +bluing +bluings +bluish +bluishness +blunder +blunderbuss +blunderbusses +blundered +blunderer +blunderers +blundering +blunderingly +blunderings +blunders +blunt +blunted +blunter +bluntest +blunting +bluntly +bluntness +blunts +blur +blurb +blurbs +blurred +blurrier +blurriest +blurrily +blurriness +blurring +blurringly +blurry +blurs +blurt +blurted +blurter +blurters +blurting +blurts +blush +blushed +blusher +blushers +blushes +blushful +blushing +blushingly +bluster +blustered +blusterer +blusterers +blustering +blusteringly +blusterous +blusters +blustery +blücher +bo +bo's'n +bo's'ns +bo'sun +bo'suns +boa +boadicea +boar +board +boarded +boarder +boarders +boarding +boardinghouse +boardinghouses +boardlike +boardman +boardmen +boardroom +boardrooms +boards +boardsailing +boardwalk +boardwalks +boarfish +boarfishes +boarhound +boarhounds +boarish +boars +boart +boarts +boas +boast +boasted +boaster +boasters +boastful +boastfully +boastfulness +boasting +boastings +boasts +boat +boatbill +boatbills +boatbuilder +boatbuilders +boated +boatel +boatels +boater +boaters +boathouse +boathouses +boating +boatlift +boatlifts +boatload +boatloads +boatman +boatmanship +boatmen +boats +boatsman +boatsmen +boatswain +boatswains +boatwright +boatwrights +boatyard +boatyards +bob +bobbed +bobber +bobberies +bobbers +bobbery +bobbie +bobbies +bobbin +bobbinet +bobbinets +bobbing +bobbins +bobble +bobbled +bobbles +bobbling +bobby +bobbysoxer +bobbysoxers +bobcat +bobcats +bobeche +bobeches +boboli +bobolink +bobolinks +bobs +bobsled +bobsledded +bobsledder +bobsledders +bobsledding +bobsleded +bobsleding +bobsleds +bobstay +bobstays +bobtail +bobtailed +bobtails +bobwhite +bobwhites +bocaccio +bocaccios +boccaccio +bocce +bocces +bocci +boccie +boccies +boccis +bock +bocks +bodacious +bodaciously +bode +boded +bodega +bodegas +bodement +bodements +bodensee +bodes +bodhisattva +bodhisattvas +bodice +bodices +bodied +bodies +bodiless +bodily +boding +bodings +bodkin +bodkins +bodleian +bodley +body +bodybuilder +bodybuilders +bodybuilding +bodyguard +bodyguards +bodying +bodysnatching +bodysuit +bodysuits +bodysurf +bodysurfed +bodysurfer +bodysurfers +bodysurfing +bodysurfs +bodyweight +bodywork +boehmite +boehmites +boeing +boeings +boeotia +boeotian +boeotians +boer +boers +boethius +boff +boffin +boffins +boffo +boffola +boffolas +boffos +boffs +bofors +bog +bogey +bogeyed +bogeying +bogeyman +bogeymen +bogeys +bogged +boggier +boggiest +bogginess +bogging +boggle +boggled +boggler +bogglers +boggles +boggling +boggy +bogie +bogies +bogle +bogles +bogotá +bogs +bogsat +bogtrotter +bogtrotters +bogus +bogwood +bogwoods +bogy +bogyman +bogymen +bohea +boheas +bohemia +bohemian +bohemianism +bohemians +bohemias +bohr +bohrium +bohunk +bohunks +bohème +boil +boilable +boiled +boiler +boilermaker +boilermakers +boilerplate +boilerplates +boilers +boiling +boiloff +boiloffs +boils +bois +boise +boisterous +boisterously +boisterousness +bokhara +bokmål +bola +bolas +bolases +bold +bolded +bolder +boldest +boldface +boldfaced +boldfaces +boldfacing +bolding +boldly +boldness +bole +bolection +bolections +bolero +boleros +boles +bolete +boletes +boleti +boletus +boletuses +boleyn +bolide +bolides +bolingbroke +bolivar +bolivars +bolivia +bolivian +boliviano +bolivianos +bolivians +boll +bollard +bollards +bolled +bolling +bollinger +bollix +bollixed +bollixes +bollixing +bolls +bollworm +bollworms +bolo +bologna +bolognan +bolognese +bolometer +bolometers +bolometric +bolometrically +boloney +bolos +bolshevik +bolsheviks +bolshevism +bolshevist +bolshevists +bolshevization +bolshevize +bolshevized +bolshevizes +bolshevizing +bolshie +bolshies +bolshy +bolster +bolstered +bolsterer +bolsterers +bolstering +bolsters +bolt +bolted +bolter +bolters +bolthole +boltholes +bolting +boltonia +boltonias +boltrope +boltropes +bolts +bolus +boluses +bolívar +bomb +bombard +bombarded +bombarder +bombardier +bombardiers +bombarding +bombardment +bombardments +bombardon +bombardons +bombards +bombast +bombaster +bombasters +bombastic +bombastically +bombasts +bombay +bombazine +bombazines +bombe +bombed +bomber +bombers +bombes +bombinate +bombinated +bombinates +bombinating +bombination +bombing +bombings +bomblet +bomblets +bombproof +bombs +bombshell +bombshells +bombsight +bombsights +bombycid +bombycids +bon +bona +bonanza +bonanzas +bonaparte +bonapartism +bonapartist +bonapartists +bonaventure +bonbon +bonbonnière +bonbonnières +bonbons +bond +bondable +bondage +bonded +bonder +bonders +bondholder +bondholders +bondi +bonding +bondings +bondmaid +bondmaids +bondman +bondmen +bonds +bondservant +bondservants +bondsman +bondsmen +bondstone +bondstones +bondwoman +bondwomen +bone +boneblack +boned +bonefish +bonefishes +bonehead +boneheaded +boneheadedness +boneheads +boneless +boner +boners +bones +boneset +bonesets +bonesetter +bonesetters +boney +boneyard +boneyards +bonfire +bonfires +bong +bonged +bonging +bongo +bongoes +bongoist +bongoists +bongos +bongs +bonhomie +bonhomies +bonier +boniest +boniface +bonifaces +boniness +boning +bonito +bonitos +bonjour +bonkers +bonn +bonne +bonnes +bonnet +bonneted +bonneting +bonnets +bonneville +bonnie +bonnier +bonniest +bonnily +bonniness +bonny +bonnyclabber +bonnyclabbers +bono +bons +bonsai +bonsoir +bonspiel +bonspiels +bontebok +bonteboks +bonum +bonus +bonuses +bony +bonze +bonzes +boo +boob +boobies +booboisie +booboisies +booboo +booboos +boobs +booby +boodle +boodles +booed +booger +boogerman +boogermen +boogers +boogeyman +boogeymen +boogie +boogied +boogies +boogying +boohoo +boohooed +boohooing +boohoos +booing +book +bookbinder +bookbinderies +bookbinders +bookbindery +bookbinding +bookbindings +bookcase +bookcases +booked +bookend +bookends +booker +bookers +bookful +bookie +bookies +booking +bookings +bookish +bookishly +bookishness +bookkeeper +bookkeepers +bookkeeping +booklet +booklets +booklists +booklore +booklores +booklouse +booklouses +bookmaker +bookmakers +bookmaking +bookman +bookmark +bookmarker +bookmarkers +bookmarks +bookmen +bookmobile +bookmobiles +bookplate +bookplates +bookrack +bookracks +bookroom +bookrooms +books +bookseller +booksellers +bookselling +bookshelf +bookshelves +bookshop +bookshops +bookstall +bookstalls +bookstand +bookstands +bookstore +bookstores +bookwork +bookworm +bookworms +boolean +boom +boomed +boomer +boomerang +boomeranged +boomeranging +boomerangs +boomers +boomier +boomiest +booming +boomlet +boomlets +booms +boomtown +boomtowns +boomy +boon +boondocks +boondoggle +boondoggled +boondoggler +boondogglers +boondoggles +boondoggling +boonies +boons +boor +boorish +boorishly +boorishness +boors +boos +boost +boosted +booster +boosterish +boosterism +boosters +boosting +boosts +boot +bootblack +bootblacks +booted +bootee +bootees +bootes +booth +booths +bootie +booties +booting +bootjack +bootjacks +bootlace +bootlaces +bootle +bootleg +bootlegged +bootlegger +bootleggers +bootlegging +bootlegs +bootless +bootlessly +bootlessness +bootlick +bootlicked +bootlicker +bootlickers +bootlicking +bootlicks +boots +bootstrap +bootstrapped +bootstrapping +bootstraps +booty +booze +boozed +boozehound +boozehounds +boozer +boozers +boozes +boozier +booziest +boozily +boozing +boozy +bop +bophuthatswana +bopped +bopper +boppers +bopping +boppish +bops +bora +boracic +borage +borages +borane +boranes +boras +borate +borated +borates +borax +boraxes +borazon +borborygmi +borborygmus +bordeaux +bordello +bordellos +border +bordereau +bordereaux +bordered +borderer +borderers +bordering +borderland +borderlands +borderline +borderlines +borders +bordetella +bordetellas +bordure +bordures +bore +boreal +borealis +boreas +borecole +borecoles +bored +boredom +borehole +boreholes +borer +borers +bores +borghese +borgia +boric +boride +borides +boring +boringly +boringness +borings +born +borne +bornean +borneo +borneol +borneols +bornholm +bornite +bornites +borodin +boron +boronic +borons +borosilicate +borosilicates +borough +boroughs +borrelia +borrelias +borrow +borrowed +borrower +borrowers +borrowing +borrowings +borrows +borsch +borsches +borscht +borschts +borsht +borshts +borstal +borstals +bort +borts +borty +borzoi +borzois +bos'n +bosc +boscage +boscages +bosch +bosh +bosk +boskage +boskages +boskier +boskiest +boskiness +bosks +bosky +bosnia +bosnian +bosnians +bosom +bosomed +bosoms +bosomy +boson +bosons +bosphorus +bosporus +bosque +bosques +bosquet +bosquets +boss +bossa +bossdom +bossdoms +bossed +bosses +bossier +bossies +bossiest +bossily +bossiness +bossing +bossism +bossisms +bossy +boston +bostonian +bostonians +bosun +bosuns +boswell +boswellian +boswellize +boswellized +boswellizes +boswellizing +boswells +bosworth +bot +botanic +botanical +botanically +botanicals +botanies +botanist +botanists +botanize +botanized +botanizer +botanizers +botanizes +botanizing +botany +botch +botched +botcher +botchers +botches +botching +botchy +botfly +both +bother +botheration +botherations +bothered +bothering +bothers +bothersome +bothnia +botonee +botonnee +botryoidal +botryoidally +botrytis +bots +botswana +botswanan +bott +botticelli +bottle +bottlebrush +bottlebrushes +bottlecap +bottlecaps +bottled +bottleful +bottleneck +bottlenecked +bottlenecking +bottlenecks +bottlenose +bottlenoses +bottler +bottlers +bottles +bottling +bottom +bottomed +bottomer +bottomers +bottoming +bottomland +bottomless +bottomlessly +bottomlessness +bottommost +bottoms +botts +botulin +botulinal +botulins +botulinum +botulinums +botulinus +botulism +boucicault +boucle +bouclé +boudicca +boudin +boudins +boudoir +boudoirs +bouffant +bouffe +bouffes +bougainvillaea +bougainvillaeas +bougainville +bougainvillea +bougainvilleas +bough +boughed +boughs +bought +bougie +bougies +bouillabaisse +bouillon +boulder +bouldered +boulderer +boulderers +bouldering +boulders +bouldery +boule +boules +boulevard +boulevardier +boulevardiers +boulevards +bouleversement +bouleversements +boulle +boulles +boulogne +bounce +bounced +bouncer +bouncers +bounces +bouncier +bounciest +bouncily +bouncing +bouncingly +bouncy +bound +boundaries +boundary +bounded +boundedness +bounden +bounder +bounderish +bounders +bounding +boundless +boundlessly +boundlessness +bounds +bounteous +bounteously +bounteousness +bountied +bounties +bountiful +bountifully +bountifulness +bounty +bouquet +bouquetier +bouquetiers +bouquets +bourbon +bourbonism +bourbons +bourdon +bourdons +bourg +bourgeois +bourgeoise +bourgeoises +bourgeoisie +bourgeoisification +bourgeoisified +bourgeoisifies +bourgeoisify +bourgeoisifying +bourgeon +bourgeoned +bourgeoning +bourgeons +bourget +bourgogne +bourgs +bourguignon +bourn +bourne +bournes +bourns +bourrée +bourrées +bourse +bourses +bouse +boused +bouses +bousing +boustrophedon +boustrophedonic +bout +boutique +boutiques +bouton +boutonniere +boutonnieres +boutonnière +boutonnières +boutons +bouts +bouvardia +bouvardias +bouvier +bouzouki +bouzoukis +bovid +bovids +bovine +bovinely +bovines +bovinity +bovril +bow +bowdlerism +bowdlerization +bowdlerizations +bowdlerize +bowdlerized +bowdlerizer +bowdlerizers +bowdlerizes +bowdlerizing +bowed +bowel +bowelless +bowels +bower +bowerbird +bowerbirds +bowered +bowering +bowers +bowery +bowfin +bowfins +bowfront +bowhead +bowheads +bowie +bowing +bowings +bowknot +bowknots +bowl +bowlder +bowlders +bowled +bowleg +bowlegged +bowlegs +bowler +bowlers +bowlful +bowlfuls +bowline +bowlines +bowling +bowls +bowman +bowmen +bows +bowse +bowsed +bowses +bowshot +bowshots +bowsing +bowsprit +bowsprits +bowstring +bowstrings +bowwow +bowwows +bowyer +bowyers +box +boxboard +boxboards +boxcar +boxcars +boxed +boxer +boxers +boxes +boxfish +boxfishes +boxful +boxfuls +boxhaul +boxhauled +boxhauling +boxhauls +boxier +boxiest +boxiness +boxing +boxings +boxlike +boxthorn +boxthorns +boxwood +boxwoods +boxy +boy +boyar +boyard +boyards +boyars +boycott +boycotted +boycotter +boycotters +boycotting +boycotts +boyfriend +boyfriends +boyhood +boyish +boyishly +boyishness +boyle +boyo +boyos +boys +boysenberries +boysenberry +bozcaada +bozeman +bozo +bozos +boîte +boîtes +boötes +bra +brabant +brabble +brabbled +brabbler +brabblers +brabbles +brabbling +brace +braced +bracelet +bracelets +bracer +bracero +braceros +bracers +braces +brachia +brachial +brachiate +brachiated +brachiates +brachiating +brachiation +brachiator +brachiators +brachiocephalic +brachiopod +brachiopods +brachiosaurus +brachium +brachycephalic +brachycephalism +brachycephaly +brachydactylia +brachydactylic +brachydactyly +brachylogies +brachylogy +brachypterism +brachypterous +brachyuran +bracing +bracingly +bracings +braciola +bracken +brackens +bracket +bracketed +bracketing +brackets +brackish +brackishness +braconid +braconids +bract +bracteal +bracteate +bracted +bracteolate +bracteole +bracteoles +bracts +brad +bradawl +bradawls +bradded +bradding +brads +bradshaw +bradycardia +bradycardias +bradycardic +bradykinin +bradykinins +bradylogia +bradylogias +brae +braes +brag +braganza +bragg +braggadocio +braggadocios +braggart +braggarts +bragged +bragger +braggers +braggest +bragging +braggy +brags +brahe +brahma +brahman +brahmanic +brahmanical +brahmanism +brahmanist +brahmanists +brahmans +brahmaputra +brahmas +brahmin +brahminism +brahmins +brahms +brahmsian +braid +braided +braider +braiders +braiding +braidings +braids +brail +brailed +brailing +braille +brailled +brailler +braillers +brailles +braillewriter +braillewriters +brailling +brails +brain +braincase +braincases +brainchild +brainchildren +brained +brainier +brainiest +brainily +braininess +braining +brainish +brainless +brainlessly +brainlessness +brainpan +brainpans +brainpower +brains +brainsick +brainsickly +brainsickness +brainstem +brainstems +brainstorm +brainstormed +brainstormer +brainstormers +brainstorming +brainstorms +brainteaser +brainteasers +brainwash +brainwashed +brainwasher +brainwashers +brainwashes +brainwashing +brainwave +brainwaves +brainwork +brainworker +brainworkers +brainworks +brainy +braise +braised +braises +braising +brake +braked +brakeless +brakeman +brakemen +brakes +braking +braky +braless +bralessness +bramble +brambleberries +brambleberry +brambles +brambling +bramblings +brambly +bran +branch +branched +branches +branchia +branchiae +branchial +branching +branchiopadous +branchiopod +branchiopodan +branchiopods +branchless +branchlet +branchlets +branchy +brand +brandade +brandades +branded +brandenburg +brander +branders +brandied +brandies +branding +brandish +brandished +brandisher +brandishers +brandishes +brandishing +brandling +brandlings +brands +brandy +brandying +brandywine +brank +branks +brannigan +brannigans +branny +brant +brants +braque +bras +brash +brasher +brashes +brashest +brashly +brashness +brass +brassard +brassards +brassbound +brasserie +brasseries +brasses +brassica +brassicas +brassie +brassier +brassiere +brassieres +brassies +brassiest +brassily +brassiness +brassware +brasswares +brassy +brasília +brat +bratislava +brats +brattice +bratticed +brattices +bratticing +brattier +brattiest +brattiness +brattish +brattishness +brattle +brattleboro +brattled +brattles +brattling +bratty +bratwurst +bratwursts +braunschweiger +braunschweigers +brava +bravado +bravadoes +bravados +bravas +brave +braved +bravely +braveness +braver +braveries +bravers +bravery +braves +bravest +braving +bravissimo +bravo +bravoed +bravoes +bravoing +bravos +bravura +bravuras +braw +brawer +brawest +brawl +brawled +brawler +brawlers +brawlier +brawliest +brawling +brawlingly +brawls +brawly +brawn +brawnier +brawniest +brawnily +brawniness +brawny +bray +brayed +brayer +brayers +braying +brays +braze +brazed +brazen +brazened +brazenfaced +brazening +brazenly +brazenness +brazens +brazer +brazers +brazes +brazier +braziers +brazil +brazilian +brazilians +brazils +brazilwood +brazilwoods +brazing +brazzaville +breach +breached +breaches +breaching +bread +breadbasket +breadbaskets +breadboard +breadboarded +breadboarding +breadboards +breadbox +breadboxes +breadcrumb +breadcrumbs +breaded +breadfruit +breadfruits +breading +breadline +breadlines +breadnut +breadnuts +breadroot +breadroots +breads +breadstuff +breadstuffs +breadth +breadths +breadthways +breadthwise +breadwinner +breadwinners +breadwinning +break +breakable +breakableness +breakables +breakage +breakages +breakaway +breakaways +breakdown +breakdowns +breaker +breakers +breakfast +breakfasted +breakfaster +breakfasters +breakfasting +breakfasts +breakfront +breakfronts +breaking +breakings +breakneck +breakoff +breakoffs +breakout +breakouts +breakpoint +breakpoints +breaks +breakthrough +breakthroughs +breakup +breakups +breakwater +breakwaters +bream +breamed +breaming +breams +breast +breastbone +breastbones +breasted +breastfed +breastfeed +breastfeeding +breastfeeds +breasting +breastplate +breastplates +breasts +breaststroke +breaststroker +breaststrokers +breaststrokes +breastwork +breastworks +breath +breathability +breathable +breathalyzer +breathalyzers +breathe +breathed +breather +breathers +breathes +breathier +breathiest +breathily +breathiness +breathing +breathings +breathless +breathlessly +breathlessness +breaths +breathtaking +breathtakingly +breathy +breccia +breccias +brecciate +brecciated +brecciates +brecciating +brecciation +brecht +brechtian +breckinridge +bred +breda +brede +bredes +breech +breechblock +breechblocks +breechcloth +breechcloths +breechclout +breechclouts +breeches +breeching +breechings +breechloader +breechloaders +breechloading +breed +breeder +breeders +breeding +breeds +breeks +breeze +breezed +breezeless +breezes +breezeway +breezeways +breezier +breeziest +breezily +breeziness +breezing +breezy +bregma +bregmata +bregmatic +bremen +bremsstrahlung +bremsstrahlungs +bren +brenner +brent +bresaola +bresaolas +brest +bretagne +brethren +breton +bretons +breughel +breve +breves +brevet +brevetcy +breveted +breveting +brevets +brevetted +brevetting +breviaries +breviary +brevity +brew +brewage +brewages +brewed +brewer +breweries +brewers +brewery +brewing +brewpub +brewpubs +brews +briand +briar +briard +briards +briarroot +briarroots +briars +briarwood +briarwoods +bribable +bribe +bribed +bribee +bribees +briber +briberies +bribers +bribery +bribes +bribing +brick +brickbat +brickbats +bricked +bricking +bricklayer +bricklayers +bricklaying +brickle +bricks +brickwork +bricky +brickyard +brickyards +bricolage +bricolages +bridal +bridals +bride +bridegroom +bridegrooms +brides +brideshead +bridesmaid +bridesmaids +bridewell +bridewells +bridge +bridgeable +bridgeboard +bridgeboards +bridged +bridgehead +bridgeheads +bridgeless +bridgeport +bridges +bridgetown +bridgework +bridging +bridie +bridle +bridled +bridler +bridlers +bridles +bridling +brie +brief +briefcase +briefcases +briefed +briefer +briefers +briefest +briefing +briefings +briefless +briefly +briefness +briefs +brier +briers +briery +bries +brig +brigade +brigaded +brigades +brigadier +brigadiers +brigading +brigadoon +brigand +brigandage +brigandine +brigandines +brigandism +brigands +brigantine +brigantines +bright +brighten +brightened +brightener +brighteners +brightening +brightens +brighter +brightest +brightly +brightness +brightwork +brightworks +brigs +brill +brilliance +brilliancy +brilliant +brilliantine +brilliantly +brilliantness +brilliants +brills +brim +brimful +brimless +brimmed +brimmer +brimmers +brimming +brims +brimstone +brimstones +brinded +brindisi +brindle +brindled +brindles +brine +brined +brinell +briner +briners +brines +bring +bringdown +bringdowns +bringer +bringers +bringing +brings +brinier +briniest +brininess +brining +brink +brinkmanship +brinksmanship +briny +brio +brioche +brioches +briolette +briolettes +briquet +briquets +briquette +briquetted +briquettes +briquetting +brisance +brisances +brisant +brisbane +brisk +brisker +briskest +brisket +briskets +briskly +briskness +brisling +brislings +bristle +bristlecone +bristled +bristlelike +bristles +bristletail +bristletails +bristlier +bristliest +bristling +bristly +bristol +bristols +brit +britain +britannia +britannic +britannica +britches +briticism +briticisms +british +britisher +britishers +britishness +briton +britons +brits +britt +brittany +britten +brittle +brittlebush +brittlebushes +brittlely +brittleness +brittler +brittlest +brittonic +britts +brno +bro +broach +broached +broacher +broachers +broaches +broaching +broad +broadax +broadaxe +broadaxes +broadband +broadcast +broadcasted +broadcaster +broadcasters +broadcasting +broadcastings +broadcasts +broadcloth +broaden +broadened +broadener +broadeners +broadening +broadens +broader +broadest +broadleaf +broadloom +broadlooms +broadly +broadminded +broadmindedly +broadmindedness +broadness +broads +broadsheet +broadsheets +broadside +broadsided +broadsides +broadsiding +broadsword +broadswords +broadtail +broadtails +broadway +brobdingnag +brobdingnagian +brobdingnagians +brocade +brocaded +brocades +brocatel +brocatelle +brocatelles +brocatels +broccoli +brochette +brochettes +brochure +brochures +brock +brockage +brockages +brocket +brockets +brocks +brogan +brogans +brogue +brogues +broider +broidered +broidering +broiders +broidery +broil +broiled +broiler +broilers +broiling +broils +broke +broken +brokenhearted +brokenheartedly +brokenly +brokenness +broker +brokerage +brokerages +brokered +brokering +brokers +brollies +brolly +bromate +bromated +bromates +bromating +brome +bromegrass +bromegrasses +bromelain +bromelains +bromeliad +bromeliads +bromelin +bromelins +bromes +bromic +bromide +bromides +bromidic +brominate +brominated +brominates +brominating +bromination +bromine +bromism +bromo +bromos +bronc +bronchi +bronchia +bronchial +bronchially +bronchiectasis +bronchiolar +bronchiole +bronchioles +bronchitic +bronchitis +bronchium +broncho +bronchodilator +bronchodilators +bronchopneumonia +bronchos +bronchoscope +bronchoscopes +bronchoscopic +bronchoscopically +bronchoscopist +bronchoscopists +bronchoscopy +bronchus +bronco +broncobuster +broncobusters +broncos +broncs +brontosaur +brontosaurs +brontosaurus +brontosauruses +brontë +brontës +bronx +bronze +bronzed +bronzer +bronzers +bronzes +bronzing +bronzy +brooch +brooches +brood +brooded +brooder +brooders +broodier +broodiest +broodiness +brooding +broodingly +broods +broody +brook +brooked +brookie +brookies +brooking +brookite +brookites +brooklet +brooklets +brooklime +brooklimes +brooklyn +brooklynese +brooks +broom +broomball +broomballer +broomballers +broomcorn +broomcorns +broomed +brooming +broomrape +broomrapes +brooms +broomstick +broomsticks +broomtail +broomtails +broomy +bros +brose +broses +broth +brothel +brothels +brother +brotherhood +brotherhoods +brotherliness +brotherly +brothers +broths +brougham +broughams +brought +brouhaha +brouhahas +brow +browallia +browallias +browbeat +browbeaten +browbeater +browbeaters +browbeating +browbeats +brown +browne +browned +browner +brownest +brownian +brownie +brownies +browning +brownings +brownish +brownness +brownnose +brownnosed +brownnoser +brownnosers +brownnoses +brownnosing +brownout +brownouts +browns +brownshirt +brownshirts +brownstone +brownstones +browny +browridge +brows +browse +browsed +browser +browsers +browses +browsing +bruce +brucella +brucellae +brucellas +brucellosis +brucine +brucines +bruckner +brueghel +bruges +bruin +bruins +bruise +bruised +bruiser +bruisers +bruises +bruising +bruit +bruited +bruiting +bruits +brulee +brulé +brulés +brumal +brumbies +brumby +brume +brumes +brummagem +brummell +brumous +brunch +brunched +brunches +brunching +brunei +bruneian +bruneians +brunel +brunelleschi +brunet +brunets +brunette +brunettes +brunhild +brunizem +brunswick +brunt +brush +brushability +brushback +brushed +brusher +brushers +brushes +brushfire +brushfires +brushier +brushing +brushings +brushland +brushoff +brushstroke +brushstrokes +brushup +brushups +brushwood +brushwork +brushy +brusk +brusque +brusquely +brusqueness +brusquer +brusquerie +brusqueries +brusquest +brussels +brut +brutal +brutalism +brutalist +brutalists +brutalities +brutality +brutalization +brutalize +brutalized +brutalizes +brutalizing +brutally +brute +brutes +brutish +brutishly +brutishness +brutism +brutum +brutus +bruxelles +bruxism +bruxisms +brynhild +bryological +bryologist +bryologists +bryology +bryonies +bryony +bryophyllum +bryophyta +bryophyte +bryophytes +bryophytic +bryozoa +bryozoan +bryozoans +brython +brythonic +brythons +brzezinski +brûlée +brûlées +bub +bubbies +bubble +bubbled +bubblegum +bubblehead +bubbleheaded +bubbleheads +bubbler +bubblers +bubbles +bubblier +bubblies +bubbliest +bubbling +bubbly +bubby +bubo +buboes +bubonic +bubonocele +bubonoceles +buccal +buccally +buccaneer +buccaneering +buccaneerish +buccaneers +buccinator +bucco +bucephalus +bucer +bucharest +buchenwald +buchu +buchus +buck +buckaroo +buckaroos +buckbean +buckbeans +buckboard +buckboards +bucked +bucker +buckeroo +buckers +bucket +bucketed +bucketful +bucketfuls +bucketing +buckets +bucketsful +buckeye +buckeyes +buckhorn +buckhorns +buckhound +buckhounds +bucking +buckinghamshire +buckjump +buckjumped +buckjumper +buckjumpers +buckjumping +buckjumps +buckle +buckled +buckler +bucklered +bucklering +bucklers +buckles +buckley's +buckling +buckminsterfullerene +buckminsterfullerenes +bucko +buckoes +buckram +buckramed +buckraming +buckrams +bucks +bucksaw +bucksaws +buckshee +buckshees +buckshot +buckskin +buckskinned +buckskins +bucktail +bucktails +buckteeth +buckthorn +buckthorns +bucktooth +bucktoothed +buckwheat +buckyball +buckyballs +buco +bucolic +bucolically +bucolics +bud +budapest +budded +budder +budders +buddha +buddhahood +buddhas +buddhism +buddhist +buddhistic +buddhistical +buddhists +buddied +buddies +budding +buddle +buddleia +buddleias +buddles +buddy +buddying +budge +budged +budgerigar +budgerigars +budges +budget +budgetary +budgeted +budgeteer +budgeteers +budgeter +budgeters +budgeting +budgets +budgie +budgies +budging +buds +budworm +budworms +buenos +buff +buffa +buffalo +buffaloberry +buffaloed +buffaloes +buffaloing +buffed +buffer +buffered +buffering +buffers +buffet +buffeted +buffeter +buffeters +buffeting +buffetings +buffets +buffi +buffing +bufflehead +buffleheads +buffo +buffoon +buffoonery +buffoonish +buffoons +buffos +buffs +bug +bugaboo +bugaboos +bugbane +bugbanes +bugbear +bugbears +bugeye +bugeyes +bugged +bugger +buggered +buggering +buggers +buggery +buggier +buggies +buggiest +bugginess +bugging +buggy +bughouse +bughouses +bugle +bugled +bugler +buglers +bugles +bugleweed +bugleweeds +bugling +bugloss +buglosses +bugs +buhl +buhls +buhrstone +buhrstones +buick +buicks +build +buildable +builddown +builddowns +builded +builder +builderer +builderers +buildering +builders +building +buildings +builds +buildup +buildups +built +buirdly +bujumbura +bukhara +bulawayo +bulb +bulbar +bulbed +bulbel +bulbels +bulbiferous +bulbil +bulbils +bulblet +bulblets +bulbourethral +bulbous +bulbously +bulbs +bulbul +bulbuls +bulgar +bulgaria +bulgarian +bulgarians +bulgars +bulge +bulged +bulges +bulgier +bulgiest +bulginess +bulging +bulgur +bulgy +bulimarexia +bulimarexias +bulimia +bulimic +bulk +bulked +bulkhead +bulkheads +bulkier +bulkiest +bulkily +bulkiness +bulking +bulks +bulky +bull +bulla +bullace +bullaces +bullae +bullate +bullbaiting +bullbat +bullbats +bullboat +bullboats +bulldog +bulldogged +bulldogger +bulldoggers +bulldogging +bulldogs +bulldoze +bulldozed +bulldozer +bulldozers +bulldozes +bulldozing +bulled +bullet +bulleted +bulletin +bulletined +bulleting +bulletining +bulletins +bulletproof +bulletproofed +bulletproofing +bulletproofs +bullets +bullfight +bullfighter +bullfighters +bullfighting +bullfights +bullfinch +bullfinches +bullfrog +bullfrogs +bullhead +bullheaded +bullheadedly +bullheadedness +bullheads +bullhorn +bullhorns +bullied +bullies +bulling +bullion +bullish +bullishly +bullishness +bullism +bullmastiff +bullmastiffs +bullnecked +bullock +bullocks +bullocky +bullous +bullpen +bullpens +bullring +bullrings +bullroarer +bullroarers +bullrush +bullrushes +bulls +bullshat +bullshit +bullshits +bullshitted +bullshitter +bullshitters +bullshitting +bullshot +bullterrier +bullterriers +bullwhacker +bullwhackers +bullwhip +bullwhipped +bullwhipping +bullwhips +bully +bullyboy +bullyboys +bullying +bullyrag +bullyragged +bullyragging +bullyrags +bulrush +bulrushes +bulwark +bulwarked +bulwarking +bulwarks +bulwer +bum +bumbershoot +bumbershoots +bumble +bumblebee +bumblebees +bumbled +bumbler +bumblers +bumbles +bumbling +bumblingly +bumboat +bumboats +bumf +bumkin +bumkins +bummalo +bummalos +bummed +bummer +bummers +bumming +bump +bumped +bumper +bumpers +bumph +bumpier +bumpiest +bumpily +bumpiness +bumping +bumpkin +bumpkinish +bumpkinly +bumpkins +bumps +bumptious +bumptiously +bumptiousness +bumpy +bums +bun +buna +bunas +bunch +bunchberries +bunchberry +bunched +bunches +bunchflower +bunchflowers +bunchgrass +bunchgrasses +bunchily +bunchiness +bunching +bunchy +bunco +buncoed +buncoing +buncombe +buncos +bund +bundist +bundists +bundle +bundled +bundler +bundlers +bundles +bundling +bunds +bung +bungalow +bungalows +bunged +bungee +bunghole +bungholes +bunging +bungle +bungled +bungler +bunglers +bungles +bunglesome +bungling +bunglingly +bungs +bunion +bunions +bunk +bunked +bunker +bunkered +bunkering +bunkerings +bunkers +bunkhouse +bunkhouses +bunking +bunkmate +bunkmates +bunko +bunkos +bunkroom +bunkrooms +bunks +bunkum +bunnies +bunny +bunraku +buns +bunsen +bunt +bunted +bunter +bunters +bunting +buntings +buntline +buntlines +bunts +bunyan +bunyanesque +bunyip +bunyips +buoy +buoyance +buoyances +buoyancy +buoyant +buoyantly +buoyed +buoying +buoys +buppie +buppies +buprestid +buprestids +bur +buran +burans +burbage +burberry +burble +burbled +burbler +burblers +burbles +burbling +burbly +burbot +burbots +burbs +burden +burdened +burdening +burdens +burdensome +burdensomely +burdensomeness +burdock +burdocks +bureau +bureaucracies +bureaucracy +bureaucrat +bureaucratese +bureaucrateses +bureaucratic +bureaucratically +bureaucratism +bureaucratization +bureaucratize +bureaucratized +bureaucratizes +bureaucratizing +bureaucrats +bureaus +bureaux +buret +burets +burette +burettes +burg +burgage +burgages +burgee +burgees +burgeon +burgeoned +burgeoning +burgeons +burger +burgers +burgess +burgesses +burgh +burghal +burgher +burghers +burghley +burghs +burglar +burglaries +burglarious +burglariously +burglarize +burglarized +burglarizes +burglarizing +burglarproof +burglarproofed +burglarproofing +burglarproofs +burglars +burglary +burgle +burgled +burgles +burgling +burgomaster +burgomasters +burgonet +burgonets +burgoo +burgoos +burgos +burgs +burgundian +burgundians +burgundies +burgundy +burial +burials +buried +burier +buriers +buries +burin +burins +burke +burked +burkes +burkina +burkinese +burking +burkitt +burl +burladero +burladeros +burlap +burlaps +burled +burleigh +burler +burlers +burlesque +burlesqued +burlesquely +burlesquer +burlesquers +burlesques +burlesquing +burley +burleys +burlier +burlies +burliest +burlily +burliness +burling +burls +burly +burma +burman +burmans +burmese +burn +burnable +burned +burner +burners +burnet +burnets +burning +burningly +burnings +burnish +burnished +burnisher +burnishers +burnishes +burnishing +burnoose +burnoosed +burnooses +burnous +burnouses +burnout +burnouts +burns +burnsides +burnt +burp +burped +burping +burps +burr +burred +burrer +burrers +burrier +burriest +burring +burrito +burritos +burro +burros +burrow +burrowed +burrower +burrowers +burrowing +burrows +burrs +burrstone +burrstones +burry +burs +bursa +bursae +bursal +bursar +bursarial +bursaries +bursars +bursary +bursas +burse +burses +bursitis +burst +bursted +burster +bursters +bursting +bursts +burthen +burthens +burton +burtons +burundi +burundian +burundians +burweed +burweeds +bury +burying +bus +busbies +busboy +busboys +busby +bused +buses +bush +bushbuck +bushbucks +bushed +bushel +busheled +busheler +bushelers +busheling +bushelman +bushels +bushes +bushfire +bushfires +bushido +bushidos +bushier +bushiest +bushily +bushiness +bushing +bushings +bushland +bushlands +bushman +bushmaster +bushmasters +bushmen +bushmills +bushnell +bushpig +bushpigs +bushranger +bushrangers +bushranging +bushtit +bushtits +bushwhack +bushwhacked +bushwhacker +bushwhackers +bushwhacking +bushwhacks +bushy +busied +busier +busies +busiest +busily +business +businesses +businesslike +businessman +businessmen +businesspeople +businessperson +businesspersons +businesswoman +businesswomen +busing +busk +busked +busker +buskers +buskin +busking +buskins +busks +busload +busloads +busman +busman's +busmen +buss +bussed +busses +bussing +bust +bustard +bustards +busted +buster +busters +busticate +busticated +busticates +busticating +bustier +bustiers +bustiest +busting +bustle +bustled +bustles +bustline +bustling +bustlingly +busts +busty +busulfan +busulfans +busy +busybodies +busybody +busying +busyness +busywork +but +butadiene +butane +butanes +butanol +butanols +butanone +butanones +butazolidin +butch +butcher +butcherbird +butcherbirds +butchered +butcherer +butcherers +butcheries +butchering +butcherly +butchers +butchery +butches +bute +butene +butenes +buteo +buteos +butler +butlers +butoxide +buts +butt +butte +butted +butter +butterball +butterballs +butterbur +butterburs +buttercup +buttercups +buttered +butterfat +butterfingered +butterfingers +butterfish +butterfishes +butterflied +butterflies +butterfly +butterflyer +butterflyers +butterflying +butteries +butteriness +buttering +butterless +buttermilk +buttermilks +butternut +butternuts +butters +butterscotch +butterweed +butterweeds +butterwort +butterworts +buttery +buttes +butties +butting +buttinski +buttinskies +buttinsky +buttock +buttocks +button +buttonball +buttonballs +buttonbush +buttonbushes +buttoned +buttoner +buttoners +buttonhole +buttonholed +buttonholer +buttonholers +buttonholes +buttonholing +buttonhook +buttonhooks +buttoning +buttonless +buttonmold +buttonmolds +buttonquail +buttonquails +buttons +buttonwood +buttonwoods +buttony +buttress +buttressed +buttresses +buttressing +butts +buttstock +buttstocks +butty +butut +bututs +butyl +butylate +butylated +butylates +butylating +butylation +butylene +butylenes +butyls +butyraceous +butyraldehyde +butyraldehydes +butyrate +butyrates +butyric +butyrin +butyrins +butyrophenone +butyrophenones +butyrophenoness +buxom +buxomly +buxomness +buxtehude +buy +buyable +buyback +buybacks +buyer +buyers +buying +buyout +buyouts +buys +buzz +buzzard +buzzards +buzzed +buzzer +buzzers +buzzes +buzzing +buzzword +buzzwords +bwana +bwanas +by +bye +byelaw +byelaws +byelorussia +byelorussian +byelorussians +byes +bygone +bygones +bylaw +bylaws +byline +bylined +byliner +byliners +bylines +bylining +byname +bynames +bypass +bypassed +bypasses +bypassing +bypast +bypath +bypaths +byplay +byplays +byproduct +byproducts +byre +byres +byroad +byroads +byron +byronic +byssi +byssinosis +byssus +byssuses +bystander +bystanders +bystreet +bystreets +byte +bytes +byway +byways +byword +bywords +byzantine +byzantines +byzantium +béarn +béarnaise +béchamel +béchamels +bêche +bêches +bête +bêtes +bêtise +bêtises +c +c'mon +cab +cabal +cabala +cabalas +cabaletta +cabalettas +cabalette +cabalism +cabalist +cabalistic +cabalistically +cabalists +caballed +caballero +caballeros +caballing +cabals +cabana +cabanas +cabaret +cabarets +cabaña +cabañas +cabbage +cabbages +cabbageworm +cabbageworms +cabbagy +cabbed +cabbie +cabbies +cabbing +cabby +cabdriver +cabdrivers +caber +cabernet +cabernets +cabers +cabin +cabined +cabinet +cabinetful +cabinetmaker +cabinetmakers +cabinetmaking +cabinetry +cabinets +cabinetwork +cabining +cabins +cable +cablecast +cablecaster +cablecasters +cablecasts +cabled +cablegram +cablegrams +cabler +cablers +cables +cablet +cablets +cablevision +cableway +cableways +cabling +cabman +cabmen +cabochon +cabochons +caboclo +caboclos +cabomba +cabombas +caboodle +caboose +cabooses +cabot +cabotage +cabotages +cabretta +cabrettas +cabrilla +cabrillas +cabriole +cabrioles +cabriolet +cabriolets +cabs +cabstand +cabstands +cacao +cacaos +cachaca +cachalot +cachalots +cachaça +cache +cachectic +cached +cachepot +cachepots +caches +cachet +cachets +cachexia +cachexias +caching +cachinnate +cachinnated +cachinnates +cachinnating +cachinnation +cachinnator +cachinnators +cachou +cachous +cachucha +cachuchas +cacique +caciques +cackle +cackled +cackler +cacklers +cackles +cackling +cacodemon +cacodemons +cacodyl +cacodylic +cacodyls +cacography +cacomistle +cacomistles +caconym +caconyms +caconymy +cacophonic +cacophonies +cacophonous +cacophonously +cacophony +cacoëthes +cacti +cactus +cactuses +cacuminal +cad +cadastral +cadastre +cadaver +cadaveric +cadaverine +cadaverines +cadaverous +cadaverously +cadaverousness +cadavers +caddie +caddied +caddies +caddis +caddish +caddishly +caddishness +caddo +caddoan +caddoans +caddos +caddy +caddying +cade +cadelle +cadelles +cadence +cadenced +cadences +cadencies +cadency +cadent +cadential +cadenza +cadenzas +cadet +cadets +cadetship +cadge +cadged +cadger +cadgers +cadges +cadging +cadillac +cadillacs +cadiz +cadmic +cadmium +cadmus +cadre +cadres +cads +caducean +caducei +caduceus +caducity +caducous +caecilian +caecilians +caelian +caelum +caerphillies +caerphilly +caesar +caesarea +caesarean +caesareans +caesarian +caesarians +caesarism +caesarist +caesaristic +caesarists +caesars +caesura +caesurae +caesural +caesuras +caesuric +cafe +cafes +cafeteria +cafeterias +cafetoria +cafetorium +cafetoriums +caffeinated +caffeine +caffeinism +caftan +caftans +café +cafés +cage +caged +cagelike +cageling +cagelings +cages +cagey +cageyness +cagier +cagiest +cagily +caginess +caging +cagliari +cahier +cahiers +cahoots +cahow +cahows +cahuilla +cahuillas +caicos +caiman +caimans +cain +cainotophobia +cainotophobias +caird +cairds +cairn +cairned +cairngorm +cairns +cairo +caisson +caissons +caitiff +caitiffs +cajan +cajans +cajole +cajoled +cajoler +cajolers +cajolery +cajoles +cajoling +cajolingly +cajun +cajuns +cake +caked +cakes +cakewalk +cakewalked +cakewalker +cakewalkers +cakewalking +cakewalks +caking +calabash +calabashes +calaboose +calabooses +calabrese +calabreses +calabria +calabrian +calabrians +caladium +calais +calamanco +calamancoes +calamander +calamanders +calamari +calamaries +calamary +calami +calamine +calamint +calamints +calamite +calamites +calamities +calamitous +calamitously +calamitousness +calamity +calamondin +calamondins +calamus +calando +calash +calashes +calathea +calatheas +calathi +calathus +calcanea +calcaneal +calcanei +calcaneocuboid +calcaneum +calcaneus +calcar +calcareous +calcareously +calcaria +calceolaria +calceolarias +calceolate +calcic +calcicole +calcicoles +calcicolous +calciferol +calciferols +calciferous +calcific +calcification +calcifications +calcified +calcifies +calcifugal +calcifuge +calcifugous +calcify +calcifying +calcimine +calcimined +calciminer +calciminers +calcimines +calcimining +calcination +calcine +calcined +calcines +calcining +calcinosis +calcite +calcitic +calcitonin +calcitonins +calcium +calcspar +calcspars +calculability +calculable +calculably +calculate +calculated +calculatedly +calculates +calculating +calculatingly +calculation +calculations +calculative +calculator +calculators +calculi +calculous +calculus +calculuses +calcutta +caldera +calderas +caldron +caldrons +caledonia +caledonian +caledonians +calendal +calendar +calendared +calendaring +calendars +calender +calendered +calenderer +calenderers +calendering +calenders +calendric +calendrical +calends +calendula +calendulas +calenture +calentures +calf +calfskin +calgarian +calgarians +calgary +caliban +caliber +calibers +calibrate +calibrated +calibrates +calibrating +calibration +calibrations +calibrator +calibrators +calices +caliche +caliches +calico +calicoback +calicobacks +calicoes +calicos +calicut +california +californian +californians +californite +californites +californium +caliginous +caligula +calinago +calinagos +calipash +calipashes +calipee +calipees +caliper +calipered +calipering +calipers +caliph +caliphate +caliphates +caliphs +calisthenic +calisthenics +calix +calk +calked +calking +calks +call +calla +callable +callback +callbacks +callboard +callboards +callboy +callboys +called +caller +callers +calligrapher +calligraphers +calligraphic +calligraphist +calligraphy +calling +callings +calliope +calliopes +calliopsis +callipygian +callisthenes +callisto +callose +calloses +callosities +callosity +callous +calloused +callouses +callousing +callously +callousness +callow +callowness +calls +callus +callused +calluses +callusing +calm +calmative +calmed +calmer +calmest +calming +calmly +calmness +calms +calomel +caloreceptor +caloreceptors +caloric +calorically +calorie +calories +calorific +calorifically +calorimeter +calorimeters +calorimetric +calorimetrically +calorimetry +calotte +calottes +calpac +calpacs +calque +calques +caltrop +caltrops +calumet +calumets +calumniate +calumniated +calumniates +calumniating +calumniation +calumniations +calumniator +calumniators +calumniatory +calumnies +calumnious +calumniously +calumny +calvados +calvarium +calvariums +calvary +calve +calved +calves +calvin +calving +calvinism +calvinist +calvinistic +calvinistical +calvinistically +calvinists +calx +calxes +calyces +calycine +calycular +calyculate +calyculi +calyculus +calypso +calypsos +calyptra +calyptrate +calyx +calyxes +calèche +cam +camaraderie +camargue +camarilla +camarillas +camas +camber +cambered +cambering +cambers +cambia +cambial +cambium +cambiums +cambodia +cambodian +cambodians +cambrai +cambria +cambrian +cambric +cambrics +cambridge +cambridgeshire +camcorder +camcorders +came +camel +camelback +camelbacks +cameleer +cameleers +camellia +camellias +camelopard +camelopardalis +camelot +camels +camembert +cameo +cameoed +cameoing +cameos +camera +camerae +cameral +cameraman +cameramen +cameraperson +camerapersons +cameras +camerawoman +camerawomen +camerawork +camerlingo +camerlingos +cameron +cameroon +cameroonian +cameroonians +cameroons +cameroun +cami +camion +camions +camis +camise +camises +camisole +camisoles +camorra +camouflage +camouflaged +camouflager +camouflagers +camouflages +camouflaging +camp +campaign +campaigned +campaigner +campaigners +campaigning +campaigns +campania +campanile +campaniles +campanologist +campanologists +campanology +campanula +campanulas +campanulate +camped +campeggio +camper +campers +campesino +campesinos +campestral +campfire +campfires +campground +campgrounds +camphene +camphenes +camphor +camphoraceous +camphorate +camphorated +camphorates +camphorating +camphoric +camphorweed +camphorweeds +camping +campion +campions +campo +camporee +camporees +campos +camps +campsite +campsites +campstool +campstools +campus +campuses +campy +campylobacterosis +campylotropous +cams +camshaft +camshafts +can +can't +canaan +canaanite +canaanites +canada +canadian +canadians +canaigre +canaigres +canaille +canal +canaletto +canalicular +canaliculate +canaliculi +canaliculus +canalization +canalize +canalized +canalizes +canalizing +canalled +canalling +canals +canapé +canapés +canard +canards +canaries +canary +canasta +canaveral +canberra +cancan +cancans +cancel +cancelable +canceled +canceler +cancelers +canceling +cancellate +cancellation +cancellations +cancelled +cancelling +cancellous +cancels +cancer +cancerian +cancerians +cancerous +cancers +cancroid +cancroids +cancún +candela +candelabra +candelabras +candelabrum +candelabrums +candelas +candelilla +candelillas +candent +candescence +candescent +candescently +candia +candid +candida +candidacies +candidacy +candidas +candidate +candidates +candidature +candidatures +candidiasis +candidly +candidness +candids +candied +candies +candle +candleberries +candleberry +candled +candlefish +candleholder +candleholders +candlelight +candlelit +candlemas +candlemases +candlenut +candlenuts +candlepin +candlepins +candlepower +candler +candlers +candles +candlesnuffer +candlesnuffers +candlestick +candlesticks +candlewick +candlewicks +candlewood +candlewoods +candling +candor +candy +candying +candytuft +candytufts +cane +canebrake +canebrakes +caned +caner +caners +canes +canescence +canescent +canfield +cangue +cangues +canicular +canid +canids +canine +canines +caning +canistel +canistels +canister +canisters +canker +cankered +cankering +cankerous +cankerroot +cankerroots +cankers +cankerworm +cankerworms +canna +cannabic +cannabidiol +cannabidiols +cannabin +cannabins +cannabis +canned +cannel +cannelloni +cannelure +cannelures +canner +canneries +canners +cannery +cannes +cannibal +cannibalism +cannibalistic +cannibalization +cannibalizations +cannibalize +cannibalized +cannibalizes +cannibalizing +cannibals +cannier +canniest +cannikin +cannikins +cannily +canniness +canning +cannoli +cannon +cannonade +cannonaded +cannonades +cannonading +cannonball +cannonballed +cannonballing +cannonballs +cannoned +cannoneer +cannoneers +cannoning +cannonries +cannonry +cannons +cannot +cannula +cannular +cannulas +cannulate +cannulated +cannulates +cannulating +cannulation +canny +canoe +canoed +canoeing +canoeist +canoeists +canoes +canola +canolas +canon +canoness +canonesses +canonic +canonical +canonically +canonicals +canonicate +canonicates +canonicity +canonist +canonistic +canonistical +canonists +canonization +canonizations +canonize +canonized +canonizer +canonizers +canonizes +canonizing +canonries +canonry +canons +canoodle +canoodled +canoodles +canoodling +canopic +canopied +canopies +canopus +canopy +canopying +canorous +canorously +canorousness +cans +cant +cantabile +cantabiles +cantabrigian +cantabrigians +cantala +cantalas +cantaloupe +cantaloupes +cantankerous +cantankerously +cantankerousness +cantata +cantatas +canted +canteen +canteens +canter +canterbury +cantered +cantering +canters +cantharides +cantharis +canthi +canthitis +canthus +canticle +canticles +cantilated +cantilates +cantilating +cantilena +cantilenas +cantilever +cantilevered +cantilevering +cantilevers +cantillate +cantillation +cantina +cantinas +canting +cantingly +cantingness +cantle +cantles +canto +canton +cantonal +cantonese +cantonment +cantonments +cantons +cantor +cantorial +cantors +cantos +cants +canuck +canucks +canute +canvas +canvasback +canvasbacks +canvases +canvass +canvassed +canvasser +canvassers +canvasses +canvassing +canyon +canyons +canzone +canzones +canzonet +canzonets +caoutchouc +caoutchoucs +cap +capabilities +capability +capable +capableness +capably +capacious +capaciously +capaciousness +capacitance +capacitances +capacitate +capacitated +capacitates +capacitating +capacitation +capacities +capacitive +capacitively +capacitor +capacitors +capacity +caparison +caparisoned +caparisoning +caparisons +cape +caped +capelin +capelins +capella +caper +capercaillie +capercaillies +capered +capering +capers +capes +capeskin +capeskins +capet +capetian +capetians +capful +capfuls +capias +capiases +capillaries +capillarities +capillarity +capillary +capita +capital +capitalism +capitalist +capitalistic +capitalistically +capitalists +capitalizable +capitalization +capitalizations +capitalize +capitalized +capitalizes +capitalizing +capitally +capitals +capitate +capitation +capitations +capitative +capitella +capitellum +capitol +capitoline +capitols +capitula +capitulant +capitular +capitularies +capitularly +capitulary +capitulate +capitulated +capitulates +capitulating +capitulation +capitulations +capitulator +capitulators +capitulatory +capitulum +caplet +caplets +capo +capon +caponata +caponatas +caponize +caponized +caponizes +caponizing +capons +caporal +caporals +capos +capote +capotes +cappadocia +cappadocian +cappadocians +capped +cappella +capper +cappers +capping +cappuccino +cappuccinos +capreomycin +capreomycins +capri +capriccio +capriccios +capriccioso +caprice +caprices +capricious +capriciously +capriciousness +capricorn +capricornian +capricornians +capricorns +caprification +caprifications +caprifig +caprifigs +capriole +caprioled +caprioles +caprioling +capris +caps +capsaicin +capsaicins +capsian +capsicum +capsicums +capsid +capsids +capsize +capsized +capsizes +capsizing +capsomere +capsomeres +capstan +capstans +capstone +capstones +capsular +capsulate +capsulated +capsulation +capsule +capsuled +capsules +capsuling +capsulize +capsulized +capsulizes +capsulizing +capsulotomies +capsulotomy +captain +captaincies +captaincy +captained +captaining +captains +captainship +captan +captans +caption +captioned +captioning +captions +captious +captiously +captiousness +captivate +captivated +captivates +captivating +captivatingly +captivation +captivator +captivators +captive +captives +captivities +captivity +captopril +captoprils +captor +captors +capture +captured +captures +capturing +capuche +capuches +capuchin +capuchins +capulet +capulets +capybara +capybaras +car +carabao +carabaos +carabid +carabids +carabineer +carabineers +carabiner +carabiners +carabiniere +carabinieri +caracal +caracalla +caracals +caracara +caracaras +caracas +caracole +caracoled +caracoles +caracoling +caractacus +caradoc +carafe +carafes +carambola +carambolas +caramel +caramelization +caramelize +caramelized +caramelizes +caramelizing +caramels +carangid +carangids +carapace +carapaces +carat +caratacus +carats +caravaggio +caravan +caravans +caravansaries +caravansary +caravel +caravels +caraway +caraways +carbamate +carbamates +carbamazepine +carbamazepines +carbamide +carbamides +carbamoyl +carbamoyls +carbanion +carbanions +carbaryl +carbaryls +carbenicillin +carbenicillins +carbide +carbides +carbine +carbines +carbinol +carbinols +carbocyclic +carbohydrase +carbohydrases +carbohydrate +carbohydrates +carbolated +carbolic +carbon +carbonaceous +carbonado +carbonadoed +carbonadoes +carbonadoing +carbonados +carbonara +carbonaras +carbonate +carbonated +carbonates +carbonating +carbonation +carbonator +carbonators +carbonic +carboniferous +carbonium +carboniums +carbonization +carbonize +carbonized +carbonizer +carbonizers +carbonizes +carbonizing +carbonous +carbons +carbonyl +carbonylic +carbonyls +carborane +carboranes +carborundum +carboxyhemoglobin +carboxyhemoglobins +carboxyl +carboxylase +carboxylases +carboxylation +carboxylations +carboxylic +carboxymethylcellulose +carboxymethylcelluloses +carboxypeptidase +carboxypeptidases +carboy +carboys +carbuncle +carbuncled +carbuncles +carbuncular +carburet +carbureted +carbureting +carburetion +carburetor +carburetors +carburets +carburization +carburize +carburized +carburizes +carburizing +carcajou +carcajous +carcanet +carcanets +carcass +carcasses +carcassonne +carcinogen +carcinogenesis +carcinogenic +carcinogenicity +carcinogens +carcinoid +carcinoids +carcinoma +carcinomas +carcinomatoid +carcinomatosis +carcinomatous +card +cardamom +cardamoms +cardboard +carded +cardholder +cardholders +cardholding +cardia +cardiac +cardiacs +cardiae +cardialgia +cardialgias +cardiff +cardigan +cardigans +cardinal +cardinalate +cardinalates +cardinalities +cardinality +cardinals +cardinalship +carding +cardioacceleration +cardioaccelerator +cardioaccelerators +cardiogenic +cardiogram +cardiograms +cardiograph +cardiographs +cardiography +cardioid +cardioids +cardiological +cardiologist +cardiologists +cardiology +cardiomegaly +cardiomyopathies +cardiomyopathy +cardiopathies +cardiopathy +cardiopulmonary +cardiorespiratory +cardiothoracic +cardiovascular +carditis +carditises +cardoon +cardoons +cards +cardsharp +cardsharper +cardsharpers +cardsharping +cardsharps +cardstock +care +cared +careen +careened +careener +careeners +careening +careens +career +careered +careering +careerism +careerist +careerists +careers +carefree +careful +carefully +carefulness +caregiver +caregivers +caregiving +careless +carelessly +carelessness +cares +caress +caressed +caresser +caressers +caresses +caressing +caressingly +caressive +caret +caretaker +caretakers +caretaking +carets +careworn +carfare +cargo +cargoes +carhop +carhops +carib +cariban +caribbean +caribbeans +caribe +caribes +caribou +caribous +caribs +caricature +caricatured +caricatures +caricaturing +caricaturist +caricaturists +caries +carillon +carillonned +carillonneur +carillonneurs +carillonning +carillons +carina +carinae +carinate +caring +carinthia +carioca +cariocan +cariocas +cariole +carioles +cariosity +carious +cariousness +cark +carked +carking +carks +carl +carling +carlings +carlisle +carlist +carlists +carlo +carload +carloads +carlos +carls +carlsbad +carlyle +carmaker +carmakers +carmel +carmelite +carmelites +carmen +carminative +carminatives +carmine +carnac +carnage +carnal +carnality +carnallite +carnallites +carnally +carnassial +carnassials +carnation +carnations +carnauba +carne +carnegie +carnelian +carnelians +carnet +carnets +carnies +carniola +carniolan +carniolans +carnitine +carnitines +carnival +carnivals +carnivore +carnivores +carnivorous +carnivorously +carnivorousness +carnotite +carnotites +carny +carob +carobs +caroche +caroches +carol +carolean +caroled +caroler +carolers +carolina +carolinas +caroline +caroling +carolingian +carolingians +carolinian +carolinians +carols +carom +caromed +caroming +caroms +carotene +carotenemia +carotenemias +carotenoid +carotenoids +carotid +carotids +carousal +carousals +carouse +caroused +carousel +carousels +carouser +carousers +carouses +carousing +carp +carpaccio +carpaccios +carpal +carpals +carpathian +carpathians +carpe +carped +carpel +carpellary +carpellate +carpels +carpentaria +carpenter +carpentered +carpentering +carpenters +carpentry +carper +carpers +carpet +carpetbag +carpetbagger +carpetbaggers +carpetbaggery +carpetbags +carpeted +carpeting +carpetings +carpets +carpetweed +carpetweeds +carpi +carping +carpingly +carpool +carpooling +carpools +carpophagous +carpophore +carpophores +carport +carports +carps +carpus +carrack +carracks +carrageen +carrageenan +carrantuohill +carrara +carrefour +carrefours +carrel +carrels +carreras +carriage +carriages +carried +carrier +carriers +carries +carrion +carroll +carrot +carrots +carroty +carrousel +carrousels +carry +carryall +carryalls +carrying +carryings +carryon +carryons +carryout +carryouts +carryover +carryovers +cars +carsick +carsickness +cart +carta +cartable +cartage +cartagena +carte +carted +cartel +cartelize +cartelized +cartelizes +cartelizing +cartels +carter +carters +cartesian +cartesianism +cartesians +carthage +carthaginian +carthaginians +carthorse +carthorses +carthusian +carthusians +cartilage +cartilaginous +carting +cartload +cartloads +cartogram +cartograms +cartographer +cartographers +cartographic +cartographical +cartography +carton +cartoned +cartoning +cartons +cartoon +cartooned +cartooning +cartoonish +cartoonist +cartoonists +cartoons +cartop +cartouche +cartouches +cartridge +cartridges +carts +cartularies +cartulary +cartwheel +cartwheels +caruncle +caruncles +caruncular +carunculate +carunculated +caruso +carvacrol +carvacrols +carve +carved +carver +carvers +carves +carving +carvings +caryatid +caryatidal +caryatidean +caryatides +caryatidic +caryatids +caryopses +caryopsis +casaba +casabas +casablanca +casanova +casanovas +casaubon +casbah +cascade +cascaded +cascades +cascading +cascara +cascaras +cascarilla +cascarillas +case +caseate +caseated +caseates +caseating +caseation +caseations +casebook +casebooks +cased +caseharden +casehardened +casehardening +casehardens +casein +caseload +caseloads +casemate +casemated +casemates +casement +casemented +casements +caseous +casern +caserne +casernes +caserns +caserta +cases +casework +caseworker +caseworkers +cash +cashable +cashbook +cashbooks +cashed +casher +cashers +cashes +cashew +cashews +cashier +cashiered +cashiering +cashiers +cashing +cashless +cashmere +cashmeres +casing +casings +casino +casinos +cask +casket +casketed +casketing +caskets +casks +caspian +casque +casqued +casques +cassandra +cassandras +cassation +cassations +cassava +cassavas +casserole +casseroles +cassette +cassettes +cassia +cassias +cassimere +cassina +cassiopeia +cassis +cassiterite +cassius +cassock +cassocked +cassocks +cassoulet +cassoulets +cassowaries +cassowary +cast +castanet +castanets +castaway +castaways +caste +castellan +castellans +castellated +castellation +caster +casters +castes +castigate +castigated +castigates +castigating +castigation +castigations +castigator +castigators +castigatory +castile +castilian +castilians +casting +castings +castle +castled +castlereagh +castles +castling +castoff +castoffs +castor +castors +castrate +castrated +castrater +castraters +castrates +castrati +castrating +castration +castrations +castrato +castrator +castrators +castroism +castroist +castroists +casts +casual +casually +casualness +casuals +casualties +casualty +casuarina +casuarinas +casuist +casuistic +casuistically +casuistries +casuistry +casuists +casus +cat +catabolic +catabolically +catabolism +catabolite +catabolites +catabolize +catabolized +catabolizes +catabolizing +catachreses +catachresis +catachrestic +catachrestical +catachrestically +cataclysm +cataclysmal +cataclysmic +cataclysms +catacomb +catacombs +catadromous +catafalque +catafalques +catalan +catalans +catalase +catalases +catalatic +catalectic +catalepsies +catalepsy +cataleptic +cataleptics +catalexis +catalog +cataloged +cataloger +catalogers +cataloging +catalogs +catalogue +catalogued +cataloguer +cataloguers +catalogues +cataloguing +catalonia +catalonian +catalonians +catalpa +catalpas +catalyses +catalysis +catalyst +catalysts +catalytic +catalytically +catalyze +catalyzed +catalyzer +catalyzers +catalyzes +catalyzing +catamaran +catamarans +catamenia +catamenial +catamenias +catamite +catamites +catamount +catamountain +catamountains +catamounts +catania +catanzaro +cataphoresis +cataphoretic +cataphoretically +cataplasia +cataplasias +cataplasm +cataplasms +cataplastic +cataplectic +cataplexies +cataplexy +catapult +catapulted +catapulting +catapults +cataract +cataracts +catarrh +catarrhal +catarrhally +catarrhous +catarrhs +catastases +catastasis +catastrophe +catastrophes +catastrophic +catastrophically +catastrophism +catastrophist +catastrophists +catatonia +catatonic +catatonically +catatonics +catawba +catawbas +catbird +catbirds +catboat +catboats +catbrier +catbriers +catcall +catcalled +catcalling +catcalls +catch +catchable +catchall +catchalls +catcher +catchers +catches +catchflies +catchfly +catchier +catchiest +catchily +catchiness +catching +catchment +catchments +catchpenny +catchphrase +catchphrases +catchpole +catchpoles +catchword +catchwords +catchy +catecheses +catechesis +catechetical +catechin +catechins +catechism +catechisms +catechist +catechistic +catechistical +catechists +catechization +catechize +catechized +catechizer +catechizers +catechizes +catechizing +catechol +catecholamine +catecholamines +catechols +catechu +catechumen +catechumens +catechus +categoric +categorical +categorically +categoricalness +categories +categorizable +categorization +categorizations +categorize +categorized +categorizes +categorizing +category +catena +catenae +catenaries +catenary +catenate +catenated +catenates +catenating +catenation +cater +catercorner +catercornered +catered +caterer +caterers +catering +caterpillar +caterpillars +caters +caterwaul +caterwauled +caterwauling +caterwauls +catfight +catfights +catfish +catfishes +catgut +cathar +cathari +catharism +catharist +catharists +cathars +catharses +catharsis +cathartic +cathartics +cathay +cathead +catheads +cathect +cathected +cathectic +cathecting +cathects +cathedra +cathedrae +cathedral +cathedrals +cathepsin +cathepsins +catherine +catheter +catheterization +catheterize +catheterized +catheterizes +catheterizing +catheters +cathexes +cathexis +cathode +cathodes +cathodic +cathodically +catholic +catholically +catholicism +catholicity +catholicize +catholicized +catholicizes +catholicizing +catholicon +catholicons +catholics +cathouse +cathouses +catiline +cation +cationic +cations +catjang +catjangs +catkin +catkins +catlike +catmint +catmints +catnap +catnapped +catnapping +catnaps +catnip +catnips +cato +catoptric +catoptrics +cats +catskill +catskills +catsup +catsups +cattail +cattails +cattalo +cattaloes +cattalos +catted +cattier +cattiest +cattily +cattiness +catting +cattle +cattleman +cattlemen +cattleya +cattleyas +catty +catullus +catwalk +catwalks +caucasian +caucasians +caucasus +caucus +caucused +caucuses +caucusing +caudad +caudal +caudally +caudate +caudation +caudex +caudexes +caudices +caudillismo +caudillo +caudillos +caudle +caudles +caught +caul +cauldron +cauldrons +caulescent +cauliflorous +cauliflory +cauliflower +cauliflowers +cauline +caulk +caulked +caulking +caulkings +caulks +cauls +causable +causal +causalities +causality +causally +causals +causation +causations +causative +causatively +cause +caused +causeless +causer +causerie +causeries +causers +causes +causeway +causeways +causing +caustic +caustically +causticity +caustics +cauteries +cauterization +cauterizations +cauterize +cauterized +cauterizes +cauterizing +cautery +caution +cautionary +cautioned +cautioner +cautioners +cautioning +cautions +cautious +cautiously +cautiousness +cava +cavae +cavalas +cavalcade +cavalcades +cavalier +cavalierly +cavaliers +cavalla +cavalries +cavalry +cavalryman +cavalrymen +cavatelli +cave +caveat +caveated +caveating +caveats +caved +cavefish +cavefishes +caveman +cavemen +caver +cavern +caverned +cavernicolous +caverning +cavernous +cavernously +caverns +cavers +caves +cavetti +cavetto +cavettos +caviar +cavies +cavil +caviled +caviler +cavilers +caviling +cavils +caving +cavitate +cavitated +cavitates +cavitating +cavitation +cavitations +cavities +cavity +cavort +cavorted +cavorting +cavorts +cavour +cavy +caw +cawdor +cawed +cawing +caws +caxton +cay +cayenne +cayman +caymans +cays +cayuga +cayugas +cayuse +cayuses +caïque +caïques +ceanothus +cease +ceased +ceaseless +ceaselessly +ceaselessness +ceases +ceasing +ceca +cecal +cecally +cecil +cecropia +cecum +cedar +cedarbird +cedarbirds +cedars +cede +ceded +cedes +cedi +cedilla +cedillas +ceding +cedis +cee +cees +ceiba +ceibas +ceil +ceiled +ceilidh +ceilidhs +ceiling +ceilinged +ceilings +ceilometer +ceilometers +ceils +celadon +celadonite +celadonites +celadons +celaeno +celandine +celandines +celeb +celebes +celebrant +celebrants +celebrate +celebrated +celebrates +celebrating +celebration +celebrations +celebrator +celebrators +celebratory +celebrities +celebrity +celebrityhood +celebs +celeriac +celeriacs +celeries +celerity +celery +celesta +celestas +celestial +celestially +celestials +celestine +celestines +celestite +celestites +celiac +celibacy +celibate +celibates +cell +cella +cellae +cellar +cellarage +cellarages +cellared +cellarer +cellarers +cellarette +cellarettes +cellaring +cellars +cellblock +cellblocks +celled +celling +cellini +cellist +cellists +cellmate +cellmates +cello +cellobiose +cellobioses +celloidin +celloidins +cellophane +cellos +cells +cellular +cellularity +cellularly +cellulase +cellulases +cellule +cellules +cellulite +cellulitis +celluloid +celluloids +cellulolytic +cellulose +cellulosic +celosia +celosias +celotex +celsius +celt +celtiberian +celtiberians +celtic +celticism +celticisms +celticist +celticists +celtics +celts +cembalist +cembalists +cembalo +cembalos +cement +cementation +cementations +cemented +cementer +cementers +cementing +cementite +cementites +cementitious +cements +cementum +cemeteries +cemetery +cenacle +cenacles +cenobite +cenobites +cenobitic +cenobitical +cenospecies +cenotaph +cenotaphic +cenotaphs +cenozoic +cense +censed +censer +censers +censes +censing +censor +censorable +censored +censorial +censoring +censorious +censoriously +censoriousness +censors +censorship +censurability +censurable +censurableness +censurably +censure +censured +censurer +censurers +censures +censuring +census +censuses +cent +cental +centals +centaur +centauries +centaurs +centaurus +centaury +centavo +centavos +centenarian +centenarians +centenaries +centenary +centennial +centennially +centennials +center +centerboard +centerboards +centered +centeredly +centeredness +centerfold +centerfolds +centering +centerline +centerlines +centermost +centerpiece +centerpieces +centers +centesimal +centesimally +centesimi +centesimo +centesimos +centiampere +centiamperes +centibecquerel +centibecquerels +centicandela +centicandelas +centicoulomb +centicoulombs +centifarad +centifarads +centigrade +centigram +centigrams +centihenries +centihenry +centihenrys +centihertz +centijoule +centijoules +centikelvin +centikelvins +centiliter +centiliters +centilumen +centilumens +centilux +centime +centimes +centimeter +centimeters +centimo +centimole +centimoles +centimos +centinewton +centinewtons +centiohm +centiohms +centipascal +centipascals +centipede +centipedes +centipoise +centipoises +centiradian +centiradians +centisecond +centiseconds +centisiemens +centisievert +centisieverts +centisteradian +centisteradians +centitesla +centiteslas +centivolt +centivolts +centiwatt +centiwatts +centiweber +centiwebers +centner +centners +cento +centos +centra +central +centralism +centralist +centralistic +centralists +centrality +centralization +centralize +centralized +centralizer +centralizers +centralizes +centralizing +centrally +centrals +centric +centrically +centricity +centrifugal +centrifugalism +centrifugally +centrifugation +centrifuge +centrifuged +centrifuges +centrifuging +centriole +centrioles +centripetal +centripetally +centrism +centrist +centrists +centrobaric +centroid +centroids +centrolecithal +centrolineal +centromere +centromeres +centromeric +centrosome +centrosomes +centrosomic +centrosphere +centrospheres +centrum +centrums +cents +centuple +centurial +centuries +centurion +centurions +century +centurylong +ceorl +ceorls +cep +cephalad +cephalalgia +cephalalgias +cephalexin +cephalexins +cephalic +cephalically +cephalin +cephalins +cephalization +cephalizations +cephalochordate +cephalochordates +cephalometer +cephalometers +cephalometric +cephalometry +cephalonia +cephalopod +cephalopodan +cephalopodans +cephalopods +cephalosporin +cephalosporins +cephalothin +cephalothins +cephalothorax +cephalothoraxes +cepheid +cepheids +cepheus +ceps +ceraceous +ceram +ceramal +ceramals +ceramic +ceramics +ceramist +ceramists +cerastes +cerate +cerated +cerates +ceratodus +ceratoduses +ceratoid +cerberean +cerberus +cercaria +cercariae +cercarial +cercarias +cerci +cercus +cere +cereal +cereals +cerebella +cerebellar +cerebellum +cerebellums +cerebra +cerebral +cerebrally +cerebrate +cerebrated +cerebrates +cerebrating +cerebration +cerebrations +cerebroside +cerebrosides +cerebrospinal +cerebrovascular +cerebrum +cerebrums +cerecloth +cered +cerement +cerements +ceremonial +ceremonialism +ceremonialist +ceremonialists +ceremonially +ceremonials +ceremonies +ceremonious +ceremoniously +ceremoniousness +ceremony +ceres +cereus +cereuses +ceric +cerise +cerium +cermet +cermets +cernuous +cero +ceros +cerotype +cerotypes +cerous +certain +certainly +certainties +certainty +certes +certifiable +certifiably +certificate +certificated +certificates +certificating +certification +certifications +certificatory +certified +certifier +certifiers +certifies +certify +certifying +certiorari +certioraris +certitude +certitudes +cerulean +ceruloplasmin +ceruloplasmins +cerumen +ceruminous +ceruse +ceruses +cerussite +cerussites +cervantes +cervical +cervices +cervicitis +cervine +cervix +cervixes +cesarean +cesareans +cesium +cespitose +cespitosely +cessation +cessations +cession +cessions +cessna +cesspit +cesspits +cesspool +cesspools +cesta +cestas +cesti +cestode +cestodes +cestus +cestuses +cetacean +cetaceans +cetaceous +cetane +cetanes +cete +cetera +ceteris +cetes +cetological +cetologist +cetologists +cetology +cevennes +ceviche +ceviches +ceylon +ceylonese +chablis +chachka +chachkas +chacma +chacmas +chaconne +chaconnes +chacun +chad +chadian +chadians +chadless +chador +chadors +chaeronea +chaeta +chaetae +chaetognath +chaetognathous +chaetognaths +chafe +chafed +chafer +chafers +chafes +chaff +chaffed +chaffer +chaffered +chafferer +chafferers +chaffering +chaffers +chaffinch +chaffinches +chaffing +chaffs +chafing +chagall +chagrin +chagrined +chagrining +chagrins +chain +chained +chaining +chainlike +chainlink +chainman +chainmen +chains +chainsaw +chainsaws +chair +chaired +chairing +chairlady +chairman +chairmanned +chairmanning +chairmans +chairmanship +chairmanships +chairmen +chairperson +chairpersons +chairs +chairwoman +chairwomen +chaise +chaises +chakra +chakras +chalaza +chalazae +chalazal +chalazas +chalazia +chalazion +chalcedon +chalcedonic +chalcedonies +chalcedony +chalcid +chalcidian +chalcidians +chalcidice +chalcids +chalcocite +chalcocites +chalcopyrite +chalcopyrites +chaldaic +chaldaics +chaldea +chaldean +chaldeans +chaldee +chaldees +chaldron +chaldrons +chalet +chalets +chaliapin +chalice +chalices +chalicothere +chalicotheres +chalk +chalkboard +chalkboards +chalked +chalkier +chalkiest +chalkiness +chalking +chalks +chalkstone +chalkstones +chalky +challah +challahs +challenge +challengeable +challenged +challenger +challengers +challenges +challenging +challengingly +challis +chalone +chalones +chalybeate +chalybeates +cham +chamaeleon +chamaephyte +chamaephytes +chamber +chambered +chambering +chamberlain +chamberlains +chambermaid +chambermaids +chambers +chambray +chameleon +chameleonic +chameleons +chamfer +chamfered +chamfering +chamfers +chamfron +chamfrons +chamise +chamises +chamizal +chamois +chamomile +chamomiles +chamonix +champ +champagne +champagnes +champaign +champaigns +champak +champaks +champed +champerties +champertous +champerty +champignon +champignons +champing +champion +championed +championing +champions +championship +championships +champlain +champlevé +champs +champêtre +champêtres +chams +chance +chanced +chanceful +chancel +chancelleries +chancellery +chancellor +chancellors +chancellorship +chancels +chanceries +chancery +chances +chancier +chanciest +chanciness +chancing +chancre +chancres +chancroid +chancroidal +chancroids +chancrous +chancy +chandelier +chandeliers +chandelle +chandelles +chandigarh +chandler +chandlers +chandlery +chandos +chandragupta +change +changeability +changeable +changeableness +changeably +changed +changeful +changefully +changefulness +changeless +changeling +changelings +changeover +changeovers +changer +changers +changes +changeup +changeups +changing +channel +channeled +channeler +channelers +channeling +channelings +channelization +channelizations +channelize +channelized +channelizes +channelizing +channels +chanoyu +chanoyus +chanson +chansons +chant +chanted +chanter +chanterelle +chanterelles +chanters +chanteuse +chanteuses +chantey +chanteys +chanticleer +chanticleers +chantilly +chanting +chantingly +chantries +chantry +chants +chanukah +chaos +chaotic +chaotically +chap +chaparral +chaparrals +chapati +chapatis +chapbook +chapbooks +chape +chapeau +chapeaus +chapeaux +chapel +chapels +chaperon +chaperonage +chaperone +chaperoned +chaperones +chaperoning +chaperons +chapes +chapfallen +chapiter +chapiters +chaplain +chaplaincies +chaplaincy +chaplains +chaplainship +chaplet +chapleted +chaplets +chaplin +chapman +chapmen +chapped +chapping +chaps +chapter +chapters +chapultepec +char +charabanc +charabancs +characin +characins +character +charactered +characterful +characteries +charactering +characteristic +characteristically +characteristics +characterization +characterizations +characterize +characterized +characterizer +characterizers +characterizes +characterizing +characterless +characters +charactery +charade +charades +charbroil +charbroiled +charbroiling +charbroils +charcoal +charcoaled +charcoaling +charcoals +charcuterie +charcuteries +chard +chardonnay +chardonnays +chare +chares +charge +chargeable +chargeableness +charged +charger +chargers +charges +charging +chargé +chargés +charier +chariest +charily +chariness +chariot +charioted +charioteer +charioteers +charioting +chariots +charism +charisma +charismata +charismatic +charismatics +charitable +charitableness +charitably +charities +charity +charivari +charivaris +charkha +charkhas +charlatan +charlatanic +charlatanical +charlatanism +charlatanry +charlatans +charlemagne +charleroi +charles +charleston +charlestons +charley +charlie +charlock +charlocks +charlotte +charlottes +charlottesville +charm +charmed +charmer +charmers +charmeuse +charmeuses +charming +charmingly +charmless +charmonium +charmoniums +charms +charnel +charnels +charolais +charon +charqui +charred +charring +chars +chart +charted +charter +chartered +charterer +charterers +charterhouse +charterhouses +chartering +charters +charting +chartings +chartism +chartist +chartists +chartres +chartreuse +chartroom +chartrooms +charts +charwoman +charwomen +chary +charybdis +chase +chased +chaser +chasers +chases +chasing +chasm +chasmal +chasmogamous +chasms +chassepots +chasseur +chasseurs +chassis +chassises +chassé +chasséd +chasséing +chassés +chaste +chastely +chasten +chastened +chastener +chasteners +chasteness +chastening +chastens +chaster +chastest +chastisable +chastise +chastised +chastisement +chastisements +chastiser +chastisers +chastises +chastising +chastity +chasuble +chasubles +chat +chateau +chateaubriand +chateaubriands +chateaus +chateaux +chatelain +chatelaine +chatelaines +chatelains +chatoyancy +chatoyant +chatoyants +chats +chattahoochee +chattanooga +chatted +chattel +chattels +chatter +chatterbox +chatterboxes +chattered +chatterer +chatterers +chattering +chatters +chatterton +chattier +chattiest +chattily +chattiness +chatting +chatty +chaucer +chaucerian +chaucerians +chauffeur +chauffeured +chauffeuring +chauffeurs +chaulmoogra +chaulmoogras +chautauqua +chauvinism +chauvinist +chauvinistic +chauvinistically +chauvinists +chaw +chawed +chawing +chaws +chayote +chayotes +chazan +chazans +cheap +cheapen +cheapened +cheapener +cheapeners +cheapening +cheapens +cheaper +cheapest +cheapie +cheapies +cheapjack +cheapjacks +cheaply +cheapness +cheapskate +cheapskates +cheat +cheated +cheater +cheaters +cheating +cheatingly +cheats +chebec +chebecs +chebyshev +check +checkable +checkbook +checkbooks +checkbox +checkboxes +checked +checker +checkerberries +checkerberry +checkerbloom +checkerblooms +checkerboard +checkerboards +checkered +checkering +checkers +checking +checklist +checklists +checkmark +checkmarks +checkmate +checkmated +checkmates +checkmating +checkoff +checkout +checkouts +checkpoint +checkpoints +checkrein +checkreins +checkroom +checkrooms +checks +checksum +checksums +checkup +checkups +cheddar +cheddars +cheek +cheekbone +cheekbones +cheeked +cheekier +cheekiest +cheekily +cheekiness +cheeking +cheeks +cheeky +cheep +cheeped +cheeper +cheepers +cheeping +cheeps +cheer +cheered +cheerer +cheerers +cheerful +cheerfully +cheerfulness +cheerier +cheeriest +cheerily +cheeriness +cheering +cheeringly +cheerio +cheerios +cheerlead +cheerleader +cheerleaders +cheerleading +cheerleads +cheerled +cheerless +cheerlessly +cheerlessness +cheers +cheery +cheese +cheeseburger +cheeseburgers +cheesecake +cheesecakes +cheesecloth +cheesed +cheeseparer +cheeseparers +cheeseparing +cheeses +cheesier +cheesiest +cheesiness +cheesing +cheesy +cheetah +cheetahs +chef +chefs +chekhov +chekhovian +chela +chelae +chelatable +chelate +chelated +chelates +chelating +chelation +chelator +chelators +chelicera +chelicerae +cheliform +chellian +chelonian +chelonians +chelsea +chemic +chemical +chemically +chemicals +chemiluminescence +chemiluminescent +chemin +chemins +chemise +chemises +chemisette +chemisettes +chemisorb +chemisorbed +chemisorbing +chemisorbs +chemisorption +chemist +chemistries +chemistry +chemists +chemoautotroph +chemoautotrophic +chemoautotrophically +chemoautotrophs +chemoautotrophy +chemoprevention +chemopreventions +chemopreventive +chemoprophylactic +chemoprophylaxis +chemoreception +chemoreceptive +chemoreceptivity +chemoreceptor +chemoreceptors +chemosensory +chemosphere +chemospheres +chemosurgery +chemosurgical +chemosynthesis +chemosynthetic +chemosynthetically +chemosystematics +chemotactic +chemotactically +chemotaxis +chemotaxonomic +chemotaxonomically +chemotaxonomist +chemotaxonomists +chemotaxonomy +chemotherapeutic +chemotherapeutically +chemotherapist +chemotherapists +chemotherapy +chemotropic +chemotropism +chemotropisms +chemurgic +chemurgical +chemurgy +chenille +chenilles +chenopod +chenopods +cheops +cheque +chequer +chequers +cheques +cherbourg +cherimoya +cherimoyas +cherish +cherishable +cherished +cherisher +cherishers +cherishes +cherishing +cherishingly +chernobyl +chernozem +chernozemic +chernozems +cherokee +cherokees +cheroot +cheroots +cherries +cherry +cherrystone +cherrystones +chersonese +chersoneses +chert +cherty +cherub +cherubic +cherubically +cherubim +cherubs +chervil +chesapeake +cheshire +chess +chessboard +chessboards +chesses +chessman +chessmen +chessylite +chessylites +chest +chested +chesterfield +chesterfields +chestier +chestiest +chestiness +chestnut +chestnuts +chests +chesty +chetrum +cheval +chevalet +chevalets +chevalier +chevaliers +chevaux +chevelure +chevelures +cheviot +cheviots +chevrolet +chevrolets +chevron +chevrons +chevrotain +chevrotains +chew +chewable +chewed +chewer +chewers +chewier +chewiest +chewiness +chewing +chewink +chewinks +chews +chewy +cheyenne +cheyennes +chez +chi +chia +chianti +chiantis +chiaroscurist +chiaroscurists +chiaroscuro +chiaroscuros +chias +chiasma +chiasmal +chiasmas +chiasmata +chiasmatic +chiasmatypies +chiasmatypy +chiasmi +chiasmic +chiasmus +chiastolite +chiastolites +chiaus +chibcha +chibchan +chibchans +chibchas +chibouk +chibouks +chic +chicago +chicagoan +chicagoans +chicana +chicane +chicaned +chicaner +chicaneries +chicaners +chicanery +chicanes +chicaning +chicano +chicanos +chicer +chicest +chichagof +chichi +chichier +chichiest +chick +chickadee +chickadees +chickaree +chickarees +chickasaw +chickasaws +chicken +chickened +chickenfeed +chickenhearted +chickening +chickenpox +chickens +chickpea +chickpeas +chicks +chickweed +chickweeds +chicle +chiclets +chicly +chicness +chicories +chicory +chid +chidden +chide +chided +chider +chiders +chides +chiding +chidingly +chief +chiefdom +chiefdoms +chiefly +chiefs +chiefship +chieftain +chieftaincy +chieftains +chieftainship +chiffchaff +chiffchaffs +chiffon +chiffonier +chiffoniers +chiffonnier +chiffonniers +chifforobe +chifforobes +chigger +chiggers +chignon +chignons +chigoe +chihuahua +chihuahuas +chilblain +chilblained +chilblains +child +childbearing +childbed +childbirth +childbirths +childermas +childermases +childfree +childhood +childish +childishly +childishness +childless +childlessness +childlike +childproof +childproofed +childproofing +childproofs +children +chile +chilean +chileans +chili +chiliad +chiliads +chiliasm +chiliast +chiliastic +chiliburger +chiliburgers +chilidog +chilidogs +chilies +chill +chilled +chiller +chillers +chillier +chilliest +chillily +chilliness +chilling +chillingly +chillness +chills +chilly +chiloe +chilopod +chilopods +chiloé +chimaera +chimaeras +chimborazo +chime +chimed +chimer +chimera +chimeras +chimeric +chimerical +chimerically +chimerism +chimerisms +chimers +chimes +chimichanga +chimichangas +chiming +chimney +chimneypiece +chimneypieces +chimneys +chimneysweep +chimneysweeper +chimneysweepers +chimneysweeps +chimp +chimpanzee +chimpanzees +chimps +chin +china +chinaberries +chinaberry +chinaman +chinamen +chinatown +chinatowns +chinaware +chinch +chincherinchee +chincherinchees +chinches +chinchilla +chinchillas +chincoteague +chindit +chindits +chindwin +chine +chines +chinese +chink +chinked +chinking +chinks +chinky +chinless +chinned +chinning +chino +chinoiserie +chinoiseries +chinook +chinookan +chinooks +chinos +chinquapin +chinquapins +chins +chintz +chintzes +chintzier +chintziest +chintzy +chip +chipboard +chipboards +chipewyan +chipewyans +chipmaker +chipmakers +chipmunk +chipmunks +chipped +chippendale +chipper +chippered +chippering +chippers +chippewa +chippewas +chippier +chippies +chippiest +chipping +chippy +chips +chiral +chirality +chiricahua +chiricahuas +chirk +chirked +chirking +chirks +chirographer +chirographers +chirographic +chirographical +chirography +chiromancer +chiromancers +chiromancy +chiron +chiropodist +chiropodists +chiropody +chiropractic +chiropractor +chiropractors +chiropteran +chiropterans +chirp +chirped +chirpier +chirpiest +chirpily +chirping +chirps +chirpy +chirr +chirred +chirring +chirrs +chirrup +chirruped +chirruping +chirrups +chisel +chiseled +chiseler +chiselers +chiseling +chisels +chit +chitchat +chitchats +chitchatted +chitchatting +chitin +chitinous +chitlins +chiton +chits +chittagong +chitter +chittered +chittering +chitterlings +chitters +chivalric +chivalries +chivalrous +chivalrously +chivalrousness +chivalry +chive +chives +chivied +chivies +chivvied +chivvies +chivvy +chivvying +chivy +chivying +chlamydate +chlamydeous +chlamydes +chlamydia +chlamydiae +chlamydial +chlamydospore +chlamydospores +chlamys +chlamyses +chloasma +chloasmata +chloe +chloracne +chloracnes +chloral +chloramine +chloramines +chloramphenicol +chlorate +chlorates +chlordane +chlordiazepoxide +chlorella +chlorenchyma +chloric +chloride +chlorides +chloridic +chlorinate +chlorinated +chlorinates +chlorinating +chlorination +chlorinations +chlorinator +chlorinators +chlorine +chlorite +chlorites +chlorobenzene +chlorocarbon +chlorocarbons +chlorofluorocarbon +chloroform +chloroformed +chloroforming +chloroforms +chlorohydrin +chloromycetin +chlorophyll +chloropicrin +chloroplast +chloroplasts +chloroprene +chloroquine +chlorosis +chlorothiazide +chlorothiazides +chlorotic +chlorotically +chlorpromazine +chlortetracycline +choanocyte +choanocytes +chock +chockablock +chocked +chockfull +chocking +chocks +chocoholic +chocoholics +chocolate +chocolates +choctaw +choctawhatchee +choctaws +choice +choicely +choiceness +choicer +choices +choicest +choir +choirboy +choirboys +choired +choirgirl +choirgirls +choiring +choirmaster +choirmasters +choirs +choiseul +choke +chokeberries +chokeberry +chokebore +chokebores +chokecherries +chokecherry +choked +chokedamp +chokehold +chokeholds +chokepoint +chokepoints +choker +chokers +chokes +chokier +chokiest +choking +chokingly +choky +cholangiographic +cholangiography +cholecalciferol +cholecyst +cholecystectomies +cholecystectomy +cholecystitis +cholecystokinin +cholecysts +cholelithiasis +choler +cholera +choleraic +choleric +cholerically +choleroid +cholestasis +cholesterin +cholesterol +cholestyramine +choline +cholinergic +cholinesterase +cholla +chomp +chomped +chomping +chomps +chomsky +chomskyan +chondrification +chondrified +chondrifies +chondrify +chondrifying +chondriosome +chondriosomes +chondrite +chondrites +chondritic +chondrocrania +chondrocranium +chondrocraniums +chondroma +chondromalacia +chondromas +chondromata +chondrule +chondrules +choose +chooser +choosers +chooses +choosier +choosiest +choosiness +choosing +choosy +chop +chophouse +chophouses +chopin +chopine +chopines +choplogic +chopped +chopper +choppered +choppering +choppers +choppier +choppiest +choppily +choppiness +chopping +choppy +chops +chopstick +chopsticks +choragi +choragic +choragus +choral +chorale +chorales +chorally +chord +chordal +chordate +chordates +chorded +chording +chords +chore +chorea +choreograph +choreographed +choreographer +choreographers +choreographic +choreographically +choreographies +choreographing +choreographs +choreography +chores +choriamb +choriambic +choriambs +choric +chorine +chorines +chorioallantoic +chorioallantois +chorion +chorionic +chorions +choripetalous +chorister +choristers +chorizo +chorizos +chorographer +chorographers +chorographic +chorographical +chorographically +chorography +choroid +choroids +chortle +chortled +chortler +chortlers +chortles +chortling +chorus +chorused +choruses +chorusing +chose +chosen +chott +chotts +choucroute +choucroutes +chough +choughs +chouse +choused +chouses +chousing +chow +chowchow +chowchows +chowder +chowders +chowed +chowhound +chowhounds +chowing +chows +chresard +chresards +chrestomathic +chrestomathies +chrestomathy +chris +chrism +chrismal +chrisms +chrisom +chrisoms +christ +christchurch +christen +christendom +christened +christening +christenings +christens +christi +christian +christiania +christianities +christianity +christianization +christianize +christianized +christianizer +christianizers +christianizes +christianizing +christianly +christians +christie +christies +christina +christine +christlike +christlikeness +christliness +christly +christmas +christmases +christmassy +christmastide +christmastime +christmastimes +christogram +christograms +christological +christologies +christology +christopher +chroma +chromaffin +chromate +chromatic +chromatically +chromaticism +chromaticity +chromatics +chromatid +chromatids +chromatin +chromatinic +chromatist +chromatists +chromatogram +chromatograms +chromatograph +chromatographed +chromatographer +chromatographers +chromatographic +chromatographically +chromatographing +chromatographs +chromatography +chromatolysis +chromatolytic +chromatophilic +chromatophore +chromatophores +chromatophoric +chrome +chromed +chromes +chromic +chroming +chromite +chromium +chromodynamics +chromogen +chromogenic +chromogens +chromolithograph +chromolithographer +chromolithographers +chromolithographic +chromolithographs +chromolithography +chromomere +chromomeres +chromomeric +chromonema +chromonemal +chromonemata +chromonemic +chromophil +chromophore +chromophores +chromophoric +chromoplast +chromoprotein +chromoproteins +chromosomal +chromosomally +chromosome +chromosomes +chromosomic +chromosphere +chromospheres +chromospheric +chromous +chronaxie +chronaxies +chronic +chronically +chronicity +chronicle +chronicled +chronicler +chroniclers +chronicles +chronicling +chronobiology +chronogram +chronogrammatic +chronogrammatically +chronograms +chronograph +chronographic +chronographically +chronographs +chronological +chronologically +chronologies +chronologist +chronologists +chronologize +chronologized +chronologizes +chronologizing +chronology +chronometer +chronometers +chronometric +chronometrical +chronometrically +chronometry +chronoscope +chronoscopes +chronoscopic +chrysalid +chrysalides +chrysalids +chrysalis +chrysalises +chrysanthemum +chrysanthemums +chryselephantine +chrysler +chryslers +chrysoberyl +chrysolite +chrysolites +chrysomelid +chrysomelids +chrysoprase +chrysoprases +chrysotherapy +chrysotile +chrysotiles +chthonic +chub +chubbier +chubbiest +chubbily +chubbiness +chubby +chubs +chuck +chucked +chuckhole +chuckholes +chucking +chuckle +chuckled +chucklehead +chuckleheaded +chuckleheads +chuckler +chucklers +chuckles +chucklesome +chuckling +chucklingly +chucks +chuckwalla +chuckwallas +chuddar +chuddars +chufa +chufas +chuff +chuffed +chuffing +chuffs +chuffy +chug +chugalug +chugalugged +chugalugging +chugalugs +chugged +chugger +chuggers +chugging +chugs +chukar +chukars +chukka +chukkas +chukker +chukkers +chum +chummed +chummier +chummiest +chummily +chumminess +chumming +chummy +chump +chumped +chumping +chumps +chums +chungking +chunk +chunked +chunkier +chunkiest +chunkily +chunkiness +chunking +chunks +chunky +chunnel +chunnels +chunter +chuntered +chuntering +chunters +church +churched +churches +churchgoer +churchgoers +churchgoing +churchier +churchiest +churchill +churchillian +churching +churchliness +churchly +churchman +churchmanly +churchmanship +churchmen +churchwarden +churchwardens +churchwoman +churchwomen +churchy +churchyard +churchyards +churl +churlish +churlishly +churlishness +churls +churn +churned +churner +churners +churning +churns +churr +churred +churrigueresque +churring +churro +churros +churrs +chute +chuted +chutes +chuting +chutist +chutists +chutney +chutneys +chutzpa +chutzpah +chutzpas +chuvash +chuvashes +chylaceous +chyle +chyles +chylomicron +chylomicrons +chylous +chyme +chymes +chymopapain +chymopapains +chymosin +chymosins +chymotrypsin +chymotrypsins +chymotryptic +chymous +châlons +château +châteaux +châtelherault +chèvre +ciao +cibber +ciboria +ciborium +cicada +cicadae +cicadas +cicala +cicalas +cicatrices +cicatricial +cicatricose +cicatrix +cicatrization +cicatrize +cicatrized +cicatrizes +cicatrizing +cicero +cicerone +cicerones +ciceroni +ciceronian +cichlid +cichlids +cider +ciders +cigar +cigarette +cigarettes +cigarillo +cigarillos +cigars +cilantro +cilia +ciliary +ciliate +ciliated +ciliately +ciliates +ciliation +cilice +cilices +cilicia +cilician +cilicians +ciliolate +cilium +cimarron +cimetidine +cimex +cimices +cimmerian +cinch +cinched +cincher +cinchers +cinches +cinching +cinchona +cinchonas +cinchonic +cinchonine +cinchonism +cincinnati +cincture +cinctured +cinctures +cincturing +cinder +cindered +cinderella +cindering +cinders +cindery +cindy +cine +cineaste +cineastes +cinema +cinemagoer +cinemagoers +cinemas +cinematheque +cinematheques +cinematic +cinematically +cinematization +cinematizations +cinematize +cinematized +cinematizes +cinematizing +cinematograph +cinematographer +cinematographers +cinematographically +cinematographs +cinematography +cineole +cineoles +cinephile +cinephiles +cineradiography +cinerama +cineraria +cinerarium +cinerary +cinereous +cinerin +cinerins +cines +cingalese +cingula +cingulate +cingulated +cingulum +cinnabar +cinnamic +cinnamon +cinquain +cinquains +cinque +cinquecentist +cinquecentists +cinquecento +cinquefoil +cinquefoils +cinques +cinéma +cipher +ciphered +ciphering +ciphers +circa +circadian +circadianly +circassia +circassian +circassians +circe +circean +circinate +circinately +circinus +circle +circled +circler +circlers +circles +circlet +circlets +circling +circuit +circuited +circuiting +circuitous +circuitously +circuitousness +circuitries +circuitry +circuits +circuity +circular +circularities +circularity +circularization +circularize +circularized +circularizer +circularizers +circularizes +circularizing +circularly +circulars +circulate +circulated +circulates +circulating +circulation +circulations +circulative +circulator +circulators +circulatory +circumambience +circumambiency +circumambient +circumambiently +circumambulate +circumambulated +circumambulates +circumambulating +circumambulation +circumambulations +circumboreal +circumcise +circumcised +circumciser +circumcisers +circumcises +circumcising +circumcision +circumcisions +circumduction +circumductions +circumference +circumferences +circumferential +circumflex +circumflexes +circumfluent +circumfuse +circumfused +circumfuses +circumfusing +circumfusion +circumlocution +circumlocutions +circumlocutorily +circumlocutory +circumlunar +circumnavigate +circumnavigated +circumnavigates +circumnavigating +circumnavigation +circumnavigations +circumnavigator +circumnavigators +circumpolar +circumrotate +circumrotated +circumrotates +circumrotating +circumrotation +circumrotations +circumrotatory +circumscissile +circumscribable +circumscribe +circumscribed +circumscriber +circumscribers +circumscribes +circumscribing +circumscription +circumscriptions +circumscriptive +circumscriptively +circumsolar +circumspect +circumspection +circumspectly +circumstance +circumstanced +circumstances +circumstancing +circumstantial +circumstantialities +circumstantiality +circumstantially +circumstantiate +circumstantiated +circumstantiates +circumstantiating +circumstantiation +circumstantiations +circumterrestrial +circumvallate +circumvallated +circumvallates +circumvallating +circumvallation +circumvallations +circumvent +circumvented +circumventer +circumventers +circumventing +circumvention +circumventions +circumventive +circumvents +circumvolution +circumvolutions +circumvolve +circumvolved +circumvolves +circumvolving +circus +circuses +circusy +cirque +cirques +cirrate +cirrhoses +cirrhosis +cirrhotic +cirri +cirriped +cirripeds +cirrocumuli +cirrocumulus +cirrostrati +cirrostratus +cirrus +ciré +cisalpine +cisatlantic +ciscaucasia +cisco +ciscoes +cislunar +cismontane +cist +cistercian +cistercians +cistern +cisterna +cisternae +cisternal +cisterns +cistron +cistronic +cistrons +cists +cit +citable +citadel +citadels +citation +citational +citations +citatory +cite +cited +cites +cithaeron +cithara +citharas +cither +cithers +citied +cities +citification +citified +citifies +citify +citifying +citing +citizen +citizeness +citizenesses +citizenly +citizenries +citizenry +citizens +citizenship +citlaltépetl +citral +citrals +citrate +citrates +citric +citriculture +citricultures +citriculturist +citriculturists +citrine +citrines +citroen +citron +citronella +citronellal +citronellals +citronellas +citronellol +citronellols +citrons +citrulline +citrullines +citrus +citruses +cittern +citterns +city +cityscape +cityscapes +citywide +civet +civets +civic +civics +civil +civilian +civilianization +civilianize +civilianized +civilianizes +civilianizing +civilians +civilities +civility +civilizable +civilization +civilizations +civilize +civilized +civilizer +civilizers +civilizes +civilizing +civilly +civism +civisms +civitavecchia +civvies +clabber +clabbered +clabbering +clabbers +clack +clacked +clacker +clackers +clacking +clacks +clactonian +clad +cladding +claddings +clade +clades +cladist +cladistic +cladistically +cladistics +cladists +cladoceran +cladocerans +cladode +cladodes +cladodial +cladogenesis +cladogenetic +cladogenetically +cladogram +cladograms +cladophyll +cladophylls +clads +clafouti +claim +claimable +claimant +claimants +claimed +claimer +claimers +claiming +claims +clair +clairaudience +clairaudiences +clairaudient +claire +clairvaux +clairvoyance +clairvoyant +clairvoyants +clam +clamant +clamantly +clambake +clambakes +clamber +clambered +clamberer +clamberers +clambering +clambers +clammed +clammer +clammers +clammier +clammiest +clammily +clamminess +clamming +clammy +clamor +clamored +clamorer +clamorers +clamoring +clamorous +clamorously +clamorousness +clamors +clamp +clampdown +clampdowns +clamped +clamper +clampers +clamping +clamps +clams +clamshell +clamshells +clamworm +clamworms +clan +clandestine +clandestinely +clandestineness +clandestinity +clang +clanged +clanging +clangor +clangored +clangoring +clangorous +clangorously +clangors +clangs +clank +clanked +clanking +clanks +clanky +clannish +clannishly +clannishness +clans +clansman +clansmen +clanswoman +clanswomen +clap +clapboard +clapboarded +clapboarding +clapboards +clapped +clapper +clappers +clapping +claps +claptrap +claque +claques +clarence +clarences +claret +clarets +claries +clarification +clarifications +clarificatory +clarified +clarifier +clarifiers +clarifies +clarify +clarifying +clarinet +clarinetist +clarinetists +clarinets +clarion +clarions +clarity +clarkia +clarkias +clary +clash +clashed +clashes +clashing +clasp +clasped +clasper +claspers +clasping +clasps +class +classed +classes +classic +classical +classicality +classically +classicalness +classicism +classicist +classicists +classicize +classicized +classicizes +classicizing +classics +classier +classiest +classifiable +classification +classifications +classificatorily +classificatory +classified +classifieds +classifier +classifiers +classifies +classify +classifying +classiness +classing +classis +classism +classisms +classist +classless +classman +classmate +classmates +classmen +classon +classons +classroom +classrooms +classy +clast +clastic +clasts +clathrate +clathrates +clatter +clattered +clatterer +clatterers +clattering +clatters +clattery +claude +claudication +claudications +claudius +claus +clausal +clause +clauses +clausewitz +claustrophobe +claustrophobia +claustrophobic +claustrophobically +clavate +clavately +clavichord +clavichordist +clavichordists +clavichords +clavicle +clavicles +clavicular +claviculate +clavier +claviers +clavus +claw +clawed +clawing +claws +clay +clayey +clayish +claylike +claymation +claymore +claymores +clays +clayware +clean +cleanable +cleaned +cleaner +cleaners +cleanest +cleaning +cleanlier +cleanliest +cleanliness +cleanly +cleanness +cleans +cleanse +cleansed +cleanser +cleansers +cleanses +cleansing +cleanthes +cleanup +cleanups +clear +clearable +clearance +clearances +clearchus +cleared +clearer +clearers +clearest +clearheaded +clearheadedly +clearing +clearinghouse +clearinghouses +clearings +clearly +clearness +clears +clearweed +clearweeds +clearwing +clearwings +cleat +cleated +cleating +cleats +cleavable +cleavage +cleavages +cleave +cleaved +cleaver +cleavers +cleaves +cleaving +clef +clefs +cleft +clefts +cleisthenes +cleistogamous +cleistogamously +cleistogamy +cleistothecia +cleistothecium +clematis +clematises +clemenceau +clemencies +clemency +clement +clementine +clementines +clemently +clench +clenched +clenches +clenching +cleome +cleomes +cleopatra +clepsydra +clepsydrae +clepsydras +clerestories +clerestory +clergies +clergy +clergyman +clergymen +clergywoman +clergywomen +cleric +clerical +clericalism +clericalist +clericalists +clerically +clericals +clerics +clerihew +clerihews +clerisies +clerisy +clerk +clerkdom +clerkdoms +clerked +clerking +clerklier +clerkliest +clerkliness +clerkly +clerks +clerkship +clerkships +cleveland +clever +cleverer +cleverest +cleverly +cleverness +cleves +clevis +clevises +clew +clewed +clewing +clews +cliché +clichéd +clichés +click +clicked +clicker +clickers +clicking +clicks +client +clientage +cliental +clientele +clienteles +clients +cliff +cliffhanger +cliffhangers +cliffhanging +clifford +cliffs +cliffy +climacteric +climacterics +climactic +climactically +climate +climates +climatic +climatically +climatologic +climatological +climatologically +climatologist +climatologists +climatology +climax +climaxed +climaxes +climaxing +climb +climbable +climbed +climber +climbers +climbing +climbs +clime +climes +clinandria +clinandrium +clinch +clinched +clincher +clinchers +clinches +clinching +cline +clines +cling +clinger +clingers +clingfish +clingfishes +clinging +clings +clingstone +clingstones +clingy +clinic +clinical +clinically +clinician +clinicians +clinics +clink +clinked +clinker +clinkered +clinkering +clinkers +clinking +clinks +clinometer +clinometers +clinometric +clinometrical +clinometry +clinquant +clinquants +clinton +clintonia +clintonias +clio +cliometric +cliometrician +cliometricians +cliometrics +clios +clip +clipboard +clipboards +clipped +clipper +clippers +clipping +clippings +clips +clipsheet +clipsheets +clique +cliqued +cliques +cliquey +cliquing +cliquish +cliquishly +cliquishness +clisthenes +clitella +clitellum +clitoral +clitoris +clitorises +clive +cloaca +cloacae +cloacal +cloak +cloaked +cloaking +cloakroom +cloakrooms +cloaks +clobber +clobbered +clobbering +clobbers +clochard +clochards +cloche +cloches +clock +clocked +clocker +clockers +clocking +clockmaker +clockmakers +clocks +clockwise +clockwork +clockworks +clod +cloddish +cloddishly +cloddishness +clodhopper +clodhoppers +clodhopping +clods +clofibrate +clofibrates +clog +clogged +clogging +clogs +cloisonné +cloister +cloistered +cloistering +cloisters +cloistral +clomiphene +clomiphenes +clomp +clomped +clomping +clomps +clonal +clonally +clone +cloned +cloner +cloners +clones +clonic +clonicity +clonidine +clonidines +cloning +clonism +clonus +clonuses +clop +clopped +clopping +clops +cloque +cloques +close +closed +closedown +closedowns +closefisted +closely +closemouthed +closeness +closeout +closeouts +closer +closers +closes +closest +closet +closeted +closetful +closeting +closets +closing +closings +clostridia +clostridial +clostridium +closure +closured +closures +closuring +clot +cloth +clothbound +clothe +clothed +clothes +clothesbasket +clothesbaskets +clotheshorse +clotheshorses +clothesline +clotheslined +clotheslines +clotheslining +clothespin +clothespins +clothespress +clothespresses +clothier +clothiers +clothing +clotho +cloths +clots +clotted +clotting +cloture +clotured +clotures +cloturing +cloud +cloudberries +cloudberry +cloudburst +cloudbursts +clouded +cloudier +cloudiest +cloudily +cloudiness +clouding +cloudland +cloudlands +cloudless +cloudlessness +cloudlet +cloudlets +clouds +cloudscape +cloudscapes +cloudy +clout +clouted +clouting +clouts +clove +cloven +clover +cloverleaf +cloverleaves +clovers +cloves +clovis +clown +clowned +clowning +clownish +clownishly +clownishness +clowns +cloxacillin +cloxacillins +cloy +cloyed +cloying +cloyingly +cloyingness +cloys +cloze +club +clubbable +clubbed +clubber +clubbers +clubbier +clubbiest +clubbiness +clubbing +clubby +clubface +clubfaces +clubfeet +clubfoot +clubfooted +clubfoots +clubhouse +clubhouses +clubman +clubmate +clubmates +clubmen +clubroom +clubrooms +clubs +clubwoman +clubwomen +cluck +clucked +clucking +clucks +clue +clued +clueing +clueless +clues +clump +clumped +clumping +clumpings +clumps +clumpy +clumsier +clumsiest +clumsily +clumsiness +clumsy +clung +cluniac +clunk +clunked +clunker +clunkers +clunkier +clunkiest +clunking +clunks +clunky +cluny +clupeid +clupeids +cluster +clustered +clustering +clusters +clutch +clutched +clutches +clutching +clutter +cluttered +cluttering +clutters +clwyd +clydesdale +clydesdales +clypeal +clypeate +clypeated +clypei +clypeus +clyster +clysters +clytemnestra +cnidoblast +cnidoblasts +cnut +coacervate +coacervated +coacervates +coacervating +coacervation +coach +coachable +coached +coacher +coachers +coaches +coaching +coachman +coachmen +coachwork +coact +coacted +coacting +coaction +coactions +coactive +coactively +coactor +coactors +coacts +coadaptation +coadapted +coadjutant +coadjutants +coadjutor +coadjutors +coadministration +coadunate +coadunation +coadunative +coagula +coagulability +coagulable +coagulant +coagulants +coagulase +coagulases +coagulate +coagulated +coagulates +coagulating +coagulation +coagulations +coagulative +coagulator +coagulators +coagulum +coal +coaled +coaler +coalers +coalesce +coalesced +coalescence +coalescent +coalesces +coalescing +coalfield +coalfields +coalfish +coalfishes +coalification +coalifications +coaling +coalition +coalitionist +coalitionists +coalitions +coals +coalsack +coalsacks +coaming +coamings +coanchor +coanchors +coarctate +coarctation +coarctations +coarse +coarsely +coarsen +coarsened +coarseness +coarsening +coarsens +coarser +coarsest +coassignee +coassignees +coast +coastal +coasted +coaster +coasters +coastguard +coastguards +coastguardsman +coastguardsmen +coasting +coastland +coastlands +coastline +coastlines +coasts +coastward +coastwards +coastwise +coat +coatdress +coatdresses +coated +coati +coatimundi +coating +coatings +coatis +coatroom +coatrooms +coats +coattail +coattails +coatzacoalcos +coauthor +coauthored +coauthoring +coauthors +coauthorship +coax +coaxed +coaxer +coaxers +coaxes +coaxial +coaxing +coaxingly +cob +cobalamin +cobalamins +cobalt +cobaltic +cobaltite +cobaltites +cobaltous +cobber +cobbers +cobbett +cobble +cobbled +cobbler +cobblers +cobbles +cobblestone +cobblestones +cobbling +cobden +cobelligerent +cobelligerents +cobia +cobias +coble +cobles +cobnut +cobnuts +cobourg +cobra +cobras +cobs +coburg +cobweb +cobwebbed +cobwebbing +cobwebby +cobwebs +coca +cocaine +cocainism +cocainisms +cocainization +cocainize +cocainized +cocainizes +cocainizing +cocaptain +cocaptains +cocarcinogen +cocarcinogenic +cocarcinogens +cocas +cocatalyst +cocatalysts +cocci +coccid +coccidia +coccidioidomycosis +coccidiosis +coccidium +coccids +coccobacilli +coccobacillus +coccoid +coccoids +coccolith +coccoliths +coccus +coccygeal +coccyges +coccyx +cochair +cochairman +cochairmen +cochairperson +cochairpersons +cochairs +cochairwoman +cochairwomen +cochampion +cochampions +cochere +cochineal +cochlea +cochleae +cochlear +cochleate +cock +cockade +cockaded +cockades +cockaigne +cockalorum +cockalorums +cockamamie +cockatiel +cockatiels +cockatoo +cockatoos +cockatrice +cockatrices +cockboat +cockboats +cockchafer +cockchafers +cockcrow +cocked +cocker +cockered +cockerel +cockerels +cockering +cockers +cockeye +cockeyed +cockeyes +cockfight +cockfighting +cockfights +cockhorse +cockhorses +cockier +cockiest +cockily +cockiness +cocking +cockle +cockleboat +cockleboats +cocklebur +cockleburs +cockled +cockles +cockleshell +cockleshells +cockling +cockloft +cocklofts +cockney +cockneys +cockpit +cockpits +cockroach +cockroaches +cocks +cockscomb +cockscombs +cocksfoot +cocksfoots +cockshies +cockshy +cocksucker +cocksuckers +cocksure +cocksurely +cocksureness +cocktail +cocktails +cocky +coco +cocoa +cocoas +cocobolo +cocobolos +cocomposer +cocomposers +coconspirator +coconspirators +coconut +coconuts +cocoon +cocooned +cocooning +cocoonings +cocoons +cocos +cocotte +cocottes +cocounsel +cocoyam +cocoyams +cocreate +cocreated +cocreates +cocreating +cocreator +cocreators +cocteau +cocultivate +cocultivated +cocultivates +cocultivating +cocultivation +coculture +cocurator +cocurators +cocurricular +cocytus +cod +coda +codas +coddle +coddled +coddler +coddlers +coddles +coddling +code +codebook +codebooks +codebreaker +codebreakers +codeclination +codeclinations +coded +codefendant +codefendants +codeine +codeines +codemaker +codemakers +coder +coders +codes +codesign +codesigned +codesigning +codesigns +codetermination +codeterminations +codetermine +codetermined +codetermines +codetermining +codevelop +codeveloped +codeveloper +codevelopers +codeveloping +codevelops +codex +codfish +codfishes +codger +codgers +codices +codicil +codicillary +codicils +codification +codifications +codified +codifier +codifiers +codifies +codify +codifying +coding +codirect +codirected +codirecting +codirection +codirector +codirectors +codirects +codiscover +codiscovered +codiscoverer +codiscoverers +codiscovering +codiscovers +codling +codlings +codominance +codominances +codominant +codominants +codon +codons +codpiece +codpieces +codrive +codriven +codriver +codrivers +codrives +codriving +codrove +cods +codswallop +codswallops +coed +coedit +coedited +coediting +coeditor +coeditors +coedits +coeds +coeducation +coeducational +coeducationally +coefficient +coefficients +coelacanth +coelacanthine +coelacanthous +coelacanths +coelentera +coelenterate +coelenterates +coelenteric +coelenteron +coelom +coelomate +coelomic +coeloms +coenocyte +coenocytes +coenocytic +coenuri +coenurus +coenzymatic +coenzymatically +coenzyme +coenzymes +coequal +coequality +coequally +coequals +coerce +coerced +coercer +coercers +coerces +coercible +coercing +coercion +coercionary +coercive +coercively +coerciveness +coessential +coessentiality +coessentially +coessentialness +coetaneous +coetaneously +coetaneousness +coeternal +coeternally +coeternity +coeur +coeval +coevally +coevals +coevolution +coevolutionary +coevolve +coevolved +coevolves +coevolving +coexecutor +coexecutors +coexist +coexisted +coexistence +coexistent +coexisting +coexists +coextend +coextended +coextending +coextends +coextension +coextensive +coextensively +cofactor +cofactors +cofavorite +cofavorites +cofeature +cofeatures +coffee +coffeecake +coffeecakes +coffeehouse +coffeehouses +coffeemaker +coffeemakers +coffeepot +coffeepots +coffees +coffer +cofferdam +cofferdams +coffered +coffering +coffers +coffin +coffined +coffining +coffins +coffle +coffled +coffles +coffling +cofinance +cofound +cofounded +cofounder +cofounders +cofounding +cofounds +cofunction +cofunctions +cog +cogency +cogeneration +cogent +cogently +cogged +cogging +cogitable +cogitate +cogitated +cogitates +cogitating +cogitation +cogitations +cogitative +cogitatively +cogitativeness +cogitator +cogitators +cognac +cognacs +cognate +cognates +cognation +cognition +cognitional +cognitive +cognitively +cognizable +cognizably +cognizance +cognizant +cognize +cognized +cognizes +cognizing +cognomen +cognomens +cognomina +cognominal +cognoscente +cognoscenti +cogon +cogons +cogs +cogwheel +cogwheels +cohabit +cohabitant +cohabitants +cohabitate +cohabitation +cohabitational +cohabited +cohabiter +cohabiters +cohabiting +cohabits +cohead +coheads +coheir +coheiress +coheiresses +coheirs +cohere +cohered +coherence +coherencies +coherency +coherent +coherently +coheres +cohering +cohesion +cohesionless +cohesive +cohesively +cohesiveness +coho +coholder +coholders +cohort +cohorts +cohos +cohosh +cohoshes +cohost +cohosted +cohostess +cohostesses +cohosting +cohosts +cohune +cohunes +coif +coifed +coiffeur +coiffeurs +coiffeuse +coiffeuses +coiffure +coiffured +coiffures +coiffuring +coifing +coifs +coign +coigns +coil +coiled +coiler +coilers +coiling +coils +coin +coinable +coinage +coinages +coincide +coincided +coincidence +coincidences +coincident +coincidental +coincidentally +coincides +coinciding +coined +coiner +coiners +coining +coins +coinsurance +coinsurances +coinsure +coinsured +coinsures +coinsuring +coinvent +coinvented +coinventing +coinventor +coinventors +coinvents +coinvestigator +coinvestigators +coinvestor +coinvestors +coir +coirs +coital +coitally +coition +coitus +cojoin +cojoined +cojoining +cojoins +coke +coked +cokehead +cokeheads +cokes +coking +col +cola +colada +colander +colanders +colas +colcannon +colcannons +colchicine +colchicines +colchicum +colcothar +colcothars +cold +coldcock +coldcocked +coldcocking +coldcocks +colder +coldest +coldhearted +coldheartedly +coldheartedness +coldly +coldness +colds +coldshoulder +coldshouldered +coldshouldering +coldshoulders +cole +colead +coleader +coleaders +coleading +coleads +colectomies +colectomy +coled +colemanite +colemanites +coleopteran +coleopterous +coleoptile +coleoptiles +coleorhiza +coleorhizae +coleridge +coles +coleslaw +coleus +coleuses +colewort +coleworts +coli +colic +colicin +colicins +colicky +colicroot +colicroots +coliform +colinear +colinearity +coliseum +coliseums +colistin +colistins +colitis +collaborate +collaborated +collaborates +collaborating +collaboration +collaborationism +collaborationist +collaborationists +collaborations +collaborative +collaboratively +collaborator +collaborators +collage +collaged +collagen +collagenase +collagenases +collagenic +collagenous +collages +collaging +collagist +collagists +collapse +collapsed +collapses +collapsibility +collapsible +collapsing +collar +collarbone +collarbones +collard +collards +collared +collaring +collars +collate +collated +collateral +collateralize +collateralized +collateralizes +collateralizing +collaterally +collates +collating +collation +collations +collator +collators +colleague +colleagues +colleagueship +collect +collectable +collectables +collectanea +collected +collectedly +collectedness +collectible +collectibles +collecting +collection +collections +collective +collectively +collectiveness +collectives +collectivism +collectivist +collectivistic +collectivistically +collectivists +collectivities +collectivity +collectivization +collectivize +collectivized +collectivizes +collectivizing +collector +collectors +collectorship +collects +colleen +colleens +college +colleges +collegia +collegial +collegiality +collegially +collegian +collegians +collegiate +collegium +collegiums +collembolan +collembolans +collenchyma +collenchymas +collenchymatous +collenchyme +collenchymes +collet +collets +collide +collided +collider +colliders +collides +colliding +collie +collier +collieries +colliers +colliery +collies +colligate +colligated +colligates +colligating +colligation +colligative +collimate +collimated +collimates +collimating +collimation +collimator +collimators +collinear +collinearity +collingwood +collins +collinsia +collision +collisional +collisions +collocate +collocated +collocates +collocating +collocation +collocational +collocations +collodion +collogue +collogued +collogues +colloguing +colloid +colloidal +colloidally +colloids +collop +collops +colloquia +colloquial +colloquialism +colloquialisms +colloquially +colloquialness +colloquies +colloquium +colloquiums +colloquy +collotype +collotypes +collude +colluded +colluder +colluders +colludes +colluding +collusion +collusive +collusively +collusiveness +colluvia +colluvial +colluvium +colluviums +collyria +collyrium +collyriums +collywobbles +coloboma +colobomata +colobomatous +colocynth +colocynths +cologne +colognes +colombia +colombian +colombians +colombo +colon +colonel +colonelcy +colonels +colonelship +colonial +colonialism +colonialist +colonialists +colonially +colonials +colonic +colonies +colonist +colonists +colonitis +colonization +colonizations +colonize +colonized +colonizer +colonizers +colonizes +colonizing +colonnade +colonnaded +colonnades +colonoscope +colonoscopes +colonoscopies +colonoscopy +colons +colony +colophon +colophons +color +colorability +colorable +colorableness +colorably +colorado +colorant +colorants +coloration +coloratura +coloraturas +colorblind +colorblindness +colorbred +colorbreed +colorbreeding +colorbreeds +colorcast +colorcasted +colorcasting +colorcasts +colorectal +colored +coloreds +colorer +colorers +colorfast +colorfastness +colorful +colorfully +colorfulness +colorific +colorimeter +colorimeters +colorimetric +colorimetrically +colorimetry +coloring +colorings +colorist +coloristic +colorists +colorization +colorizations +colorize +colorized +colorizer +colorizers +colorizes +colorizing +colorless +colorlessly +colorlessness +colors +coloscope +coloscopes +coloscopies +coloscopy +colossal +colossally +colosseum +colossi +colossians +colossus +colossuses +colostomies +colostomy +colostral +colostrum +colpitis +colportage +colportages +colporteur +colporteurs +colposcope +colposcopes +colposcopic +colposcopies +colposcopy +cols +colt +coltish +coltishly +coltishness +colts +coltsfoot +coltsfoots +colubrid +colubrids +colubrine +colugo +colugos +columba +columbaria +columbarium +columbia +columbian +columbine +columbines +columbite +columbites +columbium +columbus +columella +columellae +columellar +columellate +column +columnar +columnea +columned +columniation +columniations +columnist +columnists +columns +colza +colzas +coma +comae +comal +comanage +comanaged +comanagement +comanager +comanagers +comanages +comanaging +comanche +comanches +comas +comate +comates +comatose +comatosely +comatulid +comatulids +comb +combat +combatant +combatants +combated +combating +combative +combatively +combativeness +combats +combed +comber +combers +combinable +combination +combinational +combinations +combinative +combinatorial +combinatorics +combinatory +combine +combined +combiner +combiners +combines +combing +combings +combining +combinings +combo +combos +combs +combust +combusted +combustibility +combustible +combustibles +combustibly +combusting +combustion +combustive +combustor +combustors +combusts +come +comeback +comebacks +comecon +comedian +comedians +comedic +comedically +comedienne +comediennes +comedies +comedo +comedogenic +comedones +comedos +comedown +comedowns +comedy +comelier +comeliest +comeliness +comely +comember +comembers +comer +comers +comes +comestible +comestibles +comet +cometary +cometic +comets +comeuppance +comfier +comfiest +comfit +comfits +comfort +comfortable +comfortableness +comfortably +comforted +comforter +comforters +comforting +comfortingly +comfortless +comfortlessly +comforts +comfrey +comfreys +comfy +comic +comical +comicality +comically +comicalness +comice +comices +comics +coming +comings +comintern +comique +comitia +comitial +comities +comity +comix +comma +command +commandant +commandants +commanded +commandeer +commandeered +commandeering +commandeers +commander +commanders +commanding +commandingly +commandingness +commandment +commandments +commando +commandos +commands +commas +comme +commedia +commemorate +commemorated +commemorates +commemorating +commemoration +commemorations +commemorative +commemoratives +commemorator +commemorators +commemoratory +commence +commenced +commencement +commencements +commencer +commencers +commences +commencing +commend +commendable +commendableness +commendably +commendation +commendations +commendatory +commended +commending +commends +commensal +commensalism +commensally +commensals +commensurability +commensurable +commensurably +commensurate +commensurately +commensuration +comment +commentarial +commentaries +commentary +commentate +commentated +commentates +commentating +commentator +commentators +commented +commenting +comments +commerce +commercial +commercialism +commercialist +commercialistic +commercialists +commercialization +commercialize +commercialized +commercializes +commercializing +commercially +commercials +commie +commies +commination +comminations +comminatory +commingle +commingled +commingles +commingling +comminute +comminuted +comminutes +comminuting +comminution +comminutions +commiserate +commiserated +commiserates +commiserating +commiseration +commiserations +commiserative +commiseratively +commiserator +commiserators +commissar +commissariat +commissariats +commissaries +commissars +commissary +commission +commissionaire +commissionaires +commissional +commissioned +commissioner +commissioners +commissionership +commissioning +commissions +commissural +commissure +commissures +commissurotomies +commissurotomy +commit +commitment +commitments +commits +committable +committal +committals +committed +committee +committeeman +committeemen +committees +committeewoman +committeewomen +committing +commix +commixed +commixes +commixing +commixture +commixtures +commode +commodes +commodious +commodiously +commodiousness +commodities +commodity +commodore +commodores +common +commonage +commonages +commonalities +commonality +commonalties +commonalty +commoner +commoners +commonest +commonly +commonness +commonplace +commonplaceness +commonplaces +commons +commonsense +commonsensible +commonsensibly +commonsensical +commonweal +commonwealth +commonwealths +commotion +commove +commoved +commoves +commoving +communal +communalism +communalist +communalistic +communalists +communality +communalize +communalized +communalizes +communalizing +communally +communard +communards +commune +communed +communes +communicability +communicable +communicableness +communicably +communicant +communicants +communicate +communicated +communicates +communicating +communication +communicational +communications +communicative +communicatively +communicativeness +communicator +communicators +communicatory +communing +communion +communions +communiqué +communiqués +communism +communist +communistic +communistically +communists +communitarian +communitarians +communities +community +communization +communize +communized +communizes +communizing +commutability +commutable +commutate +commutated +commutates +commutating +commutation +commutations +commutative +commutativity +commutator +commutators +commute +commuted +commuter +commuters +commutes +commuting +como +comonomer +comonomers +comoran +comorans +comoros +comose +comp +compact +compacted +compacting +compaction +compactions +compactly +compactness +compactor +compactors +compacts +companied +companies +companion +companionable +companionableness +companionably +companionate +companioned +companioning +companionless +companions +companionship +companionships +companionway +companionways +company +companying +comparability +comparable +comparableness +comparably +comparatist +comparatists +comparative +comparatively +comparatives +comparator +comparators +compare +compared +comparer +comparers +compares +comparing +comparison +comparisons +comparitor +compart +comparted +comparting +compartment +compartmental +compartmentalization +compartmentalize +compartmentalized +compartmentalizes +compartmentalizing +compartmentation +compartmented +compartmenting +compartments +comparts +compass +compassable +compassed +compasses +compassing +compassion +compassionate +compassionated +compassionately +compassionateness +compassionates +compassionating +compassionless +compatibility +compatible +compatibleness +compatibles +compatibly +compatriot +compatriotic +compatriots +comped +compeer +compeers +compel +compellable +compellably +compellation +compellations +compelled +compeller +compellers +compelling +compellingly +compels +compend +compendia +compendious +compendiously +compendiousness +compendium +compendiums +compends +compensable +compensate +compensated +compensates +compensating +compensation +compensational +compensations +compensative +compensator +compensators +compensatory +compere +compered +comperes +compering +compete +competed +competence +competencies +competency +competent +competently +competes +competing +competition +competitions +competitive +competitively +competitiveness +competitor +competitors +compilation +compilations +compile +compiled +compiler +compilers +compiles +compiling +comping +complacence +complacency +complacent +complacently +complain +complainant +complainants +complained +complainer +complainers +complaining +complains +complaint +complaints +complaisance +complaisant +complaisantly +compleat +complect +complected +complecting +complects +complement +complemental +complementally +complementarily +complementariness +complementarity +complementary +complementation +complementations +complemented +complementing +complements +complete +completed +completely +completeness +completer +completes +completest +completing +completion +completions +completive +complex +complexes +complexion +complexional +complexioned +complexions +complexities +complexity +complexly +complexness +compliance +compliancy +compliant +compliantly +complicacies +complicacy +complicate +complicated +complicatedly +complicatedness +complicates +complicating +complication +complications +complicit +complicities +complicity +complied +complier +compliers +complies +compliment +complimentarily +complimentary +complimented +complimenting +compliments +complin +compline +complins +complot +complots +comply +complying +compo +component +componential +components +componentwise +comport +comported +comporting +comportment +comports +compos +compose +composed +composedly +composedness +composer +composers +composes +composing +composite +compositely +compositeness +composites +composition +compositional +compositionally +compositions +compositive +compositor +compositorial +compositors +compost +composted +compostela +composting +composts +composure +compote +compotes +compound +compoundable +compounded +compounder +compounding +compounds +comprador +compradors +comprehend +comprehended +comprehendible +comprehending +comprehendingly +comprehends +comprehensibility +comprehensible +comprehensibleness +comprehensibly +comprehension +comprehensions +comprehensive +comprehensively +comprehensiveness +comprehensives +compress +compressed +compresses +compressibility +compressible +compressibleness +compressing +compression +compressional +compressions +compressive +compressively +compressor +compressors +comprisable +comprise +comprised +comprises +comprising +compromise +compromised +compromiser +compromisers +compromises +compromising +comps +comptroller +comptrollers +compulsion +compulsions +compulsive +compulsively +compulsiveness +compulsives +compulsivity +compulsories +compulsorily +compulsoriness +compulsory +compunction +compunctions +compunctious +compunctiously +compurgation +compurgations +compurgator +compurgators +computability +computable +computably +computation +computational +computationally +computations +compute +computed +computer +computerate +computerdom +computerdoms +computerese +computerist +computerists +computerizable +computerization +computerize +computerized +computerizes +computerizing +computers +computes +computing +compôte +compôtes +comrade +comradely +comrades +comradeship +comsat +comsymp +comsymps +comus +comédie +con +conakry +conan +conation +conational +conations +conative +concatenate +concatenated +concatenates +concatenating +concatenation +concatenations +concave +concaved +concavely +concaveness +concaves +concaving +concavities +concavity +conceal +concealable +concealed +concealer +concealers +concealing +concealment +conceals +concede +conceded +concededly +conceder +conceders +concedes +conceding +conceit +conceited +conceitedly +conceitedness +conceiting +conceits +conceivability +conceivable +conceivableness +conceivably +conceive +conceived +conceiver +conceivers +conceives +conceiving +concelebrant +concelebrants +concelebrate +concelebrated +concelebrates +concelebrating +concelebration +concelebrations +concenter +concentered +concentering +concenters +concentrate +concentrated +concentrates +concentrating +concentration +concentrations +concentrative +concentratively +concentrator +concentrators +concentric +concentrically +concentricity +concept +conceptacle +conceptacles +conception +conceptional +conceptions +conceptive +conceptively +concepts +conceptual +conceptualism +conceptualist +conceptualistic +conceptualistically +conceptualists +conceptuality +conceptualization +conceptualizations +conceptualize +conceptualized +conceptualizer +conceptualizers +conceptualizes +conceptualizing +conceptually +conceptus +concern +concerned +concernedly +concerning +concernment +concernments +concerns +concert +concerted +concertedly +concertgoer +concertgoers +concertgoing +concerti +concertina +concertinas +concerting +concertino +concertinos +concertize +concertized +concertizes +concertizing +concertmaster +concertmasters +concertmistress +concertmistresses +concerto +concertos +concerts +concession +concessionaire +concessionaires +concessional +concessionary +concessioner +concessioners +concessions +concessive +concessively +conch +concha +conchae +conchal +conches +conchiferous +conchiolin +conchiolins +conchoidal +conchoidally +conchological +conchologist +conchologists +conchology +conchs +concierge +concierges +conciliable +conciliar +conciliate +conciliated +conciliates +conciliating +conciliation +conciliations +conciliator +conciliators +conciliatory +concinnities +concinnity +concise +concisely +conciseness +concision +concisions +conclave +conclaves +conclude +concluded +concluder +concluders +concludes +concluding +conclusion +conclusions +conclusive +conclusively +conclusiveness +conclusory +concoct +concocted +concocter +concocters +concocting +concoction +concoctions +concocts +concomitance +concomitant +concomitantly +concomitants +concord +concordance +concordances +concordant +concordantly +concordat +concordats +concords +concours +concourse +concourses +concrescence +concrescent +concrete +concreted +concretely +concreteness +concretes +concreting +concretion +concretionary +concretions +concretism +concretisms +concretist +concretists +concretization +concretize +concretized +concretizes +concretizing +concrète +concubinage +concubinages +concubine +concubines +concupiscence +concupiscent +concur +concurred +concurrence +concurrencies +concurrency +concurrent +concurrently +concurring +concurs +concuss +concussed +concusses +concussing +concussion +concussions +concussive +concussively +condemn +condemnable +condemnation +condemnations +condemnatory +condemned +condemner +condemners +condemning +condemns +condensability +condensable +condensate +condensates +condensation +condensational +condensations +condense +condensed +condenser +condensers +condenses +condensing +condescend +condescended +condescendence +condescendences +condescender +condescenders +condescending +condescendingly +condescends +condescension +condign +condignly +condiment +condimental +condiments +condition +conditional +conditionally +conditionals +conditioned +conditioner +conditioners +conditioning +conditionings +conditions +condo +condolatory +condole +condoled +condolence +condolences +condolent +condoler +condolers +condoles +condoling +condom +condominial +condominium +condominiums +condoms +condonable +condonation +condonations +condone +condoned +condoner +condoners +condones +condoning +condor +condors +condos +condottiere +condottieri +conduce +conduced +conducer +conducers +conduces +conducing +conducingly +conducive +conduciveness +conduct +conductance +conducted +conductibility +conductible +conductimetry +conducting +conduction +conductive +conductivities +conductivity +conductor +conductorial +conductors +conductorship +conductress +conductresses +conducts +conduit +conduits +conduplicate +conduplication +condylar +condyle +condyles +condyloid +condyloma +condylomas +condylomata +condylomatous +cone +coned +coneflower +coneflowers +conenose +cones +conestoga +conestogas +coney +coneys +confab +confabbed +confabbing +confabs +confabulate +confabulated +confabulates +confabulating +confabulation +confabulations +confabulator +confabulators +confabulatory +confect +confected +confecting +confection +confectionaries +confectionary +confectioned +confectioner +confectioneries +confectioners +confectionery +confectioning +confections +confects +confederacies +confederacy +confederal +confederalist +confederalists +confederate +confederated +confederates +confederating +confederation +confederationism +confederationist +confederationists +confederations +confederative +confer +conferee +conferees +conference +conferences +conferencing +conferential +conferment +conferrable +conferral +conferrals +conferred +conferrer +conferrers +conferring +confers +confess +confessable +confessed +confessedly +confesses +confessing +confession +confessional +confessionals +confessions +confessor +confessors +confetti +confidant +confidante +confidantes +confidants +confide +confided +confidence +confidences +confident +confidential +confidentiality +confidentially +confidentialness +confidently +confider +confiders +confides +confiding +confidingly +confidingness +configurable +configuration +configurational +configurationally +configurationism +configurations +configurative +configure +configured +configures +configuring +confinable +confine +confined +confinement +confinements +confiner +confiners +confines +confining +confirm +confirmability +confirmable +confirmand +confirmands +confirmation +confirmations +confirmatory +confirmed +confirmedly +confirmer +confirmers +confirming +confirms +confiscable +confiscate +confiscated +confiscates +confiscating +confiscation +confiscations +confiscator +confiscators +confiscatory +confiteor +confiteors +confiture +confitures +conflagrant +conflagration +conflagrations +conflate +conflated +conflates +conflating +conflation +conflations +conflict +conflicted +conflicting +confliction +conflictive +conflicts +conflictual +confluence +confluences +confluent +confluents +conflux +confluxes +confocal +confocally +conform +conformability +conformable +conformableness +conformably +conformal +conformance +conformant +conformation +conformational +conformationally +conformations +conformed +conformer +conformers +conforming +conformist +conformists +conformities +conformity +conforms +confound +confounded +confoundedly +confoundedness +confounder +confounders +confounding +confounds +confraternities +confraternity +confrere +confreres +confront +confrontation +confrontational +confrontationist +confrontationists +confrontations +confrontative +confronted +confronter +confronters +confronting +confrontment +confronts +confucian +confucianism +confucianist +confucianists +confucians +confucius +confusable +confuse +confused +confusedly +confusedness +confuser +confusers +confuses +confusing +confusingly +confusion +confusional +confusions +confutable +confutation +confutative +confute +confuted +confuter +confuters +confutes +confuting +conga +congaed +congaing +congas +congeal +congealable +congealed +congealer +congealers +congealing +congealment +congeals +congelation +congelations +congener +congeneric +congenerous +congeners +congenial +congeniality +congenially +congenialness +congenital +congenitally +conger +congeries +congers +congest +congested +congesting +congestion +congestive +congests +congii +congius +conglobate +conglobated +conglobates +conglobating +conglobation +conglobe +conglobed +conglobes +conglobing +conglomerate +conglomerated +conglomerates +conglomeratic +conglomerating +conglomeration +conglomerations +conglomerator +conglomerators +conglutinate +conglutinated +conglutinates +conglutinating +conglutination +congo +congolese +congou +congous +congratulate +congratulated +congratulates +congratulating +congratulation +congratulations +congratulator +congratulators +congratulatory +congregant +congregants +congregate +congregated +congregates +congregating +congregation +congregational +congregationalism +congregationalist +congregationalists +congregations +congregative +congregativeness +congregator +congregators +congress +congresses +congressional +congressionally +congressman +congressmen +congresspeople +congressperson +congresspersons +congresswoman +congresswomen +congreve +congruence +congruences +congruencies +congruency +congruent +congruently +congruities +congruity +congruous +congruously +congruousness +congé +conic +conical +conics +conidia +conidial +conidiophore +conidiophores +conidiophorous +conidium +conies +conifer +coniferous +conifers +coniine +coniines +coning +conium +coniums +conjecturable +conjecturably +conjectural +conjecturally +conjecture +conjectured +conjecturer +conjecturers +conjectures +conjecturing +conjoin +conjoined +conjoiner +conjoiners +conjoining +conjoins +conjoint +conjointly +conjugal +conjugality +conjugally +conjugant +conjugants +conjugate +conjugated +conjugately +conjugates +conjugating +conjugation +conjugational +conjugationally +conjugations +conjugative +conjugator +conjugators +conjunct +conjunction +conjunctional +conjunctionally +conjunctions +conjunctiva +conjunctivae +conjunctival +conjunctivas +conjunctive +conjunctively +conjunctives +conjunctivitis +conjunctly +conjuncts +conjuncture +conjunctures +conjunto +conjuntos +conjuration +conjure +conjured +conjurer +conjurers +conjures +conjuring +conjuror +conjurors +conk +conked +conker +conkers +conking +conks +conky +connate +connately +connateness +connatural +connaturality +connaturally +connaturalness +connect +connectable +connected +connectedly +connectedness +connectible +connecticut +connecting +connection +connectional +connectionless +connections +connective +connectively +connectives +connectivity +connector +connectors +connects +conned +conner +conners +conning +conniption +conniptions +connivance +connive +connived +connivent +conniver +connivers +connivery +connives +conniving +connoisseur +connoisseurs +connoisseurship +connotation +connotations +connotative +connotatively +connote +connoted +connotes +connoting +connubial +connubialism +connubiality +connubially +conodont +conodonts +conoid +conoids +conominee +conominees +conquer +conquerable +conquered +conquering +conqueror +conquerors +conquers +conquest +conquests +conquian +conquians +conquistador +conquistadors +conrad +cons +consanguine +consanguineous +consanguineously +consanguinities +consanguinity +conscience +conscienceless +consciences +conscientious +conscientiously +conscientiousness +conscionable +conscious +consciously +consciousness +conscript +conscripted +conscripting +conscription +conscripts +consecrate +consecrated +consecrates +consecrating +consecration +consecrations +consecrative +consecrator +consecrators +consecratory +consecution +consecutive +consecutively +consecutiveness +consensual +consensually +consensus +consensuses +consent +consentaneity +consentaneous +consentaneously +consentaneousness +consented +consenter +consenters +consenting +consents +consequence +consequences +consequent +consequential +consequentialities +consequentiality +consequentially +consequentialness +consequently +consequents +conservable +conservancies +conservancy +conservation +conservational +conservationist +conservationists +conservations +conservatism +conservative +conservatively +conservativeness +conservatives +conservatize +conservatized +conservatizes +conservatizing +conservatoire +conservatoires +conservator +conservatorial +conservatories +conservators +conservatorship +conservatory +conserve +conserved +conserver +conservers +conserves +conserving +consider +considerable +considerably +considerate +considerately +considerateness +consideration +considerations +considered +considerer +considerers +considering +considers +consigliere +consiglieri +consign +consignable +consignation +consigned +consignee +consignees +consigning +consignment +consignments +consignor +consignors +consigns +consist +consisted +consistence +consistencies +consistency +consistent +consistently +consisting +consistorial +consistories +consistory +consists +consociate +consociated +consociates +consociating +consociation +consociational +consociations +consolable +consolably +consolation +consolations +consolatory +console +consoled +consoler +consolers +consoles +consolidate +consolidated +consolidates +consolidating +consolidation +consolidations +consolidator +consolidators +consoling +consolingly +consolute +consommé +consommés +consonance +consonant +consonantal +consonantally +consonantly +consonants +consort +consorted +consortia +consortial +consorting +consortium +consortiums +consorts +conspecific +conspecifics +conspectus +conspectuses +conspicuity +conspicuous +conspicuously +conspicuousness +conspiracies +conspiracist +conspiracists +conspiracy +conspirator +conspiratorial +conspiratorialist +conspiratorialists +conspiratorially +conspirators +conspire +conspired +conspirer +conspirers +conspires +conspiring +conspiringly +constable +constables +constableship +constabular +constabularies +constabulary +constance +constancy +constant +constantan +constantans +constantine +constantinople +constantly +constants +constellate +constellated +constellates +constellating +constellation +constellational +constellations +constellatory +consternate +consternated +consternates +consternating +consternation +constipate +constipated +constipates +constipating +constipation +constituencies +constituency +constituent +constituently +constituents +constitute +constituted +constituter +constituters +constitutes +constituting +constitution +constitutional +constitutionalism +constitutionalist +constitutionalists +constitutionality +constitutionalization +constitutionalize +constitutionalized +constitutionalizes +constitutionalizing +constitutionally +constitutionals +constitutions +constitutive +constitutively +constrain +constrainable +constrained +constrainedly +constrainer +constrainers +constraining +constrains +constraint +constraints +constrict +constricted +constricting +constriction +constrictions +constrictive +constrictively +constrictor +constrictors +constricts +constringe +constringed +constringency +constringent +constringes +constringing +construal +construct +constructed +constructible +constructing +construction +constructional +constructionally +constructionist +constructionists +constructions +constructive +constructively +constructiveness +constructivism +constructivisms +constructivist +constructivists +constructor +constructors +constructs +construe +construed +construes +construing +consubstantial +consubstantiate +consubstantiated +consubstantiates +consubstantiating +consubstantiation +consubstantiations +consuetude +consuetudinary +consul +consular +consulate +consulates +consuls +consulship +consult +consultancies +consultancy +consultant +consultants +consultantship +consultation +consultations +consultative +consulted +consulter +consulters +consulting +consultor +consultors +consults +consumable +consumables +consume +consumed +consumedly +consumer +consumerism +consumerist +consumeristic +consumerists +consumers +consumership +consumes +consuming +consummate +consummated +consummately +consummates +consummating +consummation +consummations +consummative +consummator +consummators +consummatory +consumption +consumptive +consumptively +consumptives +contact +contacted +contacting +contacts +contactual +contactually +contagia +contagion +contagious +contagiously +contagiousness +contagium +contain +containable +contained +container +containerboard +containerboards +containerization +containerize +containerized +containerizes +containerizing +containerport +containerports +containers +containership +containing +containment +containments +contains +contaminant +contaminants +contaminate +contaminated +contaminates +contaminating +contamination +contaminations +contaminative +contaminator +contaminators +conte +contemn +contemned +contemner +contemners +contemning +contemns +contemplate +contemplated +contemplates +contemplating +contemplation +contemplations +contemplative +contemplatively +contemplativeness +contemplatives +contemplator +contemplators +contemporaneity +contemporaneous +contemporaneously +contemporaneousness +contemporaries +contemporarily +contemporary +contemporization +contemporize +contemporized +contemporizes +contemporizing +contempt +contemptibility +contemptible +contemptibleness +contemptibly +contempts +contemptuous +contemptuously +contemptuousness +contend +contended +contender +contenders +contending +contends +content +contented +contentedly +contentedness +contenting +contention +contentions +contentious +contentiously +contentiousness +contentment +contents +conterminous +conterminously +conterminousness +contes +contessa +contessas +contest +contestable +contestant +contestants +contestation +contested +contester +contesters +contesting +contests +context +contexts +contextual +contextualization +contextualize +contextualized +contextualizes +contextualizing +contextually +contextural +contexture +contextures +contiguities +contiguity +contiguous +contiguously +contiguousness +continence +continent +continental +continentalism +continentalist +continentalists +continentality +continentally +continentals +continently +continents +contingence +contingencies +contingency +contingent +contingently +contingents +continua +continuable +continual +continually +continuance +continuances +continuant +continuants +continuation +continuations +continuative +continuatively +continuatives +continuator +continuators +continue +continued +continuer +continuers +continues +continuing +continuities +continuity +continuo +continuos +continuous +continuously +continuousness +continuum +continuums +contort +contorted +contortedly +contortedness +contorting +contortion +contortionist +contortionistic +contortionists +contortions +contortive +contorts +contour +contoured +contouring +contours +contra +contraband +contrabandage +contrabandist +contrabandists +contrabands +contrabass +contrabasses +contrabassist +contrabassists +contrabassoon +contrabassoons +contraception +contraceptive +contraceptives +contract +contracted +contractibility +contractible +contractibleness +contractile +contractility +contracting +contraction +contractions +contractor +contractors +contracts +contractual +contractually +contracture +contractures +contracyclical +contradance +contradances +contradict +contradictable +contradicted +contradicter +contradicters +contradicting +contradiction +contradictions +contradictor +contradictories +contradictorily +contradictoriness +contradictors +contradictory +contradicts +contradistinction +contradistinctions +contradistinctive +contradistinctively +contradistinguish +contradistinguished +contradistinguishes +contradistinguishing +contragestation +contragestive +contragestives +contrail +contrails +contraindicate +contraindicated +contraindicates +contraindicating +contraindication +contraindications +contraindicative +contraire +contralateral +contralto +contraltos +contraposition +contrapositions +contrapositive +contrapositives +contrapposto +contrappostos +contraption +contraptions +contrapuntal +contrapuntally +contrapuntist +contrapuntists +contrarian +contrarians +contraries +contrarieties +contrariety +contrarily +contrariness +contrarious +contrariously +contrariwise +contrary +contras +contrast +contrasted +contrasting +contrastive +contrastively +contrasts +contrasty +contrate +contravariance +contravene +contravened +contravener +contraveners +contravenes +contravening +contravention +contretemps +contribute +contributed +contributes +contributing +contribution +contributions +contributive +contributively +contributiveness +contributor +contributories +contributors +contributory +contrite +contritely +contriteness +contrition +contrivance +contrivances +contrive +contrived +contrivedly +contriver +contrivers +contrives +contriving +control +controllability +controllable +controllably +controlled +controller +controllers +controllership +controlling +controls +controversial +controversialist +controversialists +controversiality +controversially +controversies +controversy +controvert +controverted +controvertibility +controvertible +controvertibly +controverting +controverts +contumacies +contumacious +contumaciously +contumaciousness +contumacy +contumelies +contumelious +contumeliously +contumely +contuse +contused +contuses +contusing +contusion +contusions +conundrum +conundrums +conurbation +convalesce +convalesced +convalescence +convalescent +convalescents +convalesces +convalescing +convect +convected +convecting +convection +convectional +convective +convectively +convector +convectors +convects +convenable +convene +convened +convener +conveners +convenes +convenience +conveniences +conveniencies +conveniency +convenient +conveniently +convening +convent +conventicle +conventicler +conventiclers +conventicles +convention +conventional +conventionalism +conventionalist +conventionalists +conventionalities +conventionality +conventionalization +conventionalize +conventionalized +conventionalizes +conventionalizing +conventionally +conventioneer +conventioneers +conventions +convents +conventual +conventuals +converge +converged +convergence +convergencies +convergency +convergent +converges +converging +conversance +conversances +conversancies +conversancy +conversant +conversantly +conversation +conversational +conversationalist +conversationalists +conversationally +conversations +conversazione +conversaziones +converse +conversed +conversely +converses +conversing +conversion +conversional +conversionary +conversions +convert +converted +converter +converters +convertibility +convertible +convertibleness +convertibles +convertibly +converting +convertiplane +convertiplanes +converts +convex +convexities +convexity +convexly +convey +conveyable +conveyance +conveyancer +conveyancers +conveyances +conveyancing +conveyancings +conveyed +conveyer +conveyers +conveying +conveyor +conveyors +conveys +convict +convicted +convicting +conviction +convictional +convictions +convictive +convictively +convicts +convince +convinced +convincement +convincer +convincers +convinces +convincible +convincing +convincingly +convincingness +convivial +conviviality +convivially +convocation +convocational +convocations +convoke +convoked +convoker +convokers +convokes +convoking +convolute +convoluted +convolutely +convolutes +convoluting +convolution +convolutional +convolutions +convolve +convolved +convolves +convolving +convolvuli +convolvulus +convolvuluses +convoy +convoyed +convoying +convoys +convulsant +convulsants +convulse +convulsed +convulses +convulsing +convulsion +convulsions +convulsive +convulsively +convulsiveness +cony +coo +cooed +cooer +cooers +cooing +cook +cookbook +cookbooks +cooked +cooker +cookeries +cookers +cookery +cookhouse +cookhouses +cookie +cookies +cooking +cookout +cookouts +cooks +cooktown +cookware +cool +coolant +coolants +cooled +cooler +coolers +coolest +coolgardie +coolheaded +coolie +coolies +cooling +coolish +coolly +coolness +cools +coon +cooncan +cooncans +coonhound +coonhounds +coons +coonskin +coonskins +coontie +coonties +coop +cooped +cooper +cooperage +cooperate +cooperated +cooperates +cooperating +cooperation +cooperationist +cooperationists +cooperative +cooperatively +cooperativeness +cooperatives +cooperator +cooperators +coopers +cooping +coops +coordinate +coordinated +coordinately +coordinateness +coordinates +coordinating +coordination +coordinations +coordinative +coordinator +coordinators +coos +coot +cootie +cooties +coots +cop +copacetic +copaiba +copal +coparcenaries +coparcenary +coparcener +coparceners +copartner +copartners +copartnership +cope +coped +copenhagen +copepod +copepods +coper +copernican +copernicans +copernicus +copers +copes +copestone +copestones +copied +copier +copiers +copies +copilot +copilots +coping +copings +copious +copiously +copiousness +coplanar +coplanarity +copland +copolymer +copolymeric +copolymerization +copolymerize +copolymerized +copolymerizes +copolymerizing +copolymers +copout +copouts +copped +copper +copperas +coppered +copperfield +copperhead +copperheads +coppering +copperleaf +copperleafs +copperplate +copperplates +coppers +coppersmith +coppersmiths +copperware +copperwares +coppery +coppice +coppices +copping +copra +copresent +copresented +copresenting +copresents +copresident +copresidents +coprince +coprinces +coprincipal +coprincipals +coprisoner +coprisoners +coprocessing +coprocessor +coprocessors +coproduce +coproduced +coproducer +coproducers +coproduces +coproducing +coproduction +coproductions +coprolalia +coprolalias +coprolite +coprolites +coprolitic +coprology +copromoter +copromoters +coprophagous +coprophagy +coprophilia +coprophiliac +coprophiliacs +coprophilic +coprophilous +coproprietor +coproprietors +coprosperity +cops +copse +copses +copt +copter +copters +coptic +copts +copublish +copublished +copublisher +copublishers +copublishes +copublishing +copula +copular +copulas +copulate +copulated +copulates +copulating +copulation +copulations +copulative +copulatively +copulatory +copy +copyable +copybook +copybooks +copyboy +copyboys +copycat +copycats +copycatted +copycatting +copydesk +copydesks +copyedit +copyedited +copyediting +copyeditor +copyeditors +copyedits +copyholder +copyholders +copying +copyist +copyists +copyreader +copyreaders +copyright +copyrightable +copyrighted +copyrighter +copyrighters +copyrighting +copyrights +copywriter +copywriters +coq +coquet +coquetries +coquetry +coquets +coquette +coquetted +coquettes +coquetting +coquettish +coquettishly +coquettishness +coquille +coquilles +coquina +coquinas +coquito +coquitos +coracle +coracles +coracoid +coracoids +coral +coralberries +coralberry +coralline +corallines +coralloid +coralroot +coralroots +corals +corban +corbans +corbeil +corbeils +corbel +corbeled +corbeling +corbelings +corbels +corbina +corbinas +corbusier +corcovado +cord +cordage +cordate +cordately +corded +cordelia +corder +corders +cordial +cordiale +cordiality +cordially +cordialness +cordials +cordierite +cordierites +cordiform +cordillera +cordilleran +cordilleras +cording +cordite +cordless +cordlessly +cordoba +cordon +cordoned +cordoning +cordons +cordova +cordovan +cordovans +cords +corduroy +corduroyed +corduroying +corduroys +cordwood +core +corecipient +corecipients +cored +coreligionist +coreligionists +coreopsis +corepressor +corepressors +corer +corers +cores +coresearcher +coresearchers +coresident +coresidential +coresidents +corespondency +corespondent +corespondents +corf +corfu +corgi +corgis +coria +coriaceous +coriander +coring +corinth +corinthian +corinthians +coriolanus +corium +cork +corkage +corkages +corkboard +corkboards +corked +corker +corkers +corkier +corkiest +corkiness +corking +corks +corkscrew +corkscrewed +corkscrewing +corkscrews +corkwood +corkwoods +corky +corm +cormel +cormels +cormorant +cormorants +corms +corn +cornball +cornballs +cornbraid +cornbraided +cornbraiding +cornbraids +cornbread +corncob +corncobs +corncrake +corncrakes +corncrib +corncribs +corndodger +corndodgers +cornea +corneal +corneas +corned +corneitis +cornel +cornell +cornels +corneous +corner +cornerback +cornerbacks +cornered +cornering +corners +cornerstone +cornerstones +cornerwise +cornet +cornetist +cornetists +cornets +cornfield +cornfields +cornflower +cornflowers +cornhusk +cornhusker +cornhuskers +cornhusking +cornhuskings +cornhusks +cornice +corniced +cornices +corniche +cornicing +cornicle +cornicles +corniculate +cornier +corniest +cornification +cornifications +cornified +cornifies +cornify +cornifying +cornily +corniness +corning +cornish +cornishman +cornishmen +cornishwoman +cornishwomen +cornmeal +cornpone +cornrow +cornrowed +cornrowing +cornrows +corns +cornstalk +cornstalks +cornstarch +cornu +cornua +cornual +cornucopia +cornucopian +cornucopias +cornute +cornwall +corny +corolla +corollaries +corollary +corollas +corollate +corona +coronae +coronagraph +coronagraphs +coronal +coronals +coronaries +coronary +coronas +coronation +coronations +coroner +coroners +coronership +coronet +coronets +corot +corotate +corotated +corotates +corotating +corotation +corotational +coroutine +coroutines +corpocracies +corpocracy +corpocratic +corpora +corporal +corporality +corporally +corporals +corporate +corporately +corporation +corporations +corporative +corporator +corporators +corporeal +corporeality +corporeally +corporealness +corporeity +corposant +corposants +corps +corpse +corpses +corpsman +corpsmen +corpulence +corpulent +corpulently +corpus +corpuscle +corpuscles +corpuscular +corpuses +corrade +corraded +corrades +corrading +corral +corralled +corralling +corrals +corrasion +corrasive +correct +correctable +corrected +correcting +correction +correctional +corrections +correctitude +correctitudes +corrective +correctively +correctives +correctly +correctness +corrector +correctors +corrects +correggio +correlate +correlated +correlates +correlating +correlation +correlational +correlations +correlative +correlatively +correlatives +correspond +corresponded +correspondence +correspondences +correspondencies +correspondency +correspondent +correspondently +correspondents +corresponding +correspondingly +corresponds +corresponsive +corresponsively +corrida +corridas +corridor +corridors +corrie +corries +corrigenda +corrigendum +corrigibility +corrigible +corrigibly +corrival +corrivalry +corrivals +corroborant +corroborate +corroborated +corroborates +corroborating +corroboration +corroborations +corroborative +corroborator +corroborators +corroboratory +corroboree +corroborees +corrode +corroded +corrodes +corrodible +corroding +corrosible +corrosion +corrosions +corrosive +corrosively +corrosiveness +corrosives +corrosivity +corrugate +corrugated +corrugates +corrugating +corrugation +corrugations +corrupt +corrupted +corrupter +corrupters +corruptibility +corruptible +corruptibleness +corruptibly +corrupting +corruption +corruptionist +corruptionists +corruptions +corruptive +corruptly +corruptness +corrupts +corsage +corsages +corsair +corsairs +corselet +corselets +corset +corseted +corseting +corsets +corsica +corsican +corsicans +cortege +corteges +cortex +cortexes +cortez +cortical +cortically +corticate +cortices +corticoid +corticoids +corticolous +corticospinal +corticosteroid +corticosteroids +corticosterone +corticosterones +corticotrophin +corticotrophins +corticotropin +corticotropins +cortin +cortins +cortisol +cortisols +cortisone +cortège +cortèges +coruler +corulers +corundum +corunna +coruscant +coruscate +coruscated +coruscates +coruscating +coruscation +coruscations +coruña +corves +corvette +corvettes +corvine +corvus +corvée +corybant +corybantes +corybantic +corybants +corydalis +corymb +corymbose +corymbosely +corymbous +corynebacterium +corynebacteriums +coryneform +coryphaei +coryphaeus +coryphée +coryphées +coryza +cosa +coscript +coscripted +coscripting +coscripts +cosec +cosecant +cosecants +coseismal +coseismic +cosign +cosignatories +cosignatory +cosigned +cosigner +cosigners +cosigning +cosigns +cosine +cosines +cosmetic +cosmetically +cosmetician +cosmeticians +cosmeticize +cosmeticized +cosmeticizes +cosmeticizing +cosmetics +cosmetologist +cosmetologists +cosmetology +cosmic +cosmically +cosmochemical +cosmochemistry +cosmodrome +cosmodromes +cosmogenic +cosmogonic +cosmogonical +cosmogonically +cosmogonies +cosmogonist +cosmogonists +cosmogony +cosmographer +cosmographers +cosmographic +cosmographical +cosmographically +cosmographies +cosmography +cosmologic +cosmological +cosmologically +cosmologies +cosmologist +cosmologists +cosmology +cosmonaut +cosmonauts +cosmopolis +cosmopolitan +cosmopolitanism +cosmopolitans +cosmopolite +cosmopolites +cosmopolitism +cosmos +cosmoses +cosponsor +cosponsored +cosponsoring +cosponsors +cosponsorship +cossack +cossacks +cosset +cosseted +cosseting +cossets +cost +costa +costae +costal +costar +costard +costards +costarred +costarring +costars +costate +costed +coster +costermonger +costermongers +costers +costing +costings +costive +costively +costiveness +costless +costlessness +costlier +costliest +costliness +costly +costmaries +costmary +costochondritis +costrel +costrels +costs +costume +costumed +costumer +costumers +costumes +costuming +cosurfactant +cosy +cot +cotangent +cotangential +cotangents +cote +cotenancy +cotenant +cotenants +coterie +coteries +coterminous +cotes +cothurni +cothurnus +cotidal +cotillion +cotillions +cotman +cotoneaster +cotoneasters +cotopaxi +cotransduce +cotransduced +cotransduces +cotransducing +cotransduction +cotransfer +cotransferred +cotransferring +cotransfers +cotransport +cotrustee +cotrustees +cots +cotswold +cotswolds +cotta +cottae +cottage +cottager +cottagers +cottages +cottas +cotter +cotters +cotton +cottoned +cottoning +cottonmouth +cottonmouths +cottons +cottonseed +cottonseeds +cottontail +cottontails +cottonweed +cottonweeds +cottonwood +cottonwoods +cottony +coturnix +coturnixs +cotyledon +cotyledonal +cotyledonous +cotyledons +cotyloid +couch +couchant +couched +coucher +couchers +couches +couchette +couchettes +couching +cougar +cougars +cough +coughed +coughing +coughs +could +could've +couldest +couldn +couldn't +couldst +coulee +coulees +coulisse +coulisses +couloir +couloirs +coulomb +coulombic +coulombs +coulometric +coulometrically +coulometry +coulter +coulters +coumaric +coumarin +coumarins +council +councilman +councilmen +councilor +councilors +councils +councilwoman +councilwomen +counsel +counseled +counseling +counselor +counselors +counselorship +counsels +count +countability +countable +countably +countdown +countdowns +counted +countenance +countenanced +countenancer +countenancers +countenances +countenancing +counter +counteraccusation +counteract +counteracted +counteracting +counteraction +counteractions +counteractive +counteractively +counteracts +counteradaptation +counteradvertising +counteragent +counteraggression +counterargue +counterargued +counterargues +counterarguing +counterargument +counterarguments +counterassault +counterattack +counterattacked +counterattacker +counterattacking +counterattacks +counterbalance +counterbalanced +counterbalances +counterbalancing +counterbid +counterblast +counterblockade +counterblow +counterblows +countercampaign +counterchallenge +counterchallenges +counterchange +counterchanged +counterchanges +counterchanging +countercharge +countercharged +countercharges +countercharging +countercheck +counterchecked +counterchecking +counterchecks +counterclaim +counterclaimant +counterclaimants +counterclaimed +counterclaiming +counterclaims +counterclockwise +countercommercial +countercomplaint +counterconditioning +counterconditionings +counterconspiracy +counterconvention +countercountermeasure +countercoup +countercoups +countercriticism +countercry +countercultural +counterculture +countercultures +counterculturist +counterculturists +countercurrent +countercurrently +countercurrents +countercyclical +counterdemand +counterdemonstrate +counterdemonstration +counterdemonstrations +counterdemonstrator +counterdemonstrators +counterdeployment +countered +countereducational +countereffort +counterespionage +counterevidence +counterexample +counterexamples +counterfactual +counterfeit +counterfeited +counterfeiter +counterfeiters +counterfeiting +counterfeits +counterfire +counterfoil +counterfoils +counterforce +counterforces +counterglow +counterglows +countergovernment +counterhypothesis +counterimage +counterincentive +counterinflation +counterinflationary +counterinfluence +countering +counterinstance +counterinstitution +counterinsurgencies +counterinsurgency +counterinsurgent +counterinsurgents +counterintelligence +counterinterpretation +counterintuitive +counterirritant +counterirritants +counterirritation +counterman +countermand +countermanded +countermanding +countermands +countermarch +countermarched +countermarches +countermarching +countermeasure +countermeasures +countermemo +countermen +countermine +countermined +countermines +countermining +countermobilization +countermove +countermoved +countermovement +countermoves +countermoving +countermyth +counteroffensive +counteroffensives +counteroffer +counteroffers +counterorder +counterpane +counterpanes +counterpart +counterparts +counterperson +counterpersons +counterpetition +counterpicket +counterplan +counterplans +counterplay +counterplayer +counterplays +counterplea +counterpleas +counterplot +counterplots +counterplotted +counterplotting +counterploy +counterpoint +counterpointed +counterpointing +counterpoints +counterpoise +counterpoised +counterpoises +counterpoising +counterpose +counterposed +counterposes +counterposing +counterpower +counterpressure +counterproductive +counterproductively +counterprogramming +counterprogrammings +counterproject +counterproliferation +counterpropaganda +counterproposal +counterproposals +counterprotest +counterpunch +counterpunched +counterpuncher +counterpunchers +counterpunches +counterpunching +counterquestion +counterraid +counterrally +counterreaction +counterreform +counterreformation +counterreformations +counterreformer +counterresponse +counterretaliation +counterrevolution +counterrevolutionaries +counterrevolutionary +counterrevolutionist +counterrevolutionists +counterrevolutions +counters +counterscientific +countershading +countershadings +countershaft +countershafts +countershot +countersign +countersignature +countersignatures +countersigned +countersigning +countersigns +countersink +countersinking +countersinks +countersniper +counterspell +counterspies +counterspy +counterstain +counterstained +counterstaining +counterstains +counterstate +counterstatement +counterstep +counterstrategist +counterstrategy +counterstream +counterstrike +counterstroke +counterstrokes +counterstyle +countersue +countersued +countersues +countersuggestion +countersuing +countersuit +countersuits +countersunk +countersurveillance +countertactics +countertendency +countertenor +countertenors +counterterror +counterterrorism +counterterrorist +counterterrorists +counterterrors +counterthreat +counterthrust +countertop +countertops +countertrade +countertrader +countertraders +countertrades +countertradition +countertransference +countertransferences +countertrend +countervail +countervailed +countervailing +countervails +counterviolence +counterweigh +counterweighed +counterweighing +counterweighs +counterweight +counterweighted +counterweights +counterwoman +counterwomen +counterworld +countess +countesses +counties +counting +countinghouse +countless +countlessly +countries +countrified +country +countryman +countrymen +countryseat +countryseats +countryside +countrysides +countrywide +countrywoman +countrywomen +counts +county +countywide +coup +coupe +coupes +couple +coupled +coupler +couplers +couples +couplet +couplets +coupling +couplings +coupon +couponing +couponings +coupons +coups +coupé +coupés +courage +courageous +courageously +courageousness +courant +courante +courantes +courgette +courgettes +courier +couriers +courlan +courlans +course +coursed +courser +coursers +courses +courseware +coursework +coursing +coursings +court +courted +courteous +courteously +courteousness +courtesan +courtesans +courtesies +courtesy +courthouse +courthouses +courtier +courtiers +courting +courtlier +courtliest +courtliness +courtly +courtroom +courtrooms +courts +courtship +courtships +courtside +courtyard +courtyards +couscous +cousin +cousinhood +cousinly +cousins +cousinship +couth +coutts +couture +couturier +couturiers +couturière +couturières +couvade +couvades +covalence +covalency +covalent +covalently +covariance +covariant +cove +coved +covellite +covellites +coven +covenant +covenantal +covenantally +covenanted +covenantee +covenantees +covenanter +covenanters +covenanting +covenantor +covenantors +covenants +covens +coventry +cover +coverable +coverage +coverall +coveralls +coverdale +covered +coverer +coverers +covering +coverings +coverless +coverlet +coverlets +covers +covert +covertly +covertness +coverts +coverture +covertures +coves +covet +covetable +coveted +coveter +coveters +coveting +covetingly +covetous +covetously +covetousness +covets +covey +coveys +coving +cow +coward +cowardice +cowardliness +cowardly +cowards +cowbane +cowbanes +cowbell +cowbells +cowberries +cowberry +cowbird +cowbirds +cowboy +cowboys +cowcatcher +cowcatchers +cowed +cowedly +cower +cowered +cowering +cowers +cowfish +cowfishes +cowgirl +cowgirls +cowhand +cowhands +cowherb +cowherbs +cowherd +cowherds +cowhide +cowhided +cowhides +cowhiding +cowing +cowinner +cowinners +cowl +cowled +cowlick +cowlicks +cowling +cowlings +cowls +cowman +cowmen +coworker +coworkers +cowpea +cowpeas +cowper +cowpoke +cowpokes +cowponies +cowpony +cowpox +cowpoxes +cowpuncher +cowpunchers +cowrie +cowries +cowrite +cowriter +cowriters +cowrites +cowriting +cowritten +cowrote +cowry +cows +cowshed +cowsheds +cowslip +cowslips +cox +coxa +coxae +coxal +coxalgia +coxalgias +coxalgic +coxcomb +coxcombries +coxcombry +coxcombs +coxed +coxes +coxing +coxitis +coxitises +coxsackievirus +coxsackieviruses +coxswain +coxswained +coxswaining +coxswains +coy +coydog +coydogs +coyer +coyest +coyly +coyness +coyote +coyotes +coyotillo +coyotillos +coypu +coypus +cozen +cozenage +cozenages +cozened +cozener +cozeners +cozening +cozens +cozied +cozier +cozies +coziest +cozily +coziness +cozumel +cozy +cozying +crab +crabapple +crabapples +crabbe +crabbed +crabbedly +crabbedness +crabber +crabbers +crabbier +crabbiest +crabbily +crabbiness +crabbing +crabby +crabgrass +crabmeat +crabmeats +crabs +crabstick +crabsticks +crabwise +crack +crackbrain +crackbrained +crackbrains +crackdown +crackdowns +cracked +cracker +crackerjack +crackerjacks +crackers +cracking +crackings +crackle +crackled +crackles +crackleware +cracklewares +cracklier +crackliest +crackling +cracklings +crackly +cracknel +cracknels +crackpot +crackpots +cracks +cracksman +cracksmen +crackup +crackups +cracow +cradle +cradleboard +cradleboards +cradled +cradler +cradlers +cradles +cradlesong +cradlesongs +cradling +craft +crafted +crafter +crafters +craftier +craftiest +craftily +craftiness +crafting +crafts +craftsman +craftsmanlike +craftsmanly +craftsmanship +craftsmen +craftspeople +craftsperson +craftspersons +craftswoman +craftswomen +craftwork +craftworker +craftworkers +craftworks +crafty +crag +cragged +craggier +craggiest +craggily +cragginess +craggy +crags +craig +crake +crakes +cram +crambe +crambes +crambo +cramboes +crammed +crammer +crammers +cramming +cramp +cramped +crampfish +crampfishes +cramping +crampon +crampons +cramps +crams +cranberries +cranberry +crane +craned +cranes +cranesbill +cranesbills +crania +cranial +cranially +craniate +craniates +craniectomies +craniectomy +craning +craniocerebral +craniofacial +craniological +craniologically +craniologist +craniologists +craniology +craniometer +craniometers +craniometric +craniometrical +craniometry +craniosacral +craniotomies +craniotomy +cranium +craniums +crank +crankcase +crankcases +cranked +crankier +crankiest +crankily +crankiness +cranking +crankpin +cranks +crankshaft +crankshafts +cranky +cranmer +crannied +crannies +cranny +crap +crape +craped +crapehanger +crapehangers +crapes +craping +crapped +crapper +crappers +crappie +crappier +crappies +crappiest +crapping +crappy +craps +crapshoot +crapshooter +crapshooters +crapshoots +crapulence +crapulent +crapulous +crapulously +crash +crashed +crasher +crashers +crashes +crashing +crashworthiness +crashworthy +crass +crasser +crassest +crassitude +crassly +crassness +crate +crated +crater +cratered +cratering +craterlet +craterlets +craters +crates +crating +cravat +cravats +crave +craved +craven +cravenly +cravenness +cravens +craver +cravers +craves +craving +cravingly +cravings +craw +crawdad +crawdads +crawfish +crawfished +crawfishes +crawfishing +crawl +crawled +crawler +crawlers +crawlier +crawliest +crawling +crawlingly +crawls +crawlspace +crawlspaces +crawlway +crawlways +crawly +craws +crayfish +crayfishes +crayon +crayoned +crayoning +crayonist +crayonists +crayons +craze +crazed +crazes +crazier +crazies +craziest +crazily +craziness +crazinesses +crazing +crazy +crazyweed +crazyweeds +creak +creaked +creakier +creakiest +creakily +creakiness +creaking +creakingly +creaks +creaky +cream +creamcups +creamed +creamer +creameries +creamers +creamery +creamier +creamiest +creamily +creaminess +creaming +creampuff +creampuffs +creams +creamy +crease +creased +creaseless +creaseproof +creaser +creasers +creases +creasing +creasy +create +created +creates +creatine +creatines +creating +creatinine +creatinines +creation +creational +creationism +creationist +creationists +creations +creative +creatively +creativeness +creativity +creator +creators +creatural +creature +creatureliness +creaturely +creatures +credence +credential +credentialed +credentialing +credentialism +credentialisms +credentials +credenza +credenzas +credibility +credible +credibleness +credibly +credit +creditability +creditable +creditableness +creditably +credited +crediting +creditor +creditors +credits +creditworthiness +creditworthy +credo +credos +credulity +credulous +credulously +credulousness +creed +creedal +creeds +creek +creeks +creel +creels +creep +creeper +creepers +creepier +creepiest +creepily +creepiness +creeping +creeps +creepy +cremains +cremate +cremated +cremates +cremating +cremation +cremations +cremator +crematoria +crematories +crematorium +crematoriums +cremators +crematory +creme +cremes +cremona +crenate +crenately +crenation +crenations +crenature +crenatures +crenel +crenelated +crenelation +crenellate +crenellated +crenellates +crenellating +crenellation +crenellations +crenellé +crenels +crenshaw +crenshaws +crenulate +crenulation +creodont +creodonts +creole +creoles +creolization +creolize +creolized +creolizes +creolizing +creon +creosol +creosols +creosote +creosoted +creosotes +creosoting +crepe +crepehanger +crepehangers +crepes +crepitant +crepitate +crepitated +crepitates +crepitating +crepitation +crepitations +crept +crepuscular +crepuscule +crepuscules +crescendi +crescendo +crescendoed +crescendoes +crescendoing +crescendos +crescent +crescentic +crescents +cresol +cresols +cress +cresset +cressets +cressida +crest +cresta +crested +crestfallen +crestfallenly +crestfallenness +cresting +crestings +crests +cresyl +cresylic +cresyls +cretaceous +cretaceously +cretan +cretans +crete +cretic +cretics +cretin +cretinism +cretinize +cretinized +cretinizes +cretinizing +cretinoid +cretinous +cretins +cretonne +cretonnes +crevalle +crevalles +crevasse +crevassed +crevasses +crevassing +crevice +creviced +crevices +crew +crewcut +crewed +crewel +crewels +crewelwork +crewelworks +crewing +crewman +crewmate +crewmates +crewmember +crewmembers +crewmen +crews +creüsa +cri +crib +cribbage +cribbed +cribber +cribbers +cribbing +cribriform +cribs +cricetid +cricetids +crick +cricked +cricket +cricketed +cricketer +cricketers +cricketing +crickets +crickety +cricking +cricks +cricoid +cricoids +cried +crier +criers +cries +crime +crimea +crimean +crimeless +crimelessness +crimes +criminal +criminalities +criminality +criminalization +criminalize +criminalized +criminalizes +criminalizing +criminally +criminals +criminate +criminated +criminates +criminating +crimination +criminative +criminator +criminators +criminatory +criminogenic +criminological +criminologically +criminologist +criminologists +criminology +crimp +crimped +crimper +crimpers +crimpier +crimpiest +crimpiness +crimping +crimps +crimpy +crimson +crimsoned +crimsoning +crimsons +cringe +cringed +cringes +cringing +cringle +cringles +crinkle +crinkled +crinkleroot +crinkleroots +crinkles +crinkling +crinkly +crinoid +crinoids +crinoline +crinolined +crinolines +crinum +crinums +criollo +criollos +criosphinx +criosphinxes +cripple +crippled +crippler +cripplers +cripples +crippling +cripps +cris +crises +crisis +crisp +crispate +crispation +crispations +crisped +crisper +crispers +crispest +crispier +crispiest +crispin +crispiness +crisping +crisply +crispness +crisps +crispy +crissa +crissal +crisscross +crisscrossed +crisscrosses +crisscrossing +crissum +crista +cristae +cristate +criteria +criterial +criterion +criterions +critic +critical +criticality +critically +criticalness +criticaster +criticasters +criticism +criticisms +criticizable +criticize +criticized +criticizer +criticizers +criticizes +criticizing +critics +critique +critiqued +critiques +critiquing +critter +critters +croak +croaked +croaker +croakers +croakily +croaking +croaks +croaky +croat +croatia +croatian +croatians +croats +crocein +croceins +crochet +crocheted +crocheting +crochets +crocidolite +crocidolites +crock +crocked +crockery +crocket +crockets +crocking +crocks +crocodile +crocodiles +crocodilian +crocodilians +crocoite +crocoites +crocus +crocuses +croesus +crofter +crofters +crohn +croissant +croissants +cromlech +cromlechs +cromwell +cromwellian +crone +crones +cronies +cronin +cronus +crony +cronyism +crook +crookbacked +crooked +crookedly +crookedness +crookeries +crookery +crooking +crookneck +crooknecks +crooks +croon +crooned +crooner +crooners +crooning +croons +crop +cropland +croplands +cropped +cropper +croppers +cropping +crops +croquet +croqueted +croqueting +croquets +croquette +croquettes +croquignole +croquignoles +crosier +crosiers +cross +crossbar +crossbars +crossbeam +crossbeams +crossbill +crossbills +crossbones +crossbow +crossbowman +crossbows +crossbred +crossbreed +crossbreeding +crossbreeds +crosscheck +crosschecked +crosschecking +crosschecks +crosscourt +crosscurrent +crosscurrents +crosscut +crosscuts +crosscutting +crosscuttings +crosse +crossed +crosser +crossers +crosses +crossfire +crosshair +crosshairs +crosshatch +crosshatched +crosshatches +crosshatching +crosshead +crossheads +crossing +crossings +crossly +crossness +crossopterygian +crossopterygians +crossover +crossovers +crosspatch +crosspatches +crosspiece +crosspieces +crossroad +crossroads +crossruff +crossruffed +crossruffing +crossruffs +crosstalk +crosstalks +crosstie +crossties +crosstree +crosstrees +crosswalk +crosswalks +crossway +crossways +crosswayss +crosswind +crosswinds +crosswise +crossword +crosswords +crotch +crotched +crotches +crotchet +crotchetiness +crotchets +crotchety +croton +crotons +crottin +crottins +crouch +crouched +crouches +crouching +croup +croupier +croupiers +croupous +croupy +crouse +croustade +croustades +crouton +croutons +crow +crowbar +crowbarred +crowbarring +crowbars +crowberries +crowberry +crowd +crowded +crowder +crowders +crowding +crowds +crowed +crowfoot +crowfoots +crowing +crown +crowned +crowning +crowns +crows +croze +crozes +cru +crucial +crucially +cruciate +cruciately +crucible +crucibles +crucifer +cruciferous +crucifers +crucified +crucifier +crucifiers +crucifies +crucifix +crucifixes +crucifixion +crucifixions +cruciform +cruciformly +crucify +crucifying +crud +cruddier +cruddiest +cruddiness +cruddy +crude +crudely +crudeness +cruder +crudest +crudities +crudity +crudités +cruel +crueler +cruelest +cruelly +cruelties +cruelty +cruet +cruets +cruise +cruised +cruiser +cruisers +cruiserweight +cruiserweights +cruises +cruising +cruller +crullers +crumb +crumbed +crumbing +crumble +crumbled +crumbles +crumblier +crumbliest +crumbliness +crumbling +crumbly +crumbs +crummier +crummiest +crummy +crump +crumped +crumpet +crumpets +crumping +crumple +crumpled +crumples +crumpling +crumply +crumps +crunch +crunchable +crunched +crunches +crunchier +crunchiest +crunchiness +crunching +crunchy +crupper +cruppers +crura +crural +crus +crusade +crusaded +crusader +crusaders +crusades +crusading +crusado +crusadoes +cruse +cruses +crush +crushable +crushed +crusher +crushers +crushes +crushing +crushingly +crushproof +crusoe +crust +crustacean +crustaceans +crustaceous +crustal +crusted +crustier +crustiest +crustily +crustiness +crusting +crustless +crustose +crusts +crusty +crutch +crutched +crutches +crutching +crux +cruxes +cruz +cruzeiro +cruzeiros +cry +crybabies +crybaby +crying +crymotherapies +crymotherapy +cryobank +cryobanks +cryobiological +cryobiologically +cryobiologist +cryobiologists +cryobiology +cryogen +cryogenic +cryogenically +cryogenics +cryogeny +cryolite +cryolites +cryometer +cryometers +cryonic +cryonics +cryophilic +cryopreservation +cryopreserve +cryopreserved +cryopreserves +cryopreserving +cryoprobe +cryoprobes +cryoprotectant +cryoprotectants +cryoprotective +cryoscope +cryoscopes +cryoscopic +cryoscopies +cryoscopy +cryostat +cryostatic +cryostats +cryosurgeon +cryosurgeons +cryosurgery +cryosurgical +cryotherapies +cryotherapy +crypt +cryptanalysis +cryptanalyst +cryptanalysts +cryptanalytic +cryptanalyze +cryptanalyzed +cryptanalyzes +cryptanalyzing +cryptesthesia +cryptic +cryptically +crypticness +crypto +cryptoclastic +cryptococcal +cryptococcosis +cryptococcus +cryptocrystalline +cryptogam +cryptogamic +cryptogamous +cryptogams +cryptogenic +cryptogram +cryptogrammic +cryptograms +cryptograph +cryptographed +cryptographer +cryptographers +cryptographic +cryptographically +cryptographing +cryptographs +cryptography +cryptologic +cryptological +cryptologist +cryptologists +cryptology +cryptomeria +cryptomerias +cryptorchid +cryptorchism +cryptos +cryptosporidiosis +cryptozoite +cryptozoites +cryptozoological +cryptozoologist +cryptozoologists +cryptozoology +crypts +crystal +crystalliferous +crystalline +crystallinity +crystallite +crystallites +crystallitic +crystallizable +crystallization +crystallize +crystallized +crystallizer +crystallizers +crystallizes +crystallizing +crystallographer +crystallographers +crystallographic +crystallographical +crystallographically +crystallography +crystalloid +crystalloidal +crystalloids +crystals +crécy +crèche +crèches +crème +crèmes +crêpe +crêpes +ctenidia +ctenidium +ctenoid +ctenophoran +ctenophore +ctenophores +cuadrilla +cuadrillas +cuatro +cuatros +cub +cuba +cubage +cubages +cuban +cubans +cubature +cubatures +cubbies +cubby +cubbyhole +cubbyholes +cube +cubeb +cubebs +cubed +cuber +cubers +cubes +cubic +cubical +cubically +cubicalness +cubicle +cubicles +cubicly +cubics +cubiform +cubing +cubism +cubist +cubistic +cubistically +cubists +cubit +cubits +cuboid +cuboidal +cuboids +cubs +cubé +cuchifrito +cuchifritos +cuchulain +cuckold +cuckolded +cuckolding +cuckoldries +cuckoldry +cuckolds +cuckoo +cuckooed +cuckooflower +cuckooflowers +cuckooing +cuckoopint +cuckoopints +cuckoos +cucullate +cucullately +cucumber +cucumbers +cucurbit +cucurbits +cud +cudbear +cudbears +cuddies +cuddle +cuddled +cuddles +cuddlesome +cuddlier +cuddliest +cuddling +cuddly +cuddy +cudgel +cudgeled +cudgeling +cudgels +cudweed +cudweeds +cue +cued +cueing +cuernavaca +cues +cuesta +cuestas +cuff +cuffed +cuffing +cufflink +cufflinks +cuffs +cui +cuing +cuirass +cuirassed +cuirasses +cuirassier +cuirassiers +cuirassing +cuisinart +cuisine +cuisse +cuisses +cul +culch +culches +culet +culets +culex +culiacán +culices +culinary +cull +culled +culler +cullers +cullet +cullets +cullies +culling +cullis +cullises +culloden +culls +cully +culm +culminant +culminate +culminated +culminates +culminating +culmination +culminations +culms +culotte +culottes +culpa +culpability +culpable +culpably +culprit +culprits +cult +cultic +cultigen +cultigens +cultish +cultism +cultist +cultists +cultivability +cultivable +cultivar +cultivatable +cultivate +cultivated +cultivates +cultivating +cultivation +cultivations +cultivator +cultivators +cultrate +cults +cultural +culturally +culturati +culture +cultured +cultures +culturing +cultus +cultuses +culver +culverin +culverins +culvers +culvert +culverts +cum +cumaean +cumber +cumbered +cumberer +cumberers +cumbering +cumberland +cumbers +cumbersome +cumbersomely +cumbria +cumbrian +cumbrians +cumbrous +cumbrously +cumbrousness +cumin +cummerbund +cummerbunds +cumshaw +cumshaws +cumulate +cumulated +cumulates +cumulating +cumulation +cumulations +cumulative +cumulatively +cumulativeness +cumuli +cumuliform +cumulonimbi +cumulonimbus +cumulonimbuses +cumulous +cumulus +cunard +cunctation +cunctations +cunctative +cunctator +cunctators +cuneal +cuneate +cuneately +cuneiform +cunha +cunner +cunners +cunnilingual +cunnilingus +cunnilinguses +cunning +cunningly +cunningness +cunnings +cunt +cunts +cup +cupbearer +cupbearers +cupboard +cupboards +cupcake +cupcakes +cupel +cupeled +cupeling +cupellation +cupellations +cupeller +cupellers +cupels +cupflower +cupflowers +cupful +cupfuls +cupid +cupidity +cupids +cupola +cupolas +cupped +cuppier +cuppiest +cupping +cuppings +cuppy +cupreous +cupric +cupriferous +cuprite +cuprites +cupronickel +cupronickels +cuprous +cups +cupulate +cupule +cupules +cur +curability +curable +curableness +curably +curacies +curacy +curare +curarization +curarize +curarized +curarizes +curarizing +curassow +curassows +curate +curates +curative +curatively +curativeness +curatives +curator +curatorial +curators +curatorship +curaçao +curaçaos +curb +curbed +curbing +curbs +curbside +curbsides +curbstone +curbstones +curculio +curculios +curcuma +curcumas +curd +curded +curding +curdle +curdled +curdles +curdling +curds +curdy +cure +cured +cureless +curer +curers +cures +curettage +curette +curettement +curettements +curettes +curfew +curfews +curia +curiae +curial +curie +curies +curing +curio +curios +curiosa +curiosities +curiosity +curious +curiously +curiousness +curium +curl +curled +curler +curlers +curlew +curlews +curlicue +curlicued +curlicues +curlier +curliest +curlily +curliness +curling +curlings +curls +curly +curmudgeon +curmudgeonly +curmudgeonry +curmudgeons +currant +currants +currencies +currency +current +currently +currentness +currents +curricle +curricles +curricula +curricular +curriculum +curriculums +curried +currier +currieries +curriers +curriery +curries +currish +currishly +curry +currycomb +currycombed +currycombing +currycombs +currying +curs +curse +cursed +cursedly +cursedness +curser +cursers +curses +cursing +cursive +cursively +cursiveness +cursives +cursor +cursorial +cursorily +cursoriness +cursors +cursory +curt +curtail +curtailed +curtailer +curtailers +curtailing +curtailment +curtailments +curtails +curtain +curtained +curtaining +curtains +curtate +curter +curtesies +curtest +curtesy +curtilage +curtilages +curtly +curtness +curtsey +curtseyed +curtseying +curtseys +curtsied +curtsies +curtsy +curtsying +curule +curvaceous +curvaceously +curvaceousness +curvature +curvatures +curve +curveball +curveballs +curved +curvedness +curves +curvet +curvets +curvetted +curvetting +curvilinear +curvilinearity +curvilinearly +curving +curvy +curé +curés +cuscus +cuscuses +cusec +cusecs +cushaw +cushaws +cushier +cushiest +cushily +cushiness +cushion +cushioned +cushioning +cushions +cushiony +cushitic +cushy +cusk +cusp +cuspate +cusped +cuspid +cuspidate +cuspidation +cuspidations +cuspidor +cuspidors +cuspids +cusps +cuss +cussed +cussedly +cussedness +cusses +cussing +cussword +cusswords +custard +custards +custardy +custodial +custodian +custodians +custodianship +custodies +custody +custom +customable +customarily +customariness +customary +customer +customers +customhouse +customhouses +customizable +customization +customizations +customize +customized +customizer +customizers +customizes +customizing +customs +cut +cutaneous +cutaneously +cutaway +cutaways +cutback +cutbacks +cutch +cutches +cute +cutely +cuteness +cuter +cutes +cutesier +cutesiest +cutesiness +cutest +cutesy +cutgrass +cutgrasses +cuticle +cuticles +cuticular +cutie +cuties +cutin +cutinization +cutinize +cutinized +cutinizes +cutinizing +cutins +cutis +cutlass +cutlasses +cutler +cutlers +cutlery +cutlet +cutlets +cutoff +cutoffs +cutout +cutouts +cutover +cutpurse +cutpurses +cuts +cuttable +cutter +cutters +cutthroat +cutthroats +cutting +cuttingly +cuttings +cuttingss +cuttlebone +cuttlebones +cuttlefish +cuttlefishes +cutup +cutups +cutwater +cutwaters +cutwork +cutworks +cutworm +cutworms +cuvette +cuvettes +cuvier +cyan +cyanamide +cyanamides +cyanate +cyanates +cyanic +cyanide +cyanided +cyanides +cyaniding +cyanine +cyanines +cyanoacrylate +cyanoacrylates +cyanobacterium +cyanobacteriums +cyanocobalamin +cyanocobalamins +cyanogen +cyanogenesis +cyanogenetic +cyanogens +cyanohydrin +cyanohydrins +cyanosed +cyanoses +cyanosis +cyanotic +cyanotype +cyanotypes +cyathium +cyathiums +cybele +cyberconference +cybernate +cybernated +cybernates +cybernating +cybernation +cybernetic +cybernetically +cybernetician +cyberneticians +cyberneticist +cyberneticists +cybernetics +cyberspace +cyborg +cyborgs +cycad +cycads +cyclades +cycladic +cyclamate +cyclamates +cyclamen +cyclamens +cyclase +cyclases +cycle +cycled +cycler +cyclers +cycles +cyclic +cyclical +cyclicality +cyclically +cycling +cyclist +cyclists +cyclization +cyclizations +cycloalkane +cycloalkanes +cyclohexane +cyclohexanes +cycloheximide +cycloheximides +cycloid +cycloidal +cycloids +cyclometer +cyclometers +cyclometric +cyclometry +cyclone +cyclones +cyclonic +cyclonical +cyclooxygenase +cycloparaffin +cycloparaffins +cyclopean +cyclopedia +cyclopedias +cyclopedic +cyclopedist +cyclopedists +cyclopentane +cyclopentanes +cyclopes +cyclophosphamide +cyclophosphamides +cycloplegia +cycloplegias +cyclopropane +cyclopropanes +cyclops +cyclopses +cyclorama +cycloramas +cycloramic +cycloserine +cycloserines +cycloses +cyclosis +cyclosporine +cyclosporines +cyclostomate +cyclostomatous +cyclostome +cyclostomes +cyclostyle +cyclostyled +cyclostyles +cyclostyling +cyclothyme +cyclothymes +cyclothymia +cyclothymias +cyclothymic +cyclotron +cyclotrons +cygnet +cygnets +cygnus +cylinder +cylinders +cylindric +cylindrical +cylindricality +cylindrically +cylindroid +cylindroids +cyma +cymas +cymatia +cymatium +cymbal +cymbaleer +cymbaleers +cymbalist +cymbalists +cymbals +cymbeline +cymbidium +cymbidiums +cyme +cymene +cymenes +cymes +cymiferous +cymling +cymlings +cymogene +cymogenes +cymoid +cymophane +cymophanes +cymose +cymosely +cymric +cymry +cynic +cynical +cynically +cynicalness +cynicism +cynicisms +cynics +cynoscephalae +cynosural +cynosure +cynosures +cynthia +cypress +cypresses +cyprian +cyprians +cyprinid +cyprinids +cyprinodont +cyprinodonts +cyprinoid +cyprinoids +cypriot +cypriots +cypripedium +cypripediums +cyproheptadine +cyproheptadines +cyproterone +cyproterones +cyprus +cypsela +cypselae +cyrenaic +cyrenaica +cyrenaics +cyrene +cyrillic +cyst +cystectomies +cystectomy +cysteine +cysteines +cystic +cysticerci +cysticercoid +cysticercoids +cysticercosis +cysticercus +cystine +cystines +cystitis +cystocele +cystoceles +cystoid +cystoids +cystolith +cystoliths +cystoscope +cystoscopes +cystoscopic +cystoscopy +cystostomies +cystostomy +cysts +cythera +cytherean +cytidine +cytidines +cytochemical +cytochemistry +cytochrome +cytochromes +cytogenesis +cytogenetic +cytogenetical +cytogenetically +cytogeneticist +cytogeneticists +cytogenetics +cytogeny +cytokinesis +cytokinetic +cytokinin +cytokinins +cytologic +cytological +cytologist +cytologists +cytology +cytolyses +cytolysin +cytolysins +cytolysis +cytolytic +cytomegalic +cytomegalovirus +cytomegaloviruses +cytomembrane +cytomembranes +cytopathic +cytopathogenic +cytopathogenicity +cytophilic +cytophotometer +cytophotometers +cytophotometric +cytophotometrically +cytophotometry +cytoplasm +cytoplasmic +cytoplasmically +cytoplast +cytoplastic +cytoplasts +cytosine +cytosines +cytoskeleton +cytoskeletons +cytosol +cytosols +cytostasis +cytostatic +cytostatically +cytostatics +cytotaxonomic +cytotaxonomies +cytotaxonomist +cytotaxonomists +cytotaxonomy +cytotechnologist +cytotechnologists +cytotechnology +cytotoxic +cytotoxicity +cytotoxin +cytotoxins +czar +czardas +czardom +czarevitch +czarevitches +czarevna +czarevnas +czarina +czarinas +czarism +czarisms +czarist +czarists +czaritza +czaritzas +czars +czech +czechoslovak +czechoslovakia +czechoslovakian +czechoslovakians +czechoslovaks +czechs +cádiz +cárdenas +céleste +célestes +célèbre +célèbres +cévennes +cézanne +cézannesque +cèpe +cèpes +cíbola +córdoba +côte +côtes +d +d'affaires +d'antibes +d'aosta +d'art +d'azur +d'elegance +d'esprit +d'estime +d'hôte +d'hôtel +d'oc +d'oeil +d'oeuvre +d'oeuvres +d'oyly +d'oïl +d'état +d'être +d'œil +d'œuvre +d'œuvres +da +dab +dabbed +dabber +dabbers +dabbing +dabble +dabbled +dabbler +dabblers +dabbles +dabbling +dabchick +dabchicks +dabs +dacca +dace +daces +dacha +dachas +dachau +dachshund +dachshunds +dacoit +dacoits +dacoity +dacquoise +dacquoises +dacron +dactinomycin +dactinomycins +dactyl +dactylic +dactylically +dactylogram +dactylograms +dactylographic +dactylography +dactylology +dactyls +dad +dada +dadaism +dadaist +dadaistic +dadaists +daddies +daddy +daddyish +dado +dadoed +dadoes +dadoing +dados +dadra +dads +daedal +daedalian +daedalus +daemon +daemonic +daemons +daffier +daffiest +daffily +daffiness +daffodil +daffodils +daffy +daft +dafter +daftest +daftly +daftness +dag +dagan +dagestan +dagger +daggers +dagon +dags +daguerre +daguerreotype +daguerreotyped +daguerreotyper +daguerreotypers +daguerreotypes +daguerreotyping +daguerreotypy +dagwood +dagwoods +dahabeah +dahabeahs +dahl +dahlia +dahlias +dahomey +dahoon +dahoons +daikon +dailies +dailiness +daily +daimio +daimios +daimon +daimons +daintier +dainties +daintiest +daintily +daintiness +dainty +daiquiri +daiquiris +dairies +dairy +dairyer +dairyers +dairying +dairymaid +dairymaids +dairyman +dairymen +dairywoman +dairywomen +dais +daises +daisies +daisy +dakar +dakota +dakotan +dakotans +dakotas +dalai +dalapon +dalapons +dalasi +dale +dalek +daleks +dales +daleth +dalhousie +dallas +dalles +dalliance +dalliances +dallied +dallier +dalliers +dallies +dally +dallying +dallyingly +dalmatia +dalmatian +dalmatians +dalmatic +dalmatics +dalrymple +dalton +daltonian +daltonic +daltonism +daltons +dam +damage +damageability +damageable +damaged +damager +damagers +damages +damaging +damagingly +daman +damascene +damascened +damascener +damasceners +damascenes +damascening +damascus +damask +damasked +damasking +damasks +dame +dames +daminozide +daminozides +dammar +dammars +dammed +dammer +dammers +damming +dammit +damn +damnable +damnableness +damnably +damnation +damnatory +damnder +damndest +damned +damneder +damnedest +damnification +damnified +damnifies +damnify +damnifying +damning +damningly +damns +damocles +damon +damp +damped +dampen +dampened +dampener +dampeners +dampening +dampens +damper +dampers +dampest +damping +dampings +dampish +damply +dampness +damps +dams +damsel +damselfish +damselfishes +damselflies +damselfly +damsels +damson +damsons +dan +dana +danaides +danaë +dance +danceability +danceable +danced +dancegoer +dancegoers +dancegoing +dancer +dancerly +dancers +dances +dancewear +dancewears +dancier +danciest +dancing +dancingly +dancy +dandelion +dandelions +dander +dandiacal +dandier +dandies +dandiest +dandification +dandified +dandifies +dandify +dandifying +dandily +dandle +dandled +dandles +dandling +dandruff +dandruffy +dandy +dandyish +dandyishly +dandyism +dandyisms +dane +danegeld +danegelds +danelaw +danelaws +danes +dang +danged +danger +dangerous +dangerously +dangerousness +dangers +dangle +dangleberries +dangleberry +dangled +dangler +danglers +dangles +dangling +dangly +dangs +daniel +danielle +danio +danios +danish +danishes +danite +danites +dank +danker +dankest +dankly +dankness +dans +danseur +danseurs +danseuse +danseuses +dante +dantean +danteans +dantesque +danton +danube +danubian +danville +danzig +dap +daphne +daphnes +daphnia +daphnis +dapped +dapper +dapperly +dapperness +dapping +dapple +dappled +dapples +dappling +daps +dapsone +dapsones +dardanelles +dardanus +dare +dared +daredevil +daredevilry +daredevils +daredeviltry +daren +daren't +darer +darers +dares +daresay +daring +daringly +daringness +dariole +darioles +darius +darién +darjeeling +dark +darken +darkened +darkener +darkeners +darkening +darkens +darker +darkest +darkish +darkle +darkled +darkles +darkling +darklings +darkly +darkness +darkroom +darkrooms +darks +darksome +darlene +darling +darlingly +darlingness +darlings +darn +darnation +darned +darnedest +darnedests +darnel +darnels +darner +darners +darning +darnley +darns +daro +dart +dartboard +dartboards +darted +darter +darters +darting +dartmouth +darts +darvon +darwin +darwinian +darwinians +darwinism +darwinist +darwinistic +darwinists +dash +dashboard +dashboards +dashed +dasheen +dasheens +dasher +dashers +dashes +dashi +dashiki +dashikis +dashing +dashingly +dashis +dashpot +dashpots +dassie +dassies +dastard +dastardliness +dastardly +dastards +dasyure +dasyures +data +databanks +database +databased +databases +databasing +datable +datagram +datamation +date +dateable +dated +datedly +datedness +dateless +dateline +datelined +datelines +datelining +dater +daters +dates +dating +dative +datively +datives +datum +datums +datura +daturas +daub +daubed +dauber +daubers +daubery +daubing +daubs +daugavpils +daughter +daughterless +daughterly +daughters +daunt +daunted +daunter +daunters +daunting +dauntingly +dauntless +dauntlessly +dauntlessness +daunts +dauphin +dauphine +dauphines +dauphins +dauphiné +dave +davenant +davenport +davenports +david +davit +davits +davos +davy +daw +dawdle +dawdled +dawdler +dawdlers +dawdles +dawdling +dawdlingly +dawn +dawned +dawning +dawns +daws +day +dayak +dayaks +daybed +daybeds +daybook +daybooks +daybreak +daybreaks +daycare +daydream +daydreamed +daydreamer +daydreamers +daydreaming +daydreams +daydreamt +dayflies +dayflower +dayflowers +dayfly +dayhop +dayhops +daylight +daylights +daylilies +daylily +daylong +daypack +daypacks +dayroom +dayrooms +days +dayside +daysides +dayspring +daystar +daystars +daytime +daytimes +dayton +daytona +daywear +daze +dazed +dazedly +dazedness +dazes +dazing +dazzle +dazzled +dazzler +dazzlers +dazzles +dazzling +dazzlingly +de +deaccession +deaccessioned +deaccessioning +deaccessions +deacidification +deacidified +deacidifies +deacidify +deacidifying +deacon +deaconess +deaconesses +deaconries +deaconry +deacons +deactivate +deactivated +deactivates +deactivating +deactivation +deactivations +deactivator +deactivators +dead +deadbeat +deadbeats +deadbolt +deadbolts +deaden +deadened +deadener +deadeners +deadening +deadeningly +deadenings +deadens +deader +deadest +deadeye +deadeyes +deadfall +deadfalls +deadhead +deadheaded +deadheading +deadheads +deadlier +deadliest +deadlight +deadlights +deadline +deadlined +deadlines +deadliness +deadlining +deadlock +deadlocked +deadlocking +deadlocks +deadly +deadness +deadpan +deadpanned +deadpanner +deadpanners +deadpanning +deadpans +deadweight +deadwood +deaerate +deaerated +deaerates +deaerating +deaeration +deaerator +deaerators +deaf +deafen +deafened +deafening +deafeningly +deafens +deafer +deafest +deafly +deafness +deal +dealate +dealated +dealateds +dealates +dealation +dealcoholization +dealcoholize +dealcoholized +dealcoholizes +dealcoholizing +dealer +dealers +dealership +dealerships +dealfish +dealfishes +dealignment +dealignments +dealing +dealings +deallocate +deallocated +deallocates +deallocating +deallocation +deallocations +deallocator +dealmaker +dealmakers +dealmaking +deals +dealt +deaminase +deaminases +deaminate +deaminated +deaminates +deaminating +deamination +deaminization +deaminize +deaminized +deaminizes +deaminizing +dean +deaneries +deanery +deans +deanship +dear +dearborn +dearer +dearest +dearly +dearness +dears +dearth +death +deathbed +deathbeds +deathblow +deathblows +deathless +deathlessly +deathlessness +deathlike +deathly +deaths +deathtrap +deathtraps +deathward +deathwatch +deathwatches +deattribution +deattributions +deauville +deb +debacle +debacles +debar +debark +debarkation +debarkations +debarked +debarking +debarks +debarment +debarments +debarred +debarring +debars +debase +debased +debasement +debasements +debaser +debasers +debases +debasing +debatable +debatably +debate +debated +debatement +debater +debaters +debates +debating +debauch +debauched +debauchedly +debauchee +debauchees +debaucher +debaucheries +debauchers +debauchery +debauches +debauching +debenture +debentures +debilitate +debilitated +debilitates +debilitating +debilitation +debilitations +debilitative +debilities +debility +debit +debited +debiting +debits +debonair +debonairly +debonairness +debone +deboned +deboner +deboners +debones +deboning +deborah +debouch +debouched +debouches +debouching +debouchment +debouchments +debouchure +debouchures +debra +debrief +debriefed +debriefing +debriefings +debriefs +debris +debt +debtless +debtor +debtors +debts +debug +debugged +debugger +debuggers +debugging +debugs +debunk +debunked +debunker +debunkers +debunking +debunks +debussy +debut +debutant +debutante +debutantes +debutants +debuted +debuting +debuts +decaampere +decaamperes +decabecquerel +decabecquerels +decacandela +decacandelas +decacoulomb +decacoulombs +decade +decadelong +decadence +decadencies +decadency +decadent +decadently +decadents +decades +decaf +decafarad +decafarads +decaffeinate +decaffeinated +decaffeinates +decaffeinating +decaffeination +decagon +decagonal +decagonally +decagons +decagram +decagrams +decagynous +decahedra +decahedral +decahedron +decahedrons +decahenries +decahenry +decahenrys +decahertz +decajoule +decajoules +decakelvin +decakelvins +decal +decalcification +decalcified +decalcifier +decalcifiers +decalcifies +decalcify +decalcifying +decalcomania +decalescence +decalescences +decalescent +decaliter +decaliters +decalogue +decalogues +decals +decalumen +decalumens +decalux +decameron +decameter +decameters +decametric +decamole +decamoles +decamp +decamped +decamping +decampment +decamps +decandrous +decane +decanes +decanewton +decanewtons +decant +decantation +decanted +decanter +decanters +decanting +decants +decaohm +decaohms +decapascal +decapascals +decapitate +decapitated +decapitates +decapitating +decapitation +decapitations +decapitator +decapitators +decapod +decapodal +decapodan +decapodous +decapods +decapolis +decaradian +decaradians +decarbonate +decarbonated +decarbonates +decarbonating +decarbonation +decarbonization +decarbonize +decarbonized +decarbonizer +decarbonizers +decarbonizes +decarbonizing +decarboxylase +decarboxylases +decarboxylation +decarboxylations +decarburization +decarburize +decarburized +decarburizes +decarburizing +decare +decares +decasecond +decaseconds +decasiemens +decasievert +decasieverts +decasteradian +decasteradians +decastyle +decastyles +decasualization +decasyllabic +decasyllabics +decasyllable +decasyllables +decatesla +decateslas +decathlete +decathletes +decathlon +decathlons +decatur +decavolt +decavolts +decawatt +decawatts +decaweber +decawebers +decay +decayed +decayer +decayers +decaying +decays +decca +deccan +decease +deceased +deceases +deceasing +decedent +decedents +deceit +deceitful +deceitfully +deceitfulness +deceits +deceivable +deceive +deceived +deceiver +deceivers +deceives +deceiving +deceivingly +decelerate +decelerated +decelerates +decelerating +deceleration +decelerations +decelerator +decelerators +december +decembers +decembrist +decembrists +decemvir +decemviral +decemvirate +decemvirates +decemviri +decemvirs +decencies +decency +decennaries +decennary +decennia +decennial +decennially +decennials +decennium +decenniums +decent +decently +decentness +decentralization +decentralizationist +decentralizationists +decentralizations +decentralize +decentralized +decentralizes +decentralizing +deception +deceptional +deceptions +deceptive +deceptively +deceptiveness +decerebrate +decerebrated +decerebrates +decerebrating +decerebration +decertification +decertified +decertifies +decertify +decertifying +dechlorinate +dechlorinated +dechlorinates +dechlorinating +dechlorination +deciampere +deciamperes +deciare +deciares +decibecquerel +decibecquerels +decibel +decibels +decicandela +decicandelas +decicoulomb +decicoulombs +decidability +decidable +decide +decided +decidedly +decidedness +decider +deciders +decides +deciding +decidua +deciduae +decidual +deciduas +deciduate +deciduous +deciduously +deciduousness +decifarad +decifarads +decigram +decigrams +decihenries +decihenry +decihenrys +decihertz +decijoule +decijoules +decikelvin +decikelvins +decile +deciles +deciliter +deciliters +decillion +decillions +decillionth +decillionths +decilumen +decilumens +decilux +decimal +decimalization +decimalize +decimalized +decimalizes +decimalizing +decimally +decimals +decimate +decimated +decimates +decimating +decimation +decimations +decimator +decimators +decimeter +decimeters +decimole +decimoles +decinewton +decinewtons +deciohm +deciohms +decipascal +decipascals +decipher +decipherability +decipherable +deciphered +decipherer +decipherers +deciphering +decipherment +deciphers +deciradian +deciradians +decisecond +deciseconds +decisiemens +decisievert +decisieverts +decision +decisional +decisioned +decisioning +decisions +decisive +decisively +decisiveness +decisteradian +decisteradians +decitesla +deciteslas +decivolt +decivolts +deciwatt +deciwatts +deciweber +deciwebers +deck +decked +decker +deckers +deckhand +deckhands +deckhouse +deckhouses +decking +deckle +deckled +deckles +deckling +decks +declaim +declaimed +declaimer +declaimers +declaiming +declaims +declamation +declamations +declamatory +declarable +declarant +declarants +declaration +declarations +declarative +declaratively +declaratives +declaratory +declare +declared +declarer +declarers +declares +declaring +declass +declassed +declasses +declassifiable +declassification +declassifications +declassified +declassifies +declassify +declassifying +declassing +declaw +declawed +declawing +declaws +declension +declensional +declensions +declinable +declination +declinational +declinations +decline +declined +decliner +decliners +declines +declining +declivities +declivitous +declivity +deco +decoct +decocted +decocting +decoction +decoctions +decocts +decode +decoded +decoder +decoders +decodes +decoding +decodings +decollate +decollated +decollates +decollating +decollation +decollations +decollator +decollators +decollectivization +decollectivize +decollectivized +decollectivizes +decollectivizing +decolonization +decolonize +decolonized +decolonizes +decolonizing +decolorant +decolorants +decolorization +decolorize +decolorized +decolorizer +decolorizers +decolorizes +decolorizing +decommission +decommissioned +decommissioning +decommissions +decompensate +decompensated +decompensates +decompensating +decompensation +decompile +decompiled +decompiler +decompilers +decompiles +decompiling +decomposability +decomposable +decompose +decomposed +decomposer +decomposers +decomposes +decomposing +decomposition +decompositional +decompositions +decompound +decompounded +decompounding +decompounds +decompress +decompressed +decompresses +decompressing +decompression +decompressions +deconcentrate +deconcentrated +deconcentrates +deconcentrating +deconcentration +decondition +deconditioned +deconditioning +deconditions +decongest +decongestant +decongestants +decongested +decongesting +decongestion +decongestive +decongests +deconsecrate +deconsecrated +deconsecrates +deconsecrating +deconsecration +deconsecrations +deconstruct +deconstructed +deconstructing +deconstruction +deconstructionism +deconstructionist +deconstructionists +deconstructs +decontaminant +decontaminate +decontaminated +decontaminates +decontaminating +decontamination +decontaminations +decontaminator +decontaminators +decontextualize +decontextualized +decontextualizes +decontextualizing +decontrol +decontrolled +decontrolling +decontrols +decor +decorate +decorated +decorates +decorating +decoration +decorations +decorative +decoratively +decorativeness +decorator +decorators +decorous +decorously +decorousness +decors +decorticate +decorticated +decorticates +decorticating +decortication +decorticator +decorticators +decorum +decos +decoupage +decoupages +decouple +decoupled +decoupler +decouplers +decouples +decoupling +decoy +decoyed +decoyer +decoyers +decoying +decoys +decrease +decreased +decreases +decreasing +decreasingly +decree +decreeable +decreed +decreeing +decreer +decreers +decrees +decrement +decremental +decremented +decrementing +decrements +decreolization +decreolizations +decrepit +decrepitate +decrepitated +decrepitates +decrepitating +decrepitation +decrepitly +decrepitude +decrescendo +decrescendos +decrescent +decretal +decretals +decretive +decretory +decried +decrier +decriers +decries +decriminalization +decriminalize +decriminalized +decriminalizes +decriminalizing +decry +decrying +decrypt +decrypted +decrypting +decryption +decrypts +decumbence +decumbency +decumbent +decuple +decurrent +decurrently +decussate +decussated +decussately +decussates +decussating +decussation +decussations +dedans +dedicate +dedicated +dedicatedly +dedicatee +dedicatees +dedicates +dedicating +dedication +dedications +dedicative +dedicator +dedicators +dedicatory +dedifferentiate +dedifferentiated +dedifferentiates +dedifferentiating +dedifferentiation +deduce +deduced +deduces +deducible +deducing +deduct +deducted +deductibility +deductible +deductibles +deducting +deduction +deductions +deductive +deductively +deducts +deed +deeded +deeding +deedless +deeds +deejay +deejays +deem +deemed +deeming +deems +deep +deepen +deepened +deepening +deepens +deeper +deepest +deepfreeze +deeply +deepness +deeps +deepwater +deer +deerflies +deerfly +deerhound +deerhounds +deerskin +deerskins +deerstalker +deerstalkers +deeryard +deeryards +deescalate +deescalated +deescalates +deescalating +deet +deets +deface +defaceable +defaced +defacement +defacements +defacer +defacers +defaces +defacing +defalcate +defalcated +defalcates +defalcating +defalcation +defalcations +defalcator +defalcators +defamation +defamatory +defame +defamed +defamer +defamers +defames +defaming +defang +defanged +defanging +defangs +defat +defats +defatted +defatting +default +defaulted +defaulter +defaulters +defaulting +defaults +defeasance +defeasances +defeasibility +defeasible +defeasibleness +defeat +defeated +defeater +defeaters +defeating +defeatism +defeatist +defeatists +defeats +defecate +defecated +defecates +defecating +defecation +defecations +defecator +defecators +defect +defected +defecting +defection +defections +defective +defectively +defectiveness +defectives +defector +defectors +defects +defeminize +defeminized +defeminizes +defeminizing +defend +defendable +defendant +defendants +defended +defender +defenders +defending +defends +defenestrate +defenestrated +defenestrates +defenestrating +defenestration +defenestrations +defense +defensed +defenseless +defenselessly +defenselessness +defenseman +defensemen +defenses +defensibility +defensible +defensibleness +defensibly +defensing +defensive +defensively +defensiveness +defensives +defer +deference +deferens +deferent +deferentia +deferential +deferentially +deferment +deferments +deferrable +deferral +deferrals +deferred +deferrer +deferrers +deferring +defers +defervesce +defervesced +defervescence +defervescences +defervescent +defervesces +defervescing +defiance +defiant +defiantly +defibrillate +defibrillated +defibrillates +defibrillating +defibrillation +defibrillative +defibrillator +defibrillators +defibrillatory +deficiencies +deficiency +deficient +deficiently +deficit +deficits +defied +defier +defiers +defies +defilade +defiladed +defilades +defilading +defile +defiled +defilement +defiler +defilers +defiles +defiling +defilingly +definability +definable +definably +define +defined +definement +definer +definers +defines +definienda +definiendum +definiens +definientia +defining +definite +definitely +definiteness +definition +definitional +definitions +definitive +definitively +definitiveness +definitives +definitude +definitudes +deflagrate +deflagrated +deflagrates +deflagrating +deflagration +deflate +deflated +deflates +deflating +deflation +deflationary +deflationist +deflationists +deflations +deflator +deflators +deflect +deflectable +deflected +deflecting +deflection +deflections +deflective +deflector +deflectors +deflects +deflexed +deflexion +deflexions +defloration +deflorations +deflower +deflowered +deflowerer +deflowerers +deflowering +deflowers +defoam +defoamed +defoaming +defoams +defocus +defocused +defocuses +defocusing +defocussed +defocusses +defocussing +defoe +defog +defogged +defogger +defoggers +defogging +defogs +defoliant +defoliants +defoliate +defoliated +defoliates +defoliating +defoliation +defoliator +defoliators +deforce +deforced +deforcement +deforces +deforcing +deforest +deforestation +deforested +deforester +deforesters +deforesting +deforests +deform +deformability +deformable +deformation +deformational +deformations +deformed +deforming +deformities +deformity +deforms +defraud +defraudation +defrauded +defrauder +defrauders +defrauding +defrauds +defray +defrayable +defrayal +defrayals +defrayed +defraying +defrays +defrock +defrocked +defrocking +defrocks +defrost +defrosted +defroster +defrosters +defrosting +defrosts +deft +defter +deftest +deftly +deftness +defuel +defueled +defueling +defuels +defunct +defunctive +defunctness +defund +defunded +defunding +defunds +defuse +defused +defuses +defusing +defy +defying +degas +degassed +degasses +degassing +degauss +degaussed +degausser +degaussers +degausses +degaussing +degeneracies +degeneracy +degenerate +degenerated +degenerately +degenerateness +degenerates +degenerating +degeneration +degenerations +degenerative +deglamorize +deglamorized +deglamorizes +deglamorizing +deglaze +deglazed +deglazes +deglazing +deglutinate +deglutinated +deglutinates +deglutinating +deglutination +deglutition +deglutitory +deglycerolize +deglycerolized +deglycerolizes +deglycerolizing +degradability +degradable +degradation +degradations +degrade +degraded +degradedly +degradedness +degrader +degraders +degrades +degrading +degradingly +degranulation +degrease +degreased +degreaser +degreasers +degreases +degreasing +degree +degreed +degrees +degression +degressions +degressive +degressively +degum +degumming +degust +degustation +degusted +degusting +degusts +dehire +dehired +dehires +dehiring +dehisce +dehisced +dehiscence +dehiscent +dehisces +dehiscing +dehorn +dehorned +dehorning +dehorns +dehumanization +dehumanize +dehumanized +dehumanizes +dehumanizing +dehumidification +dehumidifications +dehumidified +dehumidifier +dehumidifiers +dehumidifies +dehumidify +dehumidifying +dehydratase +dehydratases +dehydrate +dehydrated +dehydrates +dehydrating +dehydration +dehydrator +dehydrators +dehydrochlorinase +dehydrochlorinases +dehydrochlorinate +dehydrochlorinated +dehydrochlorinates +dehydrochlorinating +dehydrochlorination +dehydrogenase +dehydrogenases +dehydrogenate +dehydrogenated +dehydrogenates +dehydrogenating +dehydrogenation +dehydrogenization +dehydrogenize +dehydrogenized +dehydrogenizes +dehydrogenizing +dehypnotize +dehypnotized +dehypnotizes +dehypnotizing +dei +deice +deiced +deicer +deicers +deices +deicide +deicides +deicing +deictic +deictically +deific +deification +deified +deifier +deifiers +deifies +deify +deifying +deign +deigned +deigning +deigns +deimos +deindustrialization +deindustrialize +deindustrialized +deindustrializes +deindustrializing +deinstitutionalization +deinstitutionalize +deinstitutionalized +deinstitutionalizes +deinstitutionalizing +deionization +deionize +deionized +deionizer +deionizers +deionizes +deionizing +deipnosophist +deipnosophists +deirdre +deism +deist +deistic +deistical +deistically +deists +deities +deity +deject +dejected +dejectedly +dejectedness +dejecting +dejection +dejects +dekagram +dekagrams +dekaliter +dekaliters +dekameter +dekameters +deke +deked +dekes +deking +dekker +del +delacroix +delaminate +delaminated +delaminates +delaminating +delamination +delaminations +delate +delated +delates +delating +delation +delations +delator +delators +delaware +delawarean +delawares +delay +delayed +delayer +delayers +delaying +delays +dele +delectability +delectable +delectableness +delectables +delectably +delectation +delectations +deled +delegable +delegacies +delegacy +delegalization +delegalize +delegalized +delegalizes +delegalizing +delegate +delegated +delegates +delegating +delegation +delegations +delegator +delegators +delegitimization +delegitimize +delegitimized +delegitimizes +delegitimizing +deleing +deles +delete +deleted +deleterious +deleteriously +deleteriousness +deletes +deleting +deletion +deletions +delft +delfts +delftware +delhi +deli +deliberant +deliberate +deliberated +deliberately +deliberateness +deliberates +deliberating +deliberation +deliberations +deliberative +deliberatively +deliberativeness +deliberator +deliberators +delicacies +delicacy +delicate +delicately +delicateness +delicates +delicatessen +delicatessens +delicious +deliciously +deliciousness +delict +delicti +delicto +delicts +delight +delighted +delightedly +delightedness +delighter +delighters +delightful +delightfully +delightfulness +delighting +delights +delightsome +delightsomely +delightsomeness +delilah +delimit +delimitate +delimitated +delimitates +delimitating +delimitation +delimitative +delimited +delimiter +delimiters +delimiting +delimits +delineate +delineated +delineates +delineating +delineation +delineations +delineative +delineator +delineators +delinquencies +delinquency +delinquent +delinquently +delinquents +deliquesce +deliquesced +deliquescence +deliquescent +deliquesces +deliquescing +deliria +deliriant +delirious +deliriously +deliriousness +delirium +deliriums +delis +delist +delisted +delisting +delists +deliver +deliverability +deliverable +deliverables +deliverance +delivered +deliverer +deliverers +deliveries +delivering +delivers +delivery +deliveryman +deliverymen +dell +dell'arte +dells +delmonico +delocalization +delocalize +delocalized +delocalizes +delocalizing +delouse +deloused +delouses +delousing +delphi +delphian +delphic +delphically +delphinium +delphiniums +delphinus +delta +deltaic +deltas +deltic +deltiology +deltoid +deltoids +delude +deluded +deluder +deluders +deludes +deluding +deludingly +deluge +deluged +deluges +deluging +delusion +delusional +delusionary +delusions +delusive +delusively +delusiveness +delusory +deluster +deluxe +delve +delved +delver +delvers +delves +delving +demagnetization +demagnetize +demagnetized +demagnetizer +demagnetizers +demagnetizes +demagnetizing +demagnification +demagog +demagogic +demagogically +demagogism +demagogs +demagogue +demagoguery +demagogues +demagogy +demand +demandable +demanded +demander +demanders +demanding +demandingly +demands +demantoid +demantoids +demarcate +demarcated +demarcates +demarcating +demarcation +demarcations +demarcator +demarcators +demark +dematerialization +dematerialize +dematerialized +dematerializes +dematerializing +deme +demean +demeaned +demeaning +demeaningly +demeanor +demeanors +demeans +dement +demented +dementedly +dementedness +dementia +demential +dementing +dements +demerit +demeritorious +demeritoriously +demerits +demerol +demersal +demes +demesne +demesnes +demeter +demeton +demetons +demies +demigod +demigoddess +demigoddesses +demigods +demijohn +demijohns +demilitarization +demilitarize +demilitarized +demilitarizes +demilitarizing +demimondaine +demimondaines +demimonde +demimondes +demineralization +demineralize +demineralized +demineralizer +demineralizers +demineralizes +demineralizing +demirelief +demireliefs +demirep +demireps +demisable +demise +demised +demisemiquaver +demisemiquavers +demises +demising +demission +demissions +demit +demitasse +demitasses +demits +demitted +demitting +demiurge +demiurgeous +demiurges +demiurgic +demiurgical +demiurgically +demiworld +demiworlds +demo +demob +demobbed +demobbing +demobilization +demobilize +demobilized +demobilizes +demobilizing +demobs +democracies +democracy +democrat +democratic +democratically +democratization +democratize +democratized +democratizer +democratizes +democratizing +democrats +democritus +demodulate +demodulated +demodulates +demodulating +demodulation +demodulations +demodulator +demodulators +demoed +demogorgon +demographer +demographers +demographic +demographical +demographically +demographics +demography +demoing +demoiselle +demoiselles +demolish +demolished +demolisher +demolishers +demolishes +demolishing +demolishment +demolition +demolitionist +demolitionists +demolitions +demon +demonetization +demonetizations +demonetize +demonetized +demonetizes +demonetizing +demoniac +demoniacal +demoniacally +demonian +demonic +demonical +demonically +demonism +demonization +demonize +demonized +demonizes +demonizing +demonolatry +demonologic +demonological +demonologist +demonologists +demonology +demons +demonstrability +demonstrable +demonstrableness +demonstrably +demonstrandum +demonstrate +demonstrated +demonstrates +demonstrating +demonstration +demonstrational +demonstrations +demonstrative +demonstratively +demonstrativeness +demonstratives +demonstrator +demonstrators +demoralization +demoralize +demoralized +demoralizer +demoralizers +demoralizes +demoralizing +demoralizingly +demos +demosthenes +demote +demoted +demotes +demotic +demoting +demotion +demotions +demount +demountable +demounted +demounting +demounts +demulcent +demulcents +demur +demure +demurely +demureness +demurer +demurest +demurrable +demurrage +demurrages +demurral +demurrals +demurred +demurrer +demurrers +demurring +demurs +demy +demyelinate +demyelinated +demyelinates +demyelinating +demyelination +demystification +demystified +demystifier +demystifiers +demystifies +demystify +demystifying +demythologization +demythologize +demythologized +demythologizer +demythologizers +demythologizes +demythologizing +den +denarii +denarius +denary +denationalization +denationalize +denationalized +denationalizes +denationalizing +denaturalization +denaturalize +denaturalized +denaturalizes +denaturalizing +denaturant +denaturants +denaturation +denature +denatured +denatures +denaturing +dendriform +dendrimers +dendrite +dendrites +dendritic +dendritically +dendrobium +dendrobiums +dendrochronological +dendrochronologically +dendrochronologist +dendrochronologists +dendrochronology +dendroid +dendrologic +dendrological +dendrologist +dendrologists +dendrology +dendron +dendrons +dene +deneb +denebola +denegation +denegations +denervate +denervated +denervates +denervating +denervation +denes +dengue +deniability +deniable +deniably +denial +denials +denied +denier +deniers +denies +denigrate +denigrated +denigrates +denigrating +denigration +denigrations +denigrative +denigrator +denigrators +denigratory +denim +denims +denise +denitrification +denitrified +denitrifies +denitrify +denitrifying +denizen +denizenation +denizened +denizening +denizens +denmark +denned +denning +denominable +denominate +denominated +denominates +denominating +denomination +denominational +denominationalism +denominationalist +denominationalists +denominationally +denominations +denominative +denominatives +denominator +denominators +denormalize +denormalized +denotable +denotation +denotational +denotationally +denotations +denotative +denotatively +denote +denoted +denotement +denotes +denoting +denotive +denouement +denouements +denounce +denounced +denouncement +denouncements +denouncer +denouncers +denounces +denouncing +dens +dense +densely +denseness +denser +densest +densification +densify +densimeter +densimeters +densimetric +densities +densitometer +densitometers +densitometric +densitometry +density +dent +dental +dentalia +dentalium +dentaliums +dentally +dentals +dentate +dentately +dentation +dentations +dente +dented +denticle +denticles +denticular +denticulate +denticulated +denticulately +denticulation +dentiform +dentifrice +dentigerous +dentil +dentils +dentin +dentinal +dentine +denting +dentins +dentist +dentistry +dentists +dentition +dentoid +dents +dentulous +denture +dentures +denturist +denturists +denuclearization +denuclearize +denuclearized +denuclearizes +denuclearizing +denudate +denudated +denudates +denudating +denudation +denudations +denude +denuded +denudement +denudes +denuding +denumerability +denumerable +denumerably +denunciate +denunciated +denunciates +denunciating +denunciation +denunciations +denunciative +denunciator +denunciators +denunciatory +denver +deny +denying +denyingly +deo +deodar +deodara +deodaras +deodars +deodorant +deodorants +deodorization +deodorizations +deodorize +deodorized +deodorizer +deodorizers +deodorizes +deodorizing +deontological +deontologist +deontologists +deontology +deorbit +deorbited +deorbiting +deorbits +deoxidation +deoxidization +deoxidize +deoxidized +deoxidizer +deoxidizers +deoxidizes +deoxidizing +deoxycorticosterone +deoxycorticosterones +deoxygenate +deoxygenated +deoxygenates +deoxygenating +deoxygenation +deoxyribonuclease +deoxyribonucleases +deoxyribonucleic +deoxyribonucleotide +deoxyribonucleotides +deoxyribose +deoxyriboses +depart +departed +departeds +departing +department +departmental +departmentalization +departmentalize +departmentalized +departmentalizes +departmentalizing +departmentally +departments +departs +departure +departures +depauperate +depauperation +depend +dependability +dependable +dependableness +dependably +depended +dependence +dependences +dependencies +dependency +dependent +dependently +dependents +depending +depends +depersonalization +depersonalize +depersonalized +depersonalizes +depersonalizing +depict +depicted +depicter +depicting +depiction +depictions +depicts +depigmentation +depigmentations +depilate +depilated +depilates +depilating +depilation +depilator +depilatories +depilators +depilatory +deplane +deplaned +deplanes +deplaning +depletable +deplete +depleted +depletes +depleting +depletion +depletions +depletive +deplorability +deplorable +deplorableness +deplorably +deplore +deplored +deplorer +deplorers +deplores +deploring +deploringly +deploy +deployability +deployable +deployed +deployer +deployers +deploying +deployment +deployments +deploys +deplumation +deplume +deplumed +deplumes +depluming +depolarization +depolarize +depolarized +depolarizer +depolarizers +depolarizes +depolarizing +depoliticization +depoliticize +depoliticized +depoliticizes +depoliticizing +depollute +depolluted +depollutes +depolluting +depone +deponed +deponent +deponents +depones +deponing +depopulate +depopulated +depopulates +depopulating +depopulation +depopulations +depopulator +depopulators +deport +deportable +deportation +deportations +deported +deportee +deportees +deporting +deportment +deports +deposable +deposal +deposals +depose +deposed +deposes +deposing +deposit +depositaries +depositary +deposited +depositing +deposition +depositional +depositions +depositor +depositories +depositors +depository +deposits +depot +depots +depravation +depravations +deprave +depraved +depravedly +depravedness +depravement +depraver +depravers +depraves +depraving +depravities +depravity +deprecate +deprecated +deprecates +deprecating +deprecatingly +deprecation +deprecations +deprecative +deprecator +deprecatorily +deprecators +deprecatory +depreciable +depreciate +depreciated +depreciates +depreciating +depreciatingly +depreciation +depreciations +depreciative +depreciator +depreciators +depreciatory +depredate +depredated +depredates +depredating +depredation +depredations +depredator +depredators +depredatory +depress +depressant +depressants +depressed +depresses +depressible +depressing +depressingly +depression +depressions +depressive +depressively +depressiveness +depressives +depressor +depressors +depressurization +depressurize +depressurized +depressurizes +depressurizing +deprivable +deprival +deprivation +deprivations +deprive +deprived +deprives +depriving +deprogram +deprogrammed +deprogrammer +deprogrammers +deprogramming +deprograms +depth +depthless +depths +depurate +depurated +depurates +depurating +depuration +depurations +depurative +depurator +depurators +deputation +deputations +depute +deputed +deputes +deputies +deputing +deputization +deputize +deputized +deputizes +deputizing +deputy +dequeue +dequeued +dequeueing +dequeues +dequeuing +der +deracinate +deracinated +deracinates +deracinating +deracination +derail +derailed +derailing +derailleur +derailleurs +derailment +derailments +derails +derange +deranged +derangement +derangements +deranges +deranging +derate +derated +derates +derating +derbies +derby +derbyshire +derecognition +derecognize +derecognized +derecognizes +derecognizing +dereference +dereferenced +dereferencer +dereferencers +dereferences +dereferencing +deregulate +deregulated +deregulates +deregulating +deregulation +deregulations +deregulator +deregulators +deregulatory +derelict +dereliction +derelicts +derepress +derepressed +derepresses +derepressing +derepression +derib +deribbed +deribbing +deribs +deride +derided +derider +deriders +derides +deriding +deridingly +derision +derisive +derisively +derisiveness +derisory +derivability +derivable +derivate +derivation +derivational +derivationally +derivations +derivative +derivatively +derivativeness +derivatives +derive +derived +deriver +derivers +derives +deriving +derma +dermabrasion +dermabrasions +dermal +dermapteran +dermapterans +dermas +dermatitis +dermatogen +dermatogens +dermatoid +dermatologic +dermatological +dermatologist +dermatologists +dermatology +dermatome +dermatomes +dermatophyte +dermatophytes +dermatophytic +dermatophytosis +dermatoplasty +dermatoses +dermatosis +dermis +dermises +derogate +derogated +derogates +derogating +derogation +derogations +derogative +derogatively +derogator +derogatorily +derogatoriness +derogators +derogatory +derrick +derricks +derriere +derrieres +derring +derringer +derringers +derris +derrière +derrières +dervish +dervishes +desacralize +desacralized +desacralizes +desacralizing +desalinate +desalinated +desalinates +desalinating +desalination +desalinator +desalinators +desalinization +desalinize +desalinized +desalinizes +desalinizing +desalt +desalted +desalting +desalts +descant +descanted +descanter +descanters +descanting +descants +descartes +descend +descendant +descendants +descended +descendent +descendents +descender +descenders +descendible +descending +descends +descent +descents +deschutes +descramble +descrambled +descrambler +descramblers +descrambles +descrambling +describable +describe +described +describer +describers +describes +describing +descried +descrier +descriers +descries +description +descriptions +descriptive +descriptively +descriptiveness +descriptor +descriptors +descry +descrying +desdemona +desecrate +desecrated +desecrater +desecraters +desecrates +desecrating +desecration +desecrations +desecrator +desecrators +desegregate +desegregated +desegregates +desegregating +desegregation +desegregationist +desegregationists +deselect +deselected +deselecting +deselects +desensitization +desensitize +desensitized +desensitizer +desensitizers +desensitizes +desensitizing +desert +deserted +deserter +deserters +desertic +desertification +deserting +desertion +desertions +deserts +deserve +deserved +deservedly +deservedness +deserver +deservers +deserves +deserving +deservingly +desex +desexed +desexes +desexing +desexualization +desexualize +desexualized +desexualizes +desexualizing +desiccant +desiccants +desiccate +desiccated +desiccates +desiccating +desiccation +desiccations +desiccative +desiccator +desiccators +desiderata +desiderate +desiderated +desiderates +desiderating +desideration +desiderative +desideratum +design +designable +designate +designated +designates +designating +designation +designations +designative +designator +designators +designatory +designed +designedly +designee +designees +designer +designers +designing +designingly +designs +desipramine +desipramines +desirability +desirable +desirableness +desirables +desirably +desire +desired +desirer +desirers +desires +desiring +desirous +desirously +desirousness +desist +desistance +desisted +desisting +desists +desk +deskill +deskilled +deskilling +deskills +deskman +deskmen +desks +desktop +desktops +desman +desmans +desmid +desmids +desolate +desolated +desolately +desolateness +desolater +desolaters +desolates +desolating +desolatingly +desolation +desolator +desolators +desorb +desorbed +desorbing +desorbs +desorption +despair +despaired +despairer +despairers +despairing +despairingly +despairs +despatch +despatched +despatches +despatching +desperado +desperadoes +desperados +desperate +desperately +desperateness +desperation +despicable +despicableness +despicably +despisal +despise +despised +despisement +despisements +despiser +despisers +despises +despising +despite +despiteful +despitefully +despitefulness +despoil +despoiled +despoiler +despoilers +despoiling +despoilment +despoilments +despoils +despoliation +despond +desponded +despondence +despondency +despondent +despondently +desponding +despondingly +desponds +despot +despotic +despotically +despotism +despots +desquamate +desquamated +desquamates +desquamating +desquamation +dessert +desserts +dessertspoon +dessertspoonful +dessertspoonfuls +dessertspoons +destabilization +destabilize +destabilized +destabilizes +destabilizing +destain +destained +destaining +destains +destalinization +destalinizations +desterilize +desterilized +desterilizes +desterilizing +destination +destinations +destine +destined +destines +destinies +destining +destiny +destitute +destituteness +destitution +destroy +destroyed +destroyer +destroyers +destroying +destroys +destruct +destructed +destructibility +destructible +destructibleness +destructing +destruction +destructionist +destructionists +destructions +destructive +destructively +destructiveness +destructivity +destructor +destructors +destructs +desuetude +desulfurization +desulfurize +desulfurized +desulfurizes +desulfurizing +desultorily +desultoriness +desultory +desynchronize +desynchronized +desynchronizes +desynchronizing +detach +detachability +detachable +detachably +detached +detachedly +detachedness +detaches +detaching +detachment +detachments +detail +detailed +detailedly +detailedness +detailer +detailers +detailing +details +detain +detained +detainee +detainees +detainer +detainers +detaining +detainment +detains +detect +detectability +detectable +detected +detecter +detecters +detecting +detection +detections +detective +detectives +detector +detectors +detects +detent +detente +detentes +detention +detentions +detents +deter +deterge +deterged +detergence +detergences +detergency +detergent +detergents +deterges +deterging +deteriorate +deteriorated +deteriorates +deteriorating +deterioration +deteriorations +deteriorative +determent +determents +determinability +determinable +determinableness +determinably +determinacy +determinant +determinantal +determinants +determinate +determinately +determinateness +determinater +determinaters +determination +determinations +determinative +determinatively +determinativeness +determinatives +determine +determined +determinedly +determinedness +determiner +determiners +determines +determining +determinism +determinist +deterministic +deterministically +determinists +deterrable +deterred +deterrence +deterrent +deterrently +deterrents +deterrer +deterrers +deterring +deters +detersive +detersives +detest +detestability +detestable +detestableness +detestably +detestation +detested +detester +detesters +detesting +detests +dethatch +dethatched +dethatcher +dethatchers +dethatches +dethatching +dethrone +dethroned +dethronement +dethrones +dethroning +detinue +detinues +detonabilities +detonability +detonable +detonatable +detonate +detonated +detonates +detonating +detonation +detonations +detonative +detonator +detonators +detour +detoured +detouring +detours +detox +detoxed +detoxes +detoxicant +detoxicants +detoxicate +detoxicated +detoxicates +detoxicating +detoxication +detoxification +detoxified +detoxifies +detoxify +detoxifying +detoxing +detract +detracted +detracting +detractingly +detraction +detractions +detractive +detractively +detractor +detractors +detracts +detrain +detrained +detraining +detrainment +detrains +detribalization +detribalize +detribalized +detribalizes +detribalizing +detriment +detrimental +detrimentally +detriments +detrital +detrition +detritions +detritus +detroit +detumescence +detumescences +detumescent +deucalion +deuce +deuced +deucedly +deuces +deucing +deum +deums +deus +deuteragonist +deuteragonists +deuteranope +deuteranopia +deuteranopias +deuteranopic +deuterate +deuterated +deuterates +deuterating +deuteration +deuterations +deuterium +deuterocanonical +deuterogamy +deuteron +deuteronomic +deuteronomy +deuterons +deutoplasm +deutoplasmic +deutoplasms +deutsch +deutsche +deutschmark +deutschmarks +deutzia +deutzias +deux +devaluate +devaluated +devaluates +devaluating +devaluation +devaluations +devalue +devalued +devalues +devaluing +devanagari +devastate +devastated +devastates +devastating +devastatingly +devastation +devastations +devastative +devastator +devastators +develop +developable +developed +developer +developers +developing +development +developmental +developmentally +developments +develops +deverbative +deverbatives +devereux +devest +devested +devesting +devests +devi +deviance +deviances +deviancies +deviancy +deviant +deviants +deviate +deviated +deviates +deviating +deviation +deviational +deviationism +deviationist +deviationists +deviations +deviator +deviators +deviatory +device +devices +devil +deviled +devilfish +devilfishes +deviling +devilish +devilishly +devilishness +devilkin +devilkins +devilled +devilling +devilment +devilments +devilries +devilry +devils +deviltries +deviltry +devilwood +devilwoods +devious +deviously +deviousness +devisable +devise +devised +devisee +devisees +deviser +devisers +devises +devising +devisor +devisors +devitalization +devitalize +devitalized +devitalizes +devitalizing +devitrifiable +devitrification +devitrified +devitrifies +devitrify +devitrifying +devocalization +devocalize +devocalized +devocalizes +devocalizing +devoice +devoiced +devoices +devoicing +devoid +devoir +devoirs +devolatilization +devolatilize +devolatilized +devolatilizes +devolatilizing +devolution +devolutionary +devolutionist +devolutionists +devolve +devolved +devolvement +devolves +devolving +devon +devonian +devote +devoted +devotedly +devotedness +devotee +devotees +devotement +devotes +devoting +devotion +devotional +devotionally +devotionals +devotions +devour +devoured +devourer +devourers +devouring +devouringly +devours +devout +devouter +devoutest +devoutly +devoutness +dew +dewali +dewan +dewans +dewater +dewatered +dewatering +dewaters +dewberries +dewberry +dewclaw +dewclawed +dewdrop +dewdrops +dewed +dewfall +dewier +dewiest +dewily +dewiness +dewing +dewlap +dewlaps +dewless +deworm +dewormed +dewormer +dewormers +deworming +deworms +dews +dewy +dex +dexamethasone +dexamethasones +dexedrine +dexes +dexie +dexies +dexter +dexterity +dexterous +dexterously +dexterousness +dextral +dextrality +dextrally +dextran +dextrans +dextrin +dextro +dextroamphetamine +dextroamphetamines +dextroglucose +dextroglucoses +dextrorotation +dextrorotations +dextrorotatory +dextrorse +dextrorsely +dextrose +dhabi +dharma +dharmic +dharna +dharnas +dhaulagiri +dhole +dholes +dhoti +dhotis +dhow +dhows +dhurrie +dhurries +di +diabase +diabases +diabetes +diabetic +diabetics +diable +diablerie +diableries +diablo +diabolic +diabolical +diabolically +diabolicalness +diabolism +diabolist +diabolists +diabolize +diabolized +diabolizes +diabolizing +diacetylmorphine +diachronic +diachronically +diachronies +diachrony +diaconal +diaconate +diaconates +diacritic +diacritical +diacritically +diacritics +diadelphous +diadem +diademed +diademing +diadems +diadromous +diads +diaeresis +diagenesis +diagenetic +diageotropic +diageotropism +diaghilev +diagnosable +diagnose +diagnoseable +diagnosed +diagnoses +diagnosing +diagnosis +diagnostic +diagnostically +diagnostician +diagnosticians +diagnostics +diagonal +diagonalizable +diagonalization +diagonalize +diagonalized +diagonalizes +diagonalizing +diagonally +diagonals +diagram +diagramed +diagraming +diagrammable +diagrammatic +diagrammatical +diagrammatically +diagrammed +diagramming +diagrams +diakineses +diakinesis +diakinetic +dial +dialect +dialectal +dialectally +dialectic +dialectical +dialectically +dialectician +dialecticians +dialectics +dialectological +dialectologically +dialectologist +dialectologists +dialectology +dialects +dialed +dialer +dialers +dialing +dialled +dialling +dialog +dialoged +dialogic +dialogical +dialogically +dialoging +dialogist +dialogistic +dialogistical +dialogistically +dialogists +dialogs +dialogue +dialogued +dialoguer +dialoguers +dialogues +dialoguing +dials +dialup +dialups +dialyses +dialysis +dialytic +dialytically +dialyzabilities +dialyzability +dialyzable +dialyze +dialyzed +dialyzer +dialyzers +dialyzes +dialyzing +diamagnet +diamagnetic +diamagnetism +diamagnets +diamante +diamantes +diamanté +diamantés +diameter +diameters +diametral +diametric +diametrical +diametrically +diamine +diamines +diamond +diamondback +diamondbacks +diamonded +diamondiferous +diamonding +diamonds +diana +diandrous +diane +dianthus +diapason +diapasons +diapause +diapauses +diapedeses +diapedesis +diapedetic +diaper +diapered +diapering +diapers +diaphaneity +diaphanous +diaphanously +diaphanousness +diaphone +diaphoreses +diaphoresis +diaphoretic +diaphoretics +diaphragm +diaphragmatic +diaphragmatically +diaphragms +diaphyseal +diaphyses +diaphysial +diaphysis +diapir +diapiric +diapirs +diapophyses +diapophysial +diapophysis +diapositive +diapsid +diapsids +diarchal +diarchic +diarchies +diarchy +diaries +diarist +diarists +diarize +diarized +diarizes +diarizing +diarrhea +diarrheal +diarrheas +diarrheic +diarrhetic +diarthrodial +diarthroses +diarthrosis +diary +diaspora +diasporas +diaspore +diaspores +diastase +diastases +diastasic +diastasis +diastatic +diastema +diastemata +diastematic +diastole +diastoles +diastolic +diastrophic +diastrophically +diastrophism +diastrophisms +diatessaron +diatessarons +diathermic +diathermy +diatheses +diathesis +diathetic +diatom +diatomaceous +diatomic +diatomite +diatoms +diatonic +diatonically +diatonicism +diatribe +diatribes +diatropic +diatropism +diatropisms +diaz +diazepam +diazine +diazines +diazinon +diazinons +diazo +diazonium +diazoniums +dibasic +dibber +dibbers +dibble +dibbled +dibbler +dibblers +dibbles +dibbling +dibden +dibranchiate +dibranchiates +dibromide +dibromides +dibs +dicarboxylic +dicast +dicastic +dicasts +dice +diced +dicentra +dicentras +dicephalous +dicer +dicers +dices +dicey +dichasia +dichasial +dichasially +dichasium +dichloride +dichlorodiphenyl +dichlorodiphenyltrichloroethane +dichlorodiphenyltrichloroethanes +dichlorvos +dichogamous +dichogamy +dichondra +dichondras +dichotic +dichotically +dichotomic +dichotomies +dichotomist +dichotomists +dichotomization +dichotomize +dichotomized +dichotomizes +dichotomizing +dichotomous +dichotomously +dichotomousness +dichotomy +dichroic +dichroism +dichroisms +dichroite +dichroites +dichromat +dichromate +dichromatic +dichromatism +dichromats +dichromic +dicier +diciest +dicing +dick +dickcissel +dickcissels +dickens +dickensian +dickensians +dicker +dickered +dickering +dickers +dickey +dickeys +dickies +dicks +dicky +diclinous +dicliny +dicofol +dicofols +dicot +dicots +dicotyledon +dicotyledonous +dicotyledons +dicrotic +dicrotism +dicta +dictaphone +dictaphones +dictate +dictated +dictates +dictating +dictation +dictations +dictator +dictatorial +dictatorially +dictatorialness +dictators +dictatorship +dictatorships +diction +dictional +dictionally +dictionaries +dictionary +dictu +dictum +dictums +dictyosome +dictyosomes +dictyostelium +did +didact +didactic +didactical +didactically +didacticism +didactics +didacts +didapper +didappers +diddle +diddled +diddler +diddlers +diddles +diddling +diddly +diddlysquat +diderot +didn +didn't +dido +didoes +didos +didst +didymium +didymous +didynamous +die +dieback +diebacks +died +dieffenbachia +dieffenbachias +diego +diehard +diehards +dieldrin +dieldrins +dielectric +dielectrically +dielectrics +diem +diemen +diencephalic +diencephalon +diencephalons +dieppe +diereses +dieresis +dies +diesel +dieselize +dieselized +dieselizes +dieselizing +diesels +dieses +diesinker +diesinkers +diesinking +diesis +diestock +diestocks +diestrous +diestrus +diet +dietaries +dietarily +dietary +dieted +dieter +dieters +dietetic +dietetically +dietetics +diethyl +diethylcarbamazine +diethylstilbestrol +dietician +dieticians +dieting +dietitian +dietitians +dietrich +diets +differ +differed +difference +differenced +differences +differencing +different +differentia +differentiability +differentiable +differentiae +differential +differentially +differentials +differentiate +differentiated +differentiates +differentiating +differentiation +differentiations +differentiator +differentiators +differently +differentness +differing +differs +difficile +difficult +difficulties +difficultly +difficulty +diffidence +diffident +diffidently +diffract +diffracted +diffracting +diffraction +diffractions +diffractive +diffractively +diffractiveness +diffractometer +diffractometers +diffracts +diffuse +diffused +diffusely +diffuseness +diffuser +diffusers +diffuses +diffusible +diffusibly +diffusing +diffusion +diffusional +diffusions +diffusive +diffusively +diffusiveness +dig +digamma +digammas +digamous +digamy +digastric +digastrics +digest +digested +digester +digesters +digestibility +digestible +digestibleness +digestibly +digesting +digestion +digestions +digestive +digestively +digestiveness +digestives +digests +digger +diggers +digging +diggings +digit +digital +digitalin +digitalins +digitalis +digitalization +digitalize +digitalized +digitalizes +digitalizing +digitally +digitals +digitate +digitately +digitation +digitations +digitigrade +digitization +digitize +digitized +digitizer +digitizers +digitizes +digitizing +digitoxin +digitoxins +digits +diglossia +diglossias +diglyceride +diglycerides +dignified +dignifiedly +dignifies +dignify +dignifying +dignitaries +dignitary +dignities +dignity +digoxin +digoxins +digraph +digraphic +digraphs +digress +digressed +digresses +digressing +digression +digressional +digressionary +digressions +digressive +digressively +digressiveness +digs +dihedral +dihedrals +dihybrid +dihybrids +dihydric +dihydroxy +dihydroxyphenylalanine +dihydroxyphenylalanines +dijkstra +dijon +dikaryon +dikaryons +dike +diked +dikes +diking +diktat +diktats +dilantin +dilapidate +dilapidated +dilapidates +dilapidating +dilapidation +dilapidations +dilatability +dilatable +dilatably +dilatancies +dilatancy +dilatant +dilatants +dilatation +dilatational +dilatations +dilatator +dilatators +dilate +dilated +dilatedness +dilates +dilating +dilation +dilations +dilative +dilatometer +dilatometers +dilatometric +dilatometry +dilator +dilatorily +dilatoriness +dilators +dilatory +dildo +dildos +dilemma +dilemmas +dilemmatic +dilettante +dilettantes +dilettantish +dilettantism +diligence +diligent +diligently +dill +dillies +dills +dilly +dillydallied +dillydallies +dillydally +dillydallying +diluent +diluents +dilute +diluted +diluteness +diluter +diluters +dilutes +diluting +dilution +dilutions +dilutive +dilutor +dilutors +diluvial +dim +dime +dimenhydrinate +dimenhydrinates +dimension +dimensional +dimensionality +dimensionally +dimensioned +dimensioning +dimensionless +dimensions +dimer +dimercaprol +dimercaprols +dimeric +dimerism +dimerization +dimerize +dimerized +dimerizes +dimerizing +dimerous +dimers +dimes +dimeter +dimeters +dimethoate +dimethoates +dimethyl +dimethylnitrosamine +dimethylnitrosamines +dimethyls +dimethylsulfoxide +dimethylsulfoxides +diminish +diminishable +diminished +diminishes +diminishing +diminishment +diminishments +diminuendo +diminuendos +diminution +diminutional +diminutive +diminutively +diminutiveness +diminutives +dimities +dimittis +dimity +dimly +dimmable +dimmed +dimmer +dimmers +dimmest +dimming +dimness +dimorph +dimorphic +dimorphism +dimorphisms +dimorphous +dimorphs +dimout +dimple +dimpled +dimples +dimpling +dimply +dims +dimwit +dimwits +dimwitted +dimwittedly +dimwittedness +din +dinar +dinard +dinars +dine +dined +diner +diners +dines +dinette +dinettes +ding +dingbat +dingbats +dingdong +dingdonged +dingdonging +dingdongs +dinged +dinghies +dinghy +dingier +dingiest +dingily +dinginess +dinging +dingle +dingles +dingo +dingoes +dings +dingus +dinguses +dingy +dining +dinitrobenzene +dinitrobenzenes +dink +dinkey +dinkeys +dinkier +dinkiest +dinks +dinkum +dinky +dinned +dinner +dinnerless +dinners +dinnertime +dinnerware +dinning +dinoflagellate +dinoflagellates +dinosaur +dinosaurian +dinosaurians +dinosauric +dinosaurlike +dinosaurs +dinothere +dinotheres +dins +dint +dinted +dinting +dints +dinucleotide +dinucleotides +diocesan +diocesans +diocese +dioceses +diocletian +diode +diodes +diodorus +dioecious +dioeciously +dioecism +diogenes +dioicous +diomede +diomedes +dione +dionysia +dionysiac +dionysian +dionysius +dionysos +dionysus +diophantine +diopside +diopsides +diopter +diopters +dioptometer +dioptometers +dioptometry +dioptral +dioptric +dioptrics +diorama +dioramas +dioramic +diorite +diorites +dioritic +dioscuri +dioxane +dioxanes +dioxide +dioxides +dioxin +dioxins +dip +dipeptidase +dipeptidases +dipeptide +dipeptides +dipetalous +diphase +diphasic +diphenyl +diphenylamine +diphenylaminechloroarsine +diphenylaminechloroarsines +diphenylamines +diphenylhydantoin +diphenylhydantoins +diphenylketone +diphenylketones +diphenyls +diphosgene +diphosgenes +diphosphate +diphosphates +diphosphoglyceric +diphtheria +diphtherial +diphtheric +diphtheritic +diphtheroid +diphtheroids +diphthong +diphthongal +diphthongization +diphthongize +diphthongized +diphthongizes +diphthongizing +diphthongs +diphycercal +diphycercy +diphyletic +diphyllous +diphyodont +diplegia +diplegias +diplex +diplexer +diplexers +diploblastic +diplococcal +diplococci +diplococcic +diplococcus +diplodocus +diplodocuses +diploe +diploes +diploic +diploid +diploids +diploidy +diploma +diplomacies +diplomacy +diplomas +diplomat +diplomate +diplomates +diplomatic +diplomatically +diplomatics +diplomatist +diplomatists +diplomats +diplont +diplontic +diplonts +diplopia +diplopias +diplopic +diplopod +diplopodous +diplopods +diplosis +dipnoan +dipnoans +dipodic +dipodies +dipody +dipolar +dipole +dipoles +dipped +dipper +dipperful +dipperfuls +dippers +dippier +dippiest +dipping +dippy +dipropellant +dipropellants +diprotic +dips +dipsomania +dipsomaniac +dipsomaniacal +dipsomaniacs +dipstick +dipsticks +dipteral +dipteran +dipterans +dipterous +diptych +diptychs +dipyridamole +dipyridamoles +diquat +diquats +dirac +dire +direct +directed +directing +direction +directional +directionality +directionally +directionals +directionless +directions +directive +directives +directivity +directly +directness +directoire +director +directorate +directorates +directorial +directorially +directories +directors +directorship +directorships +directory +directress +directresses +directrices +directrix +directrixes +directs +direful +direfully +direfulness +direly +direness +direr +direst +dirge +dirgeful +dirges +dirham +dirhams +dirichlet +dirigible +dirigibles +dirk +dirked +dirking +dirks +dirndl +dirndls +dirt +dirtied +dirtier +dirties +dirtiest +dirtily +dirtiness +dirty +dirtying +disabilities +disability +disable +disabled +disablement +disables +disabling +disablingly +disabuse +disabused +disabuses +disabusing +disaccharidase +disaccharidases +disaccharide +disaccharides +disaccord +disaccorded +disaccording +disaccords +disaccustom +disaccustomed +disaccustoming +disaccustoms +disadvantage +disadvantaged +disadvantagedness +disadvantageous +disadvantageously +disadvantageousness +disadvantages +disadvantaging +disaffect +disaffected +disaffectedly +disaffecting +disaffection +disaffects +disaffiliate +disaffiliated +disaffiliates +disaffiliating +disaffiliation +disaffiliations +disaffirm +disaffirmance +disaffirmation +disaffirmed +disaffirming +disaffirms +disaggregate +disaggregated +disaggregates +disaggregating +disaggregation +disaggregative +disagree +disagreeable +disagreeableness +disagreeably +disagreed +disagreeing +disagreement +disagreements +disagrees +disallow +disallowable +disallowance +disallowed +disallowing +disallows +disambiguate +disambiguated +disambiguates +disambiguating +disambiguation +disambiguations +disannul +disannulled +disannulling +disannulment +disannuls +disappear +disappearance +disappearances +disappeared +disappearing +disappears +disappoint +disappointed +disappointedly +disappointing +disappointingly +disappointment +disappointments +disappoints +disapprobation +disapproval +disapprove +disapproved +disapprover +disapprovers +disapproves +disapproving +disapprovingly +disarm +disarmament +disarmed +disarmer +disarmers +disarming +disarmingly +disarms +disarrange +disarranged +disarrangement +disarranges +disarranging +disarray +disarrayed +disarraying +disarrays +disarticulate +disarticulated +disarticulates +disarticulating +disarticulation +disarticulator +disarticulators +disassemble +disassembled +disassembler +disassemblers +disassembles +disassembling +disassembly +disassociate +disassociated +disassociates +disassociating +disassociation +disaster +disasters +disastrous +disastrously +disastrousness +disavow +disavowable +disavowal +disavowals +disavowed +disavowing +disavows +disband +disbanded +disbanding +disbandment +disbandments +disbands +disbar +disbarment +disbarred +disbarring +disbars +disbelief +disbelieve +disbelieved +disbeliever +disbelievers +disbelieves +disbelieving +disbelievingly +disbranch +disbranched +disbranches +disbranching +disbud +disbudded +disbudding +disbuds +disburden +disburdened +disburdening +disburdenment +disburdens +disbursable +disbursal +disbursals +disburse +disbursed +disbursement +disbursements +disburser +disbursers +disburses +disbursing +disc +discalced +discard +discardable +discarded +discarder +discarders +discarding +discards +discarnate +discern +discerned +discerner +discerners +discernible +discernibly +discerning +discerningly +discernment +discerns +discharge +dischargeable +discharged +dischargee +dischargees +discharger +dischargers +discharges +discharging +disci +disciform +disciple +disciples +discipleship +disciplinable +disciplinal +disciplinarian +disciplinarians +disciplinarily +disciplinarity +disciplinary +discipline +disciplined +discipliner +discipliners +disciplines +disciplining +disclaim +disclaimed +disclaimer +disclaimers +disclaiming +disclaims +disclamation +disclamations +disclimax +disclimaxes +disclosable +disclose +disclosed +discloser +disclosers +discloses +disclosing +disclosure +disclosures +disco +discoed +discographer +discographers +discographic +discographical +discographies +discography +discoid +discoidal +discoideum +discoing +discolor +discoloration +discolored +discoloring +discolors +discombobulate +discombobulated +discombobulates +discombobulating +discombobulation +discomfit +discomfited +discomfiting +discomfits +discomfiture +discomfort +discomfortable +discomforted +discomforting +discomfortingly +discomforts +discommend +discommendable +discommended +discommending +discommends +discommode +discommoded +discommodes +discommoding +discompose +discomposed +discomposedly +discomposes +discomposing +discomposingly +discomposure +disconcert +disconcerted +disconcerting +disconcertingly +disconcertment +disconcerts +disconfirm +disconfirmatory +disconfirmed +disconfirming +disconfirms +disconformities +disconformity +disconnect +disconnected +disconnectedly +disconnectedness +disconnecting +disconnection +disconnects +disconsolate +disconsolately +disconsolateness +disconsolation +discontent +discontented +discontentedly +discontentedness +discontenting +discontentment +discontents +discontinuance +discontinuation +discontinuations +discontinue +discontinued +discontinues +discontinuing +discontinuities +discontinuity +discontinuous +discontinuously +discontinuousness +discophile +discophiles +discord +discordance +discordancy +discordant +discordantly +discorded +discording +discords +discorporate +discos +discotheque +discotheques +discothèque +discothèques +discount +discountable +discounted +discountenance +discountenanced +discountenances +discountenancing +discounter +discounters +discounting +discounts +discourage +discourageable +discouraged +discouragement +discouragements +discourager +discouragers +discourages +discouraging +discouragingly +discourse +discoursed +discourser +discoursers +discourses +discoursing +discourteous +discourteously +discourteousness +discourtesies +discourtesy +discover +discoverability +discoverable +discovered +discoverer +discoverers +discoveries +discovering +discovers +discovery +discredit +discreditable +discreditably +discredited +discrediting +discredits +discreet +discreetly +discreetness +discrepance +discrepances +discrepancies +discrepancy +discrepant +discrepantly +discrete +discretely +discreteness +discretion +discretional +discretionally +discretionarily +discretionary +discretization +discretize +discretized +discretizes +discretizing +discriminability +discriminable +discriminably +discriminant +discriminants +discriminate +discriminated +discriminately +discriminates +discriminating +discriminatingly +discrimination +discriminational +discriminations +discriminative +discriminatively +discriminator +discriminatorily +discriminators +discriminatory +discs +discursion +discursive +discursively +discursiveness +discus +discuses +discuss +discussable +discussant +discussants +discussed +discusser +discussers +discusses +discussible +discussing +discussion +discussions +disdain +disdained +disdainful +disdainfully +disdainfulness +disdaining +disdains +disease +diseased +diseases +diseconomies +diseconomy +disembark +disembarkation +disembarked +disembarking +disembarks +disembarrass +disembarrassed +disembarrasses +disembarrassing +disembarrassment +disembodied +disembodies +disembodiment +disembody +disembodying +disembogue +disembogued +disemboguement +disembogues +disemboguing +disembowel +disemboweled +disemboweling +disembowelment +disembowelments +disembowels +disemploy +disemployed +disemploying +disemployment +disemploys +disempower +disempowered +disempowering +disempowerment +disempowers +disenable +disenabled +disenables +disenabling +disenchant +disenchanted +disenchanter +disenchanters +disenchanting +disenchantingly +disenchantment +disenchants +disencumber +disencumbered +disencumbering +disencumberment +disencumbers +disendow +disendowed +disendower +disendowers +disendowing +disendowment +disendows +disenfranchise +disenfranchised +disenfranchisement +disenfranchises +disenfranchising +disengage +disengaged +disengagement +disengages +disengaging +disentail +disentailed +disentailing +disentailment +disentails +disentangle +disentangled +disentanglement +disentangles +disentangling +disenthrall +disenthralled +disenthralling +disenthralls +disentitle +disentitled +disentitles +disentitling +disentomb +disentombed +disentombing +disentombs +disentwine +disentwined +disentwines +disentwining +disequilibrate +disequilibrated +disequilibrates +disequilibrating +disequilibration +disequilibrium +disestablish +disestablished +disestablishes +disestablishing +disestablishment +disestablishmentarian +disestablishmentarians +disesteem +disesteemed +disesteeming +disesteems +diseur +diseurs +diseuse +diseuses +disfavor +disfavored +disfavoring +disfavors +disfeature +disfeatured +disfeaturement +disfeatures +disfeaturing +disfiguration +disfigure +disfigured +disfigurement +disfigurements +disfigurer +disfigurers +disfigures +disfiguring +disfranchise +disfranchised +disfranchisement +disfranchiser +disfranchisers +disfranchises +disfranchising +disfrock +disfrocked +disfrocking +disfrocks +disgorge +disgorged +disgorgement +disgorges +disgorging +disgrace +disgraced +disgraceful +disgracefully +disgracefulness +disgracer +disgracers +disgraces +disgracing +disgruntle +disgruntled +disgruntlement +disgruntles +disgruntling +disguise +disguised +disguisedly +disguisement +disguisements +disguiser +disguisers +disguises +disguising +disgust +disgusted +disgustedly +disgustful +disgustfully +disgusting +disgustingly +disgusts +dish +dishabille +disharmonic +disharmonies +disharmonious +disharmoniously +disharmonize +disharmonized +disharmonizes +disharmonizing +disharmony +dishcloth +dishcloths +dishearten +disheartened +disheartening +dishearteningly +disheartenment +disheartenments +disheartens +dished +dishes +dishevel +disheveled +disheveling +dishevelment +dishevels +dishier +dishiest +dishing +dishonest +dishonesties +dishonestly +dishonesty +dishonor +dishonorable +dishonorableness +dishonorably +dishonored +dishonorer +dishonorers +dishonoring +dishonors +dishpan +dishpans +dishrag +dishrags +dishtowel +dishtowels +dishware +dishwares +dishwasher +dishwashers +dishwashing +dishwater +dishwaters +dishy +disillusion +disillusioned +disillusioning +disillusionment +disillusions +disillusive +disincarnate +disincentive +disincentives +disinclination +disinclinations +disincline +disinclined +disinclines +disinclining +disincorporate +disincorporated +disincorporates +disincorporating +disincorporation +disinfect +disinfectant +disinfectants +disinfected +disinfecting +disinfection +disinfects +disinfest +disinfestant +disinfestants +disinfestation +disinfested +disinfesting +disinfests +disinflation +disinflationary +disinform +disinformant +disinformants +disinformation +disinformed +disinformer +disinformers +disinforming +disinforms +disingenuous +disingenuously +disingenuousness +disinherit +disinheritance +disinheritances +disinherited +disinheriting +disinherits +disinhibit +disinhibited +disinhibiting +disinhibition +disinhibitions +disinhibits +disintegrate +disintegrated +disintegrates +disintegrating +disintegration +disintegrations +disintegrative +disintegrator +disintegrators +disinter +disinterest +disinterested +disinterestedly +disinterestedness +disintermediation +disintermediations +disinterment +disinterred +disinterring +disinters +disintoxicate +disintoxicated +disintoxicates +disintoxicating +disintoxication +disinvent +disinvented +disinventing +disinvention +disinvents +disinvest +disinvested +disinvesting +disinvestment +disinvestments +disinvests +disinvitation +disinvite +disinvited +disinvites +disinviting +disjoin +disjoined +disjoining +disjoins +disjoint +disjointed +disjointedly +disjointedness +disjointing +disjoints +disjunct +disjunction +disjunctive +disjunctively +disjuncture +disjunctures +disk +disked +diskette +diskettes +disking +diskless +disklike +disks +dislikable +dislike +disliked +dislikes +disliking +dislocate +dislocated +dislocates +dislocating +dislocation +dislocations +dislodge +dislodged +dislodgement +dislodges +dislodging +dislodgment +disloyal +disloyally +disloyalties +disloyalty +dismal +dismally +dismalness +dismantle +dismantled +dismantlement +dismantles +dismantling +dismast +dismasted +dismasting +dismasts +dismay +dismayed +dismaying +dismayingly +dismays +dismember +dismembered +dismembering +dismemberment +dismembers +dismiss +dismissal +dismissals +dismissed +dismisses +dismissible +dismissing +dismission +dismissive +dismount +dismountable +dismounted +dismounting +dismounts +disney +disneyland +disobedience +disobedient +disobediently +disobey +disobeyed +disobeyer +disobeyers +disobeying +disobeys +disoblige +disobliged +disobliges +disobliging +disobligingly +disorder +disordered +disorderedly +disorderedness +disordering +disorderliness +disorderly +disorders +disorganization +disorganize +disorganized +disorganizes +disorganizing +disorient +disorientate +disorientated +disorientates +disorientating +disorientation +disoriented +disorienting +disorients +disown +disowned +disowning +disownment +disowns +disparage +disparaged +disparagement +disparager +disparagers +disparages +disparaging +disparagingly +disparate +disparately +disparateness +disparities +disparity +disparlure +disparlures +dispassion +dispassionate +dispassionately +dispassionateness +dispatch +dispatched +dispatcher +dispatchers +dispatches +dispatching +dispel +dispelled +dispelling +dispels +dispensability +dispensable +dispensableness +dispensaries +dispensary +dispensation +dispensational +dispensations +dispensatories +dispensatory +dispense +dispensed +dispenser +dispensers +dispenses +dispensing +dispeople +dispeopled +dispeoples +dispeopling +dispersal +dispersant +disperse +dispersed +dispersedly +disperser +dispersers +disperses +dispersible +dispersing +dispersion +dispersions +dispersive +dispersively +dispersiveness +dispirit +dispirited +dispiritedly +dispiritedness +dispiriting +dispirits +displace +displaceable +displaced +displacement +displacements +displacer +displacers +displaces +displacing +displant +displanted +displanting +displants +display +displayable +displayed +displaying +displays +displease +displeased +displeases +displeasing +displeasingly +displeasure +disport +disported +disporting +disportment +disports +disposability +disposable +disposal +disposals +dispose +disposed +disposer +disposers +disposes +disposing +disposition +dispositions +dispossess +dispossessed +dispossesses +dispossessing +dispossession +dispossessions +dispossessor +dispossessors +dispossessory +dispraise +dispraised +dispraiser +dispraisers +dispraises +dispraising +dispraisingly +disproof +disproportion +disproportional +disproportionally +disproportionate +disproportionately +disproportionateness +disproportionation +disproportioned +disproportioning +disproportions +disprovable +disproval +disprove +disproved +disproves +disproving +disputability +disputable +disputably +disputant +disputants +disputation +disputations +disputatious +disputatiously +disputatiousness +dispute +disputed +disputer +disputers +disputes +disputing +disqualification +disqualifications +disqualified +disqualifies +disqualify +disqualifying +disquiet +disquieted +disquieting +disquietingly +disquietly +disquietness +disquiets +disquietude +disquisition +disraeli +disrate +disrated +disrates +disrating +disregard +disregarded +disregarder +disregarders +disregardful +disregarding +disregards +disrelish +disrelished +disrelishes +disrelishing +disremember +disremembered +disremembering +disremembers +disrepair +disreputability +disreputable +disreputableness +disreputably +disrepute +disrespect +disrespectability +disrespectable +disrespected +disrespectful +disrespectfully +disrespectfulness +disrespecting +disrespects +disrobe +disrobed +disrober +disrobers +disrobes +disrobing +disrupt +disrupted +disrupter +disrupters +disrupting +disruption +disruptions +disruptive +disruptively +disruptiveness +disruptor +disruptors +disrupts +dissatisfaction +dissatisfactions +dissatisfactory +dissatisfied +dissatisfiedly +dissatisfies +dissatisfy +dissatisfying +dissect +dissected +dissectible +dissecting +dissection +dissections +dissector +dissectors +dissects +disseize +disseized +disseizes +disseizin +disseizing +disseizins +dissemblance +dissemble +dissembled +dissembler +dissemblers +dissembles +dissembling +dissemblingly +disseminate +disseminated +disseminates +disseminating +dissemination +disseminations +disseminator +disseminators +disseminule +disseminules +dissension +dissensions +dissent +dissented +dissenter +dissenters +dissentience +dissentient +dissentients +dissenting +dissentingly +dissents +dissepiment +dissepimental +dissepiments +dissert +dissertate +dissertated +dissertates +dissertating +dissertation +dissertations +dissertator +dissertators +disserted +disserting +disserts +disserve +disserved +disserves +disservice +disserving +dissever +disseverance +dissevered +dissevering +disseverment +dissevers +dissidence +dissident +dissidents +dissilient +dissimilar +dissimilarities +dissimilarity +dissimilarly +dissimilate +dissimilated +dissimilates +dissimilating +dissimilation +dissimilations +dissimilatory +dissimilitude +dissimulate +dissimulated +dissimulates +dissimulating +dissimulation +dissimulations +dissimulative +dissimulator +dissimulators +dissipate +dissipated +dissipatedly +dissipatedness +dissipater +dissipaters +dissipates +dissipating +dissipation +dissipations +dissipative +dissipator +dissipators +dissociability +dissociable +dissociableness +dissociably +dissociate +dissociated +dissociates +dissociating +dissociation +dissociations +dissociative +dissolubility +dissoluble +dissolubleness +dissolute +dissolutely +dissoluteness +dissolution +dissolutive +dissolvable +dissolve +dissolved +dissolvent +dissolvents +dissolver +dissolvers +dissolves +dissolving +dissonance +dissonances +dissonancies +dissonancy +dissonant +dissonantly +dissuade +dissuaded +dissuader +dissuaders +dissuades +dissuading +dissuasion +dissuasions +dissuasive +dissuasively +dissuasiveness +dissymmetric +dissymmetrical +dissymmetrically +dissymmetries +dissymmetry +distaff +distaffs +distal +distally +distance +distanced +distances +distancing +distant +distantly +distantness +distaste +distasted +distasteful +distastefully +distastefulness +distastes +distasting +distemper +distemperate +distempered +distempering +distempers +distend +distended +distending +distends +distensibility +distensible +distension +distensions +distention +distich +distichous +distichously +distichs +distil +distill +distillable +distillate +distillates +distillation +distillations +distilled +distiller +distilleries +distillers +distillery +distilling +distills +distils +distinct +distinction +distinctions +distinctive +distinctively +distinctiveness +distinctly +distinctness +distinguish +distinguishability +distinguishable +distinguishably +distinguished +distinguishes +distinguishing +distingué +distort +distortable +distorted +distortedly +distorter +distorters +distorting +distortion +distortional +distortionary +distortions +distortive +distorts +distract +distracted +distractedly +distracter +distracters +distractibility +distractible +distracting +distractingly +distraction +distractions +distractive +distracts +distrain +distrainable +distrained +distrainee +distrainees +distrainer +distrainers +distraining +distrainment +distrainor +distrainors +distrains +distraint +distraints +distrait +distraught +distraughtly +distress +distressed +distresses +distressful +distressfully +distressfulness +distressing +distressingly +distributable +distributaries +distributary +distribute +distributed +distributee +distributes +distributing +distribution +distributional +distributions +distributive +distributively +distributiveness +distributives +distributivity +distributor +distributors +distributorship +distributorships +district +districted +districting +districts +districtwide +distrust +distrusted +distrustful +distrustfully +distrustfulness +distrusting +distrusts +disturb +disturbance +disturbances +disturbed +disturber +disturbers +disturbing +disturbingly +disturbs +disulfide +disulfides +disulfoton +disulfotons +disunion +disunionist +disunionists +disunite +disunited +disunites +disunities +disuniting +disunity +disuse +disused +disutility +disvalue +disvalued +disvalues +disvaluing +disyllabic +disyllable +disyllables +ditch +ditched +ditcher +ditchers +ditches +ditching +dither +dithered +ditherer +ditherers +dithering +dithers +dithery +dithyramb +dithyrambic +dithyrambs +ditsier +ditsiest +ditsy +dittanies +dittany +ditties +ditto +dittoed +dittoes +dittoing +dittos +ditty +diu +diuresis +diuretic +diuretically +diuretics +diurnal +diurnally +diurnals +diuron +diurons +diva +divagate +divagated +divagates +divagating +divagation +divagations +divalent +divan +divans +divaricate +divaricated +divaricately +divaricates +divaricating +divarication +divarications +divas +dive +dived +diver +diverge +diverged +divergence +divergences +divergencies +divergency +divergent +divergently +diverges +diverging +divers +diverse +diversely +diverseness +diversification +diversified +diversifier +diversifiers +diversifies +diversiform +diversify +diversifying +diversion +diversionary +diversionist +diversionists +diversions +diversities +diversity +divert +diverted +diverter +diverters +diverticula +diverticular +diverticulitis +diverticulosis +diverticulum +divertimenti +divertimento +divertimentos +diverting +divertingly +divertissement +divertissements +diverts +dives +divest +divested +divesting +divestiture +divestitures +divestment +divestments +divests +dividable +divide +divided +dividend +dividends +divider +dividers +divides +dividing +divination +divinations +divinatory +divine +divined +divinely +divineness +diviner +diviners +divines +divinest +diving +divining +divinities +divinity +divisibility +divisible +divisibleness +divisibly +division +divisional +divisionism +divisionist +divisionists +divisions +divisive +divisively +divisiveness +divisor +divisors +divorce +divorced +divorcee +divorcees +divorcement +divorcements +divorces +divorcing +divorcé +divorcée +divorcées +divorcés +divot +divots +divulge +divulged +divulgement +divulgence +divulger +divulgers +divulges +divulging +divvied +divvies +divvy +divvying +diwali +dixie +dixiecrat +dixiecratic +dixiecrats +dixieland +dixit +dixon +dizen +dizened +dizening +dizenment +dizens +dizygotic +dizygous +dizzied +dizzier +dizzies +dizziest +dizzily +dizziness +dizzy +dizzying +dizzyingly +djakarta +djellaba +djellabah +djibouti +djiboutian +djiboutians +dna +dnieper +do +do's +doable +dobbies +dobbin +dobbins +dobby +doberman +dobermans +dobra +dobras +dobro +dobson +dobsonflies +dobsonfly +dobsons +doc +docent +docents +docetic +docetism +docetist +docetists +doch +docile +docilely +docility +dock +dockage +docked +docker +dockers +docket +docketed +docketing +dockets +dockhand +dockhands +docking +dockmackie +dockmackies +dockominium +dockominiums +docks +dockside +docksides +dockworker +dockworkers +dockyard +dockyards +docs +doctor +doctoral +doctorate +doctorates +doctored +doctoring +doctorless +doctorly +doctors +doctorship +doctrinaire +doctrinaires +doctrinairism +doctrinal +doctrinally +doctrinarian +doctrine +doctrines +docudrama +docudramas +docudramatic +document +documentable +documental +documentalist +documentalists +documentarian +documentarians +documentaries +documentarily +documentarist +documentarists +documentary +documentation +documentational +documented +documenter +documenters +documenting +documents +docutainment +docutainments +dodder +doddered +dodderer +dodderers +doddering +dodders +doddery +dodecagon +dodecagonal +dodecagons +dodecahedra +dodecahedral +dodecahedron +dodecahedrons +dodecanese +dodecaphonic +dodecaphonism +dodecaphonist +dodecaphonists +dodecaphony +dodge +dodged +dodger +dodgeries +dodgers +dodgery +dodges +dodgier +dodgiest +dodging +dodgy +dodo +dodoes +dodoma +dodos +doe +doer +doers +does +doeskin +doeskins +doesn +doesn't +doff +doffed +doffing +doffs +dog +dogbane +dogbanes +dogberries +dogberry +dogcart +dogcarts +dogcatcher +dogcatchers +doge +doges +dogface +dogfaces +dogfight +dogfighter +dogfighters +dogfighting +dogfightings +dogfights +dogfish +dogfishes +dogged +doggedly +doggedness +doggerel +doggerels +doggeries +doggery +doggie +doggier +doggies +doggiest +dogging +doggish +doggishly +doggishness +doggo +doggone +doggoned +doggoning +doggy +doghouse +doghouses +dogie +dogies +dogleg +doglegged +doglegging +doglegs +doglike +dogma +dogmas +dogmata +dogmatic +dogmatically +dogmaticalness +dogmatics +dogmatism +dogmatist +dogmatists +dogmatization +dogmatize +dogmatized +dogmatizes +dogmatizing +dognap +dognaped +dognaping +dognapped +dognapper +dognappers +dognapping +dognaps +dogrib +dogribs +dogs +dogsbodies +dogsbody +dogsled +dogsledder +dogsledders +dogsledding +dogsleds +dogtooth +dogtooths +dogtrot +dogtrots +dogtrotted +dogtrotting +dogwatch +dogwatches +dogwood +dogwoods +doilies +doily +doing +doings +doister +dojo +dojos +dolabriform +dolby +dolce +doldrums +dole +doled +doleful +dolefully +dolefulness +dolerite +doleritic +doles +dolesome +dolichocephalic +dolichocephalism +dolichocephaly +dolichocranial +dolichocrany +doling +doll +dollar +dollarfish +dollarfishes +dollars +dolled +dollhouse +dollhouses +dollied +dollies +dolling +dollish +dollishly +dollishness +dollop +dollops +dolls +dolly +dollying +dolma +dolmades +dolman +dolmans +dolmas +dolmen +dolmens +dolomite +dolomites +dolomitic +dolomitization +dolomitize +dolor +doloroso +dolorous +dolorously +dolorousness +dolors +dolphin +dolphins +dolt +doltish +doltishly +doltishness +dolts +dom +domain +domains +dome +domed +domenichino +domes +domesday +domestic +domestically +domesticate +domesticated +domesticates +domesticating +domestication +domestications +domesticities +domesticity +domesticize +domesticized +domesticizes +domesticizing +domestics +domical +domically +domicile +domiciled +domiciles +domiciliary +domiciliate +domiciliation +domiciling +dominance +dominant +dominantly +dominants +dominate +dominated +dominates +dominating +domination +dominations +dominative +dominator +dominators +dominatrices +dominatrix +dominatrixes +domineer +domineered +domineering +domineeringly +domineeringness +domineers +doming +domingo +domini +dominic +dominica +dominical +dominican +dominicans +dominie +dominies +dominion +dominions +dominique +domino +dominoes +dominos +domitian +domo +domos +doms +don +don't +don'ts +donald +donate +donated +donatello +donates +donating +donation +donations +donatism +donatist +donatists +donative +donatives +donator +donators +done +donee +donees +doneness +dong +dongs +donjon +donjons +donkey +donkeys +donkeywork +donkeyworks +donna +donnas +donne +donned +donning +donnish +donnishly +donnishness +donnybrook +donnybrooks +donnée +donor +donors +dons +donut +donuts +doodad +doodads +doodle +doodlebug +doodlebugs +doodled +doodler +doodlers +doodles +doodling +doohickey +doohickeys +doom +doomed +doomful +doomfully +dooming +dooms +doomsayer +doomsayers +doomsday +doomster +door +doorbell +doorbells +doored +doorframe +doorframes +dooring +doorjamb +doorjambs +doorkeeper +doorkeepers +doorknob +doorknobs +doorknocker +doorknockers +doorless +doorman +doormat +doormats +doormen +doornail +doornails +doorplate +doorplates +doorpost +doorposts +doors +doorsill +doorsills +doorstep +doorsteps +doorstop +doorstopper +doorstoppers +doorstops +doorway +doorways +doorwoman +doorwomen +dooryard +doozie +doozies +doozy +dopa +dopamine +dopant +dopants +dope +doped +doper +dopers +dopes +dopester +dopesters +dopey +dopier +dopiest +dopiness +doping +doppelganger +doppelgangers +doppelgänger +doppelgängers +doppler +dorado +dorbeetle +dorbeetles +dorchester +dordogne +dordrecht +dorian +dorians +doric +dories +dork +dorking +dorkings +dorks +dorm +dormancy +dormant +dormer +dormers +dormice +dormin +dormins +dormitories +dormitory +dormouse +dorms +dormy +dornick +dornicks +doronicum +doronicums +dorothy +dorp +dorps +dorris +dorsa +dorsad +dorsal +dorsally +dorset +dorsiventral +dorsiventrally +dorsolateral +dorsolaterally +dorsoventral +dorsum +dortmund +dory +dorée +dos +dosage +dosages +dose +dosed +doser +dosers +doses +dosimeter +dosimeters +dosimetric +dosimetry +dosing +doss +dossal +dossals +dossed +dosses +dossier +dossiers +dossing +dostoevski +dostoyevskian +dostoyevsky +dot +dotage +dotal +dotard +dotards +dote +doted +doter +doters +dotes +doting +dotingly +dotless +dots +dotted +dotter +dotterel +dotters +dottier +dottiest +dottily +dottiness +dotting +dottle +dottles +dotty +double +doubled +doubleday +doubleheader +doubleheaders +doubleness +doubler +doublers +doubles +doublespeak +doublet +doublethink +doublethinks +doubleton +doubletons +doubletree +doubletrees +doublets +doublewide +doublewides +doubleword +doublewords +doubling +doubloon +doubloons +doubly +doubt +doubtable +doubted +doubter +doubters +doubtful +doubtfully +doubtfulness +doubting +doubtingly +doubtless +doubtlessly +doubtlessness +doubts +douceur +douceurs +douche +douched +douches +douching +doug +dough +doughboy +doughboys +doughface +doughfaces +doughier +doughiest +doughiness +doughlike +doughnut +doughnuts +doughtier +doughtiest +doughtily +doughtiness +doughty +doughy +douglas +doum +doums +dour +dourer +dourest +dourine +dourines +dourly +dourness +douro +douse +doused +douser +dousers +douses +dousing +doute +dove +dovecote +dovecotes +dovekie +dovekies +dover +doves +dovetail +dovetailed +dovetailing +dovetails +dovish +dovishness +dow +dowager +dowagers +dowdier +dowdies +dowdiest +dowdily +dowdiness +dowdy +dowdyish +dowel +doweled +doweling +dowels +dower +dowered +dowering +dowers +dowitcher +dowitchers +down +downbeat +downbeats +downburst +downbursts +downcast +downcourt +downdraft +downdrafts +downed +downer +downers +downfall +downfallen +downfalls +downfield +downgrade +downgraded +downgrades +downgrading +downhaul +downhauls +downhearted +downheartedly +downheartedness +downhill +downhills +downier +downiest +downiness +downing +downlink +downlinked +downlinking +downlinks +download +downloadable +downloaded +downloading +downloads +downplay +downplayed +downplaying +downplays +downpour +downpours +downrange +downrigger +downriggers +downright +downrightly +downrightness +downriver +downs +downscale +downscaled +downscales +downscaling +downshift +downshifted +downshifting +downshifts +downside +downsides +downsize +downsized +downsizes +downsizing +downslide +downslides +downslope +downspin +downspins +downspout +downspouts +downstage +downstairs +downstate +downstater +downstaters +downstream +downstroke +downswing +downswings +downtick +downticks +downtime +downtimes +downtown +downtowner +downtowners +downtowns +downtrend +downtrended +downtrending +downtrends +downtrodden +downturn +downturns +downward +downwardly +downwardness +downwards +downwind +downy +downzone +downzoned +downzones +downzoning +dowries +dowry +dowse +dowsed +dowser +dowsers +dowses +dowsing +doxies +doxological +doxologically +doxologies +doxology +doxorubicin +doxorubicins +doxy +doxycycline +doxycyclines +doyen +doyenne +doyennes +doyens +doyle +doze +dozed +dozen +dozens +dozenth +dozer +dozers +dozes +dozier +doziest +dozily +doziness +dozing +dozy +doña +dr +drab +drabbed +drabber +drabbest +drabbing +drabble +drabbled +drabbles +drabbling +drably +drabness +drabs +dracaena +dracaenas +drachenfels +drachm +drachma +drachmae +drachmas +drachms +draconian +draconic +draconically +dracula +draft +draftable +drafted +draftee +draftees +drafter +drafters +draftier +draftiest +draftily +draftiness +drafting +draftings +drafts +draftsman +draftsmanship +draftsmen +draftsperson +draftspersons +draftswoman +draftswomen +drafty +drag +dragged +dragger +draggers +draggier +draggiest +dragging +draggingly +draggle +draggled +draggles +draggling +draggy +draglift +draglifts +dragline +draglines +dragnet +dragnets +dragoman +dragomans +dragomen +dragon +dragonet +dragonets +dragonflies +dragonfly +dragonhead +dragonheads +dragonish +dragonroot +dragonroots +dragons +dragoon +dragooned +dragooning +dragoons +drags +dragster +dragsters +dragée +drain +drainable +drainage +drained +drainer +drainers +draining +drainpipe +drainpipes +drains +drake +drakes +dram +drama +dramamine +dramas +dramatic +dramatically +dramatics +dramatis +dramatist +dramatists +dramatization +dramatizations +dramatize +dramatized +dramatizes +dramatizing +dramaturge +dramaturges +dramaturgic +dramaturgical +dramaturgically +dramaturgy +drams +drang +drank +drapability +drapable +drape +draped +draper +draperies +drapers +drapery +drapes +draping +drastic +drastically +drat +dratted +dratting +draught +draughts +dravidian +dravidians +dravidic +draw +drawable +drawback +drawbacks +drawbar +drawbars +drawbridge +drawbridges +drawdown +drawdowns +drawee +drawees +drawer +drawerful +drawers +drawing +drawings +drawknife +drawknives +drawl +drawled +drawler +drawlers +drawling +drawlingly +drawls +drawly +drawn +drawnwork +drawplate +drawplates +draws +drawshave +drawshaves +drawstring +drawstrings +drawtube +drawtubes +dray +drayage +drayed +draying +drayman +draymen +drays +drayton +dread +dreaded +dreadful +dreadfully +dreadfulness +dreading +dreadlocked +dreadlocks +dreadnought +dreadnoughts +dreads +dream +dreamboat +dreamboats +dreamed +dreamer +dreamers +dreamful +dreamfully +dreamfulness +dreamier +dreamiest +dreamily +dreaminess +dreaming +dreamland +dreamlands +dreamless +dreamlessly +dreamlessness +dreamlike +dreams +dreamscape +dreamscapes +dreamt +dreamtime +dreamtimes +dreamworld +dreamworlds +dreamy +drear +drearier +dreariest +drearily +dreariness +dreary +dreck +drecks +drecky +dredge +dredged +dredger +dredgers +dredges +dredging +dreg +dregs +dreidel +dreidels +drench +drenched +drencher +drenchers +drenches +drenching +dresden +dress +dressage +dressed +dresser +dressers +dresses +dressier +dressiest +dressily +dressiness +dressing +dressings +dressmaker +dressmakers +dressmaking +dressy +drew +dreyfus +drib +dribble +dribbled +dribbler +dribblers +dribbles +dribbling +driblet +driblets +dribs +dried +drier +driers +dries +driest +drift +driftage +driftages +drifted +drifter +drifters +drifting +driftingly +drifts +driftwood +drifty +drill +drillability +drillable +drilled +driller +drillers +drilling +drillings +drillmaster +drillmasters +drills +drillstock +drillstocks +drily +drink +drinkability +drinkable +drinkables +drinker +drinkers +drinking +drinks +drip +dripless +dripped +dripper +drippier +drippiest +drippily +drippiness +dripping +drippings +drippy +drips +dripstone +dripstones +drivability +drivable +drive +drivel +driveled +driveler +drivelers +driveline +drivelines +driveling +drivelled +drivelling +drivels +driven +drivenness +driver +driverless +drivers +drives +drivetrain +drivetrains +driveway +driveways +driving +drivingly +drizzle +drizzled +drizzles +drizzling +drizzly +drogue +drogues +droit +droits +droll +droller +drolleries +drollery +drollest +drollness +drolls +drolly +dromedaries +dromedary +dromond +dromonds +drone +droned +droner +droners +drones +droning +droningly +drool +drooled +drooling +drools +droop +drooped +droopier +droopiest +droopily +droopiness +drooping +droopingly +droops +droopy +drop +dropforge +dropforged +dropforges +dropforging +drophead +dropkick +dropkicked +dropkicker +dropkickers +dropkickes +dropkicking +dropkicks +droplet +droplets +droplight +droplights +dropout +dropouts +dropped +dropper +dropperful +droppers +dropping +droppings +drops +dropsical +dropsically +dropsy +dropwort +dropworts +drosera +droseras +droshkies +droshky +drosophila +dross +drossy +drought +droughtiness +droughts +droughty +drove +drover +drovers +droves +drown +drowned +drowning +drownings +drowns +drowse +drowsed +drowses +drowsier +drowsiest +drowsily +drowsiness +drowsing +drowsy +drub +drubbed +drubber +drubbers +drubbing +drubbings +drubs +drudge +drudged +drudger +drudgeries +drudgers +drudgery +drudges +drudgework +drudgeworks +drudging +drudgingly +drug +drugged +drugget +druggets +druggie +druggier +druggies +druggiest +drugging +druggist +druggists +druggy +drugless +drugmaker +drugmakers +drugola +drugolas +drugs +drugstore +drugstores +druid +druidic +druidical +druidically +druidism +druids +drum +drumbeat +drumbeater +drumbeaters +drumbeating +drumbeats +drumette +drumettes +drumfire +drumfires +drumhead +drumheads +drumlike +drumlin +drumlins +drummed +drummer +drummers +drumming +drumroll +drumrolls +drums +drumstick +drumsticks +drunk +drunkard +drunkards +drunken +drunkenly +drunkenness +drunker +drunkest +drunks +drupaceous +drupe +drupelet +drupelets +drupes +druse +druses +druthers +dry +dryable +dryad +dryadic +dryads +dryasdust +dryasdusts +dryden +dryer +dryers +dryest +drying +dryings +drylands +drylot +drylots +dryly +dryness +dryopithecine +dryopithecines +drypoint +drypoints +drys +drysalter +drysalters +drysaltery +drywall +drywalls +duad +duads +dual +dualism +dualist +dualistic +dualistically +dualists +dualities +duality +dualize +dualized +dualizes +dualizing +dually +dub +dubai +dubbed +dubber +dubbers +dubbin +dubbing +dubbins +dubieties +dubiety +dubious +dubiously +dubiousness +dubitable +dubitably +dublin +dubliner +dubliners +dubnium +dubrovnik +dubs +dubuque +ducal +ducally +ducat +ducats +duce +duces +duchess +duchesses +duchies +duchy +duck +duckbill +duckbilled +duckbills +duckboard +ducked +ducker +duckers +duckier +duckiest +ducking +duckling +ducklings +duckpin +duckpins +ducks +ducktail +ducktails +duckweed +duckweeds +ducky +duct +ductal +ducted +ductile +ductilibility +ductility +ducting +ductings +ductless +ducts +ductule +ductules +ductwork +ductworks +dud +dude +duded +dudeen +dudeens +dudes +dudgeon +dudgeons +duding +dudish +dudishly +duds +due +duel +dueled +dueler +duelers +dueling +duelist +duelists +duelled +duelling +duels +duende +duendes +dueness +duenna +duennas +duennaship +dues +duet +duets +duetted +duetting +duff +duffel +duffels +duffer +duffers +duffle +duffles +duffs +dug +dugong +dugongs +dugout +dugouts +dugs +duiker +duikers +duke +duked +dukedom +dukedoms +dukes +dukhobor +dukhobors +duking +dulcet +dulcetly +dulcification +dulcified +dulcifies +dulcify +dulcifying +dulcimer +dulcimers +dulcimore +dulcimores +dulcinea +dull +dullard +dullards +dulled +duller +dulles +dullest +dulling +dullish +dullishly +dullness +dulls +dullsville +dullsvilles +dully +dulness +dulse +dulses +duluth +duly +duma +dumas +dumb +dumbbell +dumbbells +dumbed +dumber +dumbest +dumbfound +dumbfounded +dumbfounding +dumbfounds +dumbing +dumbly +dumbness +dumbo +dumbos +dumbs +dumbstruck +dumbwaiter +dumbwaiters +dumdum +dumdums +dumfound +dumfounded +dumfounding +dumfounds +dumfries +dumka +dumky +dummied +dummies +dummkopf +dummkopfs +dummy +dummying +dumortierite +dumortierites +dump +dumpcart +dumpcarts +dumped +dumper +dumpers +dumpier +dumpiest +dumpily +dumpiness +dumping +dumpish +dumpling +dumplings +dumps +dumpsite +dumpsites +dumpster +dumpsters +dumpties +dumpty +dumpy +dun +duncan +dunce +dunces +dunderhead +dunderheaded +dunderheads +dundrearies +dune +dunedin +duneland +dunelike +dunes +dung +dungaree +dungarees +dunged +dungeon +dungeons +dunghill +dunghills +dunging +dungs +dungy +dunite +dunites +dunitic +dunk +dunked +dunker +dunkers +dunking +dunkirk +dunks +dunlin +dunlins +dunlop +dunlops +dunnage +dunnages +dunned +dunning +duns +duo +duodecimal +duodecimally +duodecimals +duodecimo +duodecimos +duodena +duodenal +duodenary +duodenum +duodenums +duologue +duologues +duomo +duomos +duopolies +duopoly +duopsonies +duopsony +duos +duotone +dupability +dupable +dupe +duped +duper +duperies +dupers +dupery +dupes +duping +duple +duplex +duplexer +duplexers +duplexes +duplexity +duplicable +duplicatable +duplicate +duplicated +duplicately +duplicates +duplicating +duplication +duplications +duplicative +duplicator +duplicators +duplicatory +duplicities +duplicitous +duplicitously +duplicitousness +duplicity +dupont +dura +durability +durable +durableness +durables +durably +dural +duralumin +duralumins +duramen +duramens +durance +duration +durations +durban +durbar +durbars +duress +durga +durham +durian +durians +during +durkheim +durkheimian +durmast +durmasts +duro +duroc +durocs +durometer +durometers +duros +durra +durras +durum +dusk +dusked +duskier +duskiest +duskily +duskiness +dusking +dusks +dusky +dust +dustbin +dustbins +dustcover +dustcovers +dusted +duster +dusters +dustheap +dustheaps +dustier +dustiest +dustily +dustiness +dusting +dustings +dustless +dustlike +dustman +dustmen +dustpan +dustpans +dusts +dustsheet +dustsheets +dustup +dustups +dusty +dutch +dutchman +dutchmen +dutchwoman +dutchwomen +duteous +duteously +dutiable +duties +dutiful +dutifully +dutifulness +duty +duumvir +duumvirate +duumvirates +duumvirs +duvet +duvets +duvetyn +duvetyns +dvorak +dvorák +dwarf +dwarfed +dwarfing +dwarfish +dwarfishly +dwarfishness +dwarfism +dwarflike +dwarfness +dwarfs +dwarves +dweeb +dweebs +dwell +dwelled +dweller +dwellers +dwelling +dwellings +dwells +dwelt +dwindle +dwindled +dwindles +dwindling +dyad +dyadic +dyadically +dyadics +dyads +dyak +dyaks +dyarchies +dyarchy +dybbuk +dybbukim +dybbuks +dye +dyeability +dyeable +dyed +dyeing +dyer +dyer's +dyers +dyes +dyestuff +dyestuffs +dyewood +dyewoods +dyfed +dying +dyke +dykes +dynamic +dynamical +dynamically +dynamicist +dynamicists +dynamics +dynamism +dynamist +dynamistic +dynamists +dynamite +dynamited +dynamiter +dynamiters +dynamites +dynamitic +dynamiting +dynamo +dynamoelectric +dynamoelectrical +dynamometer +dynamometers +dynamometric +dynamometrical +dynamometry +dynamos +dynamotor +dynamotors +dynast +dynastic +dynastically +dynasties +dynasts +dynasty +dynatron +dynatrons +dyne +dynes +dynode +dynodes +dyscalculia +dyscalculias +dyscrasia +dyscrasias +dysenteric +dysentery +dysfunction +dysfunctional +dysgenesis +dysgenic +dysgenics +dysgraphia +dysgraphias +dysgraphic +dyskinesia +dyskinesias +dyslectic +dyslexia +dyslexic +dyslexics +dyslogistic +dyslogistically +dysmenorrhea +dysmenorrheal +dysmenorrheic +dyspepsia +dyspeptic +dyspeptically +dyspeptics +dysphagia +dysphagias +dysphagic +dysphasia +dysphasic +dysphasics +dysphonia +dysphonias +dysphonic +dysphoria +dysphorias +dysphoric +dysplasia +dysplastic +dyspnea +dyspneas +dyspneic +dysprosium +dysrhythmia +dysrhythmias +dysteleological +dysteleologist +dysteleologists +dysteleology +dystopia +dystopian +dystopias +dystrophic +dystrophication +dystrophy +dysuria +dysurias +dysuric +dáil +débouché +débride +débrided +débridement +débrides +débriding +début +débutant +débutante +débutantes +débutants +débuts +débâcle +débâcles +déclassé +décolletage +décolletages +décolleté +décor +décors +dégagé +déjà +démarche +démodé +dénouement +dénouements +déshabillé +détente +détentes +détentist +détentists +développé +dürer +düsseldorf +e +e'er +each +eager +eagerer +eagerest +eagerly +eagerness +eagle +eagled +eagles +eaglet +eaglets +eagling +eagre +eagres +ealdorman +ealdormen +ear +earache +earaches +eardrop +eardrops +eardrum +eardrums +eared +earflap +earflaps +earful +earfuls +earing +earings +earl +earlap +earlaps +earldom +earldoms +earless +earlier +earliest +earliness +earlobe +earlobes +earlock +earlocks +earls +early +earmark +earmarked +earmarking +earmarkings +earmarks +earmuff +earmuffs +earn +earned +earner +earners +earnest +earnestly +earnestness +earnests +earning +earnings +earns +earp +earphone +earphones +earpiece +earpieces +earplug +earplugs +earring +earrings +ears +earshot +earshots +earsplitting +earth +earthborn +earthbound +earthed +earthen +earthenware +earthier +earthiest +earthily +earthiness +earthing +earthlight +earthlights +earthlike +earthliness +earthling +earthlings +earthly +earthman +earthmen +earthmover +earthmovers +earthmoving +earthnut +earthnuts +earthquake +earthquakes +earthrise +earthrises +earths +earthshaker +earthshakers +earthshaking +earthshakingly +earthshine +earthshines +earthstar +earthstars +earthward +earthwards +earthwork +earthworks +earthworm +earthworms +earthy +earwax +earwaxes +earwig +earwigged +earwigging +earwigs +earwitness +earwitnesses +earworm +earworms +ease +eased +easeful +easefully +easefulness +easel +easels +easement +easements +eases +easier +easiest +easily +easiness +easing +east +eastbound +easter +easterlies +easterly +eastern +easterner +easterners +easternmost +easternness +easters +eastertide +eastertides +easthampton +easting +eastings +eastward +eastwardly +eastwards +easy +easygoing +easygoingness +eat +eatable +eatables +eaten +eater +eateries +eaters +eatery +eating +eats +eau +eaux +eaves +eavesdrop +eavesdropped +eavesdropper +eavesdroppers +eavesdropping +eavesdrops +ebb +ebbed +ebbing +ebbs +ebola +eboli +ebon +ebonics +ebonies +ebonite +ebonites +ebonize +ebonized +ebonizes +ebonizing +ebons +ebony +ebracteate +ebro +ebullience +ebulliencies +ebulliency +ebullient +ebulliently +ebullition +ebullitions +eburnation +eburnations +ecce +eccentric +eccentrically +eccentricities +eccentricity +eccentrics +ecchymoses +ecchymosis +ecchymotic +ecclesia +ecclesiae +ecclesial +ecclesiastes +ecclesiastic +ecclesiastical +ecclesiastically +ecclesiasticism +ecclesiasticisms +ecclesiastics +ecclesiasticus +ecclesiological +ecclesiology +eccrine +ecdyses +ecdysiast +ecdysiasts +ecdysis +ecdysone +ecdysones +ecesis +ecesises +echard +echards +echelon +echeloned +echeloning +echelons +echeveria +echeverias +echidna +echidnas +echinate +echini +echinococci +echinococcoses +echinococcosis +echinococcus +echinoderm +echinodermal +echinodermatous +echinoderms +echinoid +echinoids +echinus +echo +echocardiogram +echocardiograms +echocardiograph +echocardiographic +echocardiographs +echocardiography +echoed +echoencephalogram +echoencephalograms +echoencephalograph +echoencephalographic +echoencephalographs +echoencephalography +echoer +echoers +echoes +echoey +echogram +echograms +echography +echoic +echoing +echolalia +echolalias +echolalic +echolocate +echolocated +echolocates +echolocating +echolocation +echovirus +echoviruses +eclair +eclairs +eclampsia +eclampsias +eclamptic +eclectic +eclectically +eclecticism +eclectics +eclipse +eclipsed +eclipses +eclipsing +ecliptic +ecliptics +eclogue +eclogues +eclosion +eclosions +ecocatastrophe +ecocatastrophes +ecocide +ecofreak +ecofreaks +ecologic +ecological +ecologically +ecologies +ecologist +ecologists +ecology +econometric +econometrical +econometrically +econometrician +econometricians +econometrics +econometrist +econometrists +economic +economical +economically +economics +economies +economist +economists +economize +economized +economizer +economizers +economizes +economizing +economy +ecophysiological +ecophysiology +ecospecies +ecosphere +ecospheres +ecosystem +ecosystems +ecoterrorism +ecoterrorist +ecoterrorists +ecotone +ecotones +ecotype +ecotypes +ecotypic +ecru +ecrus +ecstasies +ecstasy +ecstatic +ecstatically +ectocommensal +ectocommensals +ectoderm +ectodermal +ectodermic +ectogenous +ectomere +ectomeres +ectomeric +ectomorph +ectomorphic +ectomorphs +ectomorphy +ectoparasite +ectoparasites +ectoparasitic +ectoparasitism +ectopia +ectopias +ectopic +ectoplasm +ectoplasmic +ectosarc +ectosarcs +ectotherm +ectothermic +ectotherms +ectotrophic +ecuador +ecuadorean +ecuadoreans +ecuadorian +ecuadorians +ecumenical +ecumenicalism +ecumenically +ecumenicism +ecumenicisms +ecumenicist +ecumenicists +ecumenicity +ecumenics +ecumenism +ecumenist +ecumenists +eczema +eczemas +eczematous +edacious +edacities +edacity +edam +edaphic +edaphically +edda +eddic +eddied +eddies +eddo +eddoes +eddy +eddying +edelweiss +edelweisses +edema +edemas +edemata +edematous +eden +edenic +edentate +edentates +edentulous +edgar +edge +edged +edgeless +edger +edgers +edges +edgeways +edgewise +edgier +edgiest +edgily +edginess +edging +edgings +edgy +edh +edhs +edibility +edible +edibleness +edibles +edict +edictal +edicts +edification +edifice +edifices +edified +edifier +edifiers +edifies +edify +edifying +edifyingly +edinburgh +edison +edit +editable +edited +edith +editing +edition +editions +editor +editorial +editorialist +editorialists +editorialization +editorializations +editorialize +editorialized +editorializer +editorializers +editorializes +editorializing +editorially +editorials +editors +editorship +editorships +editress +editresses +edits +edmund +edom +edomite +edomites +edomitish +educability +educable +educate +educated +educatedness +educates +educating +education +educational +educationalist +educationalists +educationally +educationist +educationists +educations +educative +educator +educators +educe +educed +educes +educible +educing +eduction +eductions +eductor +eductors +edulcorate +edulcorated +edulcorates +edulcorating +edward +edwardian +eel +eelgrass +eelgrasses +eellike +eelpout +eelpouts +eels +eelskin +eelworm +eelworms +eely +eerie +eerier +eeriest +eerily +eeriness +eery +ef +efate +efface +effaceable +effaced +effacement +effacer +effacers +effaces +effacing +effect +effected +effecter +effecters +effectible +effecting +effective +effectively +effectiveness +effectives +effectivity +effector +effectors +effects +effectual +effectuality +effectually +effectualness +effectuate +effectuated +effectuates +effectuating +effectuation +effeminacy +effeminate +effeminately +effeminateness +effeminates +effeminize +effeminized +effeminizes +effeminizing +effendi +effendis +efferent +efferentia +efferently +efferents +effervesce +effervesced +effervescence +effervescency +effervescent +effervescently +effervesces +effervescing +effete +effetely +effeteness +efficacies +efficacious +efficaciously +efficaciousness +efficacity +efficacy +efficiencies +efficiency +efficient +efficiently +effigies +effigy +effloresce +effloresced +efflorescence +efflorescent +effloresces +efflorescing +effluence +effluences +effluent +effluents +effluvia +effluvial +effluvium +effluviums +efflux +effluxes +effluxion +effluxions +effort +effortful +effortfully +effortless +effortlessly +effortlessness +efforts +effronteries +effrontery +effulgence +effulgences +effulgent +effuse +effused +effuses +effusing +effusion +effusions +effusive +effusively +effusiveness +efik +efiks +eft +efts +eftsoons +egad +egads +egalitarian +egalitarianism +egalitarians +egalite +egalites +egeria +egerias +egest +egesta +egested +egesting +egestion +egestions +egestive +egests +egg +eggbeater +eggbeaters +eggcup +eggcups +egged +egger +eggers +eggfruit +eggfruits +egghead +eggheaded +eggheadedness +eggheads +egging +eggless +eggnog +eggnogs +eggplant +eggplants +eggs +eggshell +eggshells +eglantine +eglantines +ego +egocentric +egocentrically +egocentricities +egocentricity +egocentrics +egocentrism +egoism +egoisms +egoist +egoistic +egoistical +egoistically +egoists +egomania +egomaniac +egomaniacal +egomaniacally +egomaniacs +egomanias +egos +egotism +egotisms +egotist +egotistic +egotistical +egotistically +egotists +egregious +egregiously +egregiousness +egress +egressed +egresses +egressing +egression +egressions +egret +egrets +egypt +egyptian +egyptians +egyptological +egyptologist +egyptologists +egyptology +eh +eider +eiderdown +eiderdowns +eiders +eidetic +eidetically +eidola +eidolon +eidolons +eiffel +eigenfunction +eigenspace +eigenstate +eigenvalue +eigenvalues +eigenvector +eigenvectors +eight +eighteen +eighteenfold +eighteenmo +eighteenmos +eighteens +eighteenth +eighteenths +eightfold +eighth +eighthly +eighths +eighties +eightieth +eightieths +eightpenny +eights +eightvo +eightvos +eighty +eightyfold +eilat +eileen +eindhoven +einkorn +einkorns +einstein +einsteinian +einsteinium +eire +eisenach +eisenhower +eisteddfod +eisteddfodau +eisteddfods +either +ejaculate +ejaculated +ejaculates +ejaculating +ejaculation +ejaculations +ejaculator +ejaculators +ejaculatory +eject +ejecta +ejectable +ejected +ejecting +ejection +ejections +ejective +ejectment +ejectments +ejector +ejectors +ejects +eke +eked +ekes +eking +ekistic +ekistical +ekistician +ekisticians +ekistics +ekpwele +el +elaborate +elaborated +elaborately +elaborateness +elaborates +elaborating +elaboration +elaborations +elaborative +elaborator +elaborators +elagabalus +elaine +elam +elamite +elamites +eland +elands +elapid +elapids +elapse +elapsed +elapses +elapsing +elara +elasmobranch +elasmobranchs +elastase +elastases +elastic +elastically +elasticities +elasticity +elasticized +elastics +elastin +elastins +elastomer +elastomeric +elastomers +elate +elated +elatedly +elatedness +elater +elaterid +elaterids +elaterite +elaterites +elaters +elates +elating +elation +elations +elavil +elba +elbe +elbow +elbowed +elbowing +elbowroom +elbows +elder +elderberries +elderberry +eldercare +elderlies +elderliness +elderly +elders +eldership +eldest +eldritch +eleanor +eleatic +eleaticism +eleatics +elecampane +elecampanes +elect +electability +electable +elected +electing +election +electioneer +electioneered +electioneerer +electioneerers +electioneering +electioneers +elections +elective +electively +electiveness +electives +elector +electoral +electorally +electorate +electorates +electors +electra +electress +electresses +electret +electrets +electric +electrical +electrically +electrician +electricians +electricities +electricity +electrics +electrifiable +electrification +electrified +electrifier +electrifiers +electrifies +electrify +electrifying +electrifyingly +electroacoustic +electroacoustically +electroacoustics +electroanalyses +electroanalysis +electroanalytic +electroanalytical +electrocardiogram +electrocardiograms +electrocardiograph +electrocardiographic +electrocardiographically +electrocardiographs +electrocardiography +electrochemical +electrochemically +electrochemist +electrochemistry +electrochemists +electrocoagulation +electrocoagulations +electroconvulsive +electrocorticogram +electrocorticograms +electrocute +electrocuted +electrocutes +electrocuting +electrocution +electrocutions +electrode +electrodeposit +electrodeposited +electrodepositing +electrodeposition +electrodepositions +electrodeposits +electrodermal +electrodes +electrodialyses +electrodialysis +electrodialytic +electrodynamic +electrodynamics +electrodynamometer +electrodynamometers +electroencephalogram +electroencephalograms +electroencephalograph +electroencephalographic +electroencephalographs +electroencephalography +electroform +electroformed +electroforming +electroforms +electrogasdynamic +electrogasdynamics +electrogenesis +electrogenic +electrogram +electrograms +electrograph +electrographs +electrohydraulic +electrohydraulically +electrojet +electrokinetic +electrokinetics +electroless +electrologist +electrologists +electroluminescence +electroluminescences +electroluminescent +electrolyses +electrolysis +electrolyte +electrolytes +electrolytic +electrolytically +electrolyze +electrolyzed +electrolyzes +electrolyzing +electromagnet +electromagnetic +electromagnetically +electromagnetism +electromagnetisms +electromagnets +electromechanical +electromechanically +electrometallurgical +electrometallurgy +electrometer +electrometers +electromotive +electromyogram +electromyograms +electromyograph +electromyographic +electromyographically +electromyographs +electromyography +electron +electronegative +electronegativity +electronic +electronically +electronics +electrons +electrooculogram +electrooculograms +electrophile +electrophiles +electrophilic +electrophilicity +electrophorese +electrophoresed +electrophoreses +electrophoresing +electrophoresis +electrophoretic +electrophoretically +electrophoretogram +electrophoretograms +electrophori +electrophorus +electrophotographic +electrophotography +electrophysiologic +electrophysiological +electrophysiologically +electrophysiologist +electrophysiologists +electrophysiology +electroplate +electroplated +electroplates +electroplating +electropositive +electroreception +electroreceptor +electroreceptors +electroretinogram +electroretinograms +electroretinograph +electroretinographic +electroretinography +electroscope +electroscopes +electroscopic +electroshock +electroshocked +electroshocking +electroshocks +electrostatic +electrostatically +electrostatics +electrosurgeries +electrosurgery +electrosurgical +electrosurgically +electrotherapeutics +electrotherapies +electrotherapist +electrotherapists +electrotherapy +electrothermal +electrothermally +electrotonic +electrotonically +electrotonus +electrotonuses +electrotype +electrotyped +electrotyper +electrotypers +electrotypes +electrotypic +electrotyping +electrovalence +electrovalencies +electrovalency +electrovalent +electrowinning +electrum +electrums +elects +electuaries +electuary +eleemosynary +elegance +elegances +elegancies +elegancy +elegant +elegantly +elegiac +elegiacal +elegiacally +elegiacs +elegies +elegist +elegists +elegit +elegits +elegize +elegized +elegizes +elegizing +elegy +eleison +element +elemental +elementally +elementals +elementarily +elementariness +elementary +elements +elemi +elemis +elephant +elephantiasis +elephantine +elephants +eleusinian +eleusinians +eleusis +elevate +elevated +elevateds +elevates +elevating +elevation +elevations +elevator +elevators +eleven +elevenfold +elevens +elevenses +eleventh +elevenths +elevon +elevons +elf +elfin +elfish +elfishly +elfishness +elflock +elflocks +elgar +elhi +eli +elicit +elicitation +elicitations +elicited +eliciting +elicitor +elicitors +elicits +elide +elided +elides +eliding +eligibilities +eligibility +eligible +eligibles +eligibly +elijah +eliminate +eliminated +eliminates +eliminating +elimination +eliminations +eliminative +eliminator +eliminators +eliminatory +eliot +elisha +elision +elisions +elite +elites +elitism +elitisms +elitist +elitists +elixir +elixirs +elizabeth +elizabethan +elizabethans +elk +elkhound +elkhounds +elks +ell +ellagic +ellen +ellesmere +ellington +elliot +elliott +ellipse +ellipses +ellipsis +ellipsoid +ellipsoidal +ellipsoids +elliptic +elliptical +elliptically +ellipticity +ells +elm +elmo +elms +elocution +elocutionary +elocutionist +elocutionists +elodea +elodeas +eloign +eloigned +eloigning +eloigns +elongate +elongated +elongates +elongating +elongation +elongations +elope +eloped +elopement +elopements +eloper +elopers +elopes +eloping +eloquence +eloquent +eloquently +eloquentness +els +else +elsewhere +eluant +eluants +eluate +eluates +elucidate +elucidated +elucidates +elucidating +elucidation +elucidations +elucidative +elucidator +elucidators +elucidatory +elucubrate +elucubrated +elucubrates +elucubrating +elucubration +elucubrations +elude +eluded +eludes +eluding +elusion +elusions +elusive +elusively +elusiveness +elusory +elute +eluted +elutes +eluting +elution +elutions +elutriate +elutriated +elutriates +elutriating +elutriation +elutriations +elutriator +elutriators +eluvial +eluviate +eluviated +eluviates +eluviating +eluviation +eluviations +eluvium +eluviums +elver +elvers +elves +elvis +elvish +elysian +elysium +elytra +elytroid +elytron +em +emaciate +emaciated +emaciates +emaciating +emaciation +emaciations +email +emailed +emailing +emails +emalangeni +emanate +emanated +emanates +emanating +emanation +emanational +emanations +emanative +emancipate +emancipated +emancipates +emancipating +emancipation +emancipationist +emancipationists +emancipations +emancipative +emancipator +emancipators +emancipatory +emarginate +emargination +emarginations +emasculate +emasculated +emasculates +emasculating +emasculation +emasculations +emasculative +emasculator +emasculators +emasculatory +embalm +embalmed +embalmer +embalmers +embalming +embalmment +embalmments +embalms +embank +embanked +embanking +embankment +embankments +embanks +embarcadero +embarcaderos +embargo +embargoed +embargoes +embargoing +embargos +embark +embarkation +embarkations +embarked +embarking +embarkment +embarkments +embarks +embarrass +embarrassable +embarrassed +embarrassedly +embarrasses +embarrassing +embarrassingly +embarrassment +embarrassments +embassage +embassages +embassies +embassy +embattle +embattled +embattlement +embattlements +embattles +embattling +embay +embayed +embaying +embayment +embayments +embays +embed +embeddable +embedded +embedding +embedment +embedments +embeds +embellish +embellished +embellisher +embellishers +embellishes +embellishing +embellishment +embellishments +ember +embers +embezzle +embezzled +embezzlement +embezzlements +embezzler +embezzlers +embezzles +embezzling +embitter +embittered +embittering +embitterment +embitterments +embitters +emblaze +emblazed +emblazes +emblazing +emblazon +emblazoned +emblazoner +emblazoners +emblazoning +emblazonment +emblazonments +emblazonries +emblazonry +emblazons +emblem +emblematic +emblematical +emblematically +emblematize +emblematized +emblematizes +emblematizing +emblemed +emblements +embleming +emblemize +emblemized +emblemizes +emblemizing +emblems +embodied +embodier +embodiers +embodies +embodiment +embodiments +embody +embodying +embolden +emboldened +emboldening +emboldens +embolectomies +embolectomy +emboli +embolic +embolies +embolism +embolismic +embolisms +embolization +embolus +emboly +embonpoint +embonpoints +embosom +embosomed +embosoming +embosoms +emboss +embossable +embossed +embosser +embossers +embosses +embossing +embossment +embossments +embouchement +embouchure +embouchures +embourgeoisement +embourgeoisements +embowed +embowel +emboweled +emboweling +embowelled +embowelling +embowels +embower +embowered +embowering +embowers +embrace +embraceable +embraced +embracement +embracements +embraceor +embraceors +embracer +embraceries +embracers +embracery +embraces +embracing +embracingly +embracive +embranchment +embranchments +embrangle +embrangled +embranglement +embranglements +embrangles +embrangling +embrasure +embrasured +embrasures +embrittle +embrittled +embrittlement +embrittlements +embrittles +embrittling +embrocate +embrocated +embrocates +embrocating +embrocation +embrocations +embroider +embroidered +embroiderer +embroiderers +embroideries +embroidering +embroiders +embroidery +embroil +embroiled +embroiling +embroilment +embroilments +embroils +embrown +embrowned +embrowning +embrowns +embrue +embrued +embrues +embruing +embryectomies +embryectomy +embryo +embryogenesis +embryogenetic +embryogenic +embryogeny +embryoid +embryoids +embryologic +embryological +embryologically +embryologies +embryologist +embryologists +embryology +embryonal +embryonated +embryonic +embryonically +embryopathies +embryopathy +embryos +embryotic +emcee +emceed +emceeing +emcees +emend +emendable +emendate +emendated +emendates +emendating +emendation +emendations +emendator +emendators +emendatory +emended +emender +emenders +emending +emends +emerald +emeralds +emerge +emerged +emergence +emergences +emergencies +emergency +emergent +emergents +emerges +emerging +emeries +emerita +emeritae +emeritas +emeriti +emeritus +emersed +emersion +emersions +emerson +emery +emeses +emesis +emetic +emetically +emetics +emetine +emetines +emigrant +emigrants +emigrate +emigrated +emigrates +emigrating +emigration +emigrations +emigratory +emilia +emilion +eminence +eminences +eminencies +eminency +eminent +eminently +emir +emirate +emirates +emirs +emissaries +emissary +emission +emissions +emissive +emissivity +emit +emits +emittance +emitted +emitter +emitters +emitting +emma +emmanuel +emmaus +emmenagogue +emmenagogues +emmer +emmers +emmet +emmetropia +emmetropias +emmetropic +emmets +emmy +emmys +emodin +emodins +emollient +emollients +emolument +emoluments +emote +emoted +emoter +emoters +emotes +emoting +emotion +emotional +emotionalism +emotionalist +emotionalistic +emotionalists +emotionality +emotionalize +emotionalized +emotionalizes +emotionalizing +emotionally +emotionless +emotionlessly +emotionlessness +emotions +emotive +emotively +emotiveness +emotivity +empale +empaled +empales +empaling +empanada +empanel +empaneled +empaneling +empanelled +empanelling +empanels +empathetic +empathetically +empathic +empathize +empathized +empathizer +empathizers +empathizes +empathizing +empathy +empedocles +empennage +empennages +emperies +emperor +emperors +emperorship +emperorships +empery +emphases +emphasis +emphasize +emphasized +emphasizes +emphasizing +emphatic +emphatically +emphysema +emphysematous +emphysemic +emphysemics +empire +empires +empiric +empirical +empirically +empiricism +empiricist +empiricists +empirics +emplace +emplaced +emplacement +emplacements +emplaces +emplacing +emplane +emplaned +emplanes +emplaning +employ +employability +employable +employe +employed +employee +employees +employer +employers +employes +employing +employment +employments +employs +empoison +empoisoned +empoisoning +empoisonment +empoisons +emporia +emporium +emporiums +empower +empowered +empowering +empowerment +empowerments +empowers +empress +empressement +empressements +empresses +emprise +emprises +emptied +emptier +empties +emptiest +emptily +emptiness +emptor +empty +emptying +empurple +empurpled +empurples +empurpling +empyema +empyemas +empyemata +empyemic +empyreal +empyrean +empyreans +ems +emu +emulate +emulated +emulates +emulating +emulation +emulations +emulative +emulatively +emulator +emulators +emulous +emulously +emulousness +emulsible +emulsifiable +emulsification +emulsifications +emulsified +emulsifier +emulsifiers +emulsifies +emulsify +emulsifying +emulsion +emulsions +emulsive +emulsoid +emulsoidal +emulsoids +emunctories +emunctory +emus +en +enable +enabled +enabler +enablers +enables +enabling +enact +enactable +enacted +enacting +enactment +enactments +enactor +enactors +enacts +enamel +enameled +enameler +enamelers +enameling +enamelist +enamelists +enamelled +enamelling +enamels +enamelware +enamine +enamines +enamoenantiomeric +enamor +enamored +enamoring +enamors +enamour +enamoured +enamouring +enamours +enantiomer +enantiomers +enantiomorph +enantiomorphic +enantiomorphism +enantiomorphous +enantiomorphs +enarthroses +enarthrosis +enate +enates +enatic +enation +enations +encaenia +encage +encaged +encages +encaging +encamp +encamped +encamping +encampment +encampments +encamps +encapsulant +encapsulants +encapsulate +encapsulated +encapsulates +encapsulating +encapsulation +encapsulations +encapsulator +encapsulators +encapsule +encapsuled +encapsules +encapsuling +encase +encased +encasement +encasements +encases +encash +encashable +encashed +encashes +encashing +encashment +encasing +encaustic +encaustics +enceinte +enceintes +enceladus +encephala +encephalic +encephalitic +encephalitis +encephalitogen +encephalitogenic +encephalitogens +encephalogram +encephalograms +encephalograph +encephalographic +encephalographically +encephalographies +encephalographs +encephalography +encephaloma +encephalomas +encephalomata +encephalomyelitis +encephalon +encephalopathic +encephalopathies +encephalopathy +encephalous +enchain +enchained +enchaining +enchainment +enchainments +enchains +enchant +enchanted +enchanter +enchanters +enchanting +enchantingly +enchantment +enchantments +enchantress +enchantresses +enchants +enchase +enchased +enchases +enchasing +enchilada +enchiladas +enchiridia +enchiridion +enchiridions +encina +encinas +encipher +enciphered +encipherer +encipherers +enciphering +encipherment +encipherments +enciphers +encircle +encircled +encirclement +encirclements +encircles +encircling +enclasp +enclasped +enclasping +enclasps +enclave +enclaves +enclitic +enclitics +enclose +enclosed +encloses +enclosing +enclosure +enclosures +encode +encoded +encoder +encoders +encodes +encoding +encodings +encomia +encomiast +encomiastic +encomiastical +encomiasts +encomium +encomiums +encompass +encompassed +encompasses +encompassing +encompassment +encompassments +encore +encored +encores +encoring +encounter +encountered +encountering +encounters +encourage +encouraged +encouragement +encouragements +encourager +encouragers +encourages +encouraging +encouragingly +encrimson +encrimsoned +encrimsoning +encrimsons +encroach +encroached +encroacher +encroachers +encroaches +encroaching +encroachment +encroachments +encrust +encrustation +encrustations +encrusted +encrusting +encrusts +encrypt +encrypted +encrypting +encryption +encryptions +encrypts +encumber +encumbered +encumbering +encumbers +encumbrance +encumbrancer +encumbrancers +encumbrances +encyclical +encyclicals +encyclopaedia +encyclopaedias +encyclopedia +encyclopedias +encyclopedic +encyclopedically +encyclopedism +encyclopedisms +encyclopedist +encyclopedists +encyst +encystation +encystations +encysted +encysting +encystment +encystments +encysts +end +endamage +endamaged +endamages +endamaging +endameba +endamebae +endamebas +endamoeba +endanger +endangered +endangering +endangerment +endangerments +endangers +endarch +endarterectomies +endarterectomy +endarteritis +endbrain +endbrains +endear +endeared +endearing +endearingly +endearment +endearments +endears +endeavor +endeavored +endeavorer +endeavorers +endeavoring +endeavors +ended +endemic +endemically +endemicity +endemics +endemism +endemisms +ender +endergonic +endermic +endermically +enders +endexine +endexines +endgame +endgames +ending +endings +endive +endives +endleaf +endleaves +endless +endlessly +endlessness +endlong +endmost +endnote +endnotes +endobiotic +endoblast +endoblasts +endocardia +endocardial +endocarditic +endocarditis +endocardium +endocarp +endocarpal +endocarps +endochondral +endocrania +endocranium +endocrine +endocrinologic +endocrinological +endocrinologist +endocrinologists +endocrinology +endocytic +endocytose +endocytosed +endocytoses +endocytosing +endocytosis +endocytotic +endoderm +endodermal +endodermis +endoderms +endodontia +endodontic +endodontically +endodontics +endodontist +endodontists +endoenzyme +endoenzymes +endoergic +endogamous +endogamy +endogenic +endogenous +endogenously +endogeny +endolymph +endolymphatic +endolymphs +endometria +endometrial +endometrioses +endometriosis +endometrium +endomitosis +endomitotic +endomorph +endomorphic +endomorphism +endomorphs +endomorphy +endonuclease +endonucleases +endoparasite +endoparasites +endoparasitic +endoparasitism +endopeptidase +endopeptidases +endophyte +endophytes +endophytic +endoplasm +endoplasmic +endorphin +endorphins +endorsable +endorse +endorsed +endorsee +endorsees +endorsement +endorsements +endorser +endorsers +endorses +endorsing +endorsor +endorsors +endoscope +endoscopes +endoscopic +endoscopically +endoscopies +endoscopy +endoskeletal +endoskeleton +endoskeletons +endosmosis +endosmotic +endosmotically +endosperm +endospore +endospores +endosporia +endosporium +endostea +endosteal +endosteally +endosteum +endostyle +endosulfan +endosulfans +endosymbiont +endosymbiosis +endosymbiotic +endothecia +endothecium +endothelia +endothelial +endothelioid +endothelioma +endotheliomas +endotheliomata +endothelium +endotherm +endothermal +endothermic +endotherms +endothermy +endotoxic +endotoxin +endotoxins +endotracheal +endotrophic +endow +endowed +endowing +endowment +endowments +endows +endpaper +endpapers +endpin +endpins +endplate +endplates +endplay +endplayed +endplaying +endplays +endpoint +endpoints +endrin +endrins +ends +endsville +endsvilles +endue +endued +endues +enduing +endurable +endurably +endurance +endure +endured +endures +enduring +enduringly +enduringness +enduro +enduros +endways +endwise +endymion +enema +enemas +enemies +enemy +energetic +energetically +energetics +energies +energize +energized +energizer +energizers +energizes +energizing +energy +enervate +enervated +enervates +enervating +enervation +enervations +enervative +enervator +enervators +enface +enfaced +enfacement +enfacements +enfaces +enfacing +enfant +enfants +enfeeble +enfeebled +enfeeblement +enfeeblements +enfeebler +enfeeblers +enfeebles +enfeebling +enfeoff +enfeoffed +enfeoffing +enfeoffment +enfeoffments +enfeoffs +enfetter +enfettered +enfettering +enfetters +enfever +enfevered +enfevering +enfevers +enfield +enfilade +enfiladed +enfilades +enfilading +enfin +enflame +enflamed +enflames +enflaming +enfleurage +enfleurages +enflurane +enfluranes +enfold +enfolded +enfolder +enfolders +enfolding +enfolds +enforce +enforceability +enforceable +enforced +enforcement +enforcements +enforcer +enforcers +enforces +enforcing +enframe +enframed +enframement +enframes +enframing +enfranchise +enfranchised +enfranchisement +enfranchisements +enfranchises +enfranchising +engage +engaged +engagement +engagements +engager +engagers +engages +engaging +engagingly +engagé +engarland +engarlanded +engarlanding +engarlands +engels +engender +engendered +engenderer +engenderers +engendering +engenders +engild +engilded +engilding +engilds +engine +engined +engineer +engineered +engineering +engineerings +engineers +enginery +engines +engining +engird +engirded +engirding +engirdle +engirdled +engirdles +engirdling +engirds +engirt +englacial +england +englander +englanders +english +englished +englishes +englishing +englishman +englishmen +englishness +englishwoman +englishwomen +englut +engluts +englutted +englutting +engorge +engorged +engorgement +engorgements +engorges +engorging +engraft +engrafted +engrafting +engraftment +engraftments +engrafts +engrailed +engrain +engrained +engraining +engrains +engram +engrams +engrave +engraved +engraver +engravers +engraves +engraving +engravings +engross +engrossed +engrosser +engrossers +engrosses +engrossing +engrossingly +engrossment +engrossments +engulf +engulfed +engulfing +engulfment +engulfments +engulfs +enhalo +enhaloed +enhaloes +enhaloing +enhance +enhanced +enhancement +enhancements +enhancer +enhancers +enhances +enhancing +enhancive +enharmonic +enharmonically +enigma +enigmas +enigmatic +enigmatical +enigmatically +enisle +enisled +enisles +enisling +eniwetok +enjambement +enjambements +enjambment +enjambments +enjoin +enjoinder +enjoinders +enjoined +enjoiner +enjoiners +enjoining +enjoinment +enjoinments +enjoins +enjoy +enjoyable +enjoyableness +enjoyably +enjoyed +enjoyer +enjoyers +enjoying +enjoyment +enjoyments +enjoys +enkephalin +enkephalins +enkindle +enkindled +enkindler +enkindlers +enkindles +enkindling +enlace +enlaced +enlacement +enlacements +enlaces +enlacing +enlarge +enlargeable +enlarged +enlargement +enlargements +enlarger +enlargers +enlarges +enlarging +enlighten +enlightened +enlightener +enlighteners +enlightening +enlightenment +enlightenments +enlightens +enlist +enlisted +enlistee +enlistees +enlisting +enlistment +enlistments +enlists +enliven +enlivened +enlivener +enliveners +enlivening +enlivenment +enlivenments +enlivens +enmesh +enmeshed +enmeshes +enmeshing +enmeshment +enmeshments +enmities +enmity +ennead +enneads +ennoble +ennobled +ennoblement +ennoblements +ennobler +ennoblers +ennobles +ennobling +ennui +enoch +enoki +enokidake +enokidakes +enokis +enol +enolase +enolases +enolic +enological +enologist +enologists +enology +enols +enormities +enormity +enormous +enormously +enormousness +enosis +enough +enounce +enounced +enouncement +enouncements +enounces +enouncing +enow +enphytotic +enphytotics +enplane +enplaned +enplanes +enplaning +enqueue +enqueued +enqueueing +enqueues +enqueuing +enquire +enquired +enquires +enquiries +enquiring +enquiry +enrage +enraged +enragement +enragements +enrages +enraging +enrapt +enrapture +enraptured +enrapturement +enrapturements +enraptures +enrapturing +enrich +enriched +enricher +enrichers +enriches +enriching +enrichment +enrichments +enrobe +enrobed +enrobes +enrobing +enroll +enrolled +enrollee +enrollees +enrolling +enrollment +enrollments +enrolls +enroot +enrooted +enrooting +enroots +ens +ensample +ensamples +ensanguine +ensanguined +ensanguines +ensanguining +ensconce +ensconced +ensconces +ensconcing +ensemble +ensembles +enserf +enserfed +enserfing +enserfment +enserfs +enshrine +enshrined +enshrinement +enshrinements +enshrines +enshrining +enshroud +enshrouded +enshrouding +enshrouds +ensiform +ensign +ensigns +ensilage +ensilaged +ensilages +ensilaging +ensile +ensiled +ensiles +ensiling +enskied +enskies +ensky +enskying +enslave +enslaved +enslavement +enslavements +enslaver +enslavers +enslaves +enslaving +ensnare +ensnared +ensnarement +ensnarements +ensnarer +ensnarers +ensnares +ensnaring +ensnarl +ensnarled +ensnarling +ensnarls +ensorcel +ensorceled +ensorceling +ensorcell +ensorcelled +ensorcelling +ensorcellment +ensorcells +ensorcels +ensoul +ensouled +ensouling +ensouls +ensphere +ensphered +enspheres +ensphering +enstatite +enstatites +ensue +ensued +ensues +ensuing +ensure +ensured +ensures +ensuring +enswathe +enswathed +enswathes +enswathing +entablature +entablatures +entablement +entablements +entail +entailed +entailer +entailers +entailing +entailment +entailments +entails +entameba +entamebae +entamebas +entamoeba +entamoebae +entamoebas +entangle +entangled +entanglement +entanglements +entangler +entanglers +entangles +entangling +entases +entasis +entebbe +entelechies +entelechy +entendre +entendres +entente +ententes +enter +enterable +enteral +enterally +entered +enteric +entering +enteritis +enterobacteria +enterobacterium +enterobiasis +enterococcal +enterococci +enterococcus +enterocoele +enterocoeles +enterocolitis +enterogastrone +enterogastrones +enterohepatitis +enterokinase +enterokinases +enteron +enterons +enteropathies +enteropathogen +enteropathogenic +enteropathogens +enteropathy +enterostomal +enterostomies +enterostomy +enterotomies +enterotomy +enterotoxin +enterotoxins +enteroviral +enterovirus +enteroviruses +enterprise +enterpriser +enterprisers +enterprises +enterprising +enterprisingly +enters +entertain +entertained +entertainer +entertainers +entertaining +entertainingly +entertainment +entertainments +entertains +enthalpies +enthalpy +enthrall +enthralled +enthralling +enthrallingly +enthrallment +enthrallments +enthralls +enthrone +enthroned +enthronement +enthronements +enthrones +enthroning +enthuse +enthused +enthuses +enthusiasm +enthusiasms +enthusiast +enthusiastic +enthusiastically +enthusiasts +enthusing +enthymeme +enthymemes +entice +enticed +enticement +enticements +enticer +enticers +entices +enticing +enticingly +entire +entirely +entireness +entires +entireties +entirety +entities +entitle +entitled +entitlement +entitlements +entitles +entitling +entity +entoblast +entoblasts +entoderm +entodermal +entodermic +entoderms +entoil +entoiled +entoiling +entoils +entomb +entombed +entombing +entombment +entombments +entombs +entomologic +entomological +entomologically +entomologist +entomologists +entomology +entomophagous +entomophilous +entomophily +entomostracan +entomostracans +entourage +entourages +entozoa +entozoan +entozoic +entr +entr'acte +entr'actes +entrails +entrain +entrained +entrainer +entrainers +entraining +entrainment +entrainments +entrains +entrance +entranced +entrancement +entrancements +entrances +entranceway +entranceways +entrancing +entrancingly +entrant +entrants +entrap +entrapment +entrapments +entrapped +entrapping +entraps +entreat +entreated +entreaties +entreating +entreatingly +entreatment +entreatments +entreats +entreaty +entrechat +entrechats +entrecôte +entree +entrees +entremets +entrench +entrenched +entrenches +entrenching +entrenchment +entrenchments +entrepreneur +entrepreneurial +entrepreneurialism +entrepreneurism +entrepreneurs +entrepreneurship +entrepreneurships +entrepôt +entresol +entresols +entries +entropic +entropically +entropies +entropy +entrust +entrusted +entrusting +entrustment +entrusts +entry +entryway +entryways +entrée +entrées +entwine +entwined +entwinement +entwinements +entwines +entwining +entwist +entwisted +entwisting +entwists +enucleate +enucleated +enucleates +enucleating +enucleation +enucleations +enucleator +enucleators +enumerable +enumerate +enumerated +enumerates +enumerating +enumeration +enumerations +enumerative +enumerator +enumerators +enunciable +enunciate +enunciated +enunciates +enunciating +enunciation +enunciations +enunciative +enunciatively +enunciator +enunciators +enure +enured +enures +enuresis +enuretic +enuring +envelop +envelope +enveloped +enveloper +envelopers +envelopes +enveloping +envelopment +envelopments +envelops +envenom +envenomed +envenoming +envenoms +enviable +enviableness +enviably +envied +envier +enviers +envies +envious +enviously +enviousness +environ +environed +environing +environment +environmental +environmentalism +environmentalist +environmentalists +environmentally +environments +environs +envisage +envisaged +envisages +envisaging +envision +envisioned +envisioning +envisions +envoi +envois +envoy +envoys +envy +envying +envyingly +enwheel +enwheeled +enwheeling +enwheels +enwind +enwinding +enwinds +enwomb +enwombed +enwombing +enwombs +enwound +enwrap +enwrapped +enwrapping +enwraps +enwreathe +enwreathed +enwreathes +enwreathing +enzootic +enzootics +enzymatic +enzymatically +enzyme +enzymes +enzymic +enzymically +enzymologist +enzymologists +enzymology +eocene +eohippus +eolian +eolith +eolithic +eoliths +eon +eonian +eons +eos +eosin +eosinophil +eosinophilia +eosinophilias +eosinophilic +eosinophilous +eosinophils +eosins +epact +epacts +epaminondas +eparchies +eparchy +epaulet +epaulets +epaulette +epaulettes +epee +epees +epeirogenic +epeirogenically +epeirogenies +epeirogeny +epentheses +epenthesis +epenthetic +epergne +epergnes +epernay +epexegesis +epexegetic +epexegetical +epexegetically +ephah +ephahs +ephebe +ephebes +ephebic +ephedrine +ephemera +ephemerae +ephemeral +ephemerality +ephemerally +ephemeralness +ephemerals +ephemeras +ephemerid +ephemerides +ephemerids +ephemeris +ephemeron +ephemerons +ephesian +ephesians +ephesus +ephod +ephods +ephor +ephori +ephors +ephraim +epiblast +epiblastic +epiblasts +epibolic +epiboly +epic +epical +epically +epicalyces +epicalyx +epicalyxes +epicanthi +epicanthic +epicanthus +epicardia +epicardial +epicardium +epicarp +epicarps +epicene +epicenes +epicenism +epicenter +epicenters +epicentral +epichlorohydrin +epichlorohydrins +epicondyle +epicondyles +epicotyl +epicotyls +epicritic +epics +epictetus +epicure +epicurean +epicureanism +epicureanisms +epicureans +epicures +epicurism +epicurisms +epicurus +epicuticle +epicuticles +epicycle +epicycles +epicyclic +epicyclical +epicyclically +epicycloid +epicycloidal +epicycloids +epidaurus +epidemic +epidemical +epidemically +epidemicity +epidemics +epidemiologic +epidemiological +epidemiologically +epidemiologist +epidemiologists +epidemiology +epidermal +epidermic +epidermis +epidermoid +epidiascope +epidiascopes +epididymal +epididymides +epididymis +epidote +epidotes +epidotic +epidural +epidurals +epifauna +epifaunae +epifaunal +epifaunas +epigastria +epigastric +epigastrium +epigeal +epigean +epigene +epigenesis +epigenetic +epigenous +epigeous +epiglottal +epiglottic +epiglottides +epiglottis +epiglottises +epigone +epigones +epigonic +epigonism +epigram +epigrammatic +epigrammatically +epigrammatism +epigrammatisms +epigrammatist +epigrammatists +epigrammatize +epigrammatized +epigrammatizer +epigrammatizers +epigrammatizes +epigrammatizing +epigrams +epigraph +epigrapher +epigraphers +epigraphic +epigraphical +epigraphically +epigraphist +epigraphists +epigraphs +epigraphy +epigynies +epigynous +epigyny +epilepsies +epilepsy +epileptic +epileptics +epileptogenic +epileptoid +epilog +epilogs +epilogue +epilogues +epimer +epimeric +epimers +epimetheus +epimysia +epimysium +epinastic +epinasties +epinasty +epinephrine +epineuria +epineurial +epineurium +epipelagic +epipetalous +epiphanic +epiphanies +epiphanous +epiphany +epiphenomena +epiphenomenal +epiphenomenalism +epiphenomenally +epiphenomenon +epiphyseal +epiphyses +epiphysial +epiphysis +epiphyte +epiphytes +epiphytic +epiphytical +epiphytically +epiphytotic +epiphytotics +episcia +episcias +episcopacies +episcopacy +episcopal +episcopalian +episcopalians +episcopally +episcopate +episcopates +episcope +episcopes +episiotomies +episiotomy +episode +episodes +episodic +episodically +episomal +episomally +episome +episomes +epistases +epistasis +epistatic +epistaxes +epistaxis +epistemic +epistemically +epistemological +epistemologically +epistemologist +epistemologists +epistemology +epistle +epistler +epistlers +epistles +epistolary +epistoler +epistolers +epistrophe +epistyle +epistyles +epitaph +epitaphial +epitaphic +epitaphs +epitases +epitasis +epitaxial +epitaxially +epitaxies +epitaxy +epithalamia +epithalamion +epithalamium +epithalamiums +epithelia +epithelial +epithelialization +epithelializations +epithelialize +epithelialized +epithelializes +epithelializing +epithelioid +epithelioma +epitheliomas +epitheliomata +epitheliomatous +epithelium +epitheliums +epithelization +epithelizations +epithelize +epithelized +epithelizes +epithelizing +epithet +epithetic +epithetical +epithets +epitome +epitomes +epitomic +epitomical +epitomize +epitomized +epitomizes +epitomizing +epizoa +epizoic +epizoism +epizoisms +epizoite +epizoites +epizoon +epizootic +epizootically +epizootics +epoch +epochal +epochally +epochs +epode +epodes +eponym +eponymic +eponymies +eponymous +eponyms +eponymy +epopee +epopees +epos +eposes +epoxide +epoxides +epoxied +epoxies +epoxy +epoxying +epsilon +epsilons +epsom +epstein +equability +equable +equableness +equably +equal +equaled +equaling +equalitarian +equalitarianism +equalities +equality +equalization +equalizations +equalize +equalized +equalizer +equalizers +equalizes +equalizing +equalled +equalling +equally +equals +equanimities +equanimity +equate +equated +equates +equating +equation +equational +equationally +equations +equator +equatorial +equatorially +equatorials +equators +equatorward +equerries +equerry +equestrian +equestrianism +equestrians +equestrianship +equestrienne +equestriennes +equiangular +equicaloric +equid +equidistance +equidistant +equidistantly +equids +equilateral +equilateralism +equilateralist +equilateralists +equilaterally +equilaterals +equilibrate +equilibrated +equilibrates +equilibrating +equilibration +equilibrations +equilibrator +equilibrators +equilibratory +equilibria +equilibrist +equilibristic +equilibrists +equilibrium +equilibriums +equimolar +equine +equinely +equines +equinoctial +equinoctials +equinox +equinoxes +equip +equipage +equipages +equipment +equipoise +equipoised +equipoises +equipoising +equipollence +equipollences +equipollent +equipollently +equipollents +equiponderance +equiponderances +equiponderant +equiponderate +equiponderated +equiponderates +equiponderating +equipotent +equipotential +equipped +equipping +equiprobable +equips +equiseta +equisetum +equisetums +equitability +equitable +equitableness +equitably +equitant +equitation +equities +equity +equivalence +equivalences +equivalencies +equivalency +equivalent +equivalently +equivalents +equivocal +equivocalities +equivocality +equivocally +equivocalness +equivocate +equivocated +equivocates +equivocating +equivocation +equivocations +equivocator +equivocators +equivoque +equivoques +er +era +eradicable +eradicate +eradicated +eradicates +eradicating +eradication +eradications +eradicative +eradicator +eradicators +eras +erasabilities +erasability +erasable +erase +erased +eraser +erasers +erases +erasing +erasmus +erastian +erastianism +erastians +erastus +erasure +erasures +erat +erato +eratosthenes +erbium +ere +erebus +erect +erectable +erected +erectile +erectilities +erectility +erecting +erection +erections +erectly +erectness +erector +erectors +erects +erelong +eremite +eremites +eremitic +eremitical +eremurus +erenow +erepsin +erepsins +erethism +erethismic +erethisms +erewhile +erfurt +erg +ergastic +ergative +ergo +ergocalciferol +ergocalciferols +ergodic +ergodicity +ergograph +ergographic +ergographs +ergometer +ergometers +ergometric +ergonometric +ergonomic +ergonomically +ergonomics +ergonomist +ergonomists +ergonovine +ergosterol +ergosterols +ergot +ergotamine +ergotamines +ergotic +ergotism +ergotisms +ergots +ergs +eric +ericoid +ericsson +eridanus +erie +eries +erigeron +erigerons +erin +eristic +eristics +eritrea +eritrean +eritreans +erlangen +erlenmeyer +ermine +ermines +erne +ernes +erode +eroded +erodes +erodibility +erodible +eroding +erogenous +eroica +eros +erose +erosely +erosion +erosional +erosionally +erosions +erosive +erosiveness +erosivity +erotic +erotica +erotically +eroticism +eroticist +eroticists +eroticization +eroticizations +eroticize +eroticized +eroticizes +eroticizing +erotics +erotism +erotisms +erotize +erotized +erotizes +erotizing +erotogenic +erotomania +erotomanias +err +errancies +errancy +errand +errands +errant +errantly +errantries +errantry +errants +errata +erratas +erratic +erratical +erratically +erraticism +erratics +erratum +erred +errhine +errhines +erring +erroneous +erroneously +erroneousness +error +errorless +errors +errs +ersatz +ersatzes +erse +erst +erstwhile +erucic +eruct +eructate +eructated +eructates +eructating +eructation +eructations +eructative +eructed +eructing +eructs +erudite +eruditely +eruditeness +erudition +erumpent +erupt +erupted +eruptible +erupting +eruption +eruptions +eruptive +eruptively +erupts +erymanthian +erymanthos +erymanthus +eryngo +eryngoes +eryngos +erysipelas +erysipelatous +erysipeloid +erysipeloids +erythema +erythematic +erythematous +erythemic +erythorbic +erythrism +erythrismal +erythrisms +erythrite +erythrites +erythroblast +erythroblastic +erythroblastoses +erythroblastosis +erythroblasts +erythrocyte +erythrocytes +erythrocytic +erythrocytometer +erythrocytometers +erythromycin +erythropoiesis +erythropoietic +erythropoietin +erythropoietins +erzgebirge +esau +escadrille +escadrilles +escalade +escaladed +escalader +escaladers +escalades +escalading +escalate +escalated +escalates +escalating +escalation +escalations +escalator +escalators +escalatory +escallop +escalloped +escalloping +escallops +escambia +escapable +escapade +escapades +escape +escaped +escapee +escapees +escapement +escapements +escaper +escapers +escapes +escaping +escapism +escapisms +escapist +escapists +escapologist +escapologists +escapology +escargot +escargots +escarole +escaroles +escarp +escarped +escarping +escarpment +escarpments +escarps +eschalot +eschalots +eschar +escharotic +escharotics +eschars +eschatological +eschatologically +eschatologist +eschatologists +eschatology +escheat +escheatable +escheatage +escheatages +escheated +escheating +escheats +escher +escherichia +eschew +eschewal +eschewals +eschewed +eschewing +eschews +escolar +escolars +escort +escorted +escorting +escorts +escot +escoted +escoting +escots +escritoire +escritoires +escrow +escrowed +escrowing +escrows +escudo +escudos +esculent +esculents +escutcheon +escutcheoned +escutcheons +esdraelon +esdras +esemplastic +eserine +eserines +esfahan +esker +eskers +eskimo +eskimoan +eskimos +esophageal +esophagi +esophagus +esoteric +esoterica +esoterically +esotericism +esotericisms +espadrille +espadrilles +espalier +espaliered +espaliering +espaliers +esparto +espartos +español +especial +especially +esperance +esperances +esperantist +esperantists +esperanto +espial +espials +espied +espiegle +espies +espionage +esplanade +esplanades +espousal +espousals +espouse +espoused +espouser +espousers +espouses +espousing +espresso +espressos +esprit +espy +espying +espíritu +esquiline +esquimau +esquimaux +esquire +esquires +ess +essay +essayed +essayer +essayers +essaying +essayist +essayistic +essayists +essays +essen +essence +essences +essene +essenes +essenian +essenic +essenism +essential +essentialism +essentialist +essentialists +essentiality +essentially +essentialness +essentials +essequibo +essex +essoin +essoins +essonite +essonites +est +establish +establishable +established +establisher +establishers +establishes +establishing +establishment +establishmentarian +establishmentarianism +establishmentarians +establishments +estaminet +estaminets +estancia +estancias +estate +estates +esteem +esteemed +esteeming +esteems +ester +esterase +esterases +esterification +esterifications +esterified +esterifies +esterify +esterifying +esters +esther +esthesia +esthesias +esthesiometer +esthesiometers +esthete +esthetes +esthetic +esthetically +esthetician +estheticians +estheticism +esthetics +estimable +estimableness +estimably +estimate +estimated +estimates +estimating +estimation +estimations +estimative +estimator +estimators +estival +estivate +estivated +estivates +estivating +estivation +estivations +estonia +estonian +estonians +estop +estoppage +estoppages +estopped +estoppel +estoppels +estopping +estops +estradiol +estradiols +estragon +estragons +estral +estrange +estranged +estrangement +estrangements +estranger +estrangers +estranges +estranging +estray +estrayed +estraying +estrays +estremadura +estremaduran +estremadurans +estriol +estriols +estrogen +estrogenic +estrogenically +estrogens +estrone +estrones +estrous +estrual +estrum +estrums +estrus +estruses +estuarial +estuaries +estuarine +estuary +esurience +esuriency +esurient +esuriently +et +eta +etagere +etageres +etamine +etamines +etatism +etatisms +etatist +etc +etcetera +etceteras +etch +etched +etcher +etchers +etches +etching +etchings +eternal +eternality +eternalize +eternalized +eternalizes +eternalizing +eternally +eternalness +eternals +eterne +eternities +eternity +eternization +eternizations +eternize +eternized +eternizes +eternizing +etesian +eth +ethacrynic +ethambutol +ethambutols +ethamine +ethamines +ethane +ethanes +ethanol +ethanolamine +ethanolamines +ethanols +ethelbert +ethelred +ethene +ethenes +ether +ethereal +ethereality +etherealization +etherealizations +etherealize +etherealized +etherealizes +etherealizing +ethereally +etherealness +etheric +etherification +etherifications +etherified +etherifies +etherify +etherifying +etherization +etherizations +etherize +etherized +etherizer +etherizers +etherizes +etherizing +ethernet +ethernets +ethers +ethic +ethical +ethicalities +ethicality +ethically +ethicalness +ethicals +ethician +ethicians +ethicist +ethicists +ethics +ethinyl +ethinyls +ethion +ethions +ethiopia +ethiopian +ethiopians +ethiopic +ethiopics +ethmoid +ethmoidal +ethmoids +ethnarch +ethnarchs +ethnarchy +ethnic +ethnical +ethnically +ethnicities +ethnicity +ethnics +ethnobotanical +ethnobotanically +ethnobotanist +ethnobotanists +ethnobotany +ethnocentric +ethnocentrically +ethnocentricity +ethnocentrism +ethnographer +ethnographers +ethnographic +ethnographical +ethnographically +ethnography +ethnohistorian +ethnohistorians +ethnohistoric +ethnohistorical +ethnohistory +ethnologic +ethnological +ethnologically +ethnologist +ethnologists +ethnology +ethnomethodologist +ethnomethodologists +ethnomethodology +ethnomusicological +ethnomusicologist +ethnomusicologists +ethnomusicology +ethogram +ethograms +ethological +ethologies +ethologist +ethologists +ethology +ethos +ethoxy +ethoxyl +ethoxyls +eths +ethyl +ethylamine +ethylamines +ethylate +ethylated +ethylates +ethylating +ethylation +ethylations +ethylene +ethylenes +ethylenic +ethylic +ethyls +ethyne +ethynes +ethynyl +ethynyls +etiolate +etiolated +etiolates +etiolating +etiolation +etiolations +etiologic +etiological +etiologically +etiologies +etiologist +etiologists +etiology +etiquette +etiquettes +etna +eton +etonian +etonians +etruria +etrurian +etrurians +etruscan +etruscans +etude +etudes +etyma +etymological +etymologically +etymologies +etymologist +etymologists +etymologize +etymologized +etymologizes +etymologizing +etymology +etymon +etymons +euboea +eucaine +eucaines +eucalypt +eucalypti +eucalyptol +eucalyptols +eucalypts +eucalyptus +eucalyptuses +eucharist +eucharistic +eucharistical +eucharists +euchre +euchred +euchres +euchring +euchromatic +euchromatin +euchromatins +euclase +euclases +euclid +euclidean +eucrite +eucrites +eucritic +eudaemonist +eudaemonists +eudemon +eudemonism +eudemonist +eudemonistic +eudemonistical +eudemonists +eudemons +eugene +eugenic +eugenically +eugenicist +eugenicists +eugenics +eugenist +eugenists +eugenol +eugenols +euglena +euglenas +euglobulin +euglobulins +eugénie +euhemerism +euhemerisms +euhemerist +euhemeristic +euhemeristically +euhemerists +euhemerize +euhemerized +euhemerizes +euhemerizing +eukaryote +eukaryotes +eukaryotic +eulachon +eulachons +euler +eulerian +eulogia +eulogies +eulogist +eulogistic +eulogistically +eulogists +eulogium +eulogiums +eulogize +eulogized +eulogizer +eulogizers +eulogizes +eulogizing +eulogy +eumenides +eunuch +eunuchism +eunuchoid +eunuchoids +eunuchs +euonymus +euonymuses +eupatrid +eupatridae +eupatrids +eupepsia +eupepsias +eupeptic +eupeptically +euphemism +euphemisms +euphemist +euphemistic +euphemistically +euphemists +euphemize +euphemized +euphemizer +euphemizers +euphemizes +euphemizing +euphenic +euphenics +euphonic +euphonically +euphonies +euphonious +euphoniously +euphoniousness +euphonium +euphoniums +euphonize +euphonized +euphonizes +euphonizing +euphony +euphorbia +euphorbias +euphoria +euphoriant +euphoriants +euphorias +euphoric +euphorically +euphotic +euphrates +euphrosyne +euphuism +euphuisms +euphuist +euphuistic +euphuistical +euphuistically +euphuists +euplastic +euploid +euploidies +euploids +euploidy +eupnea +eupneas +eupneic +eupneically +eurasia +eurasian +eurasians +eureka +eurhythmic +eurhythmics +eurhythmy +euripedes +euripi +euripidean +euripides +euripus +euro +eurobond +eurobonds +eurocentric +eurocentrism +eurocommunism +eurocommunist +eurocommunists +eurocrat +eurocratic +eurocrats +eurocurrencies +eurocurrency +eurodollar +eurodollars +euromarket +euromarkets +europa +europe +european +europeanism +europeanization +europeanize +europeanized +europeanizes +europeanizing +europeans +europium +euros +eurus +euryale +euryales +eurybath +eurybathic +eurybaths +eurydice +euryhaline +euryphagous +eurypterid +eurypterids +eurytherm +eurythermal +eurytherms +eurythmic +eurythmics +eurythmies +eurythmy +eurytopic +eurytopicity +eusebius +eustachian +eustasies +eustasy +eustatic +eustele +eusteles +eutectic +eutectics +euterpe +euthanasia +euthanasic +euthanize +euthanized +euthanizes +euthanizing +euthenics +euthenist +euthenists +eutherian +eutherians +euthyroid +eutrophic +eutrophication +eutrophications +eutrophies +eutrophy +euxenite +euxenites +evacuant +evacuants +evacuate +evacuated +evacuates +evacuating +evacuation +evacuations +evacuative +evacuator +evacuators +evacuee +evacuees +evadable +evade +evaded +evader +evaders +evades +evadible +evading +evaginate +evaginated +evaginates +evaginating +evagination +evaginations +evaluate +evaluated +evaluates +evaluating +evaluation +evaluations +evaluative +evaluator +evaluators +evanesce +evanesced +evanescence +evanescent +evanescently +evanesces +evanescing +evangel +evangelic +evangelical +evangelicalism +evangelically +evangelicals +evangelism +evangelist +evangelistic +evangelistically +evangelists +evangelization +evangelizations +evangelize +evangelized +evangelizer +evangelizers +evangelizes +evangelizing +evangels +evanton +evaporability +evaporable +evaporate +evaporated +evaporates +evaporating +evaporation +evaporations +evaporative +evaporatively +evaporativity +evaporator +evaporators +evaporite +evaporites +evaporitic +evapotranspiration +evasion +evasions +evasive +evasively +evasiveness +eve +evection +evectional +evections +evelyn +even +evened +evener +eveners +evenfall +evenfalls +evenhanded +evenhandedly +evenhandedness +evening +evenings +eveningwear +eveningwears +evenki +evenkis +evenly +evenness +evens +evensong +evensongs +event +eventful +eventfully +eventfulness +eventide +eventides +eventless +events +eventual +eventualities +eventuality +eventually +eventuate +eventuated +eventuates +eventuating +ever +everbearing +everblooming +everest +everglade +everglades +evergreen +evergreens +everlasting +everlastingly +everlastingness +evermore +eversible +eversion +eversions +evert +everted +everting +everts +every +everybody +everybody's +everyday +everydayness +everyman +everymen +everyone +everyone's +everyplace +everything +everywhere +everywoman +everywomen +eves +evict +evicted +evictee +evictees +evicting +eviction +evictions +evictor +evictors +evicts +evidence +evidenced +evidences +evidencing +evident +evidential +evidentially +evidentiary +evidently +evil +evildoer +evildoers +evildoing +evildoings +eviler +evilest +evilly +evilness +evils +evince +evinced +evinces +evincible +evincing +eviscerate +eviscerated +eviscerates +eviscerating +evisceration +eviscerations +evitable +evocable +evocation +evocations +evocative +evocatively +evocativeness +evocator +evocators +evoke +evoked +evokes +evoking +evolute +evolutes +evolution +evolutional +evolutionarily +evolutionary +evolutionism +evolutionist +evolutionists +evolutions +evolvable +evolve +evolved +evolvement +evolvements +evolves +evolving +evulsion +evulsions +evzone +evzones +ewe +ewer +ewers +ewes +ex +exaampere +exaamperes +exabecquerel +exabecquerels +exabit +exabits +exabyte +exabytes +exacandela +exacandelas +exacerbate +exacerbated +exacerbates +exacerbating +exacerbation +exacerbations +exacoulomb +exacoulombs +exact +exacta +exactable +exactas +exacted +exacter +exacters +exacting +exactingly +exactingness +exaction +exactions +exactitude +exactly +exactness +exactor +exactors +exacts +exafarad +exafarads +exaggerate +exaggerated +exaggeratedly +exaggeratedness +exaggerates +exaggerating +exaggeration +exaggerations +exaggerative +exaggerator +exaggerators +exaggeratory +exagram +exagrams +exahenries +exahenry +exahenrys +exahertz +exajoule +exajoules +exakelvin +exakelvins +exalt +exaltation +exaltations +exalted +exaltedly +exaltedness +exalter +exalters +exalting +exalts +exalumen +exalumens +exalux +exam +examen +examens +exameter +exameters +examinable +examinant +examinants +examination +examinational +examinations +examine +examined +examinee +examinees +examiner +examiners +examines +examining +examole +examoles +example +exampled +examples +exampling +exams +exanewton +exanewtons +exanimate +exanthem +exanthema +exanthemas +exanthemata +exanthematic +exanthematous +exanthems +exaohm +exaohms +exapascal +exapascals +exaradian +exaradians +exarch +exarchal +exarchate +exarchates +exarchies +exarchs +exarchy +exasecond +exaseconds +exasiemens +exasievert +exasieverts +exasperate +exasperated +exasperatedly +exasperater +exasperaters +exasperates +exasperating +exasperatingly +exasperation +exasteradian +exasteradians +exatesla +exateslas +exavolt +exavolts +exawatt +exawatts +exaweber +exawebers +excalibur +excaliburs +excaudate +excavate +excavated +excavates +excavating +excavation +excavational +excavations +excavator +excavators +exceed +exceeded +exceeding +exceedingly +exceeds +excel +excelled +excellence +excellences +excellencies +excellency +excellent +excellently +excelling +excels +excelsior +except +excepted +excepting +exception +exceptionability +exceptionable +exceptionably +exceptional +exceptionality +exceptionally +exceptionalness +exceptions +exceptive +excepts +excerpt +excerpted +excerpter +excerpters +excerpting +excerption +excerptions +excerptor +excerptors +excerpts +excess +excessed +excesses +excessing +excessive +excessively +excessiveness +exchange +exchangeability +exchangeable +exchanged +exchanger +exchangers +exchanges +exchanging +exchequer +exchequers +excimer +excimers +excipient +excipients +exciple +exciples +excisable +excise +excised +exciseman +excisemen +excises +excising +excision +excisions +excitabilities +excitability +excitable +excitableness +excitably +excitant +excitants +excitation +excitations +excitative +excitatory +excite +excited +excitedly +excitement +excitements +exciter +exciters +excites +exciting +excitingly +exciton +excitonics +excitons +excitor +excitors +exclaim +exclaimed +exclaimer +exclaimers +exclaiming +exclaims +exclamation +exclamations +exclamatory +exclave +exclaves +excludability +excludable +exclude +excluded +excluder +excluders +excludes +excludible +excluding +exclusion +exclusionary +exclusionism +exclusionist +exclusionistic +exclusionists +exclusions +exclusive +exclusively +exclusiveness +exclusives +exclusivity +excogitate +excogitated +excogitates +excogitating +excogitation +excogitations +excogitative +excommunicable +excommunicate +excommunicated +excommunicates +excommunicating +excommunication +excommunications +excommunicative +excommunicator +excommunicators +excommunicatory +excoriate +excoriated +excoriates +excoriating +excoriation +excoriations +excoriator +excoriators +excrement +excremental +excrementitious +excrements +excrescence +excrescences +excrescencies +excrescency +excrescent +excrescently +excreta +excretal +excrete +excreted +excreter +excreters +excretes +excreting +excretion +excretions +excretory +excruciate +excruciated +excruciates +excruciating +excruciatingly +excruciation +excruciations +exculpable +exculpate +exculpated +exculpates +exculpating +exculpation +exculpations +exculpatory +excurrent +excursion +excursionist +excursionists +excursions +excursive +excursively +excursiveness +excursus +excursuses +excusable +excusableness +excusably +excusatory +excuse +excused +excuser +excusers +excuses +excusing +exec +execrable +execrableness +execrably +execrate +execrated +execrates +execrating +execration +execrations +execrative +execrator +execrators +execratory +execs +executable +executables +executant +executants +execute +executed +executer +executers +executes +executing +execution +executioner +executioners +executions +executive +executives +executor +executorial +executors +executorship +executorships +executory +executrices +executrix +executrixes +exedra +exedrae +exedras +exegeses +exegesis +exegete +exegetes +exegetic +exegetical +exegetically +exegetist +exegetists +exempla +exemplar +exemplarily +exemplariness +exemplarity +exemplars +exemplary +exempli +exemplifiable +exemplification +exemplifications +exemplified +exemplifier +exemplifiers +exemplifies +exemplify +exemplifying +exemplum +exempt +exempted +exemptible +exempting +exemption +exemptions +exempts +exenterate +exenterated +exenterates +exenterating +exenteration +exenterations +exercisable +exercise +exercised +exerciser +exercisers +exercises +exercising +exercitation +exercitations +exercycle +exergonic +exergue +exergues +exert +exerted +exerting +exertion +exertions +exerts +exes +exeter +exeunt +exfoliate +exfoliated +exfoliates +exfoliating +exfoliation +exfoliations +exfoliative +exfoliator +exfoliators +exhalant +exhalants +exhalation +exhalations +exhale +exhaled +exhalent +exhalents +exhales +exhaling +exhaust +exhausted +exhaustedly +exhauster +exhausters +exhaustibility +exhaustible +exhausting +exhaustingly +exhaustion +exhaustive +exhaustively +exhaustiveness +exhaustivity +exhaustless +exhaustlessly +exhaustlessness +exhausts +exhibit +exhibited +exhibiter +exhibiters +exhibiting +exhibition +exhibitioner +exhibitioners +exhibitionism +exhibitionist +exhibitionistic +exhibitionists +exhibitions +exhibitive +exhibitively +exhibitor +exhibitors +exhibitory +exhibits +exhilarant +exhilarants +exhilarate +exhilarated +exhilarates +exhilarating +exhilaratingly +exhilaration +exhilarative +exhilarator +exhilarators +exhort +exhortation +exhortations +exhortative +exhortatory +exhorted +exhorter +exhorters +exhorting +exhorts +exhumation +exhumations +exhume +exhumed +exhumer +exhumers +exhumes +exhuming +exigence +exigences +exigencies +exigency +exigent +exigently +exiguities +exiguity +exiguous +exiguously +exiguousness +exile +exiled +exiles +exilian +exilic +exiling +eximious +exine +exines +exist +existed +existence +existences +existent +existential +existentialism +existentialist +existentialistic +existentialistically +existentialists +existentially +existents +existing +exists +exit +exited +exiting +exits +exobiological +exobiologist +exobiologists +exobiology +exocarp +exocarps +exocet +exocets +exocrine +exocyclic +exocytose +exocytosed +exocytoses +exocytosing +exocytosis +exocytotic +exodermis +exodontia +exodontias +exodontics +exodontist +exodontists +exodus +exoduses +exoenzyme +exoenzymes +exoergic +exogamic +exogamies +exogamous +exogamy +exogenous +exogenously +exon +exonerate +exonerated +exonerates +exonerating +exoneration +exonerations +exonerative +exonic +exons +exonuclease +exonucleases +exopeptidase +exopeptidases +exophthalmic +exophthalmos +exorbitance +exorbitances +exorbitant +exorbitantly +exorcise +exorcised +exorciser +exorcisers +exorcises +exorcising +exorcism +exorcisms +exorcist +exorcistic +exorcistical +exorcists +exorcize +exorcized +exorcizes +exorcizing +exordia +exordial +exordium +exordiums +exoskeletal +exoskeleton +exoskeletons +exosmosis +exosmotic +exosphere +exospheres +exospheric +exospore +exospores +exosporia +exosporium +exostoses +exostosis +exoteric +exoterically +exothermal +exothermally +exothermic +exothermically +exotic +exotica +exotically +exoticism +exoticisms +exoticness +exotics +exotism +exotisms +exotoxin +exotoxins +expand +expandable +expanded +expander +expanders +expanding +expandor +expandors +expands +expanse +expanses +expansibility +expansible +expansile +expansion +expansional +expansionary +expansionism +expansionist +expansionistic +expansionists +expansions +expansive +expansively +expansiveness +expansivity +expatiate +expatiated +expatiates +expatiating +expatiation +expatiations +expatiatory +expatriate +expatriated +expatriates +expatriating +expatriation +expatriations +expect +expectable +expectably +expectance +expectances +expectancies +expectancy +expectant +expectantly +expectants +expectation +expectational +expectations +expectative +expected +expectedly +expectedness +expecting +expectorant +expectorants +expectorate +expectorated +expectorates +expectorating +expectoration +expectorations +expectorator +expectorators +expects +expedience +expediences +expediencies +expediency +expedient +expediential +expedientially +expediently +expedients +expedite +expedited +expediter +expediters +expedites +expediting +expedition +expeditionary +expeditions +expeditious +expeditiously +expeditiousness +expeditor +expeditors +expel +expellable +expellant +expelled +expellee +expellees +expeller +expellers +expelling +expels +expend +expendability +expendable +expendables +expendably +expended +expender +expenders +expending +expenditure +expenditures +expends +expense +expensed +expenses +expensing +expensive +expensively +expensiveness +experience +experienced +experiencer +experiencers +experiences +experiencing +experiential +experientialism +experientially +experiment +experimental +experimentalism +experimentalist +experimentalists +experimentally +experimentation +experimentations +experimented +experimenter +experimenters +experimenting +experiments +expert +experted +experting +expertise +expertism +expertly +expertness +experts +expiable +expiate +expiated +expiates +expiating +expiation +expiations +expiator +expiators +expiatory +expiration +expirations +expiratory +expire +expired +expires +expiries +expiring +expiry +explain +explainable +explained +explainer +explainers +explaining +explains +explanation +explanations +explanative +explanatively +explanatorily +explanatory +explant +explantation +explantations +explanted +explanting +explants +expletive +expletives +expletory +explicable +explicably +explicate +explicated +explicates +explicating +explication +explications +explicative +explicatively +explicatives +explicator +explicators +explicatory +explicit +explicitly +explicitness +explode +exploded +exploder +exploders +explodes +exploding +exploit +exploitability +exploitable +exploitation +exploitations +exploitative +exploitatively +exploited +exploiter +exploiters +exploiting +exploitive +exploitively +exploits +exploration +explorational +explorations +explorative +exploratively +exploratory +explore +explored +explorer +explorers +explores +exploring +explosion +explosions +explosive +explosively +explosiveness +explosives +expo +exponent +exponential +exponentially +exponentiate +exponentiated +exponentiates +exponentiating +exponentiation +exponentiations +exponents +export +exportability +exportable +exportation +exportations +exported +exporter +exporters +exporting +exports +expos +expose +exposed +exposer +exposers +exposes +exposing +exposit +exposited +expositing +exposition +expositional +expositions +expositive +expositor +expositors +expository +exposits +expostulate +expostulated +expostulates +expostulating +expostulation +expostulations +expostulative +expostulator +expostulators +expostulatory +exposure +exposures +exposé +exposés +expound +expounded +expounder +expounders +expounding +expounds +express +expressage +expressed +expresser +expressers +expresses +expressible +expressing +expression +expressional +expressionism +expressionist +expressionistic +expressionistically +expressionists +expressionless +expressionlessly +expressionlessness +expressions +expressive +expressively +expressiveness +expressivities +expressivity +expressly +expressway +expressways +expropriate +expropriated +expropriates +expropriating +expropriation +expropriations +expropriator +expropriators +expropriatory +expulse +expulsed +expulses +expulsing +expulsion +expulsions +expulsive +expunction +expunctions +expunge +expunged +expunger +expungers +expunges +expunging +expurgate +expurgated +expurgates +expurgating +expurgation +expurgations +expurgator +expurgatorial +expurgators +expurgatory +exquisite +exquisitely +exquisiteness +exsanguinate +exsanguinated +exsanguinates +exsanguinating +exsanguination +exsanguinations +exsanguine +exscind +exscinded +exscinding +exscinds +exsert +exserted +exsertile +exserting +exsertion +exsertions +exserts +exsiccate +exsiccated +exsiccates +exsiccating +exsiccation +exsiccations +exsiccative +exsiccator +exsiccators +exstipulate +extant +extemporal +extemporally +extemporaneity +extemporaneous +extemporaneously +extemporaneousness +extemporarily +extemporary +extempore +extemporization +extemporizations +extemporize +extemporized +extemporizer +extemporizers +extemporizes +extemporizing +extend +extendability +extendable +extended +extendedly +extendedness +extender +extenders +extendibility +extendible +extending +extends +extensibility +extensible +extensile +extension +extensional +extensionality +extensionally +extensions +extensities +extensity +extensive +extensively +extensiveness +extenso +extensometer +extensometers +extensor +extensors +extent +extents +extenuate +extenuated +extenuates +extenuating +extenuatingly +extenuation +extenuations +extenuative +extenuatives +extenuator +extenuators +extenuatory +exterior +exteriority +exteriorization +exteriorizations +exteriorize +exteriorized +exteriorizes +exteriorizing +exteriorly +exteriors +exterminate +exterminated +exterminates +exterminating +extermination +exterminations +exterminative +exterminator +exterminators +exterminatory +extermine +extermined +extermines +extermining +extern +external +externalism +externalisms +externalist +externalists +externalities +externality +externalization +externalizations +externalize +externalized +externalizes +externalizing +externally +externals +externe +externes +externs +externship +externships +exteroceptive +exteroceptor +exteroceptors +exterritorial +exterritoriality +exterritorially +extinct +extinction +extinctions +extinctive +extinguish +extinguishable +extinguished +extinguisher +extinguishers +extinguishes +extinguishing +extinguishment +extinguishments +extirpate +extirpated +extirpates +extirpating +extirpation +extirpations +extirpative +extirpator +extirpators +extol +extolled +extoller +extollers +extolling +extolment +extols +extort +extorted +extorter +extorters +extorting +extortion +extortionary +extortionate +extortionately +extortioner +extortioners +extortionist +extortionists +extortions +extortive +extorts +extra +extracellular +extracellularly +extrachromosomal +extracode +extracodes +extraconstitutional +extracorporeal +extracorporeally +extracranial +extract +extractability +extractable +extracted +extractible +extracting +extraction +extractions +extractive +extractively +extractives +extractor +extractors +extracts +extracurricular +extraditable +extradite +extradited +extradites +extraditing +extradition +extraditions +extrados +extradoses +extragalactic +extrahepatic +extrajudicial +extrajudicially +extralegal +extralegally +extralimital +extralinguistic +extralinguistically +extralities +extrality +extramarital +extramundane +extramural +extramurally +extramusical +extraneous +extraneously +extraneousness +extranuclear +extraocular +extraordinaire +extraordinarily +extraordinariness +extraordinary +extrapolate +extrapolated +extrapolates +extrapolating +extrapolation +extrapolations +extrapolative +extrapolator +extrapolators +extrapyramidal +extras +extrasensory +extrasolar +extrasystole +extrasystoles +extraterrestrial +extraterrestrials +extraterritorial +extraterritorialities +extraterritoriality +extraterritorially +extrauterine +extravagance +extravagances +extravagancies +extravagancy +extravagant +extravagantly +extravagantness +extravaganza +extravaganzas +extravagate +extravagated +extravagates +extravagating +extravagation +extravagations +extravasate +extravasated +extravasates +extravasating +extravasation +extravasations +extravascular +extravehicular +extraversion +extravert +extraverted +extraverting +extraverts +extrema +extreme +extremely +extremeness +extremes +extremis +extremism +extremist +extremists +extremities +extremity +extremum +extricable +extricate +extricated +extricates +extricating +extrication +extrications +extrinsic +extrinsically +extrorse +extroversion +extroversive +extroversively +extrovert +extroverted +extroverts +extrudability +extrudable +extrude +extruded +extruder +extruders +extrudes +extruding +extrusion +extrusions +extrusive +exuberance +exuberant +exuberantly +exuberate +exuberated +exuberates +exuberating +exudate +exudates +exudation +exudations +exudative +exude +exuded +exudes +exuding +exult +exultance +exultancy +exultant +exultantly +exultation +exulted +exulting +exultingly +exults +exurb +exurban +exurbanite +exurbanites +exurbia +exurbias +exurbs +exuviae +exuvial +exuviate +exuviated +exuviates +exuviating +exuviation +exuviations +exxon +eyas +eyases +eye +eyeball +eyeballed +eyeballing +eyeballs +eyebolt +eyebolts +eyebright +eyebrights +eyebrow +eyebrows +eyecup +eyecups +eyed +eyedness +eyednesses +eyedropper +eyedropperful +eyedroppers +eyeful +eyefuls +eyeglass +eyeglasses +eyehole +eyeholes +eyehook +eyehooks +eyeing +eyelash +eyelashes +eyeless +eyelet +eyelets +eyelid +eyelids +eyelift +eyelifts +eyelike +eyeliner +eyeliners +eyepiece +eyepieces +eyepopper +eyepoppers +eyepopping +eyer +eyers +eyes +eyeshade +eyeshades +eyeshot +eyeshots +eyesight +eyesights +eyesore +eyesores +eyespot +eyespots +eyestalk +eyestalks +eyestrain +eyestrings +eyeteeth +eyetooth +eyewash +eyewashes +eyewear +eyewink +eyewinks +eyewitness +eyewitnesses +eying +eyra +eyras +eyre +eyres +eyrir +ezekias +ezekiel +ezra +f +fa +fab +fabergé +fabian +fabianism +fabianist +fabianists +fabians +fabius +fable +fabled +fabler +fablers +fables +fabliau +fabliaux +fabling +fabre +fabric +fabricability +fabricable +fabricant +fabricants +fabricate +fabricated +fabricates +fabricating +fabrication +fabrications +fabricator +fabricators +fabrics +fabular +fabulate +fabulated +fabulates +fabulating +fabulation +fabulations +fabulator +fabulators +fabulist +fabulists +fabulous +fabulously +fabulousness +facade +facades +face +faceable +facecloth +facecloths +faced +facedown +facedowns +faceless +facelessness +facelift +facelifts +facemask +facemasks +faceplate +faceplates +facer +facers +faces +facet +facete +faceted +facetiae +facetious +facetiously +facetiousness +facets +facetted +faceup +facia +facial +facially +facials +facias +facie +facies +facile +facilely +facileness +facilitate +facilitated +facilitates +facilitating +facilitation +facilitative +facilitator +facilitators +facilitatory +facilities +facility +facing +facings +facsimile +facsimiles +fact +facticity +faction +factional +factionalism +factionalize +factionalized +factionalizes +factionalizing +factionally +factions +factious +factiously +factiousness +factitious +factitiously +factitiousness +factitive +factitively +facto +factoid +factoidal +factoids +factor +factorability +factorable +factorage +factorages +factored +factorial +factorials +factories +factoring +factorings +factorization +factorizations +factorize +factorized +factorizes +factorizing +factors +factorship +factory +factotum +factotums +facts +factual +factualism +factualist +factualists +factuality +factually +factualness +facture +factures +facula +faculae +facultative +facultatively +faculties +faculty +fad +faddish +faddishly +faddishness +faddism +faddisms +faddist +faddists +faddy +fade +fadeaway +fadeaways +faded +fadeless +fadelessly +fadeout +fadeouts +fader +faders +fades +fading +fadings +fado +fados +fads +faecal +faeces +faena +faenas +faerie +faeries +faeroe +faeroes +faeroese +faery +fafnir +fag +fagged +fagging +faggot +faggoted +faggoting +faggots +fagin +fagins +fagot +fagoted +fagoting +fagotings +fagots +fags +fahrenheit +faience +faiences +fail +failed +failing +failingly +failings +faille +failles +fails +failsafe +failure +failures +fain +faint +fainted +fainter +fainters +faintest +fainthearted +faintheartedly +faintheartedness +fainting +faintish +faintishness +faintly +faintness +faints +fainéant +fainéants +fair +fairbanks +faire +faired +fairer +fairest +fairfax +fairgoer +fairgoers +fairground +fairgrounds +fairhaven +fairies +fairing +fairings +fairish +fairishly +fairlead +fairleader +fairleaders +fairleads +fairly +fairness +fairs +fairwater +fairwaters +fairway +fairways +fairy +fairyism +fairyisms +fairyland +fairylands +fairylike +fairytale +fairytales +faisalabad +fait +faith +faithful +faithfully +faithfulness +faithfuls +faithless +faithlessly +faithlessness +faiths +faitour +faitours +faits +fajita +fajitas +fake +faked +faker +fakeries +fakers +fakery +fakes +faking +fakir +fakirs +falafel +falange +falangism +falangist +falangists +falasha +falashas +falcate +falcated +falces +falchion +falchions +falciform +falciparum +falcon +falconer +falconers +falconet +falconets +falconoid +falconry +falcons +falderal +falderals +faldstool +faldstools +faliscan +faliscans +falkland +falklands +fall +fallacies +fallacious +fallaciously +fallaciousness +fallacy +fallal +fallalery +fallals +fallback +fallbacks +fallboard +fallboards +fallen +faller +fallers +fallfish +fallfishes +fallibility +fallible +fallibleness +fallibly +falling +fallings +falloff +falloffs +fallopian +fallout +fallouts +fallow +fallowed +fallowing +fallowness +fallows +falls +falmouth +false +falsehood +falsehoods +falsely +falseness +falser +falsest +falsetto +falsettos +falsie +falsies +falsifiability +falsifiable +falsification +falsifications +falsified +falsifier +falsifiers +falsifies +falsify +falsifying +falsities +falsity +falstaff +falstaffian +falster +faltboat +faltboats +falter +faltered +falterer +falterers +faltering +falteringly +falters +falx +famagusta +fame +famed +fames +familial +familiar +familiarities +familiarity +familiarization +familiarizations +familiarize +familiarized +familiarizer +familiarizers +familiarizes +familiarizing +familiarly +familiarness +familiars +families +familism +familistic +famille +family +famine +famines +faming +famish +famished +famishes +famishing +famishment +famishments +famous +famously +famousness +famuli +famulus +fan +fanac +fanacs +fanatic +fanatical +fanatically +fanaticalness +fanaticism +fanaticize +fanaticized +fanaticizes +fanaticizing +fanatics +fancied +fancier +fanciers +fancies +fanciest +fanciful +fancifully +fancifulness +fancily +fanciness +fancy +fancying +fancywork +fandangle +fandangles +fandango +fandangos +fandom +fandoms +fane +fanes +fanfare +fanfares +fanfaronade +fanfaronades +fanfold +fanfolds +fang +fanged +fangs +fanion +fanions +fanjet +fanjets +fanlight +fanlights +fanlike +fanned +fanner +fanners +fannies +fanning +fanny +fanout +fans +fantabulous +fantail +fantailed +fantails +fantasia +fantasias +fantasie +fantasied +fantasies +fantasist +fantasists +fantasize +fantasized +fantasizer +fantasizes +fantasizing +fantasm +fantasms +fantast +fantastic +fantastical +fantasticality +fantastically +fantasticalness +fantasticate +fantasticated +fantasticates +fantasticating +fantastication +fantastications +fantastico +fantasticoes +fantasts +fantasy +fantasying +fantasyland +fantasylands +fante +fanti +fantoccini +fantod +fantods +fantom +fantoms +fanwise +fanwort +fanworts +fanzine +fanzines +far +farad +faradaic +faraday +faradays +faradic +faradism +faradisms +faradization +faradizations +faradize +faradized +faradizes +faradizing +farads +farandole +farandoles +faraway +farce +farced +farces +farceur +farceurs +farci +farcical +farcicality +farcically +farcicalness +farcie +farcing +farcy +fard +farded +fardel +fardels +farding +fards +fare +farebeat +farebeaten +farebeater +farebeaters +farebeating +farebeats +fared +farer +farers +fares +farewell +farewelled +farewelling +farewells +farfal +farfals +farfel +farfels +farfetched +farfetchedness +faridabad +farina +farinaceous +farinas +faring +farinha +farinhas +farinose +farkleberries +farkleberry +farl +farls +farm +farmability +farmable +farmed +farmer +farmers +farmhand +farmhands +farmhouse +farmhouses +farming +farmington +farmland +farmlands +farms +farmstead +farmsteads +farmwoman +farmwomen +farmworker +farmworkers +farmyard +farmyards +farnese +faro +faroe +faroes +faroese +farolito +farolitos +faros +farouche +farraginous +farrago +farragoes +farrier +farrieries +farriers +farriery +farrow +farrowed +farrowing +farrows +farseeing +farsi +farsighted +farsightedly +farsightedness +farsistan +fart +farted +farther +farthermost +farthest +farthing +farthingale +farthingales +farthings +farting +farts +fasces +fascia +fasciae +fascial +fascias +fasciate +fasciated +fasciation +fasciations +fascicle +fascicled +fascicles +fascicular +fascicularly +fasciculate +fasciculated +fasciculately +fasciculation +fasciculations +fascicule +fascicules +fasciculi +fasciculus +fascinate +fascinated +fascinates +fascinating +fascinatingly +fascination +fascinations +fascinator +fascinators +fascine +fascines +fascioliases +fascioliasis +fascism +fascist +fascisti +fascistic +fascistically +fascists +fash +fashed +fashes +fashing +fashion +fashionability +fashionable +fashionableness +fashionables +fashionably +fashioned +fashioner +fashioners +fashioning +fashionmonger +fashionmongers +fashions +fast +fastback +fastbacks +fastball +fastballs +fasted +fasten +fastened +fastener +fasteners +fastening +fastenings +fastens +faster +fastest +fastidious +fastidiously +fastidiousness +fastigiate +fastigiated +fastigiately +fastigium +fastigiums +fasting +fastness +fastnesses +fasts +fastuous +fat +fata +fatal +fatale +fatales +fatalism +fatalist +fatalistic +fatalistically +fatalists +fatalities +fatality +fatally +fatback +fate +fated +fateful +fatefully +fatefulness +fates +fathead +fatheaded +fatheadedly +fatheadedness +fatheads +father +fathered +fatherhood +fathering +fatherland +fatherlands +fatherless +fatherlessness +fatherlike +fatherliness +fatherly +fathers +fathom +fathomable +fathomed +fathometer +fathoming +fathomless +fathomlessly +fathomlessness +fathoms +fatidic +fatidical +fatigabilities +fatigability +fatigable +fatigue +fatigued +fatigues +fatiguing +fatiguingly +fatima +fatimid +fatimids +fatimite +fatimites +fating +fatless +fatling +fatlings +fatly +fatness +fats +fatso +fatsoes +fatstock +fatted +fatten +fattened +fattener +fatteners +fattening +fattens +fatter +fattest +fattier +fatties +fattiest +fattily +fattiness +fatting +fattish +fattishness +fatty +fatuities +fatuity +fatuous +fatuously +fatuousness +fatuus +fatwood +fatwoods +faubourg +faubourgs +faucal +fauces +faucet +faucets +faucial +faugh +faulkner +faulknerian +fault +faulted +faultfinder +faultfinders +faultfinding +faultfindings +faultier +faultiest +faultily +faultiness +faulting +faultless +faultlessly +faultlessness +faults +faulty +faun +fauna +faunae +faunal +faunally +faunas +faunistic +faunistically +fauns +faunus +faust +faustian +faustus +faut +faute +fauteuil +fauteuils +fauve +fauves +fauvism +fauvist +fauvists +faux +favela +favelas +faveolate +favonian +favor +favorable +favorableness +favorably +favored +favoredness +favorer +favorers +favoring +favoringly +favorite +favorites +favoritism +favors +favus +favuses +fawkes +fawn +fawned +fawner +fawners +fawning +fawningly +fawns +fawny +fax +faxed +faxes +faxing +fay +fayalite +fayalites +fayed +fayetteville +faying +fays +faze +fazed +fazes +fazing +façade +façades +façadism +faïence +faïences +fealties +fealty +fear +feared +fearer +fearers +fearful +fearfully +fearfulness +fearing +fearless +fearlessly +fearlessness +fears +fearsome +fearsomely +fearsomeness +feasibility +feasible +feasiblefeasters +feasibleness +feasibly +feast +feasted +feaster +feasters +feasting +feasts +feat +feater +featest +feather +featherbed +featherbedded +featherbedding +featherbeddings +featherbeds +featherbone +featherbones +featherbrain +featherbrained +featherbrains +feathered +featheredge +featheredged +featheredges +featherhead +featherheaded +featherheads +featheriness +feathering +featherings +featherless +feathers +featherstitch +featherstitched +featherstitches +featherstitching +featherweight +featherweights +feathery +featly +feats +feature +featured +featureless +features +featuring +feaze +feazed +feazes +feazing +febricity +febrifacient +febrifacients +febrific +febrifuge +febrifuges +febrile +februaries +february +februarys +fecal +feces +feckless +fecklessly +fecklessness +feckly +feculence +feculent +fecund +fecundate +fecundated +fecundates +fecundating +fecundation +fecundations +fecundity +fed +fedayee +fedayeen +federacies +federacy +federal +federalism +federalist +federalists +federalization +federalizations +federalize +federalized +federalizes +federalizing +federally +federate +federated +federates +federating +federation +federations +federative +federatively +fedora +fedoras +feds +fee +feeble +feebleminded +feeblemindedly +feeblemindedness +feebleness +feebler +feeblest +feeblish +feebly +feed +feedback +feedbag +feedbags +feedbox +feedboxes +feeder +feeders +feedhole +feedholes +feeding +feedings +feedlot +feedlots +feeds +feedstock +feedstuff +feedthrough +feedthroughs +feeing +feel +feeler +feelers +feeling +feelingly +feelingness +feelings +feels +fees +feet +feetfirst +feeze +feezes +fehling +feign +feigned +feigner +feigners +feigning +feigns +feijoada +feint +feinted +feinting +feints +feirie +feist +feistier +feistiest +feistiness +feists +feisty +felafel +feldspar +feldspars +feldspathic +felicific +felicitate +felicitated +felicitates +felicitating +felicitation +felicitations +felicitator +felicitators +felicities +felicitous +felicitously +felicitousness +felicity +felid +felids +feline +felinely +felineness +felines +felinities +felinity +felix +fell +fellable +fellah +fellaheen +fellahin +fellate +fellated +fellates +fellating +fellatio +fellation +fellations +fellatios +fellator +fellators +felled +feller +fellers +fellies +felling +fellness +felloe +felloes +fellow +fellowly +fellowman +fellowmen +fellows +fellowship +fellowships +fells +felly +felon +felones +felonies +felonious +feloniously +feloniousness +felonries +felonry +felons +felony +felsic +felsite +felsites +felsitic +felspar +felspars +felt +felted +felting +feltings +felts +felty +felucca +feluccas +felwort +felworts +female +femaleness +females +feme +femes +feminine +femininely +feminineness +feminines +femininities +femininity +feminism +feminist +feministic +feminists +feminity +feminization +feminizations +feminize +feminized +feminizes +feminizing +femme +femmes +femora +femoral +femtoampere +femtoamperes +femtobecquerel +femtobecquerels +femtocandela +femtocandelas +femtocoulomb +femtocoulombs +femtofarad +femtofarads +femtogram +femtograms +femtohenries +femtohenry +femtohenrys +femtohertz +femtojoule +femtojoules +femtokelvin +femtokelvins +femtolumen +femtolumens +femtolux +femtometer +femtometers +femtomole +femtomoles +femtonewton +femtonewtons +femtoohm +femtoohms +femtopascal +femtopascals +femtoradian +femtoradians +femtosecond +femtoseconds +femtosiemens +femtosievert +femtosieverts +femtosteradian +femtosteradians +femtotesla +femtoteslas +femtovolt +femtovolts +femtowatt +femtowatts +femtoweber +femtowebers +femur +femurs +fen +fence +fenced +fenceless +fencelessness +fencer +fencerow +fencerows +fencers +fences +fencing +fend +fended +fender +fenders +fending +fends +fenestra +fenestrae +fenestral +fenestrate +fenestrated +fenestration +fenestrations +fenfluramine +feng +fenian +fenianism +fenians +fennec +fennecs +fennel +fenny +fens +fentanyl +fentanyls +fenugreek +fenuron +fenurons +feoffee +feoffees +feoffer +feoffers +feoffment +feoffments +feoffor +feoffors +fer +feral +ferbam +ferbams +ferdinand +fere +feres +feretories +feretory +feria +feriae +ferial +ferias +ferine +ferity +fermanagh +fermat +fermata +fermatas +ferment +fermentability +fermentable +fermentation +fermentations +fermentative +fermented +fermenter +fermenters +fermenting +ferments +fermi +fermion +fermions +fermis +fermium +fern +ferneries +fernery +fernier +ferniest +fernlike +ferns +ferny +ferocious +ferociously +ferociousness +ferocity +ferrara +ferrate +ferrates +ferredoxin +ferredoxins +ferret +ferreted +ferreter +ferreters +ferreting +ferretings +ferrets +ferrety +ferriage +ferriages +ferric +ferricyanide +ferricyanides +ferried +ferries +ferriferous +ferris +ferrite +ferrites +ferritic +ferritin +ferritins +ferroalloy +ferroalloys +ferroconcrete +ferrocyanide +ferrocyanides +ferroelectric +ferroelectricity +ferroelectrics +ferromagnesian +ferromagnet +ferromagnetic +ferromagnetism +ferromagnets +ferromanganese +ferrosilicon +ferrosilicons +ferrotype +ferrotypes +ferrous +ferruginous +ferrule +ferruled +ferrules +ferruling +ferry +ferryboat +ferryboats +ferrying +ferryman +ferrymen +fertile +fertilely +fertileness +fertilities +fertility +fertilizable +fertilization +fertilizational +fertilizations +fertilize +fertilized +fertilizer +fertilizers +fertilizes +fertilizing +ferula +ferulas +ferule +feruled +ferules +ferulic +feruling +fervencies +fervency +fervent +fervently +ferventness +fervid +fervidity +fervidly +fervidness +fervor +fervors +fescennine +fescue +fescues +fess +fesse +fessed +fesses +fessing +fest +festal +festally +fester +festered +festering +festers +festinate +festinated +festinately +festinates +festinating +festival +festivalgoer +festivalgoers +festivals +festive +festively +festiveness +festivities +festivity +festoon +festooned +festooneries +festoonery +festooning +festoons +fests +festschrift +festschriften +festschrifts +feta +fetal +fetch +fetched +fetcher +fetchers +fetches +fetching +fetchingly +fete +feted +feterita +feteritas +fetes +fetich +fetiches +fetichism +feticidal +feticide +feticides +fetid +fetidly +fetidness +feting +fetish +fetishes +fetishism +fetishist +fetishistic +fetishistically +fetishists +fetishize +fetishized +fetishizes +fetishizing +fetlock +fetlocks +fetologist +fetologists +fetology +fetoprotein +fetoproteins +fetor +fetors +fetoscope +fetoscopes +fetoscopy +fetter +fetterbush +fetterbushes +fettered +fettering +fetters +fettle +fettled +fettles +fettling +fettlings +fettuccine +fetus +fetuses +feu +feud +feudal +feudalism +feudalist +feudalistic +feudalists +feudalities +feudality +feudalization +feudalizations +feudalize +feudalized +feudalizes +feudalizing +feudally +feudatories +feudatory +feuded +feuding +feudist +feudists +feuds +feuilleton +feuilletonism +feuilletonist +feuilletonistic +feuilletonists +feuilletons +fever +fevered +feverfew +feverfews +fevering +feverish +feverishly +feverishness +feverous +fevers +feverweed +feverweeds +feverwort +feverworts +few +fewer +fewest +fewness +fewtrils +fey +feyly +feyness +feynman +fez +fezzes +fiacre +fiacres +fiancee +fiancees +fianchetti +fianchetto +fianchettoed +fianchettoing +fianchettos +fiancé +fiancée +fiancées +fiancés +fiaschi +fiasco +fiascoes +fiascos +fiat +fiats +fib +fibbed +fibber +fibbers +fibbing +fiber +fiberboard +fibered +fiberfill +fiberglass +fiberization +fiberizations +fiberize +fiberized +fiberizes +fiberizing +fibers +fiberscope +fiberscopes +fibonacci +fibranne +fibrannes +fibril +fibrillar +fibrillary +fibrillate +fibrillated +fibrillates +fibrillating +fibrillation +fibrillations +fibrillose +fibrils +fibrin +fibrinogen +fibrinogenic +fibrinogenically +fibrinogenous +fibrinogens +fibrinoid +fibrinoids +fibrinolyses +fibrinolysin +fibrinolysins +fibrinolysis +fibrinolytic +fibrinous +fibroblast +fibroblastic +fibroblasts +fibrocartilage +fibrocartilages +fibrocystic +fibroid +fibroids +fibroin +fibroins +fibroma +fibromas +fibromata +fibromatous +fibronectin +fibroplasia +fibroplastic +fibroses +fibrosis +fibrositis +fibrositises +fibrotic +fibrous +fibrously +fibrousness +fibrovascular +fibs +fibula +fibulae +fibular +fibulas +fiche +fiches +fichtelgebirge +fichu +fichus +ficin +fickle +fickleness +fickler +ficklest +fickly +fico +ficoes +fictile +fiction +fictional +fictionality +fictionalization +fictionalizations +fictionalize +fictionalized +fictionalizes +fictionalizing +fictionally +fictioneer +fictioneering +fictioneers +fictionist +fictionists +fictionization +fictionizations +fictionize +fictionized +fictionizes +fictionizing +fictions +fictitious +fictitiously +fictitiousness +fictive +fictively +fictiveness +ficus +ficuses +fid +fiddle +fiddleback +fiddled +fiddlehead +fiddleheads +fiddler +fiddlers +fiddles +fiddlestick +fiddlesticks +fiddling +fide +fideism +fideist +fideistic +fideists +fidelis +fidelities +fidelity +fides +fidge +fidged +fidges +fidget +fidgeted +fidgetiness +fidgeting +fidgets +fidgety +fidging +fido +fidos +fids +fiducial +fiducially +fiduciaries +fiduciary +fidus +fie +fief +fiefdom +fiefdoms +fiefs +field +fielded +fielder +fielders +fieldfare +fieldfares +fielding +fieldpiece +fieldpieces +fields +fieldsman +fieldsmen +fieldstone +fieldstrip +fieldstripped +fieldstripping +fieldstrips +fieldwork +fieldworker +fieldworkers +fiend +fiendish +fiendishly +fiendishness +fiends +fierce +fiercely +fierceness +fiercer +fiercest +fierier +fieriest +fierily +fieriness +fiery +fiesole +fiesta +fiestas +fife +fifer +fifers +fifes +fifo +fifteen +fifteenfold +fifteens +fifteenth +fifteenths +fifth +fifthly +fifths +fifties +fiftieth +fiftieths +fifty +fiftyfold +fiftyish +fig +figaro +fight +fightability +fightable +fighter +fighters +fighting +fightingly +fights +figment +figments +figs +figural +figurant +figurants +figuration +figurations +figurative +figuratively +figurativeness +figure +figured +figurehead +figureheads +figurer +figurers +figures +figurine +figurines +figuring +figwort +figworts +fiji +fijian +fijians +fila +filament +filamentary +filamentous +filaments +filar +filaree +filarees +filaria +filariae +filarial +filarian +filariases +filariasis +filariid +filariids +filature +filatures +filbert +filberts +filch +filched +filcher +filchers +filches +filching +filchner +file +filed +filefish +filefishes +filename +filenames +filer +filers +files +filet +filets +filial +filially +filiate +filiated +filiates +filiating +filiation +filiations +filibuster +filibustered +filibusterer +filibusterers +filibustering +filibusters +filiform +filigree +filigreed +filigreeing +filigrees +filing +filings +filiopietistic +filipina +filipinas +filipino +filipinos +filippo +fill +fille +filled +filler +fillers +fillet +filleted +filleting +fillets +fillies +filling +fillings +fillip +filliped +filliping +fillips +fills +filly +fillér +fillérs +film +filmcard +filmcards +filmdom +filmed +filmgoer +filmgoers +filmgoing +filmic +filmically +filmier +filmiest +filmily +filminess +filming +filmland +filmmaker +filmmakers +filmmaking +filmographer +filmographers +filmographies +filmography +films +filmset +filmsets +filmsetter +filmsetters +filmsetting +filmsettings +filmstrip +filmstrips +filmy +filoplume +filoplumes +filose +filovirus +filoviruses +fils +filter +filterability +filterable +filtered +filterer +filterers +filtering +filterless +filters +filth +filthier +filthiest +filthily +filthiness +filthy +filtrable +filtrate +filtrated +filtrates +filtrating +filtration +filtrations +filum +filé +fimbria +fimbriae +fimbrial +fimbriate +fimbriated +fimbriation +fimbriations +fin +finable +finagle +finagled +finagler +finaglers +finagles +finagling +final +finale +finales +finalist +finalists +finalities +finality +finalization +finalizations +finalize +finalized +finalizer +finalizers +finalizes +finalizing +finally +finals +finance +financeable +financed +finances +financial +financially +financials +financier +financiers +financing +finback +finbacks +finca +fincas +finch +finches +find +findable +finder +finders +finding +findings +finds +fine +fineable +fined +finely +fineness +finer +fineries +finery +fines +finespun +finesse +finessed +finesses +finessing +finest +finfish +finfishes +fingal +finger +fingerboard +fingerboards +fingerbreadth +fingerbreadths +fingered +fingerer +fingerers +fingering +fingerings +fingerless +fingerlike +fingerling +fingerlings +fingernail +fingernails +fingerpick +fingerpicked +fingerpicker +fingerpickers +fingerpicking +fingerpicks +fingerpost +fingerposts +fingerprint +fingerprinted +fingerprinting +fingerprints +fingers +fingerspell +fingerspelled +fingerspelling +fingerspells +fingertip +fingertips +finial +finials +finical +finically +finicalness +finickier +finickiest +finickiness +finicking +finicky +fining +finis +finish +finished +finisher +finishers +finishes +finishing +finisterre +finite +finitely +finiteness +finites +finitude +finitudes +fink +finked +finking +finks +finland +finlander +finlanders +finlandization +finlandize +finlandized +finlandizes +finlandizing +finlike +finn +finnan +finnbogadóttir +finned +finnic +finnier +finniest +finning +finnish +finns +finny +finocchio +finochio +finochios +fins +finsteraarhorn +fiord +fiords +fipple +fipples +fir +firdausi +firdusi +fire +fireable +firearm +firearms +fireball +fireballs +firebase +firebases +firebird +firebirds +fireboard +fireboards +fireboat +fireboats +firebomb +firebombed +firebomber +firebombers +firebombing +firebombs +firebox +fireboxes +firebrand +firebrands +firebrat +firebrats +firebreak +firebreaks +firebrick +firebricks +firebug +firebugs +fireclay +fireclays +firecracker +firecrackers +fired +firedamp +firedog +firedogs +firedrake +firedrakes +firefighter +firefighters +firefighting +firefights +fireflies +fireflood +fireflooding +firefloodings +firefloods +firefly +fireguard +fireguards +firehouse +firehouses +fireless +firelight +firelock +firelocks +fireman +firemen +firenze +fireplace +fireplaces +fireplug +fireplugs +firepower +fireproof +fireproofed +fireproofing +fireproofs +firer +firers +fires +fireside +firesides +firestone +firestones +firestorm +firestorms +firetrap +firetraps +firewall +firewalled +firewalling +firewalls +firewater +fireweed +fireweeds +firewood +firework +fireworks +firing +firings +firkin +firkins +firm +firma +firmament +firmamental +firmaments +firmed +firmer +firmest +firming +firmly +firmness +firms +firmware +firn +firns +firozabad +firry +firs +first +firstborn +firstborns +firstfruits +firsthand +firstling +firstlings +firstly +firsts +firth +firths +fisc +fiscal +fiscally +fiscs +fish +fishability +fishable +fishbone +fishbones +fishbowl +fishbowls +fishcake +fishcakes +fished +fisher +fisheries +fisherman +fishermen +fishers +fishery +fishes +fisheye +fisheyes +fishgig +fishgigs +fishhook +fishhooks +fishier +fishiest +fishily +fishiness +fishing +fishings +fishless +fishlike +fishmeal +fishmonger +fishmongers +fishnet +fishnets +fishplate +fishplates +fishpond +fishponds +fishtail +fishtailed +fishtailing +fishtails +fishway +fishways +fishwife +fishwives +fishy +fissile +fissility +fission +fissionability +fissionable +fissional +fissioned +fissioning +fissions +fissipalmate +fissiparous +fissiparously +fissiparousness +fissiped +fissipeds +fissure +fissured +fissures +fissuring +fist +fisted +fistfight +fistfights +fistful +fistfuls +fistic +fisticuffer +fisticuffers +fisticuffs +fisting +fistnote +fistnotes +fists +fistula +fistulae +fistular +fistulas +fistulous +fit +fitch +fitches +fitchet +fitchets +fitchew +fitchews +fitful +fitfully +fitfulness +fitly +fitment +fitments +fitness +fits +fitted +fitter +fitters +fittest +fitting +fittingly +fittingness +fittings +fitzgerald +five +fivefold +fiver +fivers +fives +fix +fixable +fixate +fixated +fixates +fixating +fixation +fixations +fixative +fixatives +fixe +fixed +fixedly +fixedness +fixer +fixers +fixes +fixing +fixings +fixities +fixity +fixture +fixtures +fizz +fizzed +fizzes +fizzier +fizziest +fizzing +fizzle +fizzled +fizzles +fizzling +fizzy +fjeld +fjelds +fjord +fjords +flab +flabbergast +flabbergasted +flabbergasting +flabbergastingly +flabbergasts +flabbier +flabbiest +flabbily +flabbiness +flabby +flabella +flabellate +flabelliform +flabellum +flaccid +flaccidity +flaccidly +flaccidness +flack +flacked +flackery +flacking +flacks +flacon +flacons +flag +flagella +flagellant +flagellantism +flagellants +flagellar +flagellate +flagellated +flagellates +flagellating +flagellation +flagellations +flagellator +flagellators +flagelliform +flagellin +flagellins +flagellum +flagellums +flageolet +flageolets +flagged +flagger +flaggers +flagging +flaggingly +flagitious +flagitiously +flagitiousness +flagman +flagmen +flagon +flagons +flagpole +flagpoles +flagrance +flagrancy +flagrant +flagrante +flagrantly +flags +flagship +flagships +flagstaff +flagstaffs +flagstick +flagsticks +flagstone +flagstones +flail +flailed +flailing +flails +flair +flairs +flak +flake +flaked +flaker +flakers +flakes +flakey +flakier +flakiest +flakily +flakiness +flaking +flaky +flam +flambeau +flambeaus +flambeaux +flamboyance +flamboyancy +flamboyant +flamboyantly +flamboyants +flambé +flambéed +flambéing +flambés +flame +flamed +flamen +flamenco +flamencos +flamens +flameout +flameouts +flameproof +flameproofed +flameproofer +flameproofers +flameproofing +flameproofs +flamer +flamers +flames +flamethrower +flamethrowers +flamier +flamiest +flamines +flaming +flamingly +flamingo +flamingoes +flamingos +flaminian +flammability +flammable +flammables +flams +flamy +flan +flanders +flange +flanged +flanges +flanging +flank +flanked +flanken +flankens +flanker +flankerback +flankerbacks +flankers +flanking +flanks +flannel +flannelette +flannelettes +flannelly +flannels +flans +flap +flapdoodle +flapdoodles +flapjack +flapjacks +flappable +flapped +flapper +flappers +flapping +flappy +flaps +flare +flareback +flarebacks +flared +flares +flaring +flaringly +flash +flashback +flashbacks +flashboard +flashboards +flashbulb +flashbulbs +flashcube +flashcubes +flashed +flasher +flashers +flashes +flashflood +flashfloods +flashgun +flashguns +flashier +flashiest +flashily +flashiness +flashing +flashings +flashlamp +flashlamps +flashlight +flashlights +flashover +flashovers +flashpoint +flashpoints +flashtube +flashtubes +flashy +flask +flasks +flat +flatbed +flatbeds +flatboat +flatboats +flatbottom +flatbottomed +flatbread +flatbreads +flatcar +flatcars +flatfeet +flatfish +flatfishes +flatfoot +flatfooted +flatfooting +flatfoots +flathead +flatheads +flatiron +flatirons +flatland +flatlander +flatlanders +flatlands +flatlet +flatlets +flatling +flatlings +flatly +flatness +flats +flatted +flatten +flattened +flattener +flatteners +flattening +flattens +flatter +flattered +flatterer +flatterers +flatteries +flattering +flatteringly +flatters +flattery +flattest +flatting +flattish +flattop +flattops +flatulence +flatulencies +flatulency +flatulent +flatulently +flatus +flatware +flatways +flatwise +flatwork +flatworks +flatworm +flatworms +flaubert +flaunt +flaunted +flaunter +flaunters +flauntier +flauntiest +flauntily +flauntiness +flaunting +flauntingly +flaunts +flaunty +flauta +flautas +flautist +flautists +flavanone +flavanones +flavescent +flavian +flavin +flavine +flavines +flavins +flavius +flavone +flavones +flavonoid +flavonoids +flavonol +flavonols +flavoprotein +flavoproteins +flavor +flavored +flavorer +flavorers +flavorful +flavorfully +flavoring +flavorings +flavorist +flavorists +flavorless +flavorous +flavors +flavorsome +flavory +flaw +flawed +flawing +flawless +flawlessly +flawlessness +flaws +flawy +flax +flaxen +flaxes +flaxier +flaxiest +flaxseed +flaxseeds +flaxy +flay +flayed +flayer +flayers +flaying +flays +flea +fleabag +fleabags +fleabane +fleabanes +fleabite +fleabites +fleapit +fleapits +fleas +fleawort +fleaworts +fleck +flecked +flecking +flecks +flection +flectional +flections +fled +fledermaus +fledge +fledged +fledgeling +fledgelings +fledges +fledging +fledgling +fledglings +flee +fleece +fleeced +fleecer +fleecers +fleeces +fleech +fleeched +fleeches +fleeching +fleecier +fleeciest +fleecily +fleeciness +fleecing +fleecy +fleeing +fleer +fleered +fleering +fleeringly +fleers +flees +fleet +fleeted +fleeter +fleetest +fleeting +fleetingly +fleetingness +fleetly +fleetness +fleets +fleishig +fleming +flemings +flemish +flense +flensed +flenser +flensers +flenses +flensing +flesh +fleshed +fleshes +fleshier +fleshiest +fleshiness +fleshing +fleshless +fleshlier +fleshliest +fleshliness +fleshly +fleshment +fleshpot +fleshpots +fleshy +fletch +fletched +fletcher +fletchers +fletches +fletching +fletschhorn +fleur +fleurs +fleury +flew +flews +flex +flexagon +flexagons +flexed +flexes +flexibilities +flexibility +flexible +flexibleness +flexibly +flexile +flexing +flexion +flexions +flexitime +flexitimes +flexographer +flexographers +flexographic +flexographically +flexography +flexor +flexors +flextime +flexuosity +flexuous +flexuously +flexural +flexure +flexures +fley +fleyed +fleying +fleys +flibbertigibbet +flibbertigibbets +flibbertigibbety +flic +flick +flickable +flicked +flicker +flickered +flickering +flickeringly +flickerings +flickers +flickertail +flickertails +flickery +flicking +flicks +flics +flied +flier +fliers +flies +flight +flighted +flightier +flightiest +flightily +flightiness +flighting +flightless +flights +flightworthiness +flightworthy +flighty +flimflam +flimflammed +flimflammer +flimflammers +flimflammery +flimflamming +flimflams +flimsier +flimsies +flimsiest +flimsily +flimsiness +flimsy +flinch +flinched +flincher +flinchers +flinches +flinching +flinchingly +flinders +fling +flinger +flingers +flinging +flings +flint +flinthead +flintheads +flintier +flintiest +flintily +flintiness +flintlike +flintlock +flintlocks +flints +flinty +flip +flipbook +flipbooks +flippancies +flippancy +flippant +flippantly +flipped +flipper +flippers +flippest +flipping +flips +flirt +flirtation +flirtations +flirtatious +flirtatiously +flirtatiousness +flirted +flirter +flirters +flirting +flirts +flirty +flit +flitch +flitches +flits +flitted +flitter +flittered +flittering +flitters +flitting +flivver +flivvers +float +floatable +floatage +floatages +floatation +floated +floater +floaters +floating +floatplane +floatplanes +floats +floaty +floc +floccose +flocculate +flocculated +flocculates +flocculating +flocculation +flocculations +floccule +flocculence +flocculences +flocculent +flocculently +floccules +flocculi +flocculus +flock +flocked +flocking +flocks +flocs +floe +floes +flog +flogged +flogger +floggers +flogging +floggings +flogs +flood +flooded +flooder +flooders +floodgate +floodgates +flooding +floodlight +floodlighted +floodlighting +floodlights +floodlit +floodplain +floodplains +floods +floodtide +floodtides +floodwall +floodwalls +floodwater +floodwaters +floodway +floodways +flooey +floor +floorage +floorages +floorboard +floorboards +floored +floorer +floorers +flooring +floorings +floors +floorshow +floorshows +floorwalker +floorwalkers +floozie +floozies +floozy +flop +flophouse +flophouses +flopped +flopper +floppers +floppier +floppies +floppiest +floppily +floppiness +flopping +floppy +flops +flora +florae +floral +florally +floras +floreated +florence +florentine +florentines +flores +florescence +florescent +floret +florets +floriated +floriation +floriations +floribunda +floribundas +floricane +floricanes +floricultural +floriculturally +floriculture +floriculturist +floriculturists +florid +florida +floridan +floridans +floridean +floridian +floridians +floridity +floridly +floridness +floriferous +floriferously +floriferousness +florigen +florigenic +florigens +florilegia +florilegium +florin +florins +florist +floristic +floristically +floristics +floristry +florists +floruit +floruits +floss +flossed +flosser +flossers +flosses +flossier +flossiest +flossily +flossiness +flossing +flossy +flota +flotage +flotages +flotas +flotation +flotilla +flotillas +flotsam +flotta +flounce +flounced +flounces +flouncing +flouncings +flouncy +flounder +floundered +floundering +flounders +flour +floured +flouring +flourish +flourished +flourisher +flourishers +flourishes +flourishing +flourishingly +flours +floury +flout +flouted +flouter +flouters +flouting +floutingly +flouts +flow +flowage +flowages +flowchart +flowcharted +flowcharting +flowcharts +flowed +flower +flowerage +flowerages +flowerbed +flowerbeds +flowered +flowerer +flowerers +floweret +flowerets +flowerful +flowerier +floweriest +floweriness +flowering +flowerless +flowerlike +flowerpot +flowerpots +flowers +flowery +flowing +flowingly +flowmeter +flowmeters +flown +flows +flowstone +flowstones +flu +flub +flubbed +flubber +flubbers +flubbing +flubdub +flubdubs +flubs +fluctuant +fluctuate +fluctuated +fluctuates +fluctuating +fluctuation +fluctuational +fluctuations +flue +fluegelhorn +fluegelhorns +fluency +fluent +fluently +flueric +fluerics +flues +fluff +fluffed +fluffier +fluffiest +fluffily +fluffiness +fluffing +fluffs +fluffy +fluid +fluidal +fluidally +fluidextract +fluidextracts +fluidic +fluidics +fluidified +fluidifies +fluidify +fluidifying +fluidities +fluidity +fluidization +fluidizations +fluidize +fluidized +fluidizer +fluidizers +fluidizes +fluidizing +fluidly +fluidness +fluidram +fluidrams +fluids +fluke +flukes +flukey +flukier +flukiest +flukily +flukiness +fluky +flulike +flume +flumes +flummeries +flummery +flummox +flummoxed +flummoxes +flummoxing +flump +flumped +flumping +flumps +flung +flunk +flunked +flunker +flunkers +flunkey +flunkeys +flunkies +flunking +flunkout +flunkouts +flunks +flunky +flunkyism +fluor +fluoresce +fluoresced +fluorescein +fluoresceins +fluorescence +fluorescent +fluorescents +fluorescer +fluorescers +fluoresces +fluorescing +fluoridate +fluoridated +fluoridates +fluoridating +fluoridation +fluoridations +fluoride +fluorides +fluorimeter +fluorimeters +fluorimetric +fluorimetry +fluorinate +fluorinated +fluorinates +fluorinating +fluorination +fluorinations +fluorine +fluorite +fluorites +fluorocarbon +fluorocarbons +fluorochemical +fluorochemicals +fluorochrome +fluorochromes +fluorography +fluorometer +fluorometers +fluorometry +fluoroscope +fluoroscoped +fluoroscopes +fluoroscopic +fluoroscopically +fluoroscopies +fluoroscoping +fluoroscopist +fluoroscopists +fluoroscopy +fluorosis +fluorotic +fluorouracil +fluorouracils +fluors +fluorspar +fluorspars +fluphenazine +fluphenazines +flurazepam +flurazepams +flurried +flurries +flurry +flurrying +flush +flushable +flushed +flusher +flushers +flushes +flushest +flushing +flushless +flushness +flushometer +flushometers +fluster +flustered +flustering +flusters +flute +fluted +flutelike +fluter +fluters +flutes +flutey +fluting +flutings +flutist +flutists +flutter +flutterboard +flutterboards +fluttered +flutterer +flutterers +fluttering +flutters +fluttery +fluty +fluvial +fluviatile +fluviomarine +flux +fluxed +fluxes +fluxing +fluxion +fluxional +fluxionally +fluxionary +fluxions +fly +flyable +flyaway +flyaways +flyblew +flyblow +flyblowing +flyblown +flyblows +flyboat +flyboats +flyboy +flyboys +flyby +flybys +flycatcher +flycatchers +flyer +flyers +flying +flyings +flyleaf +flyleaves +flyman +flymen +flyover +flyovers +flypaper +flypapers +flypast +flypasts +flysch +flysches +flysheet +flysheets +flyspeck +flyspecked +flyspecking +flyspecks +flyswatter +flyswatters +flytrap +flytraps +flyway +flyways +flyweight +flyweights +flywheel +flywheels +flywhisk +flywhisks +flânerie +flâneur +flâneurs +fléchette +flèche +flèches +flügelhorn +flügelhornist +flügelhornists +flügelhorns +fo +fo'c +fo'c'sle +fo'c'sles +foal +foaled +foaling +foals +foam +foamed +foamer +foamers +foamflower +foamflowers +foamier +foamiest +foamily +foaminess +foaming +foamless +foams +foamy +fob +fobbed +fobbing +fobs +focal +focalization +focalizations +focalize +focalized +focalizes +focalizing +focally +fochabers +foci +focus +focusable +focused +focuser +focusers +focuses +focusing +focusless +focussed +focusses +focussing +fodder +foddered +foddering +fodders +fodgel +foe +foehn +foehns +foeman +foemen +foes +foetal +foetid +foetidus +foetor +foetors +foetus +fog +fogbound +fogbow +fogbows +fogdog +fogdogs +fogey +fogeys +foggage +foggages +fogged +fogger +foggers +foggier +foggiest +foggily +fogginess +fogging +foggy +foghorn +foghorns +fogies +fogless +fogs +fogy +fogyish +fogyism +fogyisms +foible +foibles +foil +foiled +foiling +foils +foilsman +foilsmen +foin +foined +foining +foins +foison +foisons +foist +foisted +foisting +foists +fokker +folacin +folacins +folate +folates +fold +foldable +foldaway +foldaways +foldboat +foldboats +folded +folder +folderol +folderols +folders +folding +foldout +foldouts +folds +foldup +foldups +folia +foliaceous +foliage +foliaged +foliages +foliar +foliate +foliated +foliates +foliating +foliation +foliations +folic +folie +foliicolous +folio +folioed +folioing +folios +foliose +folium +folk +folkie +folkier +folkies +folkiest +folkish +folkishly +folkishness +folklike +folklore +folkloric +folklorish +folklorist +folkloristic +folkloristics +folklorists +folkmoot +folkmoots +folkmote +folkmotes +folks +folksier +folksiest +folksily +folksiness +folksinger +folksingers +folksinging +folksong +folksongs +folksy +folktale +folktales +folkway +folkways +folky +follicle +follicles +follicular +folliculate +folliculated +folliculitis +follies +follow +followed +follower +followers +followership +followerships +following +followings +follows +followup +followups +folly +folsom +fomalhaut +foment +fomentation +fomentations +fomented +fomenter +fomenters +fomenting +foments +fomite +fomites +fon +fond +fondant +fondants +fonder +fondest +fondle +fondled +fondler +fondlers +fondles +fondling +fondly +fondness +fondnesses +fonds +fondu +fondue +fondued +fondues +fonduing +fondus +fongafale +fons +fonseca +font +fontainebleau +fontal +fontanel +fontanelle +fontanelles +fontanels +fontenoy +fonteyn +fontina +fontinas +fonts +food +foodie +foodies +foodless +foodlessness +foods +foodservices +foodstuff +foodstuffs +foodways +foofaraw +foofaraws +fool +fooled +fooleries +foolery +foolhardier +foolhardiest +foolhardily +foolhardiness +foolhardy +fooling +foolings +foolish +foolishly +foolishness +foolproof +fools +foolscap +foolscaps +foon +foons +foot +footage +footages +football +footballer +footballers +footballs +footbath +footbaths +footboard +footboards +footboy +footboys +footbridge +footbridges +footcloth +footcloths +footed +footedly +footer +footers +footfall +footfalls +footgear +foothill +foothills +foothold +footholds +footing +footings +footle +footled +footler +footlers +footles +footless +footlessly +footlessness +footlight +footlights +footling +footlocker +footlockers +footlong +footloose +footman +footmark +footmarks +footmen +footnote +footnoted +footnotes +footnoting +footpace +footpaces +footpad +footpads +footpath +footpaths +footprint +footprinting +footprints +footrace +footraces +footracing +footrest +footrests +footrope +footropes +foots +footsie +footslog +footslogged +footslogger +footsloggers +footslogging +footslogs +footsore +footsoreness +footstalk +footstalks +footstall +footstalls +footstep +footsteps +footstone +footstones +footstool +footstools +footsy +footwall +footwalls +footway +footways +footwear +footwork +foozle +foozled +foozler +foozlers +foozles +foozling +fop +fopped +fopperies +foppery +fopping +foppish +foppishly +foppishness +fops +for +fora +forage +foraged +forager +foragers +forages +foraging +foraker +foram +foramen +foramens +foramina +foraminal +foraminifer +foraminifera +foraminiferal +foraminiferan +foraminiferous +foraminifers +foraminous +forams +forasmuch +foray +forayed +forayer +forayers +foraying +forays +forb +forbad +forbade +forbear +forbearance +forbearer +forbearers +forbearing +forbears +forbid +forbiddance +forbidden +forbidder +forbidders +forbidding +forbiddingly +forbiddingness +forbids +forbore +forborne +forbs +forby +forbye +force +forceable +forced +forcedly +forceful +forcefully +forcefulness +forceless +forcemeat +forceps +forcepslike +forcer +forcers +forces +forcible +forcibleness +forcibly +forcing +forcipate +forcipes +ford +fordable +forded +fordid +fording +fordo +fordoes +fordoing +fordone +fords +fore +forearm +forearmed +forearming +forearms +forebay +forebays +forebear +forebears +forebode +foreboded +foreboder +foreboders +forebodes +foreboding +forebodingly +forebodingness +forebodings +forebrain +forebrains +forecaddie +forecaddies +forecast +forecastable +forecasted +forecaster +forecasters +forecasting +forecastle +forecastles +forecasts +foreclosable +foreclose +foreclosed +forecloses +foreclosing +foreclosure +foreclosures +forecourt +forecourts +foredeck +foredecks +foredid +foredo +foredoes +foredoing +foredone +foredoom +foredoomed +foredooming +foredooms +foreface +forefaces +forefather +forefathers +forefeel +forefeeling +forefeels +forefeet +forefelt +forefend +forefended +forefending +forefends +forefinger +forefingers +forefoot +forefront +foregather +foregathered +foregathering +foregathers +forego +foregoer +foregoers +foregoes +foregoing +foregone +foreground +foregrounds +foregut +foreguts +forehand +forehanded +forehandedly +forehandedness +forehands +forehead +foreheads +forehoof +foreign +foreigner +foreigners +foreignism +foreignisms +foreignness +forejudge +forejudged +forejudges +forejudging +forejudgment +forejudgments +foreknew +foreknow +foreknowing +foreknowledge +foreknown +foreknows +foreladies +forelady +foreland +forelands +foreleg +forelegs +forelimb +forelimbs +forelock +forelocks +foreman +foremanship +foremast +foremasts +foremen +foremilk +foremost +foremother +foremothers +forename +forenamed +forenames +forenoon +forenoons +forensic +forensically +forensics +foreordain +foreordained +foreordaining +foreordainment +foreordainments +foreordains +foreordination +foreordinations +forepart +foreparts +forepassed +forepast +forepaw +forepaws +forepeak +forepeaks +foreperson +forepersons +foreplay +forequarter +forequarters +foreran +forereach +forereached +forereaches +forereaching +forerun +forerunner +forerunners +forerunning +foreruns +foresaid +foresail +foresails +foresaw +foresee +foreseeability +foreseeable +foreseeing +foreseen +foreseer +foreseers +foresees +foreshadow +foreshadowed +foreshadower +foreshadowers +foreshadowing +foreshadows +foreshank +foresheet +foresheets +foreshock +foreshocks +foreshore +foreshores +foreshorten +foreshortened +foreshortening +foreshortens +foreshow +foreshowed +foreshowing +foreshown +foreshows +foreside +foresides +foresight +foresighted +foresightedly +foresightedness +foresightful +foreskin +foreskins +forespeak +forespeaking +forespeaks +forespoke +forespoken +forest +forestage +forestages +forestal +forestall +forestalled +forestaller +forestallers +forestalling +forestallment +forestalls +forestation +forestations +forestay +forestays +forestaysail +forestaysails +forested +forester +foresters +forestial +foresting +forestland +forestlands +forestry +forests +foretaste +foretasted +foretastes +foretasting +foretell +foreteller +foretellers +foretelling +foretells +forethought +forethoughtful +forethoughtfully +forethoughtfulness +forethoughts +foretime +foretimes +foretoken +foretokened +foretokening +foretokens +foretold +foretop +foretopgallant +foretopmast +foretopmasts +foretops +foretopsail +foretopsails +forever +forevermore +foreverness +forewarn +forewarned +forewarning +forewarnings +forewarns +forewent +forewing +forewings +forewoman +forewomen +foreword +forewords +foreworn +foreyard +foreyards +forfeit +forfeitable +forfeited +forfeiter +forfeiters +forfeiting +forfeits +forfeiture +forfeitures +forfend +forfended +forfending +forfends +forficate +forgather +forgathered +forgathering +forgathers +forgave +forge +forgeability +forgeable +forged +forger +forgeries +forgers +forgery +forges +forget +forgetful +forgetfully +forgetfulness +forgetive +forgets +forgettable +forgetter +forgetters +forgetting +forging +forgings +forgivable +forgivably +forgive +forgiven +forgiveness +forgiver +forgivers +forgives +forgiving +forgivingly +forgivingness +forgo +forgoer +forgoers +forgoes +forgoing +forgone +forgot +forgotten +forint +forints +fork +forkball +forkballer +forkballers +forkballs +forked +forker +forkers +forkful +forkfuls +forkier +forkiest +forking +forklift +forklifted +forklifting +forklifts +forks +forky +forlorn +forlornly +forlornness +form +forma +formability +formable +formal +formaldehyde +formalin +formalins +formalism +formalisms +formalist +formalistic +formalistically +formalists +formalities +formality +formalizable +formalization +formalizations +formalize +formalized +formalizer +formalizers +formalizes +formalizing +formally +formalness +formals +formalwear +formant +formants +format +formate +formates +formation +formational +formations +formative +formatively +formativeness +formatives +formats +formatted +formatter +formatters +formatting +forme +formed +formee +former +formerly +formers +formes +formfeed +formfeeds +formfitting +formful +formic +formica +formicaries +formicary +formicivorous +formidability +formidable +formidableness +formidably +forming +formless +formlessly +formlessness +formosa +forms +formula +formulae +formulaic +formulaically +formularies +formularization +formularizations +formularize +formularized +formularizer +formularizers +formularizes +formularizing +formulary +formulas +formulate +formulated +formulates +formulating +formulation +formulations +formulator +formulators +formulization +formulizations +formulize +formulized +formulizer +formulizers +formulizes +formulizing +formwork +formworks +formyl +formyls +fornax +fornicate +fornicated +fornicates +fornicating +fornication +fornications +fornicator +fornicators +fornices +fornix +forrader +forrarder +forsake +forsaken +forsakes +forsaking +forsook +forsooth +forspent +forswear +forswearer +forswearers +forswearing +forswears +forswore +forsworn +forsythia +forsythias +fort +fortalice +fortalices +forte +fortes +forth +forthcoming +forthcomings +forthright +forthrightly +forthrightness +forthwith +forties +fortieth +fortieths +fortifiable +fortification +fortifications +fortified +fortifier +fortifiers +fortifies +fortify +fortifying +fortifyingly +fortiori +fortis +fortises +fortissimo +fortissimos +fortississimo +fortitude +fortitudinous +fortnight +fortnightlies +fortnightly +fortnights +fortran +fortress +fortresses +fortresslike +forts +fortuities +fortuitous +fortuitously +fortuitousness +fortuity +fortuna +fortunate +fortunately +fortunateness +fortunates +fortune +fortuned +fortunes +fortuneteller +fortunetellers +fortunetelling +fortuning +forty +fortyfold +fortyish +forum +forums +forward +forwarded +forwarder +forwarders +forwarding +forwardly +forwardness +forwards +forwent +forworn +forzando +forzandos +foss +fossa +fossae +fossate +fosse +fosses +fossick +fossicked +fossicker +fossickers +fossicking +fossicks +fossil +fossiliferous +fossilization +fossilizations +fossilize +fossilized +fossilizes +fossilizing +fossils +fossorial +foster +fosterage +fostered +fosterer +fosterers +fostering +fosterling +fosterlings +fosters +fou +foucault +foudroyant +fought +foul +foulard +foulards +foulbrood +foulbroods +fouled +fouler +foulest +fouling +foully +foulmouthed +foulness +fouls +found +foundation +foundational +foundationally +foundationless +foundations +founded +founder +foundered +foundering +founders +founding +foundling +foundlings +foundries +foundry +founds +fount +fountain +fountained +fountainhead +fountainheads +fountaining +fountains +founts +four +fourchee +fourchette +fourchettes +fourdrinier +fourdriniers +fourfold +fourgon +fourgons +fourhanded +fourier +fourierism +fourierist +fourierists +fourierite +fourierites +fourpenny +fourragère +fours +fourscore +foursome +foursomes +foursquare +foursquarely +fourteen +fourteenfold +fourteens +fourteenth +fourteenths +fourth +fourthly +fourths +fovea +foveae +foveal +foveate +foveiform +foveola +foveolae +foveolas +fowl +fowled +fowler +fowlers +fowling +fowls +fox +foxed +foxes +foxfire +foxfires +foxglove +foxgloves +foxhole +foxholes +foxhound +foxhounds +foxhunt +foxhunted +foxhunter +foxhunters +foxhunting +foxhunts +foxier +foxiest +foxily +foxiness +foxing +foxtail +foxtails +foxtrot +foxtrots +foxtrotted +foxtrotting +foxy +foy +foyer +foyers +foyle +foys +fra +fracas +fracases +fractal +fractals +fracted +fraction +fractional +fractionalization +fractionalizations +fractionalize +fractionalized +fractionalizes +fractionalizing +fractionally +fractionate +fractionated +fractionates +fractionating +fractionation +fractionations +fractionator +fractionators +fractionization +fractionizations +fractionize +fractionized +fractionizes +fractionizing +fractions +fractious +fractiously +fractiousness +fractur +fracture +fractured +fractures +fracturing +fracturs +frae +frag +fragged +fragger +fraggers +fragging +fragile +fragilely +fragileness +fragilities +fragility +fragment +fragmental +fragmentally +fragmentarily +fragmentariness +fragmentary +fragmentate +fragmentated +fragmentates +fragmentating +fragmentation +fragmentations +fragmented +fragmenting +fragmentize +fragmentized +fragmentizer +fragmentizers +fragmentizes +fragmentizing +fragments +fragonard +fragrance +fragrances +fragrancy +fragrant +fragrantly +frags +fraidy +frail +frailer +frailest +frailly +frailness +frailties +frailty +fraise +fraises +fraktur +frakturs +framable +frambesia +frambesias +frame +frameable +framed +framer +framers +frames +frameshift +framework +frameworks +framing +framingham +framings +franc +franca +francas +france +franchise +franchised +franchisee +franchisees +franchiser +franchisers +franchises +franchising +franchisor +franchisors +francis +franciscan +franciscans +francisco +francium +franco +francolin +francolins +franconia +franconian +franconians +francophile +francophiles +francophilia +francophobe +francophobes +francophobia +francophobic +francophone +francophones +francophonic +francs +frangibility +frangible +frangibleness +frangipane +frangipani +frangipanis +franglais +frank +franked +frankenstein +frankenstein's +frankensteinian +frankensteins +franker +frankers +frankest +frankfort +frankforter +frankforters +frankfurt +frankfurter +frankfurters +frankincense +franking +frankish +franklin +franklinite +franklinites +franklins +frankly +frankness +frankpledge +frankpledges +franks +franseria +franserias +frantic +frantically +franticly +franticness +française +frap +frappe +frapped +frappes +frapping +frappé +frappés +fraps +fraser +frat +fraternal +fraternalism +fraternally +fraternities +fraternity +fraternization +fraternizations +fraternize +fraternized +fraternizer +fraternizers +fraternizes +fraternizing +fratricidal +fratricide +fratricides +frats +frau +fraud +frauds +fraudulence +fraudulent +fraudulently +fraudulentness +frauen +fraught +fraughted +fraughting +fraughts +fraunhofer +fraxinella +fraxinellas +fray +frayed +fraying +frays +frazzle +frazzled +frazzles +frazzling +freak +freaked +freakier +freakiest +freakily +freakiness +freaking +freakish +freakishly +freakishness +freaks +freaky +freckle +freckled +freckles +freckling +freckly +frederick +fredericton +free +freebase +freebased +freebaser +freebasers +freebases +freebasing +freebee +freebees +freebie +freebies +freeboard +freeboards +freeboot +freebooted +freebooter +freebooters +freebooting +freeboots +freeborn +freed +freedman +freedmen +freedom +freedoms +freedwoman +freedwomen +freeform +freehand +freehanded +freehandedly +freehandedness +freehearted +freeheartedly +freeheartedness +freehold +freeholder +freeholders +freeholds +freeing +freelance +freelanced +freelancer +freelancers +freelances +freelancing +freeload +freeloaded +freeloader +freeloaders +freeloading +freeloads +freely +freeman +freemartin +freemartins +freemason +freemasonry +freemasons +freemen +freeness +freeport +freer +freers +frees +freesia +freesias +freest +freestanding +freestone +freestones +freestyle +freestyles +freethinker +freethinkers +freethinking +freetown +freeware +freeway +freeways +freewheel +freewheeled +freewheeler +freewheelers +freewheeling +freewheelingly +freewheels +freewill +freezable +freeze +freezer +freezers +freezes +freezing +freiberg +freiburg +freight +freightage +freighted +freighter +freighters +freighting +freightliner +freightliners +freights +fremantle +fremitus +fremontia +fremontias +frena +french +frenched +frenches +frenchification +frenchified +frenchifies +frenchify +frenchifying +frenching +frenchman +frenchmen +frenchness +frenchwoman +frenchwomen +frenetic +frenetical +frenetically +freneticism +frenula +frenulum +frenum +frenums +frenzied +frenziedly +frenzies +frenzy +frenzying +freon +frequence +frequences +frequencies +frequency +frequent +frequentation +frequentations +frequentative +frequentatives +frequented +frequenter +frequenters +frequenting +frequently +frequentness +frequents +fresco +frescoed +frescoer +frescoers +frescoes +frescoing +frescoist +frescoists +frescos +fresh +freshen +freshened +freshener +fresheners +freshening +freshens +fresher +freshest +freshet +freshets +freshly +freshman +freshmen +freshness +freshwater +fresnel +fresno +fret +fretful +fretfully +fretfulness +fretless +frets +fretsaw +fretsaws +fretted +fretter +fretters +fretting +fretwork +freud +freudian +freudianism +freudians +frey +freya +freyr +friability +friable +friableness +friar +friarbird +friarbirds +friaries +friarly +friars +friary +fribble +fribbled +fribbler +fribblers +fribbles +fribbling +fribourg +fricandeau +fricandeaus +fricassee +fricasseed +fricasseeing +fricassees +fricative +fricatives +friction +frictional +frictionally +frictionless +frictionlessly +frictions +friday +fridays +fridge +fridges +fried +friedland +friedrichshafen +friend +friended +friending +friendless +friendlessness +friendlier +friendlies +friendliest +friendlily +friendliness +friendly +friends +friendship +friendships +frier +friers +fries +friesian +friesians +friesland +frieze +friezes +frig +frigate +frigates +frigg +frigga +frigged +frigging +fright +frighted +frighten +frightened +frightener +frighteners +frightening +frighteningly +frightens +frightful +frightfully +frightfulness +frighting +frights +frigid +frigidaire +frigidities +frigidity +frigidly +frigidness +frigorific +frigorifical +frigs +frijol +frijole +frijoles +frill +frilled +frillier +frilliest +frilliness +frilling +frills +frilly +fringe +fringed +fringes +fringing +fringy +fripperies +frippery +frisbee +frisbees +frisch +frisette +frisettes +friseur +friseurs +frisian +frisians +frisk +frisked +frisker +friskers +frisket +friskets +friskier +friskiest +friskily +friskiness +frisking +frisks +frisky +frisson +frissons +frisé +frisée +frit +frith +friths +fritillaries +fritillary +frits +frittata +frittatas +fritted +fritter +frittered +fritterer +fritterers +frittering +fritters +fritting +fritz +fritzes +friuli +frivol +frivoled +frivoler +frivolers +frivoling +frivolities +frivolity +frivolled +frivoller +frivollers +frivolling +frivolous +frivolously +frivolousness +frivols +frizette +frizettes +frizz +frizzed +frizzer +frizzers +frizzes +frizzier +frizziest +frizzily +frizziness +frizzing +frizzle +frizzled +frizzles +frizzlier +frizzliest +frizzling +frizzly +frizzy +fro +frobenius +frobisher +frock +frocked +frocking +frocks +froe +froebel +froes +frog +frogeye +frogeyes +frogfish +frogfishes +froghopper +froghoppers +frogman +frogmen +frogmouth +frogmouths +frogs +froissart +frolic +frolicked +frolicker +frolickers +frolicking +frolics +frolicsome +from +frond +fronded +frondescence +frondescent +frondeur +frondeurs +frondose +frondosely +fronds +frons +front +frontage +frontages +frontal +frontality +frontally +frontals +frontcourt +frontcourts +fronted +frontenis +frontes +frontier +frontiers +frontiersman +frontiersmen +frontierswoman +frontierswomen +fronting +frontispiece +frontispieces +frontless +frontlet +frontlets +frontline +frontogeneses +frontogenesis +frontolyses +frontolysis +fronton +frontons +frontrunner +frontrunners +fronts +frontward +frontwards +frore +frosh +froshes +frost +frostbelt +frostbit +frostbite +frostbites +frostbiting +frostbitten +frosted +frostfish +frostfishes +frostier +frostiest +frostily +frostiness +frosting +frostings +frosts +frostwork +frostworks +frosty +froth +frothed +frothier +frothiest +frothily +frothiness +frothing +froths +frothy +frottage +frottages +froufrou +froufrous +frow +froward +frowardly +frowardness +frown +frowned +frowner +frowners +frowning +frowningly +frowns +frows +frowsier +frowsiest +frowstier +frowstiest +frowsty +frowsy +frowzier +frowziest +frowziness +frowzy +froze +frozen +frozenly +frozenness +fructiferous +fructification +fructifications +fructified +fructifies +fructify +fructifying +fructose +fructuous +frugal +frugalities +frugality +frugally +frugalness +frugivore +frugivores +frugivorous +fruit +fruitage +fruitages +fruitarian +fruitarians +fruitcake +fruitcakes +fruited +fruiterer +fruiterers +fruitful +fruitfully +fruitfulness +fruitier +fruitiest +fruitiness +fruiting +fruition +fruitions +fruitless +fruitlessly +fruitlessness +fruitlet +fruitlets +fruits +fruitwood +fruitwoods +fruity +frumentaceous +frumenties +frumenty +frump +frumpier +frumpiest +frumpily +frumpiness +frumpish +frumpishly +frumpishness +frumps +frumpy +frusta +frustrate +frustrated +frustrater +frustraters +frustrates +frustrating +frustratingly +frustration +frustrations +frustule +frustules +frustum +frustums +frutescence +frutescent +fruticose +fry +fryer +fryers +frying +fräulein +fräuleins +ftp +fu +fubsier +fubsiest +fubsy +fuchsia +fuchsias +fuchsin +fuchsine +fuchsines +fuchsins +fuck +fucked +fucker +fuckers +fucking +fucks +fuckup +fuckups +fucoid +fucoids +fucose +fucoses +fucoxanthin +fucoxanthins +fucus +fucuses +fud +fuddle +fuddled +fuddles +fuddling +fudge +fudged +fudges +fudging +fuds +fuego +fuehrer +fuehrers +fuel +fueled +fueler +fuelers +fueling +fuelled +fuelling +fuels +fuertaventura +fuerteventura +fug +fugacious +fugaciously +fugaciousness +fugacities +fugacity +fugal +fugally +fugged +fugging +fuggy +fugit +fugitive +fugitively +fugitiveness +fugitives +fugle +fugled +fugleman +fuglemen +fugles +fugling +fugs +fugu +fugue +fugued +fugues +fuguing +fuguist +fuguists +fugus +fuissé +fujairah +fuji +fujian +fujinoyama +fujis +fujisan +fujisawa +fukien +fula +fulani +fulanis +fulas +fulbright +fulcra +fulcrum +fulcrums +fulfil +fulfill +fulfilled +fulfiller +fulfillers +fulfilling +fulfillment +fulfillments +fulfills +fulfilment +fulfils +fulgent +fulgently +fulgurant +fulgurate +fulgurated +fulgurates +fulgurating +fulguration +fulgurations +fulgurite +fulgurites +fulgurous +fulham +fulhams +fuliginous +fuliginously +full +fullback +fullbacks +fulled +fuller +fullerene +fullerenes +fullers +fullest +fulling +fullmouthed +fullness +fulls +fulltime +fully +fulmar +fulmars +fulminant +fulminate +fulminated +fulminates +fulminating +fulmination +fulminations +fulminator +fulminators +fulminatory +fulmine +fulmined +fulmines +fulminic +fulmining +fulness +fulsome +fulsomely +fulsomeness +fulvous +fumarase +fumarases +fumarate +fumarates +fumaric +fumarole +fumaroles +fumarolic +fumatoria +fumatories +fumatorium +fumatoriums +fumatory +fumble +fumbled +fumbler +fumblers +fumbles +fumbling +fumblingly +fume +fumed +fumes +fumet +fumets +fumier +fumiest +fumigant +fumigants +fumigate +fumigated +fumigates +fumigating +fumigation +fumigations +fumigator +fumigators +fuming +fumitories +fumitory +fumy +fun +funafuti +funambulism +funambulist +funambulists +funchal +function +functional +functionalism +functionalist +functionalistic +functionalists +functionalities +functionality +functionally +functionaries +functionary +functioned +functioning +functionless +functions +functor +functors +fund +fundable +fundament +fundamental +fundamentalism +fundamentalist +fundamentalistic +fundamentalists +fundamentally +fundamentals +fundaments +funded +fundi +fundic +funding +fundraise +fundraised +fundraiser +fundraisers +fundraises +fundraising +funds +fundus +funeral +funerals +funerary +funereal +funereally +funfair +funfairs +funfest +funfests +fungal +fungi +fungibility +fungible +fungibles +fungicidal +fungicidally +fungicide +fungicides +fungiform +fungistat +fungistats +fungivorous +fungo +fungoes +fungoid +fungoids +fungous +fungus +funguses +funicle +funicles +funicular +funiculars +funiculi +funiculus +funk +funked +funkia +funkias +funkier +funkiest +funkiness +funking +funks +funky +funned +funnel +funneled +funnelform +funneling +funnelled +funnelling +funnels +funnier +funnies +funniest +funnily +funniness +funning +funny +funnyman +funnymen +funs +fur +furan +furane +furanes +furanose +furanoses +furans +furbearer +furbearers +furbearing +furbelow +furbelowed +furbelowing +furbelows +furbish +furbished +furbisher +furbishers +furbishes +furbishing +furcate +furcated +furcately +furcates +furcating +furcation +furcations +furcula +furculae +furcular +furfur +furfuraceous +furfural +furfurals +furfuran +furfurans +furfures +furies +furioso +furious +furiously +furl +furled +furless +furling +furlong +furlongs +furlough +furloughed +furloughing +furloughs +furls +furmities +furmity +furnace +furnaces +furnish +furnished +furnisher +furnishers +furnishes +furnishing +furnishings +furniture +furor +furore +furores +furors +furosemide +furosemides +furred +furrier +furrieries +furriers +furriery +furriest +furriner +furriners +furriness +furring +furrings +furrow +furrowed +furrowing +furrows +furry +furs +further +furtherance +furthered +furtherer +furtherers +furthering +furthermore +furthermost +furthers +furthest +furtive +furtively +furtiveness +furuncle +furuncles +furuncular +furunculosis +furunculous +fury +furze +furzes +furzy +fusain +fusains +fusaria +fusarium +fuscous +fuse +fused +fusee +fusees +fusel +fuselage +fuselages +fusels +fuser +fusers +fuses +fusibility +fusible +fusibleness +fusiform +fusil +fusile +fusileer +fusileers +fusilier +fusiliers +fusillade +fusilladed +fusillades +fusillading +fusils +fusing +fusion +fusionism +fusionist +fusionists +fusions +fuss +fussbudget +fussbudgets +fussbudgety +fussed +fusser +fussers +fusses +fussier +fussiest +fussily +fussiness +fussing +fusspot +fusspots +fussy +fustian +fustians +fustic +fustics +fustier +fustiest +fustigate +fustigated +fustigates +fustigating +fustigation +fustigations +fustily +fustiness +fusty +fusuma +futhark +futharks +futhorc +futhork +futile +futilely +futileness +futilitarian +futilitarianism +futilitarians +futilities +futility +futon +futons +futtock +futtocks +futuna +future +futureless +futurelessness +futures +futurism +futurisms +futurist +futuristic +futuristically +futuristics +futurists +futurities +futurity +futurological +futurologist +futurologists +futurology +futz +futzed +futzes +futzing +fuze +fuzed +fuzee +fuzees +fuzes +fuzing +fuzz +fuzzed +fuzzes +fuzzier +fuzziest +fuzzily +fuzziness +fuzzing +fuzzy +fuzzyheaded +fuzzyheadedness +fyce +fyces +fyke +fykes +fylfot +fylfots +fyn +fátima +fès +fête +fêted +fêtes +fêting +föhn +föhns +führer +führers +g +gab +gabardine +gabardines +gabbed +gabber +gabbers +gabbier +gabbiest +gabbiness +gabbing +gabble +gabbled +gabbler +gabblers +gabbles +gabbling +gabbro +gabbroic +gabbroid +gabbros +gabby +gabelle +gabelles +gaberdine +gaberdines +gabfest +gabfests +gabies +gabion +gabions +gable +gabled +gabler +gables +gabon +gabonese +gaboon +gaboons +gaborone +gabriel +gabs +gaby +gad +gadabout +gadabouts +gadara +gadarene +gadarenes +gaddafi +gadded +gadder +gadders +gadding +gadflies +gadfly +gadget +gadgeteer +gadgeteers +gadgetry +gadgets +gadgety +gadid +gadids +gadoid +gadoids +gadolinite +gadolinites +gadolinium +gadoliniums +gadroon +gadrooned +gadrooning +gadroonings +gadroons +gads +gadwall +gadwalls +gadzooks +gaea +gael +gaeldom +gaelic +gaels +gaff +gaffe +gaffed +gaffer +gaffers +gaffes +gaffing +gaffs +gag +gaga +gage +gaged +gager +gagers +gages +gagged +gagger +gaggers +gagging +gaggle +gaggles +gaging +gagman +gagmen +gags +gagster +gagsters +gahnite +gahnites +gaia +gaieties +gaiety +gaillardia +gaillardias +gaily +gain +gained +gainer +gainers +gainesville +gainful +gainfully +gainfulness +gaingiving +gaining +gains +gainsaid +gainsay +gainsayer +gainsayers +gainsaying +gainsays +gainsborough +gainst +gaiseric +gait +gaited +gaiter +gaiters +gaithersburg +gaiting +gaits +gaius +gal +gala +galabia +galabias +galactic +galactopoiesis +galactopoietic +galactorrhea +galactosamine +galactosamines +galactose +galactosemia +galactosemias +galactosemic +galactosidase +galactosidases +galactoside +galactosides +galago +galagos +galah +galahad +galahads +galahs +galangal +galangals +galantine +galantines +galanty +galapagos +galas +galatea +galateas +galatia +galatian +galatians +galavant +galavanted +galavanting +galavants +galax +galaxes +galaxies +galaxy +galbanum +galbanums +gale +galea +galeae +galeate +galeated +galen +galena +galenas +galenical +galenicals +galenism +galenist +galenists +galere +galeres +galerius +gales +galibi +galibis +galicia +galician +galicians +galilean +galileans +galilee +galilees +galileo +galimatias +galimatiases +galingale +galingales +galiot +galiots +galipot +galipots +galivant +galivanted +galivanting +galivants +gall +galla +gallamine +gallant +gallanted +gallanting +gallantly +gallantries +gallantry +gallants +gallas +gallate +gallates +gallbladder +gallbladders +galleass +galleasses +galled +gallein +galleins +galleon +galleons +galleria +gallerias +galleried +galleries +gallery +galleta +galletas +galley +galleys +gallflies +gallfly +gallia +galliard +galliards +gallic +gallican +gallicanism +gallicans +gallicism +gallicisms +gallicization +gallicizations +gallicize +gallicized +gallicizes +gallicizing +gallied +gallies +galligaskins +gallimaufries +gallimaufry +gallinacean +gallinaceans +gallinaceous +gallinas +galling +gallingly +gallinipper +gallinippers +gallinule +gallinules +galliot +galliots +gallipoli +gallipot +gallipots +gallium +gallivant +gallivanted +gallivanting +gallivants +galliwasp +galliwasps +gallnut +gallnuts +gallo +galloglass +galloglasses +gallomania +gallomanias +gallon +gallonage +gallonages +gallons +galloon +gallooned +galloons +gallop +gallopade +galloped +galloper +gallopers +galloping +gallops +galloway +gallowglass +gallowglasses +gallows +gallowses +galls +gallstone +gallstones +gallus +galluses +gally +gallying +galois +galoot +galoots +galop +galops +galore +galosh +galoshed +galoshes +gals +galsworthy +galumph +galumphed +galumphing +galumphs +galvanic +galvanically +galvanism +galvanisms +galvanization +galvanizations +galvanize +galvanized +galvanizer +galvanizers +galvanizes +galvanizing +galvanomagnetic +galvanometer +galvanometers +galvanometric +galvanometrical +galvanometry +galvanoscope +galvanoscopes +galvanoscopic +galvanoscopy +galveston +galway +galwegian +galwegians +galyak +galyaks +galápagos +galère +gam +gama +gamage +gamay +gamays +gamba +gambado +gambadoes +gambados +gambas +gambia +gambian +gambians +gambier +gambiers +gambir +gambirs +gambit +gambits +gamble +gambled +gambler +gamblers +gambles +gambling +gamboge +gamboges +gambol +gamboled +gamboling +gambolled +gambolling +gambols +gambrel +gambrels +gambusia +gambusias +game +gamecock +gamecocks +gamed +gamekeeper +gamekeepers +gamelan +gamelans +gamelike +gamely +gameness +gamer +games +gamesman +gamesmanship +gamesmen +gamesome +gamesomely +gamesomeness +gamest +gamester +gamesters +gametangia +gametangial +gametangium +gamete +gametes +gametic +gametically +gametocyte +gametocytes +gametogenesis +gametogenic +gametogenous +gametophore +gametophores +gametophoric +gametophyte +gametophytes +gametophytic +gamey +gamic +gamier +gamiest +gamily +gamin +gamine +gamines +gaminess +gaming +gamings +gamins +gamma +gammas +gammed +gammer +gammers +gamming +gammon +gammoned +gammoner +gammoners +gammoning +gammons +gamogenesis +gamogenetic +gamogenetically +gamopetalous +gamophyllous +gamosepalous +gamow +gamp +gamps +gams +gamut +gamuts +gamy +gan +ganciclovir +gander +ganders +gandhi +gandhian +ganef +ganefs +ganesha +gang +ganga +gangbang +gangbanged +gangbanging +gangbangs +gangbuster +gangbusters +ganged +ganger +gangers +ganges +ganging +gangland +ganglia +gangliate +gangliated +ganglier +gangliest +gangling +ganglion +ganglionated +ganglionic +ganglions +ganglioside +gangliosides +gangly +gangplank +gangplanks +gangplow +gangplows +gangpunch +gangpunched +gangpunches +gangpunching +gangrel +gangrels +gangrene +gangrened +gangrenes +gangrening +gangrenous +gangs +gangster +gangsterdom +gangsterism +gangsters +gangue +gangues +gangway +gangways +ganister +ganisters +ganja +ganjas +gannet +gannets +gannister +gannisters +ganof +ganofs +ganoid +ganoids +gansu +gantlet +gantleted +gantleting +gantlets +gantline +gantlines +gantlope +gantlopes +gantries +gantry +gantt +ganymede +gaol +gaoled +gaoler +gaolers +gaoling +gaols +gap +gape +gaped +gaper +gapers +gapes +gapeworm +gapeworms +gaping +gapingly +gapped +gapping +gappy +gaps +gar +garage +garageable +garaged +garageman +garagemen +garages +garaging +garamond +garb +garbage +garbanzo +garbanzos +garbed +garbing +garble +garbled +garbler +garblers +garbles +garbling +garbo +garboard +garboards +garboil +garboils +garbologist +garbologists +garbology +garbs +garcía +garda +gardant +garde +garden +gardened +gardener +gardeners +gardenful +gardenia +gardenias +gardening +gardens +garderobe +garderobes +gardiners +gardyloo +garfield +garfish +garfishes +garganey +garganeys +gargantua +gargantuan +gargantuas +garget +gargets +gargle +gargled +gargles +gargling +gargoyle +gargoyles +garibaldi +garibaldis +garish +garishly +garishness +garland +garlanded +garlanding +garlands +garlic +garlicked +garlicking +garlicks +garlicky +garment +garmented +garmenting +garments +garner +garnered +garnering +garners +garnet +garnetiferous +garnets +garni +garnierite +garnierites +garnis +garnish +garnished +garnishee +garnisheed +garnisheeing +garnishees +garnishes +garnishing +garnishment +garnishments +garniture +garnitures +garonne +garotte +garotted +garotter +garotters +garottes +garotting +garpike +garpikes +garred +garret +garrets +garrick +garring +garrison +garrisoned +garrisoning +garrisons +garron +garrons +garrote +garroted +garroter +garroters +garrotes +garroting +garrotte +garrotted +garrottes +garrotting +garrulity +garrulous +garrulously +garrulousness +gars +garter +gartered +gartering +garters +garth +garths +garve +garvey +garveys +garçon +garçons +gas +gasbag +gasbags +gascon +gasconade +gasconaded +gasconader +gasconaders +gasconades +gasconading +gascons +gascony +gasdynamic +gasdynamicist +gasdynamicists +gasdynamics +gaseous +gaseousness +gases +gash +gashed +gasherbrum +gashes +gashing +gasholder +gasholders +gashouse +gashouses +gasifiable +gasification +gasifications +gasified +gasifier +gasifiers +gasifies +gasiform +gasify +gasifying +gaskell +gasket +gaskets +gaskin +gaskins +gaslight +gaslights +gaslit +gasogene +gasogenes +gasohol +gasolene +gasolenes +gasolier +gasoliers +gasoline +gasolines +gasolinic +gasometer +gasometers +gasp +gaspar +gasped +gasper +gaspers +gasping +gaspingly +gasps +gaspé +gassed +gasser +gassers +gasses +gassier +gassiest +gassily +gassiness +gassing +gassings +gassy +gast +gasted +gastight +gastightness +gasting +gastness +gastraea +gastraeas +gastrea +gastreas +gastrectomies +gastrectomy +gastric +gastrin +gastrins +gastritis +gastrocnemii +gastrocnemius +gastroenteric +gastroenteritis +gastroenterologic +gastroenterological +gastroenterologist +gastroenterologists +gastroenterology +gastrointestinal +gastrolith +gastroliths +gastrologic +gastrological +gastrologically +gastrologist +gastrologists +gastrology +gastronome +gastronomer +gastronomers +gastronomes +gastronomic +gastronomical +gastronomically +gastronomies +gastronomist +gastronomists +gastronomy +gastropod +gastropodan +gastropodous +gastropods +gastroscope +gastroscopes +gastroscopic +gastroscopist +gastroscopists +gastroscopy +gastrostomies +gastrostomy +gastrotomies +gastrotomy +gastrotrich +gastrotriches +gastrovascular +gastrula +gastrulae +gastrular +gastrulas +gastrulate +gastrulated +gastrulates +gastrulating +gastrulation +gastrulations +gasts +gasworks +gat +gate +gateau +gateaux +gatecrash +gatecrashed +gatecrasher +gatecrashers +gatecrashes +gatecrashing +gated +gatefold +gatefolds +gatehouse +gatehouses +gatekeeper +gatekeepers +gatepost +gateposts +gater +gaters +gates +gateway +gatewayed +gatewaying +gateways +gather +gathered +gatherer +gatherers +gathering +gatherings +gathers +gatherum +gatherums +gatineau +gating +gatling +gatlings +gator +gatorade +gators +gats +gatún +gauche +gauchely +gaucheness +gaucher +gaucherie +gaucheries +gauchest +gaucho +gauchos +gaud +gaudeamus +gauderies +gaudery +gaudier +gaudies +gaudiest +gaudily +gaudiness +gauds +gaudy +gaufer +gaufers +gauffer +gauffered +gauffering +gauffers +gaugamela +gauge +gaugeable +gauged +gauger +gaugers +gauges +gauging +gauguin +gaul +gaulish +gaulle +gaullism +gaullist +gaullists +gauls +gault +gaults +gaum +gaumed +gauming +gaumont +gaums +gaunt +gaunter +gauntest +gauntlet +gauntleted +gauntlets +gauntly +gauntness +gaur +gaurs +gauss +gausses +gaussian +gautama +gauze +gauzelike +gauzes +gauzier +gauziest +gauzily +gauziness +gauzy +gavage +gavages +gavarnie +gave +gavel +gaveled +gaveling +gavelkind +gavelled +gavelling +gavels +gavial +gavials +gavotte +gavotted +gavottes +gavotting +gawain +gawk +gawked +gawker +gawkers +gawkier +gawkiest +gawkily +gawking +gawkish +gawkishly +gawkishness +gawks +gawky +gawp +gawped +gawper +gawpers +gawping +gawps +gay +gayal +gayals +gayer +gayest +gayety +gayly +gayness +gays +gaza +gazar +gazars +gaze +gazebo +gazeboes +gazebos +gazed +gazehound +gazehounds +gazelle +gazelles +gazer +gazers +gazes +gazette +gazetted +gazetteer +gazetteers +gazettes +gazetting +gaziantep +gazillion +gazillionaire +gazillionaires +gazillions +gazing +gazogene +gazogenes +gazpacho +gazpachos +gdansk +geanticlinal +geanticline +geanticlines +gear +gearbox +gearboxes +geared +gearing +gearings +gearless +gears +gearshift +gearshifts +gearwheel +gearwheels +geat +geats +gebel +geber +gecko +geckoes +geckos +gedankenexperiment +gedankenexperiments +gee +geechee +geechees +geed +geegaw +geegaws +geeing +geek +geekish +geeks +geeky +geelong +gees +geese +geezer +geezers +gefilte +gegenschein +gegenscheins +gehenna +gehennas +gehrig +geiger +geisha +geishas +gel +gelable +gelada +gelate +gelated +gelates +gelati +gelatin +gelatine +gelatines +gelating +gelatinization +gelatinizations +gelatinize +gelatinized +gelatinizes +gelatinizing +gelatinous +gelatinously +gelatinousness +gelatins +gelation +gelations +gelato +geld +gelded +gelderland +gelding +geldings +gelds +gelee +gelees +gelid +gelidities +gelidity +gelidly +gelidness +gelignite +gelignites +gellant +gellants +gelled +gelling +gels +gelsenkirchen +gelt +gelts +geländesprung +geländesprungs +gem +gemara +gemaric +gemarist +gemarists +geminal +geminally +geminate +geminated +geminates +geminating +gemination +geminations +gemini +geminian +geminians +geminis +gemlike +gemma +gemmae +gemmate +gemmated +gemmates +gemmating +gemmation +gemmations +gemmed +gemming +gemmiparous +gemmiparously +gemmologist +gemmologists +gemmology +gemmulation +gemmulations +gemmule +gemmules +gemmuliferous +gemmy +gemological +gemologist +gemologists +gemology +gemot +gemote +gemotes +gemots +gems +gemsbok +gemsboks +gemstone +gemstones +gemütlich +gemütlichkeit +gendarme +gendarmerie +gendarmeries +gendarmes +gender +gendered +gendering +genderless +genders +gene +genealogical +genealogically +genealogies +genealogist +genealogists +genealogize +genealogized +genealogizes +genealogizing +genealogy +genera +generable +general +generalcies +generalcy +generalissimo +generalissimos +generalist +generalists +generalities +generality +generalizability +generalizable +generalization +generalizations +generalize +generalized +generalizer +generalizers +generalizes +generalizing +generally +generalness +generals +generalship +generalships +generate +generated +generates +generating +generation +generational +generations +generative +generatively +generativeness +generator +generators +generatrices +generatrix +generic +generically +genericness +generics +generis +generosities +generosity +generous +generously +generousness +genes +genesee +geneses +genesis +genet +genetic +genetical +genetically +geneticist +geneticists +genetics +genets +geneva +genevan +genevans +genevese +genghis +genial +geniality +genially +genialness +genials +genic +genically +geniculate +geniculated +geniculately +geniculation +geniculations +genie +genies +genii +genip +genipap +genipaps +genips +genital +genitalia +genitalic +genitally +genitals +genitival +genitivally +genitive +genitives +genitor +genitors +genitourinary +geniture +genitures +genius +geniuses +genoa +genoas +genocidal +genocidally +genocide +genocides +genoese +genoise +genoises +genom +genome +genomes +genomic +genomics +genoms +genotype +genotypes +genotypic +genotypical +genotypically +genotypicity +genova +genre +genres +genro +genros +gens +genseric +gent +gentamicin +gentamicins +genteel +genteelism +genteelisms +genteelly +genteelness +gentes +gentian +gentians +gentile +gentiles +gentilesse +gentilesses +gentilities +gentility +gentle +gentled +gentlefolk +gentlefolks +gentleman +gentlemanlike +gentlemanlikeness +gentlemanliness +gentlemanly +gentlemen +gentleness +gentlepeople +gentlepeoples +gentleperson +gentlepersons +gentler +gentles +gentlest +gentlewoman +gentlewomen +gentling +gently +gentrice +gentrices +gentries +gentrification +gentrifications +gentrified +gentrifier +gentrifiers +gentrifies +gentrify +gentrifying +gentry +gents +genuflect +genuflected +genuflecting +genuflection +genuflections +genuflects +genuflexion +genuine +genuinely +genuineness +genus +geobotanic +geobotanical +geobotanically +geobotanist +geobotanists +geobotany +geocentric +geocentrically +geocentricism +geochemical +geochemically +geochemist +geochemistry +geochemists +geochronologic +geochronological +geochronologically +geochronologist +geochronologists +geochronology +geochronometric +geochronometry +geocode +geocodes +geocorona +geocoronas +geode +geodes +geodesic +geodesics +geodesist +geodesists +geodesy +geodetic +geodetical +geodetically +geoduck +geoducks +geoeconomic +geoeconomically +geoeconomics +geoeconomist +geoeconomists +geographer +geographers +geographic +geographical +geographically +geographies +geography +geohydrologic +geohydrologist +geohydrologists +geohydrology +geoid +geoidal +geoids +geologic +geological +geologically +geologies +geologist +geologists +geologize +geologized +geologizes +geologizing +geology +geomagnetic +geomagnetically +geomagnetism +geomancer +geomancers +geomancy +geomantic +geometer +geometers +geometric +geometrical +geometrically +geometrician +geometricians +geometricize +geometricized +geometricizes +geometricizing +geometrics +geometrid +geometrids +geometries +geometrize +geometrized +geometrizes +geometrizing +geometry +geomorphic +geomorphologic +geomorphological +geomorphologically +geomorphologist +geomorphologists +geomorphology +geophagism +geophagist +geophagists +geophagy +geophone +geophones +geophysical +geophysically +geophysicist +geophysicists +geophysics +geophyte +geophytes +geopolitical +geopolitically +geopolitician +geopoliticians +geopolitics +geoponic +geoponics +geopressured +geopressurized +geordie +geordies +george +georges +georgetown +georgette +georgettes +georgia +georgian +georgians +georgic +georgical +georgics +geoscience +geosciences +geoscientist +geoscientists +geostationary +geostrategic +geostrategies +geostrategist +geostrategists +geostrategy +geostrophic +geostrophically +geosynchronous +geosynchronously +geosynclinal +geosyncline +geosynclines +geotactic +geotactically +geotaxes +geotaxis +geotectonic +geothermal +geothermally +geothermic +geotropic +geotropically +geotropism +gerah +gerahs +geraint +geranial +geranials +geraniol +geraniols +geranium +geraniums +gerardia +gerardias +gerbera +gerberas +gerbil +gerbille +gerbilles +gerbils +gerent +gerents +gerenuk +gerenuks +gerfalcon +gerfalcons +geriatric +geriatrician +geriatricians +geriatrics +geriatrist +geriatrists +germ +german +germander +germanders +germane +germanely +germaneness +germania +germanic +germanicus +germanism +germanisms +germanist +germanists +germanium +germanization +germanizations +germanize +germanized +germanizer +germanizers +germanizes +germanizing +germanophile +germanophiles +germanophobe +germanophobes +germanophobia +germans +germantown +germany +germen +germens +germfree +germicidal +germicide +germicides +germier +germiest +germinability +germinal +germinally +germinate +germinated +germinates +germinating +germination +germinations +germinative +germinator +germinators +germiness +germproof +germs +germy +gerodontic +gerodontics +gerona +geronimo +gerontic +gerontocracies +gerontocracy +gerontocrat +gerontocratic +gerontocrats +gerontologic +gerontological +gerontologist +gerontologists +gerontology +gerontomorphic +gerrymander +gerrymandered +gerrymandering +gerrymanders +gershwin +gertrude +gertrudis +gerund +gerundial +gerundive +gerundives +gerunds +geryon +gesneriad +gesneriads +gesso +gessoed +gessoes +gest +gestalt +gestalten +gestaltist +gestaltists +gestalts +gestapo +gestapos +gestate +gestated +gestates +gestating +gestation +gestational +gestations +gestatory +geste +gestes +gestic +gesticulate +gesticulated +gesticulates +gesticulating +gesticulation +gesticulations +gesticulative +gesticulator +gesticulators +gesticulatory +gests +gestural +gesturally +gesture +gestured +gesturer +gesturers +gestures +gesturing +gesundheit +get +geta +getable +getas +getatable +getaway +getaways +gethsemane +gethsemanes +gets +gettable +getter +getters +getting +getty +gettysburg +getup +getups +geum +geums +gewgaw +gewgaws +gewürztraminer +gewürztraminers +gey +geyser +geyserite +geyserites +geysers +ghaghara +ghaghra +ghana +ghanaian +ghanaians +gharial +gharials +gharries +gharry +ghast +ghastful +ghastfully +ghastlier +ghastliest +ghastliness +ghastly +ghat +ghats +ghaut +ghauts +ghazi +ghaziabad +ghazies +ghee +ghees +ghent +gherkin +gherkins +ghetto +ghettoed +ghettoes +ghettoing +ghettoization +ghettoizations +ghettoize +ghettoized +ghettoizes +ghettoizing +ghettos +ghi +ghibelline +ghibellines +ghibli +ghiblis +ghillie +ghillies +ghis +ghost +ghosted +ghosting +ghostings +ghostlier +ghostliest +ghostlike +ghostliness +ghostly +ghosts +ghostweed +ghostweeds +ghostwrite +ghostwriter +ghostwriters +ghostwrites +ghostwriting +ghostwritten +ghostwrote +ghosty +ghoul +ghoulish +ghoulishly +ghoulishness +ghouls +giant +giantess +giantesses +giantism +giantisms +giantlike +giants +giaour +giaours +giardia +giardias +giardiasis +gib +gibbed +gibber +gibbered +gibberellic +gibberellin +gibberellins +gibbering +gibberish +gibbers +gibbet +gibbeted +gibbeting +gibbets +gibbetted +gibbetting +gibbing +gibbon +gibbons +gibbosities +gibbosity +gibbous +gibbously +gibbousness +gibe +gibed +gibeon +gibeonite +gibeonites +giber +gibers +gibes +gibing +gibingly +giblet +giblets +gibraltar +gibraltarian +gibraltarians +gibs +gibson +gibsons +gid +giddap +giddied +giddier +giddies +giddiest +giddily +giddiness +giddy +giddyap +giddying +giddyup +gideon +gids +gie +gied +gieing +gies +gift +giftable +giftables +gifted +giftedly +giftedness +gifting +gifts +giftware +giftwares +gig +gigaampere +gigaamperes +gigabecquerel +gigabecquerels +gigabit +gigabits +gigabyte +gigabytes +gigacandela +gigacandelas +gigacoulomb +gigacoulombs +gigacycle +gigacycles +gigafarad +gigafarads +gigaflop +gigaflops +gigagram +gigagrams +gigahenries +gigahenry +gigahenrys +gigahertz +gigajoule +gigajoules +gigakelvin +gigakelvins +gigalumen +gigalumens +gigalux +gigameter +gigameters +gigamole +gigamoles +giganewton +giganewtons +gigantesque +gigantic +gigantically +gigantism +gigantisms +gigaohm +gigaohms +gigapascal +gigapascals +gigaradian +gigaradians +gigas +gigasecond +gigaseconds +gigasiemens +gigasievert +gigasieverts +gigasteradian +gigasteradians +gigatesla +gigateslas +gigaton +gigatons +gigavolt +gigavolts +gigawatt +gigawatts +gigaweber +gigawebers +gigged +gigging +giggle +giggled +giggler +gigglers +giggles +giggling +gigglingly +giggly +gigolo +gigolos +gigot +gigots +gigs +gigue +gigues +gikuyu +gikuyus +gila +gilbert +gilbertian +gilberts +gilboa +gild +gildas +gilded +gilder +gilders +gilding +gildings +gilds +gilead +giles +gilgamesh +gill +gilled +giller +gillers +gillette +gillie +gillied +gillies +gilling +gillnet +gillnets +gillnetted +gillnetting +gills +gillyflower +gillyflowers +gillying +gilsonite +gilt +gilts +gimbal +gimbaled +gimbaling +gimballed +gimballing +gimbals +gimcrack +gimcrackery +gimcracks +gimel +gimels +gimignano +gimlet +gimleted +gimleting +gimlets +gimmal +gimmals +gimme +gimmes +gimmick +gimmicked +gimmicking +gimmickries +gimmickry +gimmicks +gimmicky +gimp +gimped +gimping +gimps +gimpy +gin +ginger +gingerbread +gingerbreaded +gingerbreads +gingerbready +gingered +gingering +gingerliness +gingerly +gingerroot +gingerroots +gingers +gingersnap +gingersnaps +gingery +gingham +ginghams +gingiva +gingivae +gingival +gingivectomies +gingivectomy +gingivitis +gingko +gingkoes +gink +ginkgo +ginkgoes +ginks +ginned +ginner +ginners +ginning +ginny +gins +ginsberg +ginseng +ginsengs +ginzo +ginzoes +giorgione +giotto +giovanni +gip +gipped +gipping +gips +gipsies +gipsy +giraffe +giraffes +giraffish +girandole +girandoles +girasol +girasole +girasoles +girasols +gird +girded +girder +girders +girding +girdle +girdled +girdler +girdlers +girdles +girdling +girds +girl +girlfriend +girlfriends +girlhood +girlie +girlies +girlish +girlishly +girlishness +girls +girly +girn +girned +girning +girns +giro +giroed +giroes +giroing +giron +gironde +girondin +girondins +girondist +girondists +girons +giros +girosol +girosols +girt +girted +girth +girthed +girthing +girths +girting +girts +gisarme +gisarmes +gismo +gismos +gist +gists +git +gite +gites +gittern +gitterns +giulia +giuseppe +give +giveaway +giveaways +giveback +givebacks +given +givens +giver +givers +gives +giving +gizmo +gizmos +gizzard +gizzards +glabella +glabellae +glabellar +glabrate +glabrescent +glabrous +glabrousness +glacial +glacially +glaciate +glaciated +glaciates +glaciating +glaciation +glaciations +glacier +glaciered +glaciers +glaciologic +glaciological +glaciologist +glaciologists +glaciology +glacis +glacé +glacéed +glacéing +glacés +glad +gladded +gladden +gladdened +gladdening +gladdens +gladder +gladdest +gladding +glade +glades +gladiate +gladiator +gladiatorial +gladiators +gladiola +gladiolas +gladioli +gladiolus +gladioluses +gladly +gladness +glads +gladsome +gladsomely +gladsomeness +gladstone +gladstones +glady +glagolithic +glagolitic +glaiket +glaikit +glair +glaire +glaires +glairier +glairiest +glairs +glairy +glaive +glaives +glamor +glamored +glamorgan +glamoring +glamorization +glamorizations +glamorize +glamorized +glamorizer +glamorizers +glamorizes +glamorizing +glamorless +glamorous +glamorously +glamorousness +glamors +glamour +glamoured +glamouring +glamourization +glamourizations +glamourize +glamourized +glamourizer +glamourizers +glamourizes +glamourizing +glamourous +glamourously +glamourousness +glamours +glance +glanced +glances +glancing +glancingly +gland +glandered +glanderous +glanders +glandes +glandless +glands +glandular +glandularly +glans +glare +glared +glares +glarier +glariest +glaring +glaringly +glaringness +glary +glasgow +glasnost +glass +glassblower +glassblowers +glassblowing +glassed +glasses +glassfish +glassfishes +glassful +glassfuls +glasshouse +glasshouses +glassie +glassier +glassies +glassiest +glassily +glassine +glassines +glassiness +glassing +glassless +glasslike +glassmaker +glassmakers +glassmaking +glassware +glasswork +glassworker +glassworkers +glassworks +glasswort +glassworts +glassy +glastonbury +glaswegian +glaswegians +glauber +glaucoma +glaucomatous +glauconite +glauconites +glauconitic +glaucous +glaucousness +glaze +glazed +glazer +glazers +glazes +glazier +glazieries +glaziers +glaziery +glazing +glazings +gleam +gleamed +gleamer +gleamers +gleaming +gleams +gleamy +glean +gleanable +gleaned +gleaner +gleaners +gleaning +gleanings +gleans +gleba +glebae +glebe +glebes +glede +gledes +glee +gleed +gleeds +gleeful +gleefully +gleefulness +gleek +gleeked +gleeking +gleeks +gleeman +gleemen +glees +gleesome +gleet +gleets +gleety +gleg +glen +glenda +glendale +glengarries +glengarry +glens +gley +gleys +glia +gliadin +gliadins +glial +glias +glib +glibber +glibbest +glibly +glibness +glide +glided +glider +gliders +glides +gliding +glim +glimmer +glimmered +glimmering +glimmerings +glimmers +glimpse +glimpsed +glimpser +glimpsers +glimpses +glimpsing +glims +glint +glinted +glintier +glintiest +glinting +glints +glinty +glioma +gliomas +gliomata +glissade +glissaded +glissader +glissaders +glissades +glissading +glissandi +glissando +glissandos +glisten +glistened +glistening +glistens +glister +glistered +glistering +glisters +glitch +glitches +glitchy +glitter +glitterati +glittered +glittering +glitteringly +glitters +glittertinden +glittery +glitz +glitzed +glitzes +glitziness +glitzing +glitzy +gloam +gloaming +gloams +gloat +gloated +gloater +gloaters +gloating +gloats +glob +global +globalism +globalisms +globalist +globalists +globalization +globalizations +globalize +globalized +globalizer +globalizers +globalizes +globalizing +globally +globals +globate +globe +globed +globefish +globefishes +globeflower +globeflowers +globes +globetrot +globetrots +globetrotted +globetrotter +globetrotters +globetrotting +globin +globing +globins +globoid +globoids +globose +globosely +globoseness +globosity +globous +globs +globular +globularly +globularness +globule +globules +globuliferous +globulin +globulins +glochid +glochidia +glochidiate +glochidium +glochids +glockenspiel +glockenspiels +glogg +gloggs +glom +glomera +glomerate +glomerular +glomerulate +glomerule +glomerules +glomeruli +glomerulus +glomma +glommed +glomming +gloms +glomus +gloom +gloomed +gloomier +gloomiest +gloomily +gloominess +glooming +glooms +gloomy +glop +gloped +gloping +gloppy +glops +gloria +gloriam +gloriana +glorias +gloried +glories +glorification +glorifications +glorified +glorifier +glorifiers +glorifies +glorify +glorifying +gloriole +glorioles +gloriosi +gloriosus +glorious +gloriously +gloriousness +glory +glorying +gloss +glossa +glossae +glossal +glossarial +glossaries +glossarist +glossarists +glossary +glossas +glossed +glosser +glossers +glosses +glossier +glossies +glossiest +glossily +glossiness +glossing +glossitic +glossitis +glossographer +glossographers +glossography +glossolalia +glossolalias +glossolalist +glossolalists +glossopharyngeal +glossy +glottal +glottides +glottis +glottises +glottochronological +glottochronology +gloucester +gloucestershire +glout +glouted +glouting +glouts +glove +gloved +glover +glovers +gloves +gloving +glow +glowed +glower +glowered +glowering +gloweringly +glowers +glowing +glowingly +glows +glowworm +glowworms +gloxinia +gloxinias +gloze +glozed +glozes +glozing +glucagon +gluck +glucocorticoid +glucocorticoids +gluconeogenesis +gluconeogenetic +glucose +glucoside +glucosides +glucosidic +glucosidically +glue +glued +glueing +glues +gluey +gluily +gluiness +gluing +glum +glumaceous +glume +glumes +glumly +glummer +glummest +glumness +glums +gluon +gluons +glut +glutamate +glutamates +glutamic +glutamine +glutamines +glutaraldehyde +glutaraldehydes +gluteal +glutei +gluten +glutenous +glutens +glutethimide +glutethimides +gluteus +glutinosity +glutinous +glutinously +glutinousness +gluts +glutted +glutting +glutton +gluttonies +gluttonize +gluttonized +gluttonizes +gluttonizing +gluttonous +gluttonously +gluttonousness +gluttons +gluttony +glycan +glycans +glyceraldehyde +glyceraldehydes +glyceric +glyceride +glycerides +glycerin +glycerinate +glycerinated +glycerinates +glycerinating +glycerine +glycerines +glycerins +glycerol +glycerolize +glycerolized +glycerolizes +glycerolizing +glycerols +glyceryl +glyceryls +glycin +glycine +glycines +glycins +glycogen +glycogenesis +glycogenetic +glycogenic +glycogenolyses +glycogenolysis +glycogenolytic +glycogens +glycol +glycolic +glycolipid +glycolipids +glycols +glycolyses +glycolysis +glycolytic +glycopeptide +glycopeptides +glycoprotein +glycoproteins +glycosaminoglycan +glycosaminoglycans +glycosidase +glycosidases +glycoside +glycosides +glycosidic +glycosidically +glycosuria +glycosuric +glycosyl +glycosylate +glycosylated +glycosylates +glycosylating +glycosylation +glycosyls +glycyl +glycyls +glyph +glyphic +glyphs +glyptic +glyptics +glyptograph +glyptographer +glyptographers +glyptographic +glyptographical +glyptographs +glyptography +glåma +glögg +glöggs +gmelina +gmelinas +gnar +gnarl +gnarled +gnarling +gnarls +gnarly +gnarr +gnarred +gnarring +gnarrs +gnars +gnash +gnashed +gnashes +gnashing +gnat +gnatcatcher +gnatcatchers +gnathal +gnathic +gnathite +gnathites +gnats +gnatty +gnaw +gnawed +gnawer +gnawers +gnawing +gnaws +gneiss +gneisses +gneissic +gneissoid +gneissose +gniezno +gnocchi +gnome +gnomelike +gnomes +gnomic +gnomish +gnomon +gnomonic +gnomonical +gnomons +gnosis +gnostic +gnosticism +gnostics +gnotobiotic +gnotobiotically +gnu +gnus +go +goa +goad +goaded +goading +goads +goal +goaled +goalie +goalies +goaling +goalkeeper +goalkeepers +goalless +goalpost +goalposts +goals +goaltender +goaltenders +goaltending +goaltendings +goanese +goas +goat +goatee +goateed +goatees +goatfish +goatfishes +goatherd +goatherds +goatish +goatlike +goats +goatsbeard +goatskin +goatskins +goatsucker +goatsuckers +gob +gobbet +gobbets +gobble +gobbled +gobbledegook +gobbledygook +gobbler +gobblers +gobbles +gobbling +gobelin +gobelins +gobi +gobies +goblet +goblets +goblin +goblins +gobo +goboes +gobos +gobs +goby +god +godalmighty +godavari +godchild +godchildren +goddam +goddamn +goddamned +goddamning +goddamns +goddams +goddard +goddaughter +goddaughters +godded +goddess +goddesses +godding +godfather +godfathered +godfathering +godfathers +godforsaken +godhead +godheads +godhood +godhoods +godiva +godless +godlessly +godlessness +godlier +godliest +godlike +godlikeness +godliness +godling +godlings +godly +godmother +godmothered +godmothering +godmothers +godown +godowns +godoxious +godparent +godparents +gods +godsend +godsends +godson +godsons +godspeed +godspeeds +godthåb +godunov +godwit +godwits +goebbels +goer +goering +goers +goes +goethe +goethite +goethites +gofer +gofers +goffer +goffered +goffering +goffers +goggle +goggled +goggler +gogglers +goggles +goggling +goggly +gogh +gogol +gogra +goidelic +going +goings +goiter +goiters +goitre +goitres +goitrogen +goitrogenic +goitrogenicity +goitrous +goiânia +golan +golconda +golcondas +gold +goldbeater +goldbeaters +goldbeating +goldbeatings +goldberg +goldbergian +goldbrick +goldbricked +goldbricker +goldbrickers +goldbricking +goldbricks +goldbug +goldbugs +golden +goldeneye +goldeneyes +goldenly +goldenness +goldenrod +goldenrods +goldenseal +goldenseals +goldfield +goldfields +goldfinch +goldfinches +goldfish +goldfishes +goldilocks +golds +goldsmith +goldsmiths +goldstone +goldstones +goldthread +goldthreads +goldwyn +golem +golems +golf +golfed +golfer +golfers +golfing +golflinks +golfs +golgi +golgotha +golgothas +goliard +goliardic +goliards +goliath +goliaths +gollancz +golliwog +golliwogg +golliwoggs +golliwogs +golly +gombeen +gombeens +gomorrah +gomorrahs +gomphoses +gomphosis +gonad +gonadal +gonadectomies +gonadectomized +gonadectomy +gonadic +gonadotrophic +gonadotrophin +gonadotrophins +gonadotropic +gonadotropin +gonadotropins +gonads +gond +gondi +gondola +gondolas +gondolier +gondoliers +gonds +gondwana +gondwanaland +gondwanalands +gone +goner +goneril +goners +gonfalon +gonfalonier +gonfaloniers +gonfalons +gong +gonged +gonging +gongorism +gongorisms +gongoristic +gongs +gonidia +gonidial +gonidium +gonif +gonifs +goniometer +goniometers +goniometric +goniometrical +goniometry +gonion +gonions +gonococcal +gonococci +gonococcic +gonococcus +gonocyte +gonocytes +gonophore +gonophores +gonophoric +gonophorous +gonopore +gonopores +gonorrhea +gonorrheal +gonorrheic +gonzo +goo +goober +goobers +good +goodbye +goodbyes +gooder +gooders +goodhearted +goodheartedly +goodheartedness +goodie +goodies +goodish +goodlier +goodliest +goodliness +goodly +goodman +goodmen +goodness +goodnight +goodnights +goods +goodwife +goodwill +goodwills +goodwin +goodwives +goody +goodyear +gooey +goof +goofball +goofballs +goofed +goofier +goofiest +goofily +goofiness +goofing +goofproof +goofs +goofy +googol +googolplex +googolplexes +googols +gooier +gooiest +gook +gooks +goombah +goombahs +goon +gooney +gooneys +goonies +goons +goony +goop +goops +goopy +goos +goosander +goosanders +goose +gooseberries +gooseberry +goosed +goosefish +goosefishes +gooseflesh +goosefoot +goosefoots +gooseneck +goosenecked +goosenecks +gooses +goosestep +goosestepped +goosestepping +goosesteps +goosey +goosier +goosiest +goosing +goosy +gopher +gophers +gorbachev +gordian +gordon +gordons +gore +gored +gores +gorge +gorged +gorgeous +gorgeously +gorgeousness +gorger +gorgerin +gorgerins +gorgers +gorges +gorget +gorgets +gorging +gorgon +gorgonian +gorgonians +gorgonize +gorgonized +gorgonizes +gorgonizing +gorgons +gorgonzola +gorier +goriest +gorilla +gorillas +gorily +goriness +goring +gorki +gorky +gormandize +gormandized +gormandizer +gormandizers +gormandizes +gormandizing +gormless +gorp +gorps +gorse +gorses +gorsy +gory +gosh +goshawk +goshawks +goshen +gosiute +gosiutes +gosling +goslings +gospel +gospeler +gospelers +gospeller +gospellers +gospels +gosport +gosports +gossamer +gossamers +gossamery +gossan +gossans +gossip +gossiped +gossiper +gossipers +gossiping +gossipmonger +gossipmongers +gossipries +gossipry +gossips +gossipy +gossypol +gossypols +got +goth +gotha +gotham +gothamite +gothamites +gothenburg +gothic +gothically +gothicism +gothicisms +gothicist +gothicists +gothicize +gothicized +gothicizes +gothicizing +goths +gotland +gotten +gotterdammerung +gotterdämmerung +gotthard +gottwaldov +gouache +gouaches +gouda +gouge +gouged +gouger +gougers +gouges +gouging +goulash +goulashes +gounod +gourami +gouramis +gourd +gourde +gourdes +gourds +gourmand +gourmandise +gourmandises +gourmandism +gourmandize +gourmandized +gourmandizes +gourmandizing +gourmandlike +gourmands +gourmet +gourmets +gout +goutiness +gouts +goutweed +goutweeds +gouty +govern +governable +governance +governances +governed +governess +governesses +governessy +governing +government +governmental +governmentalism +governmentalist +governmentalists +governmentalize +governmentalized +governmentalizes +governmentalizing +governmentally +governmentese +governments +governor +governorate +governorates +governors +governorship +governorships +governs +gowan +gowans +gowany +gown +gowned +gowning +gowns +gownsman +gownsmen +goy +goya +goyim +goyish +goys +goût +graaff +graafian +grab +grabbed +grabber +grabbers +grabbier +grabbiest +grabbiness +grabbing +grabble +grabbled +grabbler +grabblers +grabbles +grabbling +grabby +graben +grabens +grabs +grace +graced +graceful +gracefully +gracefulness +graceless +gracelessly +gracelessness +graces +gracile +gracileness +gracility +gracing +gracioso +graciosos +gracious +graciously +graciousness +grackle +grackles +grad +gradable +gradate +gradated +gradates +gradating +gradation +gradational +gradationally +gradations +grade +graded +gradeless +grader +graders +grades +gradient +gradients +gradin +gradine +gradines +grading +gradings +gradins +gradiometer +gradiometers +grads +gradual +gradualism +gradualist +gradualistic +gradualists +gradually +gradualness +graduals +graduand +graduands +graduate +graduated +graduates +graduating +graduation +graduations +graduator +graduators +graffiti +graffitist +graffitists +graffito +graft +graftage +graftages +grafted +grafter +grafters +grafting +grafts +graham +grahams +grail +grails +grain +grained +grainer +grainers +grainfield +grainfields +grainier +grainiest +graininess +graining +grains +grainy +gram +grama +gramarye +gramaryes +gramas +gramercy +gramicidin +gramineous +gramineousness +graminivorous +gramma +grammar +grammarian +grammarians +grammars +grammas +grammatical +grammaticality +grammatically +grammaticalness +grammatologic +grammatological +grammatologist +grammatologists +grammatology +gramme +grammes +grammies +grammy +gramophone +gramophones +gramp +grampian +gramps +grampus +grampuses +grams +grana +granada +granadilla +granadillas +granaries +granary +grand +grandad +grandaddies +grandaddy +grandads +grandam +grandame +grandames +grandams +grandaunt +grandaunts +grandbabies +grandbaby +grandchild +grandchildren +granddad +granddaddies +granddaddy +granddads +granddaughter +granddaughters +grande +grandee +grandees +grander +grandest +grandeur +grandeurs +grandfather +grandfathered +grandfathering +grandfatherly +grandfathers +grandiloquence +grandiloquent +grandiloquently +grandiose +grandiosely +grandioseness +grandiosity +grandioso +grandkid +grandkids +grandly +grandma +grandmas +grandmaster +grandmasters +grandmother +grandmotherly +grandmothers +grandnephew +grandnephews +grandness +grandniece +grandnieces +grandpa +grandparent +grandparental +grandparenthood +grandparents +grandpas +grands +grandsir +grandsire +grandsires +grandsirs +grandson +grandsons +grandstand +grandstanded +grandstander +grandstanders +grandstanding +grandstands +granduncle +granduncles +grange +granger +grangerism +grangers +granges +granite +granites +graniteware +granitewares +granitic +granitoid +granivorous +grannie +grannies +granny +granola +granolas +granolith +granolithic +granoliths +granophyre +granophyres +granophyric +grant +grantable +granted +grantee +grantees +granter +granters +granting +grantor +grantors +grants +grantsman +grantsmanship +grantsmanships +grantsmen +granular +granularity +granularly +granulate +granulated +granulates +granulating +granulation +granulations +granulative +granulator +granulators +granule +granules +granulite +granulites +granulitic +granulize +granulized +granulizes +granulizing +granulocyte +granulocytes +granulocytic +granulocytopoiesis +granuloma +granulomas +granulomata +granulomatous +granulose +granum +grape +grapefruit +grapefruits +grapes +grapeshot +grapeshots +grapevine +grapevines +grapey +graph +graphed +grapheme +graphemes +graphemic +graphemically +graphemics +graphic +graphical +graphically +graphicness +graphics +graphing +graphite +graphites +graphitic +graphitizable +graphitization +graphitize +graphitized +graphitizes +graphitizing +graphological +graphologies +graphologist +graphologists +graphology +graphotype +graphotypes +graphs +grapier +grapiest +grapiness +grapnel +grapnels +grappa +grappas +grapple +grappled +grappler +grapplers +grapples +grappling +grapplings +graptolite +graptolites +grapy +gras +grasp +graspable +grasped +grasper +graspers +grasping +graspingly +graspingness +grasps +grass +grassed +grasser +grassers +grasses +grassfire +grassfires +grasshopper +grasshoppers +grassier +grassiest +grassing +grassland +grasslands +grasslike +grassplot +grassplots +grassroots +grassy +grat +grata +grate +grated +grateful +gratefully +gratefulness +grater +graters +grates +gratia +gratian +gratias +graticule +graticules +gratification +gratifications +gratified +gratifier +gratifiers +gratifies +gratify +gratifying +gratifyingly +gratin +grating +gratingly +gratings +gratins +gratis +gratitude +gratuities +gratuitous +gratuitously +gratuitousness +gratuity +gratulate +gratulated +gratulates +gratulating +gratulation +gratulations +gratulatory +graupel +graupels +gravamen +gravamens +gravamina +grave +graved +gravedigger +gravediggers +gravel +graveled +graveless +graveling +gravelled +gravelling +gravelly +gravels +gravely +graven +graveness +graver +gravers +graves +graveside +gravesides +gravesite +gravesites +gravest +gravestone +gravestones +graveyard +graveyards +gravid +gravida +gravidae +gravidas +gravidities +gravidity +gravidly +gravidness +gravies +gravimeter +gravimeters +gravimetric +gravimetrical +gravimetrically +gravimetry +graving +gravis +gravisphere +gravispheres +gravitas +gravitate +gravitated +gravitater +gravitaters +gravitates +gravitating +gravitation +gravitational +gravitationally +gravitations +gravitative +gravities +graviton +gravitons +gravity +gravlax +gravure +gravures +gravy +gray +graybeard +graybeards +grayed +grayer +grayest +grayfish +grayfishes +graying +grayish +graylag +graylags +grayling +graylings +grayly +graymail +graymails +grayness +grays +graysbies +graysby +graywacke +graywackes +graz +grazable +graze +grazeable +grazed +grazer +grazers +grazes +grazier +graziers +grazing +grazings +grazioso +grease +greased +greaseless +greasepaint +greasepaints +greaseproof +greaser +greasers +greases +greasewood +greasier +greasiest +greasily +greasiness +greasing +greasy +great +greatcoat +greatcoats +greaten +greatened +greatening +greatens +greater +greatest +greathearted +greatheartedly +greatheartedness +greatly +greatness +greats +greave +greaves +grebe +grebes +grecian +grecianize +grecianized +grecianizes +grecianizing +grecians +grecism +grecisms +grecize +grecized +grecizes +grecizing +greco +gree +greece +greed +greedier +greediest +greedily +greediness +greedy +greeing +greek +greeks +green +greenback +greenbacker +greenbackers +greenbackism +greenbacks +greenbelt +greenbelts +greenbrier +greenbriers +greenbug +greenbugs +greene +greened +greener +greeneries +greenery +greenest +greenfinch +greenfinches +greenflies +greenfly +greengage +greengages +greengrocer +greengroceries +greengrocers +greengrocery +greenhead +greenheads +greenheart +greenhearts +greenhorn +greenhorns +greenhouse +greenhouses +greenie +greenies +greening +greenings +greenish +greenishness +greenland +greenlander +greenlanders +greenlandic +greenlet +greenlets +greenling +greenlings +greenly +greenmail +greenmailer +greenmailers +greenmails +greenmarket +greenmarkets +greenness +greenockite +greenockites +greenroom +greenrooms +greens +greensand +greensands +greenshank +greenshanks +greensick +greensickness +greenside +greenskeeper +greenskeepers +greenstick +greenstone +greenstones +greensward +greenway +greenways +greenwich +greenwood +greenwoods +greeny +grees +greet +greeted +greeter +greeters +greeting +greetings +greets +gregarine +gregarines +gregarinian +gregarious +gregariously +gregariousness +gregorian +gregory +greige +greisen +greisens +gremlin +gremlins +grenada +grenade +grenades +grenadian +grenadians +grenadier +grenadiers +grenadine +grenadines +grendel +grenoble +gresham +gressorial +grew +grewsome +grex +grexs +grey +greyed +greyer +greyest +greyhen +greyhens +greyhound +greyhounds +greying +greyish +greylag +greylags +greyness +greys +gribble +gribbles +grid +gridded +gridder +gridders +griddle +griddlecake +griddlecakes +griddled +griddles +griddling +gridiron +gridirons +gridlock +gridlocked +gridlocking +gridlocks +grids +grief +griefs +grieg +grievance +grievances +grievant +grievants +grieve +grieved +griever +grievers +grieves +grieving +grievingly +grievous +grievously +grievousness +griffin +griffins +griffon +griffons +grift +grifted +grifter +grifters +grifting +grifts +grig +grigri +grigris +grigs +grill +grillage +grillages +grille +grilled +griller +grilleries +grillers +grillery +grilles +grilling +grillroom +grillrooms +grills +grillwork +grilse +grim +grimace +grimaced +grimacer +grimacers +grimaces +grimacing +grimalkin +grimalkins +grime +grimed +grimes +grimier +grimiest +grimily +griminess +griming +grimly +grimm +grimmer +grimmest +grimness +grimsel +grimy +grin +grind +grinder +grinders +grinding +grindingly +grindings +grinds +grindstone +grindstones +gringo +gringos +grinned +grinner +grinners +grinning +grinningly +grins +griot +griots +grip +gripe +griped +griper +gripers +gripes +griping +grippe +gripped +gripper +grippers +grippes +gripping +grippingly +grippy +grips +gripsack +gripsacks +gris +grisaille +grisailles +grise +griselda +griseofulvin +griseofulvins +griseous +grises +grisette +grisettes +grislier +grisliest +grisliness +grisly +grison +grisons +grist +gristle +gristles +gristlier +gristliest +gristliness +gristly +gristmill +gristmills +grit +grith +griths +grits +gritted +grittier +grittiest +grittily +grittiness +gritting +gritty +grivet +grivets +grizzle +grizzled +grizzles +grizzlier +grizzlies +grizzliest +grizzling +grizzly +groan +groaned +groaner +groaners +groaning +groaningly +groans +groat +groats +groatss +grocer +groceries +grocers +grocery +grog +groggier +groggiest +groggily +grogginess +groggy +grogram +grograms +grogs +grogshop +grogshops +groin +groined +groining +groins +grok +grokked +grokking +groks +grolier +grommet +grommets +gromwell +gromwells +groom +groomed +groomer +groomers +grooming +grooms +groomsman +groomsmen +groove +grooved +groover +groovers +grooves +groovier +grooviest +grooviness +grooving +groovy +grope +groped +groper +gropers +gropes +groping +gropingly +gropings +grosbeak +grosbeaks +groschen +grosgrain +grosgrains +gross +grossed +grosser +grossers +grosses +grossest +grossglockner +grossing +grossly +grossness +grossular +grossularite +grossularites +grossulars +grosz +groszy +grot +grotesque +grotesquely +grotesqueness +grotesquerie +grotesqueries +grotesquery +grotesques +grots +grottier +grottiest +grottiness +grotto +grottoes +grottos +grotty +grouch +grouched +grouches +grouchier +grouchiest +grouchily +grouchiness +grouching +grouchy +ground +groundbreaker +groundbreakers +groundbreaking +groundbreakings +grounded +grounder +grounders +groundhog +groundhogs +grounding +groundkeeper +groundkeepers +groundless +groundlessly +groundlessness +groundling +groundlings +groundmass +groundmasses +groundnut +groundnuts +groundout +groundouts +grounds +groundsel +groundsels +groundsheet +groundsheets +groundside +groundsides +groundsill +groundsills +groundskeeper +groundskeepers +groundskeeping +groundsman +groundsmen +groundstroke +groundstrokes +groundswell +groundswells +groundwater +groundwork +group +groupable +grouped +grouper +groupers +groupie +groupies +grouping +groupings +groups +groupthink +groupthinks +grouse +groused +grouser +grousers +grouses +grousing +grout +grouted +grouter +grouters +grouting +grouts +grove +grovel +groveled +groveler +grovelers +groveling +grovelingly +grovelled +grovelling +grovels +groves +grow +grower +growers +growing +growingly +growl +growled +growler +growlers +growlier +growliest +growliness +growling +growlingly +growls +growly +grown +grownup +grownups +grows +growth +growths +groyne +groynes +grub +grubbed +grubber +grubbers +grubbier +grubbiest +grubbily +grubbiness +grubbing +grubby +grubs +grubstake +grubstaked +grubstaker +grubstakers +grubstakes +grubstaking +grudge +grudged +grudger +grudgers +grudges +grudging +grudgingly +grudziadz +gruel +grueling +gruelingly +gruelling +gruesome +gruesomely +gruesomeness +gruff +gruffer +gruffest +gruffly +gruffness +grumble +grumbled +grumbler +grumblers +grumbles +grumbling +grumblingly +grumbly +grummet +grummets +grump +grumped +grumpier +grumpiest +grumpily +grumpiness +grumping +grumps +grumpy +grundy +grunge +grunges +grungier +grungiest +grungy +grunion +grunions +grunt +grunted +grunter +grunters +grunting +gruntingly +gruntle +gruntled +gruntles +gruntling +grunts +grus +grutten +gruyere +gruyère +gryphon +gryphons +grâce +guacamole +guacharo +guacharos +guadalajara +guadalcanal +guadalquivir +guadalupe +guadeloupe +guadeloupian +guadeloupians +guaiac +guaiacol +guaiacols +guaiacs +guaiacum +guaiacums +guam +guamanian +guamanians +guan +guanabara +guanaco +guanacos +guanethidine +guanethidines +guangdong +guangxi +guangzhou +guanidine +guanine +guanines +guano +guanos +guanosine +guanosines +guans +guantánamo +guanylic +guaporé +guar +guarani +guaranies +guaranis +guarantee +guaranteed +guaranteeing +guarantees +guarantied +guaranties +guarantor +guarantors +guaranty +guarantying +guard +guardant +guardants +guarded +guardedly +guardedness +guarder +guarders +guardhouse +guardhouses +guardian +guardians +guardianship +guardianships +guarding +guardmember +guardmembers +guardrail +guardrails +guardroom +guardrooms +guards +guardsman +guardsmen +guarneri +guarnerius +guars +guatemala +guatemalan +guatemalans +guava +guavas +guayaquil +guayule +guayules +gubernator +gubernatorial +gubernators +guck +gudgeon +gudgeons +gudrun +guelder +guelf +guelfs +guelph +guelphs +guenevere +guenon +guenons +guerdon +guerdoned +guerdoning +guerdons +gueridon +gueridons +guerilla +guerillas +guernica +guernsey +guernseys +guerre +guerrilla +guerrillas +guess +guessed +guesser +guessers +guesses +guessing +guesstimate +guesstimated +guesstimates +guesstimating +guesswork +guest +guested +guesthouse +guesthouses +guesting +guestroom +guestrooms +guests +guff +guffaw +guffawed +guffawing +guffaws +guffs +guggenheim +guggle +guggled +guggles +guggling +guianese +guidable +guidance +guide +guideboard +guideboards +guidebook +guidebooks +guided +guideline +guidelines +guidepost +guideposts +guider +guiders +guides +guideway +guideways +guideword +guidewords +guiding +guidon +guidons +guienne +guignol +guild +guildenstern +guilder +guilders +guildhall +guildhalls +guilds +guildship +guildsman +guildsmen +guile +guiled +guileful +guilefully +guilefulness +guileless +guilelessly +guilelessness +guiles +guiling +guillemot +guillemots +guilloche +guilloches +guillotine +guillotined +guillotines +guillotining +guilt +guiltier +guiltiest +guiltily +guiltiness +guiltless +guiltlessly +guiltlessness +guilty +guimpe +guimpes +guinea +guinean +guineans +guineas +guinevere +guinness +guipure +guipures +guiro +guisard +guisards +guise +guises +guitar +guitarfish +guitarfishes +guitarist +guitarists +guitars +gujarat +gujarati +gujaratis +gujerati +gujeratis +gujranwala +gul +gulag +gulags +gular +gulch +gulches +gulden +guldens +gules +guleses +gulf +gulfed +gulfing +gulfs +gulfweed +gulfweeds +gull +gullability +gullable +gullably +gullah +gulled +gullet +gullets +gulley +gullibility +gullible +gullibly +gullied +gullies +gulling +gulliver +gulls +gullwing +gully +gullying +gulosities +gulosity +gulp +gulped +gulper +gulpers +gulping +gulpingly +gulps +guls +gum +gumball +gumballs +gumbo +gumboil +gumboils +gumbos +gumdrop +gumdrops +gumma +gummas +gummata +gummatous +gummed +gummer +gummers +gummier +gummiest +gumminess +gumming +gummite +gummites +gummose +gummoses +gummosis +gummous +gummy +gumption +gums +gumshoe +gumshoed +gumshoeing +gumshoes +gumwood +gumwoods +gun +gunboat +gunboats +guncotton +gundog +gundogs +gunfight +gunfighter +gunfighters +gunfights +gunfire +gunflint +gunflints +gung +gunite +gunites +gunk +gunky +gunlock +gunlocks +gunman +gunmen +gunmetal +gunmetals +gunnar +gunnbjørn +gunned +gunnel +gunnels +gunner +gunnera +gunneras +gunneries +gunners +gunnery +gunnies +gunning +gunnings +gunny +gunnysack +gunnysacks +gunplay +gunpoint +gunpoints +gunpowder +gunpowders +gunroom +gunrooms +gunrunner +gunrunners +gunrunning +guns +gunsel +gunsels +gunship +gunships +gunshot +gunshots +gunslinger +gunslingers +gunslinging +gunsmith +gunsmiths +gunstock +gunstocks +gunther +gunwale +gunwales +guoyu +guoyus +guppies +guppy +gurdies +gurdy +gurgitation +gurgitations +gurgle +gurgled +gurgles +gurgling +gurglingly +gurkha +gurkhas +gurnard +gurnards +gurney +gurneys +gurries +gurry +guru +gurus +gush +gushed +gusher +gushers +gushes +gushier +gushiest +gushily +gushiness +gushing +gushingly +gushy +gusset +gusseted +gusseting +gussets +gussied +gussies +gussy +gussying +gust +gustation +gustations +gustative +gustatorily +gustatory +gustavus +gusted +gustier +gustiest +gustily +gustiness +gusting +gusto +gustoes +gusts +gusty +gut +gutbucket +gutbuckets +gutenberg +guthrie +guthrun +gutless +gutlessly +gutlessness +guts +gutsier +gutsiest +gutsily +gutsiness +gutsy +gutta +guttae +guttate +guttated +guttation +guttations +gutted +gutter +guttered +guttering +gutters +guttersnipe +guttersnipes +guttersnipish +guttier +guttiest +gutting +guttural +gutturalism +gutturality +gutturalization +gutturalizations +gutturalize +gutturalized +gutturalizes +gutturalizing +gutturally +gutturalness +gutturals +gutty +guy +guyana +guyanese +guyed +guyenne +guying +guyot +guyots +guys +guzzle +guzzled +guzzler +guzzlers +guzzles +guzzling +gweduc +gweducs +gwent +gwynedd +gybe +gybed +gybes +gybing +gym +gymkhana +gymkhanas +gymnasia +gymnasium +gymnasiums +gymnast +gymnastic +gymnastically +gymnastics +gymnasts +gymnosophist +gymnosophists +gymnosperm +gymnospermous +gymnosperms +gymnospermy +gyms +gynandries +gynandromorph +gynandromorphic +gynandromorphism +gynandromorphous +gynandromorphy +gynandrous +gynandry +gynarchic +gynarchies +gynarchy +gynecocracies +gynecocracy +gynecocratic +gynecoid +gynecologic +gynecological +gynecologist +gynecologists +gynecology +gynecomastia +gynecopathies +gynecopathy +gynocracies +gynocracy +gynodioecious +gynodioecism +gynoecia +gynoecium +gynogenesis +gynophore +gynophores +gynophoric +gyoza +gyozas +gyoár +gyp +gypped +gypper +gyppers +gypping +gyps +gypseous +gypsied +gypsies +gypsiferous +gypsophila +gypsophilas +gypsophile +gypsophiles +gypsum +gypsums +gypsy +gypsying +gyral +gyrally +gyrate +gyrated +gyrates +gyrating +gyration +gyrational +gyrations +gyrator +gyrators +gyratory +gyre +gyred +gyrene +gyrenes +gyres +gyrfalcon +gyrfalcons +gyri +gyring +gyro +gyrocompass +gyrocompasses +gyrofrequency +gyromagnetic +gyron +gyrons +gyroplane +gyroplanes +gyros +gyroscope +gyroscopes +gyroscopic +gyroscopically +gyrostabilizer +gyrostabilizers +gyrostat +gyrostatic +gyrostatically +gyrostats +gyrus +gyve +gyved +gyves +gyving +gâteau +gâteaux +gît +göta +göteborg +götterdämmerung +götterdämmerungs +göttingen +gütersloh +h +ha +haakon +haarlem +haarlemmermeer +habakkuk +habanera +habaneras +habdalah +habdalahs +habeas +haber +haberdasher +haberdasheries +haberdashers +haberdashery +habergeon +habergeons +habile +habiliment +habiliments +habilitate +habilitated +habilitates +habilitating +habilitation +habilitations +habit +habitability +habitable +habitableness +habitably +habitan +habitans +habitant +habitants +habitat +habitation +habitations +habitats +habited +habiting +habits +habitual +habitually +habitualness +habituate +habituated +habituates +habituating +habituation +habituations +habitude +habitudes +habitus +habitué +habitués +haboob +haboobs +habsburg +habsburgs +hacek +haceks +hachinohe +hachioji +hachure +hachured +hachures +hachuring +hacienda +haciendas +hack +hackable +hackamore +hackamores +hackberries +hackberry +hackbut +hackbuteer +hackbuteers +hackbuts +hackbutter +hackbutters +hacked +hackensack +hacker +hackers +hackie +hackies +hacking +hackle +hackleback +hacklebacks +hackled +hackler +hacklers +hackles +hackling +hackly +hackman +hackmatack +hackmatacks +hackmen +hackney +hackneyed +hackneying +hackneys +hacks +hacksaw +hacksawed +hacksawing +hacksaws +hackwork +had +hadal +haddie +haddock +haddocks +hade +hadean +hades +hadith +hadj +hadjes +hadji +hadjis +hadley +hadn +hadn't +hadrian +hadron +hadronic +hadrons +hadrosaur +hadrosaurs +hadst +hae +haeckel +haed +haeing +haen +haes +haet +haets +hafez +haffet +haffets +hafiz +hafizes +hafnium +haft +haftarah +hafted +hafting +haftorah +hafts +hafun +hag +hagar +hagen +hagerstown +hagfish +hagfishes +haggada +haggadah +haggadic +haggadist +haggadistic +haggadists +haggadoth +haggai +haggard +haggardly +haggardness +haggards +haggis +haggises +haggish +haggishly +haggishness +haggle +haggled +haggler +hagglers +haggles +haggling +hagiarchies +hagiarchy +hagiocracies +hagiocracy +hagiographa +hagiographer +hagiographers +hagiographic +hagiographical +hagiographies +hagiography +hagiolatries +hagiolatry +hagiologic +hagiological +hagiologies +hagiologist +hagiologists +hagiology +hagioscope +hagioscopes +hagioscopic +hagridden +hagride +hagrides +hagriding +hagrode +hags +hague +hah +hahn +hahnemann +hahnium +haick +haida +haidan +haidas +haifa +haig +haighthaicks +haik +haikou +haiks +haiku +haikus +hail +haile +hailed +hailer +hailers +hailing +hails +hailstone +hailstones +hailstorm +hailstorms +haimish +hainan +hainault +hainaut +haiphong +hair +hairball +hairballs +hairbreadth +hairbreadths +hairbrush +hairbrushes +haircloth +haircloths +haircut +haircuts +haircutter +haircutters +haircutting +haircuttings +hairdo +hairdos +hairdresser +hairdressers +hairdressing +hairdressings +hairdryer +hairdryers +haired +hairier +hairiest +hairiness +hairless +hairlessness +hairlike +hairline +hairlines +hairnet +hairnets +hairpiece +hairpieces +hairpin +hairpins +hairs +hairsbreadth +hairsbreadths +hairsplitter +hairsplitters +hairsplitting +hairsplittings +hairspray +hairsprays +hairspring +hairsprings +hairstreak +hairstreaks +hairstyle +hairstyles +hairstyling +hairstylings +hairstylist +hairstylists +hairweave +hairweaver +hairweavers +hairweaves +hairweaving +hairweavings +hairworm +hairworms +hairwove +hairwoven +hairy +haiti +haitian +haitians +haj +hajes +haji +hajis +hajj +hajjes +hajji +hajjis +haka +hakas +hake +hakeem +hakeems +hakenkreuz +hakenkreuzes +hakes +hakim +hakims +hakluyt +hakodate +haku +hakus +halacha +halachas +halakah +halakahs +halakic +halal +halala +halalas +halals +halation +halations +halavah +halavahs +halberd +halberdier +halberdiers +halberds +halbert +halberts +halcyon +halcyons +haldane +hale +haleakala +haled +haleness +haler +halers +haleru +hales +halest +halethorpe +haley +half +halfback +halfbacks +halfbeak +halfbeaks +halfcocked +halfhearted +halfheartedly +halfheartedness +halfness +halfpence +halfpennies +halfpenny +halfpennyworth +halftime +halftimes +halftone +halftones +halftoning +halfway +halfwit +halfwits +halfword +halfwords +halibut +halibuts +halicarnassus +halide +halides +halidom +halidome +halidomes +halidoms +halifax +haling +halite +halitosis +hall +hallah +hallahs +hallandale +hallel +hallels +hallelujah +hallelujahs +halley +halliard +halliards +hallmark +hallmarked +hallmarking +hallmarks +hallo +halloa +halloaed +halloaing +halloas +halloed +halloo +hallooed +hallooing +halloos +hallos +hallow +hallowe +hallowe'en +hallowe'ens +hallowed +halloween +halloweens +hallowing +hallowmas +hallowmases +hallowmass +hallows +halls +hallstatt +halluces +hallucinate +hallucinated +hallucinates +hallucinating +hallucination +hallucinational +hallucinations +hallucinative +hallucinator +hallucinators +hallucinatory +hallucinogen +hallucinogenic +hallucinogens +hallucinosis +hallux +hallway +hallways +halma +halmahera +halo +halobiont +halobionts +halocarbon +halocarbons +halocline +haloclines +haloed +haloes +halogen +halogenate +halogenated +halogenates +halogenating +halogenation +halogenations +halogenous +halogens +haloing +halomorphic +halon +halons +haloperidol +halophile +halophiles +halophilic +halophilous +halophyte +halophytes +halophytic +halos +halothane +halothanes +halsted +halt +halted +haltemprice +halter +halterbreak +halterbreaking +halterbreaks +halterbroke +halterbroken +haltere +haltered +halteres +haltering +halters +halting +haltingly +halts +halva +halvah +halvahs +halvas +halve +halved +halvers +halves +halving +halyard +halyards +halévy +ham +hama +hamadan +hamadryad +hamadryades +hamadryads +hamadryas +hamadryases +hamah +hamal +hamals +hamamatsu +haman +hamartia +hamartias +hamate +hamates +hamburg +hamburger +hamburgers +hamburgs +hamden +hame +hamelin +hameln +hames +hamilcar +hamilton +hamiltonian +hamiltonians +hamite +hamites +hamitic +hamitics +hamito +hamlet +hamlets +hamlin +hammal +hammals +hammarskjöld +hammed +hammer +hammered +hammerer +hammerers +hammerfest +hammerhead +hammerheads +hammering +hammerkop +hammerkops +hammerless +hammerlock +hammerlocks +hammers +hammerstein +hammertoe +hammertoes +hammier +hammiest +hammily +hamminess +hamming +hammock +hammocks +hammond +hammurabi +hammy +hamper +hampered +hampering +hampers +hampshire +hampton +hams +hamster +hamsters +hamstring +hamstringing +hamstrings +hamstrung +hamtramck +hamuli +hamulus +hamza +hamzah +hamzahs +hamzas +han +hanau +hancock +hand +handan +handbag +handbags +handball +handballs +handbarrow +handbarrows +handbill +handbills +handblown +handbook +handbooks +handbrake +handbrakes +handbreadth +handbreadths +handcar +handcars +handcart +handcarts +handclap +handclaps +handclasp +handclasps +handcraft +handcrafted +handcrafter +handcrafters +handcrafting +handcraftmanship +handcrafts +handcraftsman +handcraftsmanship +handcraftsmen +handcuff +handcuffed +handcuffing +handcuffs +handed +handedly +handedness +handel +handelian +hander +handers +handfast +handfasts +handful +handfuls +handgrip +handgrips +handgun +handguns +handheld +handhelds +handhold +handholding +handholdings +handholds +handicap +handicapped +handicapper +handicappers +handicapping +handicaps +handicraft +handicrafter +handicrafters +handicrafts +handicraftsman +handicraftsmen +handicraftswoman +handicraftswomen +handier +handies +handiest +handily +handiness +handing +handiwork +handkerchief +handkerchiefs +handkerchieves +handle +handleable +handlebar +handlebars +handled +handleless +handler +handlers +handles +handless +handlin +handling +handlings +handlist +handlists +handloom +handlooms +handmade +handmaid +handmaiden +handmaidens +handmaids +handoff +handoffs +handout +handouts +handpick +handpicked +handpicking +handpicks +handpress +handpresses +handprint +handprints +handrail +handrails +hands +handsaw +handsaws +handsbreadth +handsel +handseled +handseling +handselled +handselling +handsels +handset +handsets +handsful +handshake +handshakes +handshaking +handsome +handsomely +handsomeness +handsomer +handsomest +handspike +handspikes +handspring +handsprings +handstand +handstands +handwheel +handwheels +handwork +handworker +handworkers +handwoven +handwringer +handwringers +handwringing +handwringings +handwrite +handwrites +handwriting +handwritings +handwritten +handwrote +handwrought +handy +handyman +handymen +hang +hangable +hangar +hangars +hangchou +hangchow +hangdog +hangdogs +hanged +hanger +hangers +hanging +hangings +hangman +hangmen +hangnail +hangnails +hangout +hangouts +hangover +hangovers +hangs +hangtag +hangtags +hangzhou +hank +hanker +hankered +hankerer +hankerers +hankering +hankerings +hankers +hankie +hankies +hanks +hanky +hannibal +hanno +hannover +hanoi +hanover +hanoverian +hanoverians +hans +hansa +hansard +hansards +hanse +hanseatic +hansel +hanseled +hanseling +hanselled +hanselling +hansels +hansen +hansen's +hanses +hansom +hansoms +hantan +hantavirus +hanukah +hanukkah +hanukkahs +hanuman +hanumans +hao +haole +haoles +haos +hap +hapax +haphazard +haphazardly +haphazardness +haphazardry +haphtarah +haphtaroth +haphtoros +haphtorot +haphtoroth +hapless +haplessly +haplessness +haplite +haplites +haploid +haploidies +haploids +haploidy +haplology +haplont +haplonts +haplosis +haply +happed +happen +happenchance +happenchances +happened +happening +happenings +happens +happenstance +happenstances +happi +happier +happiest +happily +happiness +happinesses +happing +happy +haps +hapsburg +hapsburgs +hapten +haptene +haptenes +haptenic +haptens +haptic +haptoglobin +haptoglobins +hara +haran +harangue +harangued +haranguer +haranguers +harangues +haranguing +harappa +harare +harass +harassed +harasser +harassers +harasses +harassing +harassment +harassments +harbinger +harbingered +harbingering +harbingers +harbor +harborage +harborages +harbored +harborer +harborers +harborful +harboring +harborless +harbormaster +harbormasters +harbors +harbour +harboured +harbourer +harbourers +harbouring +harbours +hard +hardback +hardbacks +hardball +hardballs +hardboard +hardboards +hardboiled +hardboot +hardboots +hardbound +hardbounds +hardcase +hardcopies +hardcopy +hardcore +hardcover +hardcovers +hardecanute +hardedge +hardedges +harden +hardened +hardener +hardeners +hardening +hardenings +hardens +harder +hardest +hardfisted +hardhack +hardhacks +hardhanded +hardhandedness +hardhat +hardhats +hardhead +hardheaded +hardheadedly +hardheadedness +hardheads +hardhearted +hardheartedly +hardheartedness +hardicanute +hardier +hardies +hardiest +hardihood +hardily +hardiment +hardiness +hardly +hardmouthed +hardness +hardnesses +hardpan +hardpans +hardscrabble +hardscrabbles +hardship +hardships +hardstand +hardstanding +hardstands +hardtack +hardtacks +hardtop +hardtops +hardware +hardwire +hardwired +hardwires +hardwiring +hardwood +hardwoods +hardworking +hardy +hare +harebell +harebells +harebrain +harebrained +harebrains +hared +harelip +harelipped +harelips +harem +harems +hares +haricot +haricots +harijan +harijans +haring +hark +harked +harken +harkened +harkening +harkens +harking +harks +harlem +harlemite +harlemites +harlequin +harlequinade +harlequinades +harlequins +harlot +harlotries +harlotry +harlots +harlow +harm +harmattan +harmattans +harmed +harmer +harmers +harmful +harmfully +harmfulness +harming +harmless +harmlessly +harmlessness +harmolodic +harmonic +harmonica +harmonically +harmonicas +harmonics +harmonies +harmonious +harmoniously +harmoniousness +harmonist +harmonistic +harmonistically +harmonists +harmonium +harmoniums +harmonization +harmonizations +harmonize +harmonized +harmonizer +harmonizers +harmonizes +harmonizing +harmony +harms +harness +harnessed +harnesser +harnessers +harnesses +harnessing +harney +harold +harp +harped +harper +harpers +harpies +harping +harpist +harpists +harpoon +harpooned +harpooner +harpooners +harpooning +harpoons +harps +harpsichord +harpsichordist +harpsichordists +harpsichords +harpy +harquebus +harquebuses +harquebusier +harquebusiers +harran +harridan +harridans +harried +harrier +harriers +harries +harriman +harrington +harris +harrisburg +harrison +harrisonburg +harrow +harrowed +harrower +harrowers +harrowing +harrows +harrumph +harrumphed +harrumphing +harrumphs +harry +harrying +harsh +harshen +harshened +harshening +harshens +harsher +harshest +harshly +harshness +harslet +harslets +hart +hartebeest +hartebeests +hartford +harts +hartshorn +hartshorns +harum +haruspex +haruspication +haruspications +haruspices +harvard +harvest +harvestability +harvestable +harvested +harvester +harvesters +harvesting +harvestman +harvestmen +harvests +harvesttime +harvesttimes +harvey +haryana +harz +has +hasdrubal +hasenpfeffer +hasenpfeffers +hash +hashana +hashanah +hashed +hasheesh +hashemite +hashemites +hasher +hashers +hashes +hashimite +hashimites +hashing +hashish +hashishes +hashona +hashonah +hasid +hasidic +hasidim +hasidism +haslet +haslets +hasmonaean +hasmonean +hasn +hasn't +hasp +hasped +hasping +hasps +hassid +hassium +hassle +hassled +hassles +hassling +hassock +hassocks +hast +hasta +hastate +hastately +haste +hasted +hasten +hastened +hastener +hasteners +hastening +hastens +hastes +hastier +hastiest +hastily +hastiness +hasting +hastings +hasty +hat +hatband +hatbands +hatbox +hatboxes +hatch +hatchability +hatchable +hatchback +hatchbacks +hatcheck +hatchecks +hatched +hatchel +hatcheled +hatcheling +hatchelled +hatchelling +hatchels +hatcher +hatcheries +hatchers +hatchery +hatches +hatchet +hatchets +hatching +hatchings +hatchling +hatchlings +hatchment +hatchments +hatchway +hatchways +hate +hated +hateful +hatefully +hatefulness +hater +haters +hates +hath +hating +hatless +hatmaker +hatmakers +hatpin +hatpins +hatred +hatreds +hats +hatshepsut +hatted +hatter +hatteras +hatters +hattiesburg +hatting +haubergeon +haubergeons +hauberk +hauberks +haugh +haughs +haughtier +haughtiest +haughtily +haughtiness +haughty +haul +haulage +haulages +hauled +hauler +haulers +hauling +haulm +haulms +hauls +haunch +haunches +haunt +haunted +haunter +haunters +haunting +hauntingly +haunts +hauraki +hausa +hausas +hausfrau +hausfraus +haustella +haustellate +haustellum +haustoria +haustorial +haustorium +haut +hautbois +hautboy +hautboys +haute +hauteur +havana +havanan +havanans +havant +havasupai +havasupais +havdalah +havdalahs +have +haveli +havelock +havelocks +haven +haven't +havened +havening +havens +haver +havered +havering +havers +haversack +haversacks +haversian +haves +having +havoc +havocked +havocking +havocs +havre +haw +hawaii +hawaiian +hawaiians +hawed +hawfinch +hawfinches +hawing +hawk +hawked +hawker +hawkers +hawkeye +hawkeyes +hawking +hawkins +hawkish +hawkishly +hawkishness +hawkmoth +hawkmoths +hawks +hawksbill +hawksbills +hawkshaw +hawkshaws +hawkweed +hawkweeds +haworthia +haworthias +haws +hawse +hawsehole +hawseholes +hawser +hawsers +hawses +hawthorn +hawthorne +hawthorns +hay +haycock +haycocks +haydn +hayed +hayer +hayers +hayes +hayfield +hayfields +hayfork +hayforks +haying +haylage +haylages +hayloft +haylofts +haymaker +haymakers +haymaking +haymow +haymows +hayrack +hayracks +hayrick +hayricks +hayride +hayrides +hays +hayseed +hayseeds +haystack +haystacks +haywire +hazan +hazanim +hazard +hazarded +hazarding +hazardous +hazardously +hazardousness +hazards +haze +hazed +hazel +hazelnut +hazelnuts +hazels +hazer +hazers +hazes +hazier +haziest +hazily +haziness +hazing +hazings +hazleton +hazlitt +hazy +hazzan +hazzans +he +he'd +he'll +he's +head +headache +headaches +headachy +headband +headbands +headboard +headboards +headcheese +headcount +headcounter +headcounters +headcounts +headdress +headdresses +headed +headedness +header +headers +headfast +headfasts +headfirst +headforemost +headful +headfuls +headgate +headgates +headgear +headhunt +headhunted +headhunter +headhunters +headhunting +headhunts +headier +headiest +headily +headiness +heading +headings +headlamp +headlamps +headland +headlands +headless +headlessness +headlight +headlights +headline +headlined +headliner +headliners +headlines +headlining +headlock +headlocks +headlong +headman +headmaster +headmasters +headmastership +headmen +headmistress +headmistresses +headmost +headnote +headnotes +headphone +headphones +headpiece +headpieces +headpin +headpins +headquarter +headquartered +headquartering +headquarters +headrace +headraces +headrest +headrests +headroom +heads +headsail +headsails +headscarf +headscarfs +headscarves +headset +headsets +headshake +headshakes +headshaking +headship +headships +headshot +headshots +headshrinker +headshrinkers +headsman +headsmen +headspace +headspaces +headspring +headsprings +headstall +headstalls +headstand +headstands +headstock +headstocks +headstone +headstones +headstream +headstreams +headstrong +headwaiter +headwaiters +headwall +headwalls +headwater +headwaters +headway +headwear +headwears +headwind +headwinds +headword +headwords +headwork +headworker +headworkers +heady +heal +healable +healed +healer +healers +healing +heals +health +healthful +healthfully +healthfulness +healthier +healthiest +healthily +healthiness +healths +healthy +heap +heaped +heaping +heaps +heapsort +hear +hearable +heard +hearer +hearers +hearing +hearings +hearken +hearkened +hearkening +hearkens +hears +hearsay +hearse +hearsed +hearses +hearsing +heart +heartache +heartaches +heartbeat +heartbeats +heartbreak +heartbreaker +heartbreakers +heartbreaking +heartbreakingly +heartbreaks +heartbroken +heartbrokenly +heartbrokenness +heartburn +heartburning +hearted +heartedly +heartedness +hearten +heartened +heartening +hearteningly +heartens +heartfelt +hearth +hearthrug +hearthrugs +hearths +hearthside +hearthsides +hearthstone +hearthstones +heartier +hearties +heartiest +heartily +heartiness +hearting +heartland +heartlands +heartleaf +heartleafs +heartless +heartlessly +heartlessness +heartrending +heartrendingly +hearts +heartsease +heartseases +heartsick +heartsickness +heartsome +heartsomely +heartsore +heartstring +heartstrings +heartthrob +heartthrobs +heartwarming +heartwarmingly +heartwood +heartworm +heartworms +hearty +heat +heatable +heated +heatedly +heater +heaters +heath +heathen +heathendom +heathenish +heathenishly +heathenishness +heathenism +heathenize +heathenized +heathenizes +heathenizing +heathenry +heathens +heather +heathers +heathery +heathless +heathlike +heathrow +heaths +heathy +heating +heatless +heatproof +heats +heatstroke +heatstrokes +heave +heaved +heaven +heavenliness +heavenly +heavens +heavenward +heavenwards +heaver +heavers +heaves +heavier +heavies +heaviest +heavily +heaviness +heaving +heaviside +heavy +heavyhearted +heavyheartedly +heavyheartedness +heavyset +heavyweight +heavyweights +hebdomad +hebdomadal +hebdomadally +hebdomads +hebe +hebei +hebephrenia +hebephrenias +hebephrenic +hebetate +hebetated +hebetates +hebetating +hebetation +hebetations +hebetative +hebetude +hebetudes +hebetudinous +hebraic +hebraical +hebraically +hebraism +hebraist +hebraistic +hebraistical +hebraistically +hebraists +hebraization +hebraizations +hebraize +hebraized +hebraizes +hebraizing +hebrew +hebrews +hebridean +hebrideans +hebrides +hebron +hecate +hecatomb +hecatombs +heck +heckelphone +heckelphones +heckle +heckled +heckler +hecklers +heckles +heckling +heckuva +hectare +hectares +hectic +hectically +hectoampere +hectoamperes +hectobecquerel +hectobecquerels +hectocandela +hectocandelas +hectocotyli +hectocotylus +hectocoulomb +hectocoulombs +hectofarad +hectofarads +hectogram +hectograms +hectograph +hectographed +hectographic +hectographically +hectographing +hectographs +hectohenries +hectohenry +hectohenrys +hectohertz +hectojoule +hectojoules +hectokelvin +hectokelvins +hectoliter +hectoliters +hectolumen +hectolumens +hectolux +hectometer +hectometers +hectomole +hectomoles +hectonewton +hectonewtons +hectoohm +hectoohms +hectopascal +hectopascals +hector +hectoradian +hectoradians +hectored +hectoring +hectors +hectosecond +hectoseconds +hectosiemens +hectosievert +hectosieverts +hectosteradian +hectosteradians +hectotesla +hectoteslas +hectovolt +hectovolts +hectowatt +hectowatts +hectoweber +hectowebers +hecuba +hedda +heddle +heddles +heder +heders +hedge +hedged +hedgehog +hedgehogs +hedgehop +hedgehopped +hedgehopper +hedgehoppers +hedgehopping +hedgehops +hedgepig +hedgepigs +hedger +hedgerow +hedgerows +hedgers +hedges +hedging +hedgingly +hedgy +hedjaz +hedonic +hedonically +hedonics +hedonism +hedonist +hedonistic +hedonistically +hedonists +hee +heebie +heed +heeded +heedful +heedfully +heedfulness +heeding +heedless +heedlessly +heedlessness +heeds +heehaw +heehawed +heehawing +heehaws +heel +heelball +heelballs +heeled +heeler +heelers +heeling +heelless +heelpiece +heelpieces +heelpost +heelposts +heels +heeltap +heeltaps +heelwork +heelworks +heft +hefted +heftier +heftiest +heftily +heftiness +hefting +hefts +hefty +hegang +hegari +hegaris +hegel +hegelian +hegelianism +hegelians +hegemonic +hegemonies +hegemonism +hegemonist +hegemonists +hegemony +hegira +hegiras +heidelberg +heifer +heifers +heigh +height +heighten +heightened +heightener +heighteners +heightening +heightens +heights +heilbronn +heilongjiang +heilungkiang +heimish +heimlich +heinie +heinies +heinous +heinously +heinousness +heir +heirdom +heirdoms +heiress +heiresses +heirless +heirloom +heirlooms +heirs +heirship +heirships +heisenberg +heist +heisted +heisting +heists +hejaz +hejira +hejiras +hekate +hekla +held +heldentenor +heldentenors +helen +helena +helens +helgoland +heliacal +heliacally +heliborne +helical +helically +helices +helicoid +helicoidal +helicoids +helicon +helicons +helicopter +helicoptered +helicoptering +helicopters +helicultural +heliculturalist +heliculturalists +heliculture +heligoland +heliocentric +heliocentrical +heliocentricity +heliogabalus +heliograph +heliographed +heliographer +heliographers +heliographic +heliographing +heliographs +heliography +heliolatrous +heliolatry +heliometer +heliometers +heliometric +heliometrical +heliometrically +heliometry +heliopolis +helios +helioseismology +heliosphere +heliospheres +heliostat +heliostats +heliotactic +heliotaxis +heliotaxises +heliotherapies +heliotherapy +heliotrope +heliotropes +heliotropic +heliotropically +heliotropin +heliotropins +heliotropism +heliotype +heliotyped +heliotypes +heliotypic +heliotyping +heliotypy +heliozoan +heliozoans +heliozoic +helipad +helipads +heliport +heliports +helistop +helistops +helium +helix +helixes +hell +hellacious +helladic +hellas +hellbender +hellbenders +hellbox +hellboxes +hellbroth +hellcat +hellcats +helldiver +helldivers +hellebore +hellebores +helled +hellene +hellenes +hellenian +hellenians +hellenic +hellenism +hellenist +hellenistic +hellenistical +hellenists +hellenization +hellenizations +hellenize +hellenized +hellenizer +hellenizers +hellenizes +hellenizing +heller +helleri +helleries +hellers +hellespont +hellfire +hellfires +hellgrammite +hellgrammites +hellhole +hellholes +hellhound +hellhounds +helling +hellion +hellions +hellish +hellishly +hellishness +hello +helloed +helloes +helloing +hellos +hells +helluva +helm +helmed +helmet +helmeted +helmeting +helmetlike +helmets +helming +helminth +helminthiases +helminthiasis +helminthic +helminthics +helminthologist +helminthologists +helminthology +helminths +helms +helmsman +helmsmanship +helmsmen +helo +helos +helot +helotism +helotisms +helotries +helotry +helots +help +helped +helper +helpers +helpful +helpfully +helpfulness +helping +helpings +helpless +helplessly +helplessness +helpmate +helpmates +helpmeet +helpmeets +helps +helsingborg +helsingør +helsinki +helter +helve +helves +helvetia +helvetian +helvetians +helvetic +helvetica +helvetii +hem +hemacytometer +hemacytometers +hemagglutinate +hemagglutinated +hemagglutinates +hemagglutinating +hemagglutination +hemagglutinations +hemagglutinin +hemagglutinins +hemal +hemangioma +hemangiomas +hemangiomata +hemaphereses +hemapheresis +hematein +hemateins +hematic +hematics +hematin +hematinic +hematinics +hematins +hematite +hematites +hematitic +hematoblast +hematoblastic +hematoblasts +hematocrit +hematocrits +hematogenesis +hematogenetic +hematogenic +hematogenous +hematologic +hematological +hematologically +hematologist +hematologists +hematology +hematolysis +hematoma +hematomas +hematomata +hematophagous +hematopoiesis +hematopoietic +hematoporphyrin +hematoporphyrins +hematothermia +hematoxylin +hematoxylins +hematozoa +hematozoal +hematozoic +hematozoon +hematuria +hematurias +hematuric +heme +hemelytra +hemelytron +hemeralopia +hemeralopias +hemeralopic +hemerocallis +hemerocallises +hemes +hemialgia +hemialgias +hemic +hemicellulose +hemicelluloses +hemichordate +hemichordates +hemicycle +hemicycles +hemidemisemiquaver +hemidemisemiquavers +hemihedral +hemihydrate +hemihydrated +hemihydrates +hemimetabolic +hemimetabolism +hemimetabolous +hemimorphic +hemimorphism +hemimorphite +hemimorphites +hemin +hemingway +hemins +hemiola +hemiolas +hemiparasite +hemiparasites +hemiparasitic +hemiplegia +hemiplegias +hemiplegic +hemiplegics +hemipteran +hemipterans +hemipterous +hemisphere +hemispheres +hemispheric +hemispherical +hemispherically +hemistich +hemistichs +hemline +hemlines +hemlock +hemlocks +hemmed +hemmer +hemmers +hemming +hemochromatosis +hemocoel +hemocoels +hemocyanin +hemocyanins +hemocyte +hemocytes +hemodialyses +hemodialysis +hemodynamic +hemodynamically +hemodynamics +hemoflagellate +hemoflagellates +hemoglobin +hemoglobinopathies +hemoglobinopathy +hemoglobins +hemoglobinuria +hemoglobinurias +hemoglobinuric +hemolymph +hemolymphatic +hemolymphs +hemolysin +hemolysins +hemolysis +hemolytic +hemolyze +hemolyzed +hemolyzes +hemolyzing +hemophilia +hemophiliac +hemophiliacs +hemophilic +hemophobia +hemophobic +hemopoiesis +hemopoietic +hemoprotein +hemoproteins +hemoptysis +hemorrhage +hemorrhaged +hemorrhages +hemorrhagic +hemorrhaging +hemorrhoid +hemorrhoidal +hemorrhoidectomies +hemorrhoidectomy +hemorrhoids +hemosiderin +hemosiderins +hemostasia +hemostasis +hemostat +hemostatic +hemostatics +hemostats +hemp +hempen +hemps +hems +hemstitch +hemstitched +hemstitcher +hemstitchers +hemstitches +hemstitching +hen +henbane +henbanes +henbit +henbits +hence +henceforth +henceforward +henchman +henchmen +hencoop +hencoops +hendecasyllabic +hendecasyllabics +hendecasyllable +hendecasyllables +hendiadys +hendiadyses +hendrix +henequen +henequens +henequin +henequins +hengist +henhouse +henhouses +henna +hennaed +hennaing +hennas +henneries +hennery +hennish +hennishly +hennishness +henotheism +henotheist +henotheistic +henotheists +henpeck +henpecked +henpecking +henpecks +henries +henry +henrys +hens +hent +hented +henting +hents +hep +heparin +heparinize +heparinized +heparinizes +heparinizing +hepatic +hepatica +hepaticas +hepatics +hepatitides +hepatitis +hepatocellular +hepatocyte +hepatocytes +hepatoma +hepatomas +hepatomata +hepatomegalies +hepatomegaly +hepatotoxic +hepatotoxicity +hepatotoxin +hepatotoxins +hepcat +hepcats +hephaestos +hephaestus +hepper +heppest +hepplewhite +heptachlor +heptachlors +heptad +heptads +heptagon +heptagonal +heptagons +heptahedra +heptahedral +heptahedron +heptahedrons +heptameter +heptameters +heptane +heptanes +heptarchic +heptarchical +heptarchies +heptarchy +heptastich +heptastiches +heptateuch +heptathlon +heptathlons +heptavalent +heptose +heptoses +her +hera +heraclea +heracles +heraclitean +heraclitus +heraclius +herakles +herald +heralded +heraldic +heraldically +heralding +heraldist +heraldists +heraldries +heraldry +heralds +herb +herbaceous +herbage +herbal +herbalist +herbalists +herbals +herbaria +herbarium +herbariums +herbed +herbert +herbicidal +herbicidally +herbicide +herbicides +herbivore +herbivores +herbivorous +herbivorously +herblike +herbs +herby +herculaneum +herculean +hercules +hercynian +herd +herded +herder +herders +herdic +herdics +herding +herdlike +herds +herdsman +herdsmen +here +hereabout +hereabouts +hereafter +hereaway +hereaways +hereby +hereditament +hereditaments +hereditarian +hereditarianism +hereditarians +hereditarily +hereditariness +hereditary +heredities +hereditist +hereditists +heredity +hereford +herefords +herein +hereinabove +hereinafter +hereinbefore +hereinbelow +hereinto +hereof +hereon +herero +hereros +heresiarch +heresiarchs +heresies +heresy +heretic +heretical +heretically +hereticalness +heretics +hereto +heretofore +hereunder +hereunto +hereupon +hereward +herewith +heriot +heriots +heritabilities +heritability +heritable +heritably +heritage +heritages +heritor +heritors +heriz +herizes +herky +herl +herls +herm +herma +hermae +hermai +herman +hermaphrodism +hermaphrodite +hermaphrodites +hermaphroditic +hermaphroditically +hermaphroditism +hermaphroditus +hermas +hermatypic +hermeneutic +hermeneutical +hermeneutically +hermeneutics +hermeneutist +hermeneutists +hermes +hermetic +hermetical +hermetically +hermeticism +hermetism +hermetist +hermetists +hermit +hermitage +hermitages +hermitian +hermitic +hermitical +hermitically +hermitism +hermits +hermon +hermosillo +herms +hern +hernia +herniae +hernial +hernias +herniate +herniated +herniates +herniating +herniation +herniations +herns +hero +herod +herodas +herodian +herodias +herodotus +heroes +heroic +heroical +heroically +heroicalness +heroicomic +heroicomical +heroics +heroin +heroine +heroines +heroinism +heroinisms +heroism +heron +heronries +heronry +herons +heros +herpes +herpesvirus +herpesviruses +herpetic +herpetologic +herpetological +herpetologically +herpetologist +herpetologists +herpetology +herr +herren +herrenvolk +herrenvolks +herrick +herring +herringbone +herringboned +herringbones +herringboning +herrings +hers +herschel +herself +hershey +herstories +herstory +hertfordshire +hertz +hertzian +hertzsprung +herzegovina +herzegovinian +herzegovinians +heshvan +heshvans +heshwan +heshwans +hesiod +hesitance +hesitancies +hesitancy +hesitant +hesitantly +hesitate +hesitated +hesitater +hesitaters +hesitates +hesitating +hesitatingly +hesitation +hesitations +hesperian +hesperidean +hesperides +hesperidia +hesperidian +hesperidin +hesperidins +hesperidium +hesperus +hess +hesse +hessian +hessians +hessite +hessites +hessonite +hessonites +hest +hestia +hests +het +hetaera +hetaerae +hetaeras +hetaeric +hetaira +hetairai +hetairas +hetero +heteroatom +heteroatoms +heterocarpies +heterocarpous +heterocarpy +heterocercal +heterochromatic +heterochromatin +heterochromatins +heterochromatism +heterochromatisms +heterochromosome +heterochromosomes +heterocycle +heterocycles +heterocyclic +heterocyst +heterocysts +heterodox +heterodoxies +heterodoxy +heterodyne +heterodyned +heterodynes +heterodyning +heteroecious +heteroecism +heterogamete +heterogametes +heterogametic +heterogamic +heterogamies +heterogamous +heterogamy +heterogeneity +heterogeneous +heterogeneously +heterogeneousness +heterogenic +heterogenous +heterogeny +heterogonic +heterogonous +heterogony +heterograft +heterografts +heterogynous +heterokaryon +heterokaryons +heterokaryotic +heterolecithal +heterologous +heterologously +heterology +heterolyses +heterolysis +heterolytic +heteromerous +heteromorphic +heteromorphism +heteronomous +heteronomously +heteronomy +heteronym +heteronymous +heteronyms +heteroousian +heterophil +heterophile +heterophonic +heterophony +heterophyllous +heterophylly +heterophyte +heterophytes +heterophytic +heteroplastic +heteroplasties +heteroplasty +heteroploid +heteroploids +heteroploidy +heteropterous +heteros +heterosexism +heterosexual +heterosexuality +heterosexually +heterosexuals +heterosis +heterosporous +heterospory +heterostyled +heterostylous +heterostyly +heterotactic +heterotactous +heterotaxes +heterotaxia +heterotaxias +heterotaxies +heterotaxis +heterotaxy +heterothallic +heterothallism +heterotic +heterotopia +heterotopias +heterotopic +heterotopies +heterotopy +heterotroph +heterotrophic +heterotrophically +heterotrophs +heterotrophy +heterotypic +heterotypical +heterousian +heterozygosis +heterozygosity +heterozygote +heterozygotes +heterozygous +heth +hetman +hetmans +heulandite +heulandites +heuristic +heuristically +heuristics +hew +hewed +hewer +hewers +hewing +hewn +hews +hex +hexachlorethane +hexachlorethanes +hexachloride +hexachloroethane +hexachloroethanes +hexachlorophene +hexachord +hexachords +hexad +hexadecimal +hexadecimally +hexadecimals +hexadic +hexads +hexafluoride +hexagon +hexagonal +hexagonally +hexagons +hexagram +hexagrams +hexahedra +hexahedral +hexahedron +hexahedrons +hexahydrate +hexamerism +hexamerous +hexameter +hexameters +hexamethonium +hexamethylenetetramine +hexamethylenetetramines +hexametric +hexametrical +hexane +hexaploid +hexaploids +hexaploidy +hexapod +hexapodous +hexapods +hexastyle +hexateuch +hexavalent +hexed +hexer +hexerei +hexereis +hexers +hexes +hexing +hexosan +hexosans +hexose +hexoses +hexyl +hexylresorcinol +hexylresorcinols +hexyls +hey +heyday +heydays +heywood +hezekiah +hi +hialeah +hiatal +hiatus +hiatuses +hiawatha +hibachi +hibachis +hibernacula +hibernaculum +hibernal +hibernate +hibernated +hibernates +hibernating +hibernation +hibernations +hibernator +hibernators +hibernia +hibernian +hibernians +hiberno +hibiscus +hibiscuses +hic +hiccough +hiccoughed +hiccoughing +hiccoughs +hiccup +hiccuped +hiccuping +hiccupped +hiccupping +hiccups +hick +hickey +hickeys +hickories +hickory +hicks +hid +hidalgo +hidalgos +hidatsa +hidatsas +hidden +hiddenite +hiddenites +hiddenness +hide +hideaway +hideaways +hidebound +hided +hideosity +hideous +hideously +hideousness +hideout +hideouts +hider +hiders +hides +hiding +hidings +hidroses +hidrosis +hidrotic +hie +hied +hieing +hiemal +hierapolis +hierarch +hierarchal +hierarchic +hierarchical +hierarchically +hierarchies +hierarchization +hierarchizations +hierarchize +hierarchized +hierarchizes +hierarchizing +hierarchs +hierarchy +hieratic +hieratically +hierocracies +hierocracy +hierocratic +hierocratical +hierodule +hierodules +hierodulic +hieroglyph +hieroglyphic +hieroglyphical +hieroglyphically +hieroglyphics +hieroglyphs +hierologies +hierologist +hierologists +hierology +hierophant +hierophantic +hierophants +hies +hifalutin +higashiosaka +higgle +higgled +higgledy +higgler +higglers +higgles +higgling +high +highball +highballed +highballing +highballs +highbinder +highbinders +highborn +highboy +highboys +highbred +highbrow +highbrowed +highbrowism +highbrows +highbush +highchair +highchairs +higher +highest +highfalutin +highfaluting +highflier +highfliers +highflyer +highflyers +highflying +highhanded +highhandedly +highhandedness +highjack +highjacked +highjacker +highjackers +highjacking +highjacks +highland +highlander +highlanders +highlands +highlife +highlifer +highlifers +highlifes +highlight +highlighted +highlighter +highlighters +highlighting +highlights +highline +highly +highness +highnesses +highroad +highroads +highs +hight +hightail +hightailed +hightailing +hightails +highway +highwayman +highwaymen +highways +hijack +hijacked +hijacker +hijackers +hijacking +hijackings +hijacks +hijiki +hijikis +hijinks +hike +hiked +hiker +hikers +hikes +hiking +hila +hilar +hilarious +hilariously +hilariousness +hilarities +hilarity +hilary +hilbert +hildebrand +hildesheim +hilding +hildings +hill +hillbillies +hillbilly +hillcrest +hillcrests +hilled +hillel +hiller +hillers +hilliard +hillier +hilliest +hilliness +hilling +hillock +hillocks +hillocky +hills +hillscape +hillside +hillsides +hilltop +hilltops +hilly +hilo +hilt +hilted +hilton +hilts +hilum +hilversum +him +himachal +himalaya +himalayan +himalayans +himalayas +himalia +himatia +himation +himations +himmler +himself +himyarite +himyarites +himyaritic +hin +hinayana +hinayanist +hinayanistic +hinayanists +hind +hindbrain +hindbrains +hindemith +hindenburg +hinder +hindered +hinderer +hinderers +hindering +hindermost +hinders +hindgut +hindguts +hindi +hindmost +hindoo +hindquarter +hindquarters +hindrance +hindrances +hinds +hindsight +hindu +hinduism +hindus +hindustan +hindustani +hinge +hinged +hinges +hinging +hinnies +hinny +hins +hint +hinted +hinter +hinterland +hinterlands +hinters +hinting +hints +hip +hipbone +hipbones +hipline +hiplines +hiply +hipness +hipparchus +hipped +hipper +hippest +hippias +hippie +hippiedom +hippiehood +hippies +hipping +hippo +hippocampal +hippocampi +hippocampus +hippocras +hippocrases +hippocrates +hippocratic +hippocrene +hippodrome +hippodromes +hippogriff +hippogriffs +hippogryph +hippolyta +hippolytus +hippomenes +hippopotami +hippopotamus +hippopotamuses +hippos +hippy +hips +hipster +hipsterism +hipsters +hirable +hiragana +hircine +hire +hireable +hired +hireling +hirelings +hirer +hirers +hires +hiring +hirohito +hiroshima +hirsute +hirsuteness +hirsutism +hirudin +hirudins +his +hispanic +hispanicism +hispanicisms +hispanicization +hispanicizations +hispanicize +hispanicized +hispanicizes +hispanicizing +hispanics +hispaniola +hispanism +hispanisms +hispanist +hispanists +hispano +hispanophile +hispanophiles +hispanophilia +hispanophobe +hispanophobes +hispanophobia +hispanos +hispid +hispidity +hiss +hissarlik +hissed +hisself +hisser +hissers +hisses +hissing +hissingly +hissy +hist +histaminase +histaminases +histamine +histaminergic +histamines +histaminic +histidine +histidines +histiocyte +histiocytes +histiocytic +histiocytoses +histiocytosis +histochemical +histochemically +histochemistry +histocompatibilities +histocompatibility +histocompatible +histodialyses +histodialysis +histogenesis +histogenetic +histogenetically +histogenic +histogenically +histogram +histograms +histologic +histological +histologically +histologies +histologist +histologists +histology +histolysis +histolytic +histolytically +histomoniases +histomoniasis +histone +histones +histopathologic +histopathological +histopathologically +histopathologist +histopathologists +histopathology +histophysiologic +histophysiological +histophysiology +histoplasmoses +histoplasmosis +historian +historians +historiated +historic +historical +historically +historicalness +historicism +historicist +historicists +historicity +historicization +historicizations +historicize +historicized +historicizes +historicizing +historied +histories +historiographer +historiographers +historiographic +historiographical +historiographically +historiography +history +histrionic +histrionical +histrionically +histrionics +hit +hitachi +hitch +hitched +hitcher +hitchers +hitches +hitchhike +hitchhiked +hitchhiker +hitchhikers +hitchhikes +hitchhiking +hitching +hither +hithermost +hitherto +hitherward +hitherwards +hitler +hitlerism +hitlerite +hitlerites +hitless +hits +hittable +hitter +hitters +hitting +hittite +hittites +hive +hived +hiveless +hives +hiving +hiwassee +hkakabo +hmm +hmong +hmongs +ho +hoagie +hoagies +hoagy +hoar +hoard +hoarded +hoarder +hoarders +hoarding +hoardings +hoards +hoarfrost +hoarfrosts +hoarier +hoariest +hoarily +hoariness +hoars +hoarse +hoarsely +hoarsen +hoarsened +hoarseness +hoarsening +hoarsens +hoarser +hoarsest +hoary +hoatzin +hoatzins +hoax +hoaxed +hoaxer +hoaxers +hoaxes +hoaxing +hob +hobart +hobbed +hobbes +hobbesian +hobbies +hobbing +hobbism +hobbist +hobbists +hobbit +hobbits +hobble +hobblebush +hobblebushes +hobbled +hobbledehoy +hobbledehoys +hobbler +hobblers +hobbles +hobbling +hobby +hobbyhorse +hobbyhorses +hobbyist +hobbyists +hobgoblin +hobgoblins +hobnail +hobnailed +hobnails +hobnob +hobnobbed +hobnobber +hobnobbers +hobnobbing +hobnobs +hobo +hoboed +hoboes +hoboing +hoboism +hoboken +hobos +hobs +hoc +hock +hocked +hocker +hockers +hockey +hocking +hocks +hockshop +hockshops +hocus +hocused +hocuses +hocusing +hocussed +hocusses +hocussing +hod +hodgepodge +hodgepodges +hodgkin +hodoscope +hodoscopes +hods +hoe +hoecake +hoecakes +hoed +hoedown +hoedowns +hoeing +hoer +hoers +hoes +hog +hogan +hogans +hogarth +hogback +hogbacks +hogfish +hogfishes +hogg +hogged +hogging +hoggish +hoggishly +hoggishness +hoggs +hogmanay +hogmanays +hognose +hogs +hogshead +hogsheads +hogwash +hogweed +hogweeds +hohenlohe +hohenstaufen +hohenstaufens +hohenzollern +hohenzollerns +hoi +hoick +hoicked +hoicking +hoicks +hoise +hoised +hoises +hoisin +hoising +hoist +hoisted +hoister +hoisters +hoisting +hoists +hoity +hokan +hokang +hoke +hoked +hokes +hokey +hokeyness +hokeypokey +hokeypokeys +hokier +hokiest +hokily +hokiness +hoking +hokkaido +hokku +hokum +hokums +hokusai +hokypokies +holandric +holarctic +holbein +hold +holdall +holdalls +holdback +holdbacks +holden +holder +holders +holdfast +holdfasts +holding +holdings +holdout +holdouts +holdover +holdovers +holds +holdup +holdups +hole +holed +holes +holey +holiday +holidayed +holidayer +holidayers +holidaying +holidaymaker +holidaymakers +holidays +holier +holies +holiest +holily +holiness +holing +holinshed +holism +holisms +holist +holistic +holistically +holists +holla +hollaed +hollaing +holland +hollandaise +hollander +hollanders +hollas +holler +hollered +hollering +hollerith +hollers +hollies +hollo +holloa +holloaed +holloaing +holloas +holloed +holloes +holloing +hollos +hollow +holloware +hollowed +hollower +hollowest +hollowing +hollowly +hollowness +hollows +hollowware +holly +hollyhock +hollyhocks +hollywood +holm +holmes +holmic +holmium +holms +holoblastic +holoblastically +holocaust +holocaustal +holocaustic +holocausts +holocene +holocrine +holoenzyme +holoenzymes +holofernes +hologamous +hologram +holograms +holograph +holographic +holographical +holographically +holographs +holography +hologynic +holohedral +holometabolism +holometabolous +holophrastic +holophytic +holoplankton +holoplanktons +holothurian +holothurians +holotype +holotypes +holotypic +holozoic +holp +holpen +holst +holstein +holsteins +holster +holstered +holstering +holsters +holt +holts +holy +holyoke +holystone +holystoned +holystones +holystoning +homage +homager +homagers +hombre +hombres +homburg +homburgs +home +homebodies +homebody +homebound +homeboy +homeboys +homebred +homebuilder +homebuilders +homebuilding +homebuilt +homebuyer +homebuyers +homecoming +homecomings +homed +homefolk +homefolks +homegrown +homeland +homelands +homeless +homelessness +homelier +homeliest +homelike +homeliness +homely +homemade +homemaker +homemakers +homemaking +homeobox +homeoboxes +homeomorphic +homeomorphism +homeomorphisms +homeomorphous +homeopath +homeopathic +homeopathically +homeopathies +homeopathist +homeopathists +homeopaths +homeopathy +homeostasis +homeostatic +homeotherm +homeothermal +homeothermic +homeothermous +homeotherms +homeowner +homeowners +homeownership +homer +homered +homeric +homerically +homering +homeroom +homerooms +homers +homes +homesick +homesickness +homesite +homesites +homespun +homestead +homesteaded +homesteader +homesteaders +homesteading +homesteads +homestretch +homestretches +hometown +hometowns +homeward +homewards +homework +homey +homeyness +homicidal +homicidally +homicide +homicides +homier +homiest +homiletic +homiletical +homiletically +homiletics +homilies +homilist +homilists +homily +hominem +hominess +homing +hominid +hominidae +hominids +hominization +hominizations +hominoid +hominoids +hominy +hommos +homo +homocentric +homocercal +homochirality +homochromatic +homochromatism +homoecious +homoerotic +homoeroticism +homoerotism +homogametic +homogamous +homogamy +homogenate +homogenates +homogeneities +homogeneity +homogeneous +homogeneously +homogeneousness +homogenies +homogenization +homogenizations +homogenize +homogenized +homogenizer +homogenizers +homogenizes +homogenizing +homogenous +homogeny +homograft +homografts +homograph +homographic +homographs +homoiotherm +homoiothermal +homoiothermic +homoiothermous +homoiotherms +homoiousian +homoiousians +homolecithal +homolog +homologate +homologated +homologates +homologating +homologation +homologic +homological +homologically +homologies +homologize +homologized +homologizer +homologizers +homologizes +homologizing +homologous +homolographic +homologs +homologue +homologues +homology +homolosine +homolysis +homolytic +homomorphic +homomorphism +homomorphisms +homomorphous +homonuclear +homonym +homonymic +homonymies +homonymous +homonymously +homonyms +homonymy +homoousian +homoousians +homophile +homophiles +homophobe +homophobes +homophobia +homophobic +homophone +homophones +homophonic +homophonies +homophonous +homophony +homophylic +homophylies +homophyly +homoplasies +homoplastic +homoplastically +homoplasy +homopolar +homopolymer +homopolymers +homopteran +homopterans +homopterous +homos +homoscedastic +homoscedasticity +homosexual +homosexuality +homosexually +homosexuals +homosporous +homospory +homostyled +homostylous +homostyly +homotaxial +homotaxic +homotaxis +homotaxises +homothallic +homothallism +homotransplant +homotransplantation +homozygosis +homozygosity +homozygote +homozygotes +homozygotic +homozygous +homozygously +homunculi +homunculus +homy +hon +honan +honans +honcho +honchoed +honchoing +honchos +honduran +hondurans +honduras +hone +honed +honer +honers +hones +honest +honesties +honestly +honesty +honewort +honeworts +honey +honeybee +honeybees +honeyberries +honeyberry +honeybunch +honeybunches +honeycomb +honeycombed +honeycombing +honeycombs +honeycreeper +honeycreepers +honeydew +honeydews +honeyeater +honeyeaters +honeyed +honeying +honeymoon +honeymooned +honeymooner +honeymooners +honeymooning +honeymoons +honeys +honeysuckle +honeysuckles +honeywell +honfleur +hong +hongs +honiara +honied +honing +honk +honked +honker +honkers +honkey +honkeys +honkie +honkies +honking +honks +honky +honkytonks +honolulu +honor +honorabilities +honorability +honorable +honorableness +honorably +honoraria +honorarily +honorarium +honorariums +honorary +honored +honoree +honorees +honorer +honorers +honorific +honorifically +honorifics +honoring +honors +honshu +hoo +hooch +hooches +hood +hooded +hoodedness +hooding +hoodlike +hoodlum +hoodlumish +hoodlumism +hoodlums +hoodmold +hoodmolds +hoodoo +hoodooed +hoodooing +hoodooism +hoodoos +hoods +hoodwink +hoodwinked +hoodwinker +hoodwinkers +hoodwinking +hoodwinks +hooey +hoof +hoofbeat +hoofbeats +hoofbound +hoofed +hoofer +hoofers +hoofing +hoofprint +hoofprints +hoofs +hook +hookah +hookahs +hooked +hookedness +hooker +hookers +hookey +hookeys +hookies +hooking +hooklet +hooklets +hooknose +hooknosed +hooknoses +hooks +hookup +hookups +hookworm +hookworms +hooky +hooligan +hooliganism +hooligans +hoop +hooped +hooper +hoopers +hooping +hoopla +hooplike +hoopoe +hoopoes +hoops +hoopskirt +hoopskirts +hoorah +hoorahs +hooray +hoorayed +hooraying +hoorays +hoosegow +hoosegows +hoosier +hoosiers +hoot +hootch +hootches +hootchy +hooted +hootenannies +hootenanny +hooter +hooters +hooting +hoots +hooved +hooverville +hoovervilles +hooves +hop +hopatcong +hope +hoped +hopeful +hopefully +hopefulness +hopefuls +hopeh +hopei +hopeless +hopelessly +hopelessness +hoper +hopers +hopes +hopewell +hophead +hopheads +hopi +hoping +hopis +hoplite +hoplites +hoplitic +hopped +hopper +hoppergrass +hoppergrasses +hoppers +hopping +hops +hopsack +hopsacking +hopsacks +hopscotch +hopscotched +hopscotches +hopscotching +hora +horace +horah +horahs +horary +horas +horatian +horatio +horde +hordes +horehound +horehounds +horizon +horizonal +horizons +horizontal +horizontally +horizontals +hormogonia +hormogonium +hormonal +hormonally +hormone +hormonelike +hormones +hormonic +horn +hornbeam +hornbeams +hornbill +hornbills +hornblende +hornblower +hornbook +hornbooks +horned +hornedness +horner +hornet +hornets +hornfels +hornier +horniest +horniness +horning +hornist +hornists +hornito +hornitos +hornless +hornlessness +hornlike +hornpipe +hornpipes +hornpout +hornpouts +horns +hornswoggle +hornswoggled +hornswoggles +hornswoggling +horntail +horntails +hornworm +hornworms +hornwort +hornworts +horny +horologe +horologer +horologers +horologes +horologic +horological +horologist +horologists +horologium +horology +horometrical +horoscope +horoscopes +horrendous +horrendously +horrent +horrible +horribleness +horribly +horrid +horridly +horridness +horrific +horrifically +horrification +horrified +horrifiedly +horrifies +horrify +horrifying +horrifyingly +horripilate +horripilated +horripilates +horripilating +horripilation +horripilations +horror +horrors +horrorstricken +horrorstruck +hors +horsa +horse +horseback +horsebacks +horsecar +horsecars +horsed +horsefeathers +horseflesh +horseflies +horsefly +horsehair +horsehide +horsehides +horselaugh +horselaughs +horseleech +horseleeches +horseless +horselike +horseman +horsemanship +horsemeat +horsemen +horsemint +horsemints +horseplay +horseplayer +horseplayers +horsepower +horserace +horseraces +horseracing +horseradish +horseradishes +horses +horseshit +horseshits +horseshoe +horseshoed +horseshoeing +horseshoer +horseshoers +horseshoes +horsetail +horsetails +horseweed +horseweeds +horsewhip +horsewhipped +horsewhipping +horsewhips +horsewoman +horsewomen +horsey +horsier +horsiest +horsily +horsiness +horsing +horst +horsts +horsy +hortative +hortatively +hortatory +horticultural +horticulturalist +horticulturalists +horticulturally +horticulture +horticulturist +horticulturists +horus +hosanna +hosannah +hosannahs +hosannas +hose +hosea +hosed +hosel +hosels +hoses +hosey +hoseyed +hoseying +hoseys +hosiery +hosing +hospice +hospices +hospitable +hospitably +hospital +hospitaler +hospitalers +hospitalities +hospitality +hospitalization +hospitalizations +hospitalize +hospitalized +hospitalizes +hospitalizing +hospitaller +hospitallers +hospitals +host +hosta +hostage +hostages +hostas +hosted +hostel +hosteled +hosteler +hostelers +hosteling +hostelries +hostelry +hostels +hostess +hostesses +hostile +hostilely +hostiles +hostilities +hostility +hosting +hostler +hostlers +hostly +hosts +hot +hotbed +hotbeds +hotblood +hotbloods +hotbox +hotboxes +hotcake +hotcakes +hotch +hotched +hotches +hotching +hotchpot +hotchpotch +hotchpotches +hotchpots +hotdog +hotdogged +hotdogging +hotdogs +hotel +hotelier +hoteliers +hotelkeeper +hotelkeepers +hotelman +hotelmen +hotels +hotfoot +hotfooted +hotfooting +hotfoots +hothead +hotheaded +hotheadedly +hotheadedness +hotheads +hothouse +hothouses +hotkey +hotline +hotlines +hotly +hotness +hotplate +hotplates +hotpot +hotpots +hotrod +hotrods +hots +hotshot +hotshots +hotspot +hotspots +hotspur +hotted +hottentot +hottentots +hotter +hottest +hotting +hottish +houdah +houdahs +houdan +houdans +houdini +hound +hounded +hounder +hounders +hounding +hounds +houndstooth +hour +hourglass +hourglasses +houri +houris +hourlies +hourlong +hourly +hours +housatonic +house +houseboat +houseboats +housebound +houseboy +houseboys +housebreak +housebreaker +housebreakers +housebreaking +housebreaks +housebroke +housebroken +housecarl +housecarls +houseclean +housecleaned +housecleaner +housecleaners +housecleaning +housecleans +housecoat +housecoats +housed +housedog +housedogs +housedress +housedresses +housefather +housefathers +houseflies +housefly +housefront +housefronts +houseful +housefuls +houseguest +houseguests +household +householder +householders +households +househusband +househusbands +housekeep +housekeeper +housekeepers +housekeeping +housekeeps +housekept +housel +houseled +houseleek +houseleeks +houseless +houselessness +houselights +houseling +housels +housemaid +housemaids +houseman +housemaster +housemasters +housemate +housemates +housemen +housemother +housemothers +housepainter +housepainters +houseparent +houseparents +houseperson +housepersons +houseplant +houseplants +houseroom +houserooms +housers +houses +housesat +housesit +housesits +housesitting +housetop +housetops +housetrain +housetrained +housetraining +housetrains +housewares +housewarming +housewarmings +housewife +housewifeliness +housewifely +housewifery +housewives +housework +houseworker +houseworkers +housing +housings +houston +houstonian +houstonians +hove +hovel +hovels +hover +hovercraft +hovercrafts +hovered +hoverer +hoverers +hovering +hoveringly +hovers +how +howard +howards +howbeit +howdah +howdahs +howdy +howe +howes +however +howf +howff +howffs +howfs +howitzer +howitzers +howl +howled +howler +howlers +howling +howls +hows +howsoever +hoy +hoya +hoyas +hoyden +hoydenish +hoydens +hoyle +hoys +html +hualapai +hualapais +huang +huarache +huaraches +huascarán +hub +hubba +hubbard +hubbies +hubble +hubbub +hubbubs +hubby +hubcap +hubcaps +hubris +hubristic +hubristically +hubs +huck +huckaback +huckabacks +huckleberries +huckleberry +hucks +huckster +huckstered +huckstering +hucksterism +hucksters +huddle +huddled +huddler +huddlers +huddles +huddling +hudibras +hudibrastic +hudson +hue +hued +hues +huevos +huff +huffed +huffier +huffiest +huffily +huffiness +huffing +huffish +huffishly +huffishness +huffs +huffy +hug +huge +hugely +hugeness +hugeous +hugeously +hugeousness +huger +hugest +huggable +hugged +hugger +huggermugger +huggermuggered +huggermuggering +huggermuggers +huggermuggery +huggers +hugging +hugo +hugs +huguenot +huguenotic +huguenotism +huguenots +huh +hui +huipil +huipils +huis +hula +hulas +hulk +hulked +hulking +hulks +hulky +hull +hullaballoo +hullaballoos +hullabaloo +hullabaloos +hulled +huller +hullers +hulling +hullo +hulls +hum +human +humane +humanely +humaneness +humanhood +humanism +humanist +humanistic +humanistically +humanists +humanitarian +humanitarianism +humanitarians +humanities +humanity +humanization +humanize +humanized +humanizer +humanizers +humanizes +humanizing +humankind +humanlike +humanly +humanness +humanoid +humanoids +humans +humate +humates +humberside +humble +humblebee +humblebees +humbled +humbleness +humbler +humblers +humbles +humblest +humbling +humbly +humboldt +humbug +humbugged +humbugger +humbuggers +humbuggery +humbugging +humbugs +humdinger +humdingers +humdrum +hume +humectant +humectants +humectation +humeral +humerals +humeri +humerus +humic +humid +humidification +humidifications +humidified +humidifier +humidifiers +humidifies +humidify +humidifying +humidistat +humidistats +humidity +humidly +humidor +humidors +humification +humifications +humified +humiliate +humiliated +humiliates +humiliating +humiliatingly +humiliation +humiliations +humilities +humility +hummable +hummed +hummer +hummers +humming +hummingbird +hummingbirds +hummock +hummocks +hummocky +hummus +humongous +humor +humoral +humored +humoredly +humoresque +humoresques +humoring +humorist +humoristic +humorists +humorless +humorlessly +humorlessness +humorous +humorously +humorousness +humors +hump +humpback +humpbacked +humpbacks +humped +humperdinck +humph +humphed +humphing +humphrey +humphreys +humphs +humpier +humpiest +humping +humps +humpty +humpy +hums +humungous +humus +humuses +hun +hunan +hunch +hunchback +hunchbacked +hunchbacks +hunched +hunches +hunching +hundred +hundredfold +hundreds +hundredth +hundredths +hundredweight +hundredweights +hung +hungarian +hungarians +hungary +hunger +hungered +hungering +hungers +hungrier +hungriest +hungrily +hungriness +hungry +hunk +hunker +hunkered +hunkering +hunkers +hunkies +hunkpapa +hunkpapas +hunks +hunky +hunnish +hunnishness +huns +hunt +hunted +hunter +hunters +hunting +huntings +huntington +huntress +huntresses +hunts +huntsman +huntsmen +huntsville +hup +hurdle +hurdled +hurdler +hurdlers +hurdles +hurdling +hurdy +hurl +hurled +hurler +hurlers +hurlies +hurling +hurlings +hurls +hurly +huron +hurons +hurrah +hurrahed +hurrahing +hurrahs +hurray +hurricane +hurricanes +hurried +hurriedly +hurriedness +hurrier +hurriers +hurries +hurry +hurrying +hurt +hurter +hurters +hurtful +hurtfully +hurtfulness +hurting +hurtle +hurtled +hurtles +hurtless +hurtling +hurts +husband +husbanded +husbander +husbanders +husbanding +husbandly +husbandman +husbandmen +husbandry +husbands +hush +hushed +hushes +hushing +hushpuppies +hushpuppy +husk +husked +husker +huskers +huskier +huskies +huskiest +huskily +huskiness +husking +huskings +husks +husky +huss +hussar +hussars +hussies +hussite +hussites +hussitism +hussy +hustings +hustle +hustled +hustler +hustlers +hustles +hustling +hut +hutch +hutches +hutment +huts +hutted +hutterite +hutterites +hutting +hutu +hutus +hutzpa +hutzpah +huxley +huygens +huzza +huzzah +huzzahs +huzzas +huáscar +hwang +hwei +hweis +hyacinth +hyacinthine +hyacinths +hyacinthus +hyades +hyaena +hyaenas +hyalin +hyaline +hyalines +hyalinization +hyalins +hyalite +hyalites +hyaloid +hyaloplasm +hyaloplasms +hyaluronic +hyaluronidase +hyaluronidases +hyannis +hybrid +hybridism +hybridist +hybridists +hybridity +hybridization +hybridizations +hybridize +hybridized +hybridizer +hybridizers +hybridizes +hybridizing +hybridoma +hybridomas +hybrids +hybris +hydathode +hydathodes +hydatid +hydatids +hyde +hyderabad +hydra +hydrae +hydralazine +hydralazines +hydramine +hydramines +hydrangea +hydrangeas +hydrant +hydranth +hydranths +hydrants +hydrarch +hydras +hydrase +hydrases +hydrastine +hydrastines +hydrate +hydrated +hydrates +hydrating +hydration +hydrations +hydrator +hydrators +hydraulic +hydraulically +hydraulics +hydrazide +hydrazides +hydrazine +hydric +hydride +hydrides +hydrilla +hydrillas +hydriodic +hydro +hydrobiological +hydrobiologist +hydrobiologists +hydrobiology +hydrobromic +hydrocarbon +hydrocarbonaceous +hydrocarbonic +hydrocarbonous +hydrocarbons +hydrocele +hydroceles +hydrocephalic +hydrocephaloid +hydrocephalous +hydrocephalus +hydrocephaly +hydrochemistry +hydrochloric +hydrochloride +hydrochlorides +hydrochlorothiazide +hydrochlorothiazides +hydrocolloid +hydrocolloidal +hydrocolloids +hydrocoral +hydrocorals +hydrocortisone +hydrocrack +hydrocracked +hydrocracker +hydrocrackers +hydrocracking +hydrocrackings +hydrocracks +hydrocyanic +hydrodynamic +hydrodynamical +hydrodynamically +hydrodynamicist +hydrodynamicists +hydrodynamics +hydroelectric +hydroelectrically +hydroelectricity +hydrofluoric +hydrofoil +hydrofoils +hydroformer +hydroformers +hydroforming +hydroformings +hydrogen +hydrogenase +hydrogenases +hydrogenate +hydrogenated +hydrogenates +hydrogenating +hydrogenation +hydrogenations +hydrogenolysis +hydrogenous +hydrogeologic +hydrogeological +hydrogeologist +hydrogeologists +hydrogeology +hydrographer +hydrographers +hydrographic +hydrographically +hydrographies +hydrography +hydroid +hydroids +hydrokinetic +hydrokinetical +hydrokinetics +hydrolase +hydrolases +hydrologic +hydrological +hydrologically +hydrologist +hydrologists +hydrology +hydrolysate +hydrolysates +hydrolysis +hydrolyte +hydrolytic +hydrolytically +hydrolyzable +hydrolyzate +hydrolyzates +hydrolyzation +hydrolyze +hydrolyzed +hydrolyzes +hydrolyzing +hydromagnetic +hydromagnetics +hydromancy +hydromechanical +hydromechanics +hydromedusa +hydromedusae +hydromedusas +hydromel +hydromels +hydrometallurgical +hydrometallurgy +hydrometeor +hydrometeorological +hydrometeorologist +hydrometeorologists +hydrometeorology +hydrometeors +hydrometer +hydrometers +hydrometric +hydrometrical +hydrometrically +hydrometry +hydromorphic +hydronic +hydronically +hydronium +hydroniums +hydropath +hydropathic +hydropathical +hydropathies +hydropathist +hydropathists +hydropaths +hydropathy +hydroperoxide +hydrophane +hydrophanes +hydrophanous +hydrophile +hydrophiles +hydrophilic +hydrophilicity +hydrophilous +hydrophily +hydrophobia +hydrophobias +hydrophobic +hydrophobicity +hydrophone +hydrophones +hydrophyte +hydrophytes +hydrophytic +hydroplane +hydroplaned +hydroplanes +hydroplaning +hydroponic +hydroponically +hydroponicist +hydroponicists +hydroponics +hydroponist +hydroponists +hydropower +hydroquinol +hydroquinols +hydroquinone +hydroquinones +hydros +hydroscope +hydroscopes +hydroscopic +hydrosere +hydrosol +hydrosolic +hydrosols +hydrospace +hydrospaces +hydrosphere +hydrospheres +hydrospheric +hydrostatic +hydrostatical +hydrostatically +hydrostatics +hydrosulfate +hydrosulfates +hydrosulfide +hydrosulfides +hydrosulfite +hydrosulfites +hydrosulfurous +hydrotactic +hydrotaxis +hydrotaxises +hydrotherapeutic +hydrotherapeutics +hydrotherapies +hydrotherapy +hydrothermal +hydrothermally +hydrothorax +hydrothoraxes +hydrotropic +hydrotropically +hydrotropism +hydrous +hydroxide +hydroxides +hydroxy +hydroxyapatite +hydroxyapatites +hydroxyl +hydroxylamine +hydroxylamines +hydroxylate +hydroxylated +hydroxylates +hydroxylating +hydroxylation +hydroxylic +hydroxyls +hydroxyproline +hydroxyzine +hydrozoa +hydrozoan +hydrozoans +hydrus +hyena +hyenas +hyenic +hyetal +hyetometer +hyetometers +hyetometrograph +hyetometrographs +hygeia +hygiene +hygienic +hygienically +hygienics +hygienist +hygienists +hygrograph +hygrographs +hygrometer +hygrometers +hygrometric +hygrometry +hygrophyte +hygrophytes +hygrophytic +hygroscope +hygroscopes +hygroscopic +hygroscopically +hygroscopicity +hygrostat +hygrostats +hying +hyla +hylas +hylozoic +hylozoism +hylozoist +hylozoistic +hylozoists +hymen +hymenal +hymeneal +hymeneally +hymeneals +hymenia +hymenial +hymenium +hymeniums +hymenopteran +hymenopterans +hymenopteron +hymenopterons +hymenopterous +hymens +hymettus +hymie +hymies +hymn +hymnal +hymnals +hymnaries +hymnary +hymnbook +hymnbooks +hymned +hymning +hymnodies +hymnodist +hymnodists +hymnody +hymnography +hymnologic +hymnological +hymnologist +hymnologists +hymnology +hymns +hyoid +hyoids +hyoscine +hyoscines +hyoscyamine +hyoscyamines +hypabyssal +hypabyssally +hypaethral +hypanthia +hypanthial +hypanthium +hype +hyped +hyper +hyperacid +hyperacidity +hyperactive +hyperactively +hyperactivity +hyperacuity +hyperacute +hyperaesthesia +hyperaesthesias +hyperaesthetic +hyperaggressive +hyperalert +hyperarid +hyperarousal +hyperaware +hyperawareness +hyperbaric +hyperbarically +hyperbaton +hyperbatons +hyperbola +hyperbolae +hyperbolas +hyperbole +hyperbolic +hyperbolical +hyperbolically +hyperbolism +hyperbolisms +hyperbolist +hyperbolists +hyperbolize +hyperbolized +hyperbolizes +hyperbolizing +hyperboloid +hyperboloidal +hyperboloids +hyperborean +hyperboreans +hypercalcemia +hypercalcemias +hypercapnia +hypercapnias +hypercatabolism +hypercatalectic +hypercatalexis +hypercautious +hypercharge +hypercharged +hypercharges +hypercholesterolemia +hypercholesterolemias +hypercivilized +hypercoagulability +hypercoagulable +hypercompetitive +hyperconcentration +hyperconscious +hyperconsciousness +hypercorrect +hypercorrection +hypercorrections +hypercorrectly +hypercorrectness +hypercritic +hypercritical +hypercritically +hypercriticism +hypercriticisms +hypercriticize +hypercriticizes +hypercritics +hypercube +hypercubes +hyperdense +hyperdevelopment +hyperefficient +hyperemia +hyperemic +hyperemotional +hyperemotionality +hyperendemic +hyperenergetic +hyperesthesia +hyperesthesias +hyperesthetic +hypereutectic +hyperexcitability +hyperexcitable +hyperexcited +hyperexcitement +hyperexcretion +hyperextend +hyperextended +hyperextending +hyperextends +hyperextension +hyperextensions +hyperfastidious +hyperfine +hyperfunction +hyperfunctional +hyperfunctioning +hypergamies +hypergamy +hypergeometric +hyperglycemia +hyperglycemic +hypergol +hypergolic +hypergolically +hyperimmune +hyperimmunization +hyperimmunize +hyperimmunized +hyperimmunizes +hyperimmunizing +hyperinflated +hyperinflation +hyperinflationary +hyperinflations +hyperinnervation +hyperinsulinism +hyperinsulinisms +hyperintellectual +hyperintelligent +hyperintense +hyperinvolution +hyperion +hyperirritability +hyperirritable +hyperkeratoses +hyperkeratosis +hyperkeratotic +hyperkinesia +hyperkinesis +hyperkinetic +hyperlink +hyperlinks +hyperlipemia +hyperlipemias +hyperlipidemia +hyperlipidemias +hypermania +hypermanic +hypermarket +hypermarkets +hypermasculine +hypermedia +hypermetabolic +hypermetabolism +hypermeter +hypermeters +hypermetric +hypermetrical +hypermetropia +hypermetropias +hypermetropic +hypermetropical +hypermetropy +hypermnesia +hypermnesias +hypermnesic +hypermobility +hypermodern +hypermodernist +hypermutability +hypermutable +hypernationalistic +hyperon +hyperons +hyperope +hyperopia +hyperopias +hyperopic +hyperostoses +hyperostosis +hyperostotic +hyperparasite +hyperparasites +hyperparasitic +hyperparasitism +hyperparathyroidism +hyperphagia +hyperphagic +hyperphysical +hyperpigmentation +hyperpigmented +hyperpituitarism +hyperpituitarisms +hyperpituitary +hyperplane +hyperplanes +hyperplasia +hyperplasias +hyperplastic +hyperploid +hyperploidy +hyperpnea +hyperpneas +hyperpneic +hyperpolarize +hyperpolarized +hyperpolarizes +hyperpolarizing +hyperproducer +hyperproducers +hyperproduction +hyperpure +hyperpyretic +hyperpyrexia +hyperpyrexial +hyperpyrexias +hyperrational +hyperrationality +hyperreactive +hyperreactivity +hyperreactor +hyperreactors +hyperrealism +hyperrealisms +hyperrealist +hyperrealistic +hyperrealists +hyperresponsive +hyperromantic +hypersaline +hypersalinity +hypersalivation +hypersecretion +hypersensitive +hypersensitiveness +hypersensitivities +hypersensitivity +hypersensitization +hypersensitize +hypersensitized +hypersensitizes +hypersensitizing +hypersexual +hypersexuality +hypersomnolence +hypersonic +hypersonically +hyperspace +hyperspaces +hyperstatic +hypersthene +hypersthenes +hypersthenic +hyperstimulate +hyperstimulated +hyperstimulates +hyperstimulating +hyperstimulation +hypersurface +hypersurfaces +hypersusceptibility +hypersusceptible +hypertense +hypertension +hypertensive +hypertext +hypertexts +hyperthermal +hyperthermia +hyperthermias +hyperthermic +hyperthyroid +hyperthyroidism +hypertonia +hypertonias +hypertonic +hypertonicity +hypertrophic +hypertrophied +hypertrophies +hypertrophy +hypertrophying +hypertypical +hypervelocity +hyperventilate +hyperventilated +hyperventilates +hyperventilating +hyperventilation +hypervigilance +hypervigilant +hypervirulent +hyperviscosity +hypervitaminoses +hypervitaminosis +hypes +hypesthesia +hypesthesias +hypethral +hypha +hyphae +hyphal +hyphen +hyphenate +hyphenated +hyphenates +hyphenating +hyphenation +hyphenations +hyphened +hyphening +hyphenless +hyphens +hyping +hypnagogic +hypnoanalyses +hypnoanalysis +hypnogenesis +hypnogenetic +hypnogenetically +hypnogogic +hypnoid +hypnoidal +hypnopedia +hypnopedias +hypnophobia +hypnophobias +hypnophobic +hypnopompic +hypnos +hypnoses +hypnosis +hypnotherapies +hypnotherapy +hypnotic +hypnotically +hypnotics +hypnotism +hypnotist +hypnotists +hypnotizability +hypnotizable +hypnotization +hypnotize +hypnotized +hypnotizer +hypnotizers +hypnotizes +hypnotizing +hypo +hypoacidities +hypoacidity +hypoactive +hypoallergenic +hypobaric +hypobarism +hypoblast +hypoblastic +hypoblasts +hypocaust +hypocausts +hypocenter +hypocenters +hypocentral +hypochlorite +hypochlorites +hypochlorous +hypochondria +hypochondriac +hypochondriacal +hypochondriacally +hypochondriacs +hypochondriases +hypochondriasis +hypochondrium +hypocorism +hypocorisms +hypocoristic +hypocoristical +hypocoristically +hypocotyl +hypocotyls +hypocrisies +hypocrisy +hypocrite +hypocrites +hypocritical +hypocritically +hypocycloid +hypocycloids +hypoderm +hypodermal +hypodermic +hypodermically +hypodermics +hypodermis +hypodermises +hypoderms +hypoed +hypoesthesia +hypoesthesias +hypoeutectic +hypogastria +hypogastric +hypogastrium +hypogea +hypogeal +hypogeally +hypogean +hypogene +hypogenous +hypogeous +hypogeum +hypoglossal +hypoglycemia +hypoglycemic +hypogynous +hypogyny +hypoing +hypolimnetic +hypolimnial +hypolimnion +hypolimnions +hypomania +hypomanias +hypomanic +hypomorphic +hyponastic +hyponasties +hyponasty +hypophosphite +hypophosphites +hypophosphorous +hypophyseal +hypophyses +hypophysial +hypophysis +hypopituitarism +hypopituitarisms +hypopituitary +hypoplasia +hypoplasias +hypoplastic +hypoploid +hypoploidy +hypopnea +hypopneas +hypopneic +hypos +hyposensitive +hyposensitivities +hyposensitivity +hyposensitization +hyposensitizations +hyposensitize +hyposensitized +hyposensitizes +hyposensitizing +hypostases +hypostasis +hypostatic +hypostatical +hypostatically +hypostatization +hypostatize +hypostatized +hypostatizes +hypostatizing +hyposthenia +hyposthenias +hyposthenic +hypostyle +hypostyles +hyposulfite +hyposulfites +hyposulfurous +hypotactic +hypotaxis +hypotaxises +hypotension +hypotensions +hypotensive +hypotensives +hypotenuse +hypotenuses +hypothalamic +hypothalamus +hypothalamuses +hypothecate +hypothecated +hypothecates +hypothecating +hypothecation +hypothecations +hypothecator +hypothecators +hypothenuse +hypothermal +hypothermia +hypothermic +hypotheses +hypothesi +hypothesis +hypothesize +hypothesized +hypothesizer +hypothesizers +hypothesizes +hypothesizing +hypothetic +hypothetical +hypothetically +hypothyroid +hypothyroidism +hypotonic +hypotonicity +hypotrophic +hypotrophies +hypotrophy +hypoventilation +hypoventilations +hypoxanthine +hypoxanthines +hypoxemia +hypoxemias +hypoxemic +hypoxia +hypoxias +hypoxic +hypsographic +hypsographical +hypsographies +hypsography +hypsometer +hypsometers +hypsometric +hypsometrical +hypsometrically +hypsometrist +hypsometrists +hypsometry +hyraces +hyrax +hyraxes +hyson +hysons +hyssop +hyssops +hysterectomies +hysterectomize +hysterectomized +hysterectomizes +hysterectomizing +hysterectomy +hystereses +hysteresis +hysteretic +hysteria +hysterias +hysteric +hysterical +hysterically +hysterics +hysterogenic +hysteroid +hysteron +hysterotomies +hysterotomy +hälsingborg +héloise +hôte +hôtel +i +i'd +i'll +i'm +i've +iago +iamb +iambi +iambic +iambics +iambs +iambus +iambuses +iapetus +iatrogenic +iatrogenically +iberia +iberian +iberians +ibex +ibexes +ibibio +ibibios +ibid +ibidem +ibis +ibises +ibiza +ibizan +ibo +ibos +ibsen +ibsenian +ibsenism +ibsenite +ibsenites +ibuprofen +icaria +icarus +ice +iceball +iceballs +iceberg +icebergs +iceblink +iceblinks +iceboat +iceboater +iceboaters +iceboating +iceboats +icebound +icebox +iceboxes +icebreaker +icebreakers +icebreaking +icecap +icecaps +iced +icefall +icefalls +icehouse +icehouses +iceland +icelander +icelanders +icelandic +iceless +icelike +icemaker +icemakers +iceman +icemen +iceni +icenian +icenic +icepack +icepacks +ices +icescape +icescapes +ich +ichihara +ichikawa +ichinomiya +ichneumon +ichneumons +ichnite +ichnites +ichnographies +ichnography +ichnolite +ichnolites +ichor +ichorous +ichors +ichthyic +ichthyofauna +ichthyofaunal +ichthyofaunas +ichthyoid +ichthyoids +ichthyologic +ichthyological +ichthyologically +ichthyologist +ichthyologists +ichthyology +ichthyophagous +ichthyornis +ichthyornises +ichthyosaur +ichthyosauri +ichthyosaurian +ichthyosaurs +ichthyosaurus +ichthyosis +ici +icicle +icicles +icier +iciest +icily +iciness +icing +icings +ickier +ickiest +ickiness +icky +icon +iconic +iconically +iconicity +iconified +iconifies +iconify +iconifying +iconoclasm +iconoclast +iconoclastic +iconoclastically +iconoclasts +iconographer +iconographers +iconographic +iconographical +iconographically +iconographies +iconography +iconolater +iconolaters +iconolatric +iconolatry +iconological +iconologist +iconologists +iconology +iconoscope +iconoscopes +iconostases +iconostasis +icons +icosahedra +icosahedral +icosahedron +icosahedrons +icteric +icterics +icterus +ictinus +ictus +ictuses +icy +id +ida +idaho +idahoan +idahoans +idahoes +idahos +idea +ideal +idealess +idealism +idealist +idealistic +idealistically +idealists +idealities +ideality +idealization +idealizations +idealize +idealized +idealizer +idealizers +idealizes +idealizing +idealless +ideally +idealogue +idealogy +ideals +ideas +ideate +ideated +ideates +ideating +ideation +ideational +ideationally +ideations +idem +idempotent +identic +identical +identically +identicalness +identics +identifiable +identifiably +identification +identifications +identified +identifier +identifiers +identifies +identify +identifying +identities +identity +identité +ideogram +ideogramic +ideogrammatic +ideogrammatically +ideogrammic +ideograms +ideograph +ideographic +ideographically +ideographs +ideography +ideologic +ideological +ideologically +ideologies +ideologist +ideologists +ideologize +ideologized +ideologizes +ideologizing +ideologue +ideologues +ideology +ideomotor +ides +idioblast +idioblastic +idioblasts +idiocies +idiocy +idiographic +idiolect +idiolectal +idiolectic +idiolects +idiom +idiomatic +idiomatically +idiomaticness +idiomorphic +idioms +idiopathic +idiopathically +idiopathies +idiopathy +idiosyncrasies +idiosyncrasy +idiosyncratic +idiosyncratically +idiot +idiotic +idiotical +idiotically +idiotism +idiots +idiotype +idiotypic +idle +idled +idleness +idler +idlers +idles +idlesse +idlest +idling +idly +idocrase +idocrases +idol +idolater +idolaters +idolator +idolators +idolatries +idolatrous +idolatrously +idolatrousness +idolatry +idolization +idolizations +idolize +idolized +idolizer +idolizers +idolizes +idolizing +idols +ids +idyl +idyll +idyllic +idyllically +idyllist +idyllists +idylls +idyls +idée +idées +if +iffier +iffiest +iffiness +iffy +ifni +ifs +igbo +igbos +igg +igged +igging +iggs +igitur +igloo +igloos +ignatius +igneous +ignes +ignescent +igni +ignimbrite +ignimbrites +ignis +ignitability +ignitable +ignite +ignited +igniter +igniters +ignites +ignitible +igniting +ignition +ignitions +ignitor +ignitors +ignitron +ignitrons +ignobility +ignoble +ignobleness +ignobly +ignominies +ignominious +ignominiously +ignominiousness +ignominy +ignorable +ignoramus +ignoramuses +ignorance +ignorant +ignorantia +ignorantly +ignorantness +ignoratio +ignore +ignored +ignorer +ignorers +ignores +ignoring +ignotius +ignotum +igorot +igorots +igraine +iguana +iguanas +iguanodon +iguanodons +iguassú +iguaçú +ihram +ihrams +ijmuiden +ijsselmeer +ikaria +ikat +ikebana +ikhnaton +ikon +ikons +il +ilang +ilea +ileac +ileal +ileitis +ileostomies +ileostomy +ileum +ileus +ilex +ilexes +ilia +iliac +iliad +iliadic +ilial +iliamna +ilion +ilium +ilk +ilka +ill +illae +illampu +illation +illations +illative +illatively +illatives +illaudable +illaudably +illegal +illegalities +illegality +illegalization +illegalize +illegalized +illegalizes +illegalizing +illegally +illegals +illegibility +illegible +illegibleness +illegibly +illegitimacies +illegitimacy +illegitimate +illegitimated +illegitimately +illegitimates +illegitimating +illegitimatize +illegitimatizes +iller +illiberal +illiberalism +illiberality +illiberally +illiberalness +illicit +illicitly +illicitness +illimani +illimitability +illimitable +illimitableness +illimitably +illinoian +illinois +illinoisan +illinoisans +illiquid +illiquidity +illis +illite +illiteracies +illiteracy +illiterate +illiterately +illiterateness +illiterates +illitic +illness +illnesses +illocutionary +illogic +illogical +illogicalities +illogicality +illogically +illogicalness +ills +illume +illumed +illumes +illuminable +illuminance +illuminances +illuminant +illuminants +illuminate +illuminated +illuminates +illuminati +illuminating +illuminatingly +illumination +illuminations +illuminative +illuminator +illuminators +illumine +illumined +illumines +illuming +illumining +illuminism +illuminist +illuminists +illusion +illusional +illusionary +illusionism +illusionist +illusionistic +illusionistically +illusionists +illusionless +illusions +illusive +illusively +illusiveness +illusorily +illusoriness +illusory +illustratable +illustrate +illustrated +illustrates +illustrating +illustration +illustrational +illustrations +illustrative +illustratively +illustrator +illustrators +illustrious +illustriously +illustriousness +illuvial +illuviate +illuviated +illuviates +illuviating +illuviation +illuviations +illy +illyria +illyrian +illyrians +illyricums +ilmenite +ilmenites +ilocano +ilocanos +iloilo +ilokano +ilokanos +ilorin +ils +image +imaged +imageless +imager +imageries +imagers +imagery +images +imaginability +imaginable +imaginableness +imaginably +imaginaire +imaginal +imaginaries +imaginarily +imaginariness +imaginary +imagination +imaginational +imaginations +imaginative +imaginatively +imaginativeness +imagine +imagined +imaginer +imaginers +imagines +imaging +imagings +imagining +imaginings +imagism +imagist +imagistic +imagistically +imagists +imago +imagoes +imam +imamate +imamates +imams +imaret +imarets +imari +imbalance +imbalanced +imbalances +imbecile +imbecilely +imbeciles +imbecilic +imbecilities +imbecility +imbed +imbedded +imbedding +imbedment +imbeds +imbibe +imbibed +imbiber +imbibers +imbibes +imbibing +imbibition +imbibitional +imbibitions +imbitter +imbosom +imbricate +imbricated +imbricates +imbricating +imbrication +imbrications +imbroglio +imbroglios +imbrown +imbrue +imbrued +imbrues +imbruing +imbrute +imbruted +imbrutes +imbruting +imbue +imbued +imbues +imbuing +imidazole +imidazoles +imide +imides +imidic +imido +imine +imines +imino +imipramine +imipramines +imitable +imitate +imitated +imitates +imitating +imitation +imitational +imitations +imitative +imitatively +imitativeness +imitator +imitators +immaculacies +immaculacy +immaculate +immaculately +immaculateness +immane +immanence +immanency +immanent +immanentism +immanentist +immanentistic +immanentists +immanently +immanuel +immaterial +immaterialism +immaterialist +immaterialists +immaterialities +immateriality +immaterialize +immaterialized +immaterializes +immaterializing +immaterially +immaterialness +immature +immaturely +immatureness +immaturity +immeasurability +immeasurable +immeasurableness +immeasurably +immediacies +immediacy +immediate +immediately +immediateness +immedicable +immedicably +immelmann +immemorial +immemorially +immense +immensely +immenseness +immensities +immensity +immensurable +immerge +immerged +immergence +immergences +immerges +immerging +immerse +immersed +immerses +immersible +immersing +immersion +immersions +immesh +immeshed +immeshes +immeshing +immethodical +immethodically +immigrant +immigrants +immigrate +immigrated +immigrates +immigrating +immigration +immigrational +immigrations +imminence +imminencies +imminency +imminent +imminently +imminentness +immingle +immiscibility +immiscible +immiscibly +immitigability +immitigable +immitigableness +immitigably +immittance +immittances +immix +immixed +immixes +immixing +immixture +immixtures +immobile +immobilism +immobility +immobilization +immobilizations +immobilize +immobilized +immobilizer +immobilizers +immobilizes +immobilizing +immoderacies +immoderacy +immoderate +immoderately +immoderateness +immoderation +immodest +immodestly +immodesty +immolate +immolated +immolates +immolating +immolation +immolations +immolator +immolators +immoral +immoralism +immoralist +immoralists +immoralities +immorality +immorally +immortal +immortality +immortalization +immortalize +immortalized +immortalizer +immortalizers +immortalizes +immortalizing +immortally +immortals +immortelle +immortelles +immotile +immotility +immovability +immovable +immovableness +immovables +immovably +immune +immunes +immunities +immunity +immunization +immunizations +immunize +immunized +immunizes +immunizing +immunoassay +immunoassayable +immunoassays +immunoblot +immunoblotting +immunochemical +immunochemically +immunochemist +immunochemistry +immunochemists +immunocompetence +immunocompetent +immunocompromised +immunocytochemical +immunocytochemically +immunocytochemistry +immunodeficiencies +immunodeficiency +immunodeficient +immunodepressant +immunodepressants +immunodepression +immunodepressive +immunodiagnosis +immunodiagnostic +immunodiffusion +immunoelectrophoresis +immunoelectrophoretic +immunoelectrophoretically +immunofluorescence +immunofluorescences +immunofluorescent +immunogen +immunogenesis +immunogenetic +immunogenetically +immunogeneticist +immunogeneticists +immunogenetics +immunogenic +immunogenicity +immunogens +immunoglobulin +immunoglobulins +immunohematologic +immunohematological +immunohematologist +immunohematologists +immunohematology +immunohistochemical +immunohistochemistry +immunologic +immunological +immunologically +immunologist +immunologists +immunology +immunomodulator +immunomodulators +immunomodulatory +immunopathologic +immunopathological +immunopathologist +immunopathologists +immunopathology +immunoprecipitate +immunoprecipitated +immunoprecipitates +immunoprecipitating +immunoprecipitation +immunoreaction +immunoreactions +immunoreactive +immunoreactivity +immunoregulation +immunoregulatory +immunosorbent +immunosuppress +immunosuppressant +immunosuppressants +immunosuppressed +immunosuppresses +immunosuppressing +immunosuppression +immunosuppressive +immunotherapeutic +immunotherapies +immunotherapist +immunotherapists +immunotherapy +immure +immured +immurement +immurements +immures +immuring +immutability +immutable +immutableness +immutably +imogen +imp +impact +impacted +impacter +impacters +impacting +impaction +impactions +impactive +impactor +impactors +impacts +impaint +impainted +impainting +impaints +impair +impaired +impairer +impairers +impairing +impairment +impairments +impairs +impala +impalas +impale +impaled +impalement +impalements +impaler +impalers +impales +impaling +impalpability +impalpable +impalpably +impanel +impaneled +impaneling +impanelled +impanelling +impanelment +impanelments +impanels +imparadise +imparadised +imparadises +imparadising +imparities +imparity +impart +impartation +imparted +impartial +impartiality +impartially +impartialness +impartibility +impartible +impartibly +imparting +impartment +imparts +impassability +impassable +impassableness +impassably +impasse +impasses +impassibility +impassible +impassibleness +impassibly +impassion +impassioned +impassioning +impassions +impassive +impassively +impassiveness +impassivity +impaste +impasted +impastes +impasting +impasto +impastoed +impastos +impatience +impatiens +impatient +impatiently +impawn +impawned +impawning +impawns +impeach +impeachability +impeachable +impeached +impeachers +impeaches +impeaching +impeachment +impeachments +impearl +impearled +impearling +impearls +impeccability +impeccable +impeccably +impecuniosity +impecunious +impecuniously +impecuniousness +imped +impedance +impede +impeded +impeder +impeders +impedes +impediment +impedimenta +impedimental +impedimentary +impediments +impeding +impel +impelled +impeller +impellers +impelling +impellor +impellors +impels +impend +impended +impendent +impending +impends +impenetrability +impenetrable +impenetrableness +impenetrably +impenetrate +impenitence +impenitent +impenitently +impenitents +impera +imperative +imperatively +imperativeness +imperatives +imperator +imperatorial +imperators +imperatriz +imperceivable +imperceptibility +imperceptible +imperceptibleness +imperceptibly +imperceptive +imperceptiveness +imperceptivity +impercipience +impercipient +imperfect +imperfecta +imperfectability +imperfection +imperfections +imperfective +imperfectly +imperfectness +imperfects +imperforate +imperforates +imperia +imperial +imperialism +imperialist +imperialistic +imperialistically +imperialists +imperially +imperials +imperil +imperiled +imperiling +imperilled +imperilling +imperilment +imperilments +imperils +imperious +imperiously +imperiousness +imperishability +imperishable +imperishableness +imperishably +imperium +impermanence +impermanency +impermanent +impermanently +impermeabilities +impermeability +impermeable +impermeableness +impermeably +impermissibility +impermissible +impermissibly +impersonal +impersonality +impersonalization +impersonalize +impersonalized +impersonalizes +impersonalizing +impersonally +impersonate +impersonated +impersonates +impersonating +impersonation +impersonations +impersonator +impersonators +impertinence +impertinencies +impertinency +impertinent +impertinently +imperturbability +imperturbable +imperturbableness +imperturbably +impervious +imperviously +imperviousness +impetiginous +impetigo +impetigos +impetrate +impetrated +impetrates +impetrating +impetration +impetrations +impetuosities +impetuosity +impetuous +impetuously +impetuousness +impetus +impetuses +impieties +impiety +imping +impinge +impinged +impingement +impingements +impinger +impingers +impinges +impinging +impious +impiously +impiousness +impish +impishly +impishness +impitoyable +impitoyables +implacability +implacable +implacableness +implacably +implant +implantable +implantation +implantations +implanted +implanter +implanters +implanting +implants +implausibility +implausible +implausibleness +implausibly +implead +impleaded +impleading +impleads +implement +implementation +implementations +implemented +implementer +implementers +implementing +implementor +implementors +implements +implicate +implicated +implicates +implicating +implication +implications +implicative +implicatively +implicativeness +implicit +implicitly +implicitness +implied +implies +implode +imploded +implodes +imploding +imploration +implorations +implore +implored +implorer +implorers +implores +imploring +imploringly +implosion +implosions +implosive +implosives +implume +imply +implying +impolite +impolitely +impoliteness +impolitic +impolitical +impolitically +impoliticly +imponderability +imponderable +imponderableness +imponderables +imponderably +impone +imponed +impones +imponing +import +importability +importable +importance +importancy +important +importantly +importation +importations +imported +importer +importers +importing +imports +importunate +importunately +importunateness +importune +importuned +importunely +importuner +importuners +importunes +importuning +importunities +importunity +impose +imposed +imposer +imposers +imposes +imposing +imposingly +imposition +impositions +impossibilities +impossibility +impossible +impossibleness +impossibly +impost +imposter +imposters +imposthume +impostor +impostors +imposts +impostume +imposture +impostures +impotence +impotencies +impotency +impotent +impotently +impound +impoundage +impoundages +impounded +impounder +impounders +impounding +impoundment +impoundments +impounds +impoverish +impoverished +impoverisher +impoverishers +impoverishes +impoverishing +impoverishment +impoverishments +impracticability +impracticable +impracticableness +impracticably +impractical +impracticalities +impracticality +impractically +impracticalness +imprecate +imprecated +imprecates +imprecating +imprecation +imprecations +imprecator +imprecators +imprecatory +imprecise +imprecisely +impreciseness +imprecision +imprecisions +impregnability +impregnable +impregnableness +impregnably +impregnant +impregnants +impregnate +impregnated +impregnates +impregnating +impregnation +impregnations +impregnator +impregnators +impresa +impresario +impresarios +impresas +impress +impressed +impresser +impressers +impresses +impressibility +impressible +impressibly +impressing +impression +impressionability +impressionable +impressionableness +impressionably +impressionism +impressionist +impressionistic +impressionistically +impressionists +impressions +impressive +impressively +impressiveness +impressment +impressments +impressure +impressures +imprest +imprests +imprimatur +imprimaturs +imprimis +imprint +imprinted +imprinter +imprinters +imprinting +imprintings +imprints +imprison +imprisonable +imprisoned +imprisoning +imprisonment +imprisonments +imprisons +improbabilist +improbabilists +improbabilities +improbability +improbable +improbableness +improbably +improbity +impromptu +impromptus +improper +improperly +improperness +impropriate +impropriated +impropriates +impropriating +impropriation +improprieties +impropriety +improvability +improvable +improve +improved +improvement +improvements +improver +improvers +improves +improvidence +improvident +improvidently +improving +improvisation +improvisational +improvisationally +improvisations +improvisator +improvisatore +improvisatores +improvisatori +improvisatorial +improvisators +improvisatory +improvise +improvised +improviser +improvisers +improvises +improvising +improvisor +improvisors +improviste +imprudence +imprudent +imprudently +imps +impudence +impudences +impudencies +impudency +impudent +impudently +impudicity +impugn +impugnable +impugned +impugner +impugners +impugning +impugns +impuissance +impuissances +impuissant +impulse +impulsed +impulses +impulsing +impulsion +impulsive +impulsively +impulsiveness +impulsivity +impunities +impunity +impure +impurely +impureness +impurer +impurest +impurities +impurity +imputability +imputable +imputably +imputation +imputations +imputative +imputatively +impute +imputed +imputes +imputing +in +inability +inaccessibility +inaccessible +inaccessibly +inaccuracies +inaccuracy +inaccurate +inaccurately +inaccurateness +inaction +inactivate +inactivated +inactivates +inactivating +inactivation +inactivations +inactive +inactively +inactiveness +inactivity +inadequacies +inadequacy +inadequate +inadequately +inadequateness +inadmissibility +inadmissible +inadmissibly +inadvertence +inadvertencies +inadvertency +inadvertent +inadvertently +inadvisability +inadvisable +inadvisably +inalienability +inalienable +inalienably +inalterability +inalterable +inalterableness +inalterably +inamorata +inamoratas +inamorato +inamoratos +inane +inanely +inaneness +inaner +inanest +inanimate +inanimately +inanimateness +inanities +inanition +inanity +inapparent +inapparently +inappeasable +inappetence +inappetences +inappetencies +inappetency +inappetent +inapplicability +inapplicable +inapplicably +inapposite +inappositely +inappositeness +inappreciable +inappreciably +inappreciative +inappreciatively +inappreciativeness +inapproachability +inapproachable +inapproachably +inappropriate +inappropriately +inappropriateness +inapt +inaptitude +inaptly +inaptness +inarguable +inarguably +inarticulacy +inarticulate +inarticulately +inarticulateness +inartistic +inartistically +inasmuch +inassimilable +inattention +inattentive +inattentively +inattentiveness +inaudibility +inaudible +inaudibly +inaugural +inaugurals +inaugurate +inaugurated +inaugurates +inaugurating +inauguration +inaugurations +inaugurator +inaugurators +inauguratory +inauspicious +inauspiciously +inauspiciousness +inauthentic +inauthenticity +inboard +inboards +inborn +inbound +inbounded +inbounding +inbounds +inbreathe +inbreathed +inbreathes +inbreathing +inbred +inbreed +inbreeder +inbreeders +inbreeding +inbreedings +inbreeds +inbuilt +inca +incaic +incalculability +incalculable +incalculableness +incalculably +incalescence +incalescent +incan +incandesce +incandesced +incandescence +incandescent +incandescently +incandesces +incandescing +incans +incantation +incantational +incantations +incantatory +incapability +incapable +incapableness +incapably +incapacitant +incapacitants +incapacitate +incapacitated +incapacitates +incapacitating +incapacitation +incapacitations +incapacities +incapacity +incapsulate +incapsulated +incapsulates +incapsulating +incapsulation +incapsulations +incapsulator +incapsulators +incarcerate +incarcerated +incarcerates +incarcerating +incarceration +incarcerations +incarcerator +incarcerators +incarnadine +incarnadined +incarnadines +incarnadining +incarnate +incarnated +incarnates +incarnating +incarnation +incarnations +incarnator +incarnators +incas +incase +incased +incasement +incasements +incases +incasing +incautious +incautiously +incautiousness +incendiaries +incendiarism +incendiary +incense +incensed +incenses +incensing +incentive +incentives +incentivize +incentivized +incentivizes +incentivizing +incept +incepted +incepting +inception +inceptions +inceptive +inceptives +inceptor +inceptors +incepts +incertitude +incessancy +incessant +incessantly +incest +incestuous +incestuously +incestuousness +inch +inched +incher +inchers +inches +inching +inchmeal +inchoate +inchoately +inchoateness +inchoative +inchoatively +inchoatives +inchworm +inchworms +incidence +incidences +incident +incidental +incidentally +incidentals +incidents +incinerate +incinerated +incinerates +incinerating +incineration +incinerations +incinerator +incinerators +incipience +incipiency +incipient +incipiently +incipit +incipits +incise +incised +incises +incising +incision +incisions +incisive +incisively +incisiveness +incisor +incisors +incitation +incitations +incite +incited +incitement +incitements +inciter +inciters +incites +inciting +incivilities +incivility +inclasp +inclasped +inclasping +inclasps +inclemency +inclement +inclemently +inclinable +inclination +inclinations +incline +inclined +incliner +incliners +inclines +inclining +inclinometer +inclinometers +inclose +inclosed +incloses +inclosing +includable +include +included +includes +includible +including +inclusion +inclusionary +inclusions +inclusive +inclusively +inclusiveness +incoercible +incogitant +incognita +incognitas +incognito +incognitos +incognitum +incognizance +incognizant +incoherence +incoherencies +incoherency +incoherent +incoherently +incoherentness +incombustibility +incombustible +incombustibles +incombustibly +income +incomes +incoming +incomings +incommensurability +incommensurable +incommensurables +incommensurably +incommensurate +incommensurately +incommensurateness +incommode +incommoded +incommodes +incommoding +incommodious +incommodiously +incommodiousness +incommodities +incommodity +incommunicability +incommunicable +incommunicably +incommunicado +incommunicative +incommunicatively +incommunicativeness +incommutability +incommutable +incommutableness +incommutably +incomparability +incomparable +incomparableness +incomparably +incompatibilities +incompatibility +incompatible +incompatibleness +incompatibles +incompatibly +incompetence +incompetency +incompetent +incompetently +incompetents +incomplete +incompletely +incompleteness +incompletion +incompletions +incompliance +incompliancy +incompliant +incompliantly +incomprehensibility +incomprehensible +incomprehensibleness +incomprehensibly +incomprehension +incomprehensive +incomprehensively +incomprehensiveness +incompressibility +incompressible +incomputability +incomputable +inconceivability +inconceivable +inconceivableness +inconceivably +inconcinnity +inconclusive +inconclusively +inconclusiveness +incondensability +incondensable +incondensible +incondite +inconditely +inconformity +incongruence +incongruences +incongruent +incongruently +incongruities +incongruity +incongruous +incongruously +incongruousness +inconsequence +inconsequent +inconsequential +inconsequentiality +inconsequentially +inconsequentialness +inconsequently +inconsiderable +inconsiderableness +inconsiderably +inconsiderate +inconsiderately +inconsiderateness +inconsideration +inconsistence +inconsistences +inconsistencies +inconsistency +inconsistent +inconsistently +inconsolability +inconsolable +inconsolableness +inconsolably +inconsonance +inconsonant +inconsonantly +inconspicuous +inconspicuously +inconspicuousness +inconstancies +inconstancy +inconstant +inconstantly +inconsumable +inconsumably +incontestability +incontestable +incontestableness +incontestably +incontinence +incontinent +incontinently +incontrollable +incontrovertibility +incontrovertible +incontrovertibleness +incontrovertibly +inconvenience +inconvenienced +inconveniences +inconveniencing +inconvenient +inconveniently +inconvertibility +inconvertible +inconvertibleness +inconvertibly +inconvincible +incoordinate +incoordinately +incoordination +incoordinations +incorporable +incorporate +incorporated +incorporates +incorporating +incorporation +incorporations +incorporative +incorporator +incorporators +incorporeal +incorporeality +incorporeally +incorporeity +incorrect +incorrectly +incorrectness +incorrigibility +incorrigible +incorrigibleness +incorrigibles +incorrigibly +incorrupt +incorruptibility +incorruptible +incorruptibly +incorruption +incorruptly +incorruptness +increasable +increase +increased +increaser +increasers +increases +increasing +increasingly +increate +increately +incredibility +incredible +incredibleness +incredibly +incredulity +incredulous +incredulously +incredulousness +increment +incremental +incrementalism +incrementalist +incrementalists +incrementally +incremented +incrementing +increments +increscent +incretion +incretions +incriminate +incriminated +incriminates +incriminating +incrimination +incriminations +incriminator +incriminators +incriminatory +incrust +incrustation +incrustations +incrusted +incrusting +incrusts +incubate +incubated +incubates +incubating +incubation +incubational +incubations +incubative +incubator +incubators +incubi +incubus +incubuses +incudes +inculcate +inculcated +inculcates +inculcating +inculcation +inculcations +inculcator +inculcators +inculpable +inculpate +inculpated +inculpates +inculpating +inculpation +inculpations +inculpatory +incult +incumbencies +incumbency +incumbent +incumbently +incumbents +incunable +incunables +incunabula +incunabular +incunabulars +incunabulis +incunabulum +incur +incurability +incurable +incurableness +incurables +incurably +incuriosity +incurious +incuriously +incuriousness +incurred +incurrence +incurrences +incurrent +incurring +incurs +incursion +incursions +incurvate +incurvated +incurvates +incurvating +incurvation +incurvations +incurvature +incurve +incurved +incurves +incurving +incus +incuse +incused +incuses +incusing +indaba +indabas +indagate +indagated +indagates +indagating +indagation +indagator +indagators +indamine +indamines +indebted +indebtedness +indecencies +indecency +indecent +indecently +indecipherability +indecipherable +indecipherableness +indecipherably +indecision +indecisive +indecisively +indecisiveness +indeclinable +indecomposable +indecorous +indecorously +indecorousness +indecorum +indecorums +indeed +indefatigability +indefatigable +indefatigableness +indefatigably +indefeasibility +indefeasible +indefeasibly +indefectibility +indefectible +indefectibly +indefensibility +indefensible +indefensibleness +indefensibly +indefinability +indefinable +indefinableness +indefinables +indefinably +indefinite +indefinitely +indefiniteness +indehiscence +indehiscent +indelibility +indelible +indelibleness +indelibly +indelicacies +indelicacy +indelicate +indelicately +indelicateness +indemnification +indemnifications +indemnificatory +indemnified +indemnifier +indemnifiers +indemnifies +indemnify +indemnifying +indemnities +indemnity +indemonstrability +indemonstrable +indemonstrableness +indemonstrably +indene +indenes +indent +indentation +indentations +indented +indenter +indenters +indenting +indention +indents +indenture +indentured +indentures +indenturing +independence +independencies +independency +independent +independently +independents +inderal +indescribability +indescribable +indescribableness +indescribably +indestructibility +indestructible +indestructibleness +indestructibly +indeterminable +indeterminably +indeterminacy +indeterminate +indeterminately +indeterminateness +indetermination +indeterminations +indeterminism +indeterminist +indeterministic +indeterminists +index +indexation +indexed +indexer +indexers +indexes +indexical +indexing +india +indiaman +indian +indiana +indianapolis +indianism +indianist +indianists +indianization +indianize +indianized +indianizes +indianizing +indianness +indians +indic +indican +indicans +indicant +indicants +indicate +indicated +indicates +indicating +indication +indicational +indications +indicative +indicatively +indicatives +indicator +indicators +indicatory +indices +indicia +indicium +indics +indict +indictable +indicted +indictee +indictees +indicter +indicters +indicting +indiction +indictions +indictment +indictments +indictor +indictors +indicts +indie +indies +indifference +indifferency +indifferent +indifferentism +indifferentist +indifferentists +indifferently +indigen +indigence +indigene +indigenes +indigenization +indigenizations +indigenize +indigenized +indigenizes +indigenizing +indigenous +indigenously +indigenousness +indigens +indigent +indigently +indigents +indigested +indigestibility +indigestible +indigestibly +indigestion +indigirka +indign +indignant +indignantly +indignation +indignities +indignity +indigo +indigoes +indigos +indigotin +indigotins +indirect +indirection +indirectly +indirectness +indiscernible +indiscernibly +indisciplinable +indiscipline +indisciplined +indisciplines +indiscoverable +indiscreet +indiscreetly +indiscreetness +indiscrete +indiscretion +indiscretions +indiscriminate +indiscriminately +indiscriminateness +indiscriminating +indiscriminatingly +indiscrimination +indiscriminations +indiscriminative +indispensability +indispensable +indispensableness +indispensables +indispensably +indispose +indisposed +indisposes +indisposing +indisposition +indispositions +indisputable +indisputableness +indisputably +indissociable +indissociably +indissolubility +indissoluble +indissolubleness +indissolubly +indistinct +indistinctive +indistinctively +indistinctiveness +indistinctly +indistinctness +indistinguishability +indistinguishable +indistinguishableness +indistinguishably +indite +indited +inditement +inditements +inditer +inditers +indites +inditing +indium +indiums +individual +individualism +individualist +individualistic +individualistically +individualists +individualities +individuality +individualization +individualizations +individualize +individualized +individualizes +individualizing +individually +individuals +individuate +individuated +individuates +individuating +individuation +indivisibility +indivisible +indivisibleness +indivisibly +indo +indochina +indochinese +indocile +indocility +indocin +indoctrinate +indoctrinated +indoctrinates +indoctrinating +indoctrination +indoctrinations +indoctrinator +indoctrinators +indole +indoleacetic +indoleamine +indoleamines +indolebutyric +indolence +indolent +indolently +indoles +indologist +indologists +indology +indomethacin +indomethacins +indomitability +indomitable +indomitableness +indomitably +indonesia +indonesian +indonesians +indoor +indoors +indophenol +indophenols +indorsable +indorse +indorsed +indorsement +indorsements +indorser +indorsers +indorses +indorsing +indorsor +indorsors +indoxyl +indoxyls +indra +indraft +indrafts +indrawn +indri +indris +indubitability +indubitable +indubitableness +indubitably +induce +induced +inducement +inducements +inducer +inducers +induces +inducibility +inducible +inducing +induct +inductance +inducted +inductee +inductees +inducting +induction +inductions +inductive +inductively +inductiveness +inductor +inductors +inducts +indue +indued +indues +induing +indulge +indulged +indulgence +indulgenced +indulgences +indulgencing +indulgent +indulgently +indulger +indulgers +indulges +indulging +indult +indults +indument +indumenta +induments +indumentum +induplicate +indurate +indurated +indurates +indurating +induration +indurations +indurative +indus +indusia +indusium +industrial +industrialism +industrialist +industrialists +industrialization +industrializations +industrialize +industrialized +industrializes +industrializing +industrially +industrials +industries +industrious +industriously +industriousness +industry +industrywide +indwell +indweller +indwellers +indwelling +indwells +indwelt +inebriant +inebriants +inebriate +inebriated +inebriates +inebriating +inebriation +inebriations +inebriety +inedibility +inedible +inedibly +inedited +ineducability +ineducable +ineffability +ineffable +ineffableness +ineffably +ineffaceability +ineffaceable +ineffaceably +ineffective +ineffectively +ineffectiveness +ineffectual +ineffectuality +ineffectually +ineffectualness +inefficacious +inefficaciously +inefficaciousness +inefficacy +inefficiencies +inefficiency +inefficient +inefficiently +inegalitarian +inelastic +inelasticity +inelegance +inelegant +inelegantly +ineligibility +ineligible +ineligibles +ineligibly +ineloquence +ineloquent +ineloquently +ineluctability +ineluctable +ineluctably +ineludible +inenarrable +inept +ineptitude +ineptly +ineptness +inequalities +inequality +inequitable +inequitableness +inequitably +inequities +inequity +inequivalve +inequivalved +ineradicability +ineradicable +ineradicably +inerrancy +inerrant +inerrantism +inerrantist +inerrantists +inert +inertia +inertial +inertially +inertly +inertness +inescapable +inescapably +inessential +inessentiality +inessentials +inestimable +inestimably +inevitabilist +inevitabilists +inevitabilities +inevitability +inevitable +inevitableness +inevitably +inexact +inexactitude +inexactitudes +inexactly +inexactness +inexcusable +inexcusableness +inexcusably +inexhaustibility +inexhaustible +inexhaustibleness +inexhaustibly +inexistence +inexistent +inexorability +inexorable +inexorableness +inexorably +inexpedience +inexpediency +inexpedient +inexpediently +inexpensive +inexpensively +inexpensiveness +inexperience +inexperienced +inexpert +inexpertly +inexpertness +inexpiable +inexpiably +inexplainable +inexplainably +inexplicability +inexplicable +inexplicableness +inexplicably +inexplicit +inexpressibility +inexpressible +inexpressibleness +inexpressibly +inexpressive +inexpressively +inexpressiveness +inexpugnability +inexpugnable +inexpugnableness +inexpugnably +inexpungible +inextensible +inextinguishable +inextinguishably +inextirpable +inextricability +inextricable +inextricableness +inextricably +infall +infallibility +infallible +infallibleness +infallibly +infalling +infalls +infamies +infamous +infamously +infamousness +infamy +infancies +infancy +infant +infanta +infantas +infante +infantes +infanticidal +infanticide +infanticides +infantile +infantilism +infantility +infantilization +infantilizations +infantilize +infantilized +infantilizes +infantilizing +infantine +infantries +infantry +infantryman +infantrymen +infants +infantum +infarct +infarcted +infarction +infarctions +infarcts +infare +infares +infatuate +infatuated +infatuatedly +infatuates +infatuating +infatuation +infatuations +infauna +infaunal +infaunas +infaustus +infeasibility +infeasible +infect +infecta +infected +infecting +infection +infections +infectious +infectiously +infectiousness +infective +infectiveness +infectivity +infector +infectors +infects +infecundity +infelicities +infelicitous +infelicitously +infelicity +infer +inferable +inferably +inference +inferences +inferential +inferentially +inferior +inferiority +inferiorly +inferiors +infernal +infernally +inferno +infernos +inferred +inferrer +inferrers +inferrible +inferring +infers +infertile +infertility +infest +infestant +infestants +infestation +infestations +infested +infester +infesters +infesting +infests +infidel +infidelities +infidelity +infidelium +infidels +infield +infielder +infielders +infields +infight +infighter +infighters +infighting +infights +infill +infills +infiltrate +infiltrated +infiltrates +infiltrating +infiltration +infiltrations +infiltrative +infiltrator +infiltrators +infinite +infinitely +infiniteness +infinitesimal +infinitesimally +infinitesimals +infinities +infinitival +infinitive +infinitively +infinitives +infinitude +infinitudes +infinitum +infinity +infirm +infirmaries +infirmary +infirmities +infirmity +infirmly +infix +infixation +infixations +infixed +infixes +infixing +inflame +inflamed +inflamer +inflamers +inflames +inflaming +inflammability +inflammable +inflammableness +inflammably +inflammation +inflammations +inflammatorily +inflammatory +inflatable +inflatables +inflate +inflated +inflater +inflaters +inflates +inflating +inflation +inflationary +inflationism +inflationist +inflationists +inflations +inflator +inflators +inflect +inflectable +inflected +inflecting +inflection +inflectional +inflectionally +inflections +inflective +inflector +inflectors +inflects +inflexed +inflexibility +inflexible +inflexibleness +inflexibly +inflexion +inflexions +inflict +inflicted +inflicter +inflicters +inflicting +infliction +inflictions +inflictive +inflictor +inflictors +inflicts +inflorescence +inflorescences +inflorescent +inflow +inflows +influence +influenceable +influenced +influencer +influencers +influences +influencing +influent +influential +influentially +influentials +influents +influenza +influenzal +influx +influxes +info +infobahn +infold +infolded +infolder +infolders +infolding +infoldment +infoldments +infolds +infomercial +infomercials +inform +informal +informalities +informality +informally +informant +informants +informatics +information +informational +informationally +informative +informatively +informativeness +informatorily +informatory +informed +informedly +informer +informercial +informercials +informers +informing +informs +infotainment +infotainments +infra +infraclass +infraclasses +infract +infracted +infracting +infraction +infractions +infractor +infractors +infracts +infrahuman +infrahumans +infrangibility +infrangible +infrangibly +infrared +infrareds +infrasonic +infrasound +infrasounds +infraspecific +infrastructure +infrastructures +infrequence +infrequency +infrequent +infrequently +infringe +infringed +infringement +infringements +infringer +infringers +infringes +infringing +infructescence +infructescences +infundibula +infundibular +infundibulate +infundibuliform +infundibulum +infuriate +infuriated +infuriates +infuriating +infuriatingly +infuriation +infuriations +infuse +infused +infuser +infusers +infuses +infusibility +infusible +infusibleness +infusing +infusion +infusions +infusorial +infusorian +infusorians +infâme +ing +ingather +ingathered +ingathering +ingathers +ingeminate +ingeminated +ingeminates +ingeminating +ingenious +ingeniously +ingeniousness +ingenue +ingenues +ingenuities +ingenuity +ingenuous +ingenuously +ingenuousness +ingest +ingesta +ingested +ingestible +ingesting +ingestion +ingestions +ingestive +ingests +ingle +inglenook +inglenooks +ingles +inglese +inglorious +ingloriously +ingloriousness +ingoing +ingot +ingots +ingrain +ingrained +ingrainedly +ingraining +ingrains +ingrate +ingrates +ingratiate +ingratiated +ingratiates +ingratiating +ingratiatingly +ingratiation +ingratiations +ingratiatory +ingratitude +ingredient +ingredients +ingres +ingress +ingression +ingressions +ingressive +ingressiveness +ingrowing +ingrown +ingrownness +ingrowth +ingrowths +inguinal +inguinale +ingurgitate +ingurgitated +ingurgitates +ingurgitating +ingurgitation +ingurgitations +ingénue +ingénues +inhabit +inhabitability +inhabitable +inhabitancies +inhabitancy +inhabitant +inhabitants +inhabitation +inhabitations +inhabited +inhabiter +inhabiters +inhabiting +inhabits +inhalant +inhalants +inhalation +inhalational +inhalations +inhalator +inhalators +inhale +inhaled +inhaler +inhalers +inhales +inhaling +inharmonic +inharmonies +inharmonious +inharmoniously +inharmoniousness +inharmony +inhere +inhered +inherence +inherency +inherent +inherently +inheres +inhering +inherit +inheritability +inheritable +inheritableness +inheritance +inheritances +inherited +inheriting +inheritor +inheritors +inheritress +inheritresses +inheritrix +inheritrixes +inherits +inhibin +inhibins +inhibit +inhibitable +inhibited +inhibiter +inhibiters +inhibiting +inhibition +inhibitions +inhibitive +inhibitor +inhibitors +inhibitory +inhibits +inholder +inholders +inholding +inholdings +inhomogeneities +inhomogeneity +inhomogeneous +inhospitable +inhospitableness +inhospitably +inhospitality +inhuman +inhumane +inhumanely +inhumanities +inhumanity +inhumanly +inhumanness +inhumation +inhumations +inhume +inhumed +inhumer +inhumers +inhumes +inhuming +inigo +inimical +inimically +inimitability +inimitable +inimitableness +inimitably +inion +inions +iniquities +iniquitous +iniquitously +iniquitousness +iniquity +initial +initialed +initialing +initialism +initialization +initializations +initialize +initialized +initializer +initializers +initializes +initializing +initialled +initialling +initially +initialness +initials +initiate +initiated +initiates +initiating +initiation +initiations +initiative +initiatively +initiatives +initiator +initiators +initiatory +initio +inject +injectable +injectables +injectant +injectants +injected +injecting +injection +injections +injective +injector +injectors +injects +injudicious +injudiciously +injudiciousness +injunction +injunctions +injunctive +injure +injured +injurer +injurers +injures +injuries +injuring +injurious +injuriously +injuriousness +injury +injustice +injustices +ink +inkberries +inkberry +inkblot +inkblots +inked +inker +inkers +inkhorn +inkhorns +inkier +inkiest +inkiness +inking +inkle +inkles +inkling +inklings +inkpot +inkpots +inks +inkstand +inkstands +inkstone +inkstones +inkwell +inkwells +inky +inlace +inlaced +inlacement +inlacements +inlaces +inlacing +inlaid +inland +inlander +inlanders +inlay +inlayer +inlayers +inlaying +inlays +inlet +inlets +inlier +inliers +inly +inlying +inmate +inmates +inmesh +inmeshed +inmeshes +inmeshing +inmeshment +inmeshments +inmost +inn +innards +innate +innately +innateness +inner +innerly +innermost +innerness +innersole +innersoles +innerspring +innersprings +innervate +innervated +innervates +innervating +innervation +innervational +innervations +innerve +innerved +innerves +innerving +innerwear +innigkeit +inning +innings +innkeeper +innkeepers +innocence +innocencies +innocency +innocent +innocently +innocents +innocuous +innocuously +innocuousness +innominate +innovate +innovated +innovates +innovating +innovation +innovational +innovations +innovative +innovatively +innovativeness +innovator +innovators +innovatory +inns +innsbruck +innuendo +innuendoes +innuit +innuits +innumerable +innumerableness +innumerably +innumeracy +innumerate +innumerates +innumerous +innutrition +innutritious +inobservance +inobservant +inobtrusive +inocula +inoculability +inoculable +inoculant +inoculants +inoculate +inoculated +inoculates +inoculating +inoculation +inoculations +inoculative +inoculator +inoculators +inoculum +inoculums +inodorous +inoffensive +inoffensively +inoffensiveness +inofficious +inoperable +inoperably +inoperative +inoperativeness +inoperculate +inopportune +inopportunely +inopportuneness +inordinacy +inordinate +inordinately +inordinateness +inorganic +inorganically +inosculate +inosculated +inosculates +inosculating +inosculation +inosculations +inositol +inositols +inotropic +inpatient +inpatients +inphase +inpouring +inpourings +input +inputs +inputted +inputting +inquest +inquests +inquietude +inquietudes +inquiline +inquilines +inquilinism +inquilinity +inquilinous +inquire +inquired +inquirer +inquirers +inquires +inquiries +inquiring +inquiringly +inquiry +inquisition +inquisitional +inquisitions +inquisitive +inquisitively +inquisitiveness +inquisitor +inquisitorial +inquisitorially +inquisitors +inro +inroad +inroads +inrush +inrushes +ins +insalivate +insalivated +insalivates +insalivating +insalivation +insalivations +insalubrious +insalubriously +insalubrity +insane +insanely +insaneness +insanitary +insanitation +insanities +insanity +insatiability +insatiable +insatiableness +insatiably +insatiate +insatiately +insatiateness +inscape +inscapes +inscribe +inscribed +inscriber +inscribers +inscribes +inscribing +inscription +inscriptional +inscriptions +inscriptive +inscriptively +inscroll +inscrolled +inscrolling +inscrolls +inscrutability +inscrutable +inscrutableness +inscrutably +insculp +insculped +insculping +insculps +inseam +inseams +insect +insectaria +insectaries +insectarium +insectary +insecticidal +insecticidally +insecticide +insecticides +insectile +insectival +insectivore +insectivores +insectivorous +insects +insecure +insecurely +insecureness +insecurities +insecurity +inselberg +inselberge +inselberges +inselbergs +inseminate +inseminated +inseminates +inseminating +insemination +inseminations +inseminator +inseminators +insensate +insensately +insensateness +insensibility +insensible +insensibleness +insensibly +insensitive +insensitively +insensitiveness +insensitivity +insentience +insentient +inseparability +inseparable +inseparableness +inseparably +insert +inserted +inserter +inserters +inserting +insertion +insertional +insertions +inserts +insessorial +inset +insets +insetted +insetting +inshallah +inshore +inshrine +inshrined +inshrinement +inshrinements +inshrines +inshrining +inside +insider +insiders +insides +insidious +insidiously +insidiousness +insight +insightful +insightfully +insightfulness +insights +insigne +insignia +insignias +insignificance +insignificancies +insignificancy +insignificant +insignificantly +insincere +insincerely +insincerity +insinuate +insinuated +insinuates +insinuating +insinuatingly +insinuation +insinuations +insinuative +insinuator +insinuators +insinuatory +insipid +insipidities +insipidity +insipidly +insipidness +insipidus +insipience +insist +insisted +insistence +insistency +insistent +insistently +insister +insisters +insisting +insistingly +insists +insnare +insnared +insnarement +insnarements +insnarer +insnarers +insnares +insnaring +insobriety +insociability +insociable +insociably +insofar +insolate +insolated +insolates +insolating +insolation +insolations +insole +insolence +insolent +insolently +insolents +insoles +insolubility +insolubilization +insolubilizations +insolubilize +insolubilized +insolubilizes +insolubilizing +insoluble +insolubleness +insolubles +insolubly +insolvability +insolvable +insolvably +insolvencies +insolvency +insolvent +insolvents +insomnia +insomniac +insomniacs +insomuch +insouciance +insouciant +insouciantly +insoul +insouled +insouling +insouls +inspan +inspanned +inspanning +inspans +inspect +inspected +inspecting +inspection +inspectional +inspections +inspective +inspector +inspectoral +inspectorate +inspectorates +inspectorial +inspectors +inspectorship +inspectorships +inspects +insphere +insphered +inspheres +insphering +inspiration +inspirational +inspirationally +inspirations +inspirator +inspirators +inspiratory +inspire +inspired +inspiredly +inspirer +inspirers +inspires +inspiring +inspiringly +inspirit +inspirited +inspiriting +inspiritingly +inspirits +inspissate +inspissated +inspissates +inspissating +inspissation +inspissations +inspissator +inspissators +instabilities +instability +instal +install +installation +installations +installed +installer +installers +installing +installment +installments +installs +instalment +instalments +instals +instance +instanced +instances +instancies +instancing +instancy +instant +instantaneity +instantaneous +instantaneously +instantaneousness +instanter +instantiate +instantiated +instantiates +instantiating +instantiation +instantiations +instantly +instantness +instants +instar +instarred +instarring +instars +instate +instated +instatement +instates +instating +instauration +instaurations +instead +instep +insteps +instigate +instigated +instigates +instigating +instigation +instigations +instigative +instigator +instigators +instil +instill +instillation +instillations +instilled +instiller +instillers +instilling +instillment +instills +instils +instinct +instinctive +instinctively +instincts +instinctual +instinctually +institute +instituted +instituter +instituters +institutes +instituting +institution +institutional +institutionalism +institutionalist +institutionalists +institutionalization +institutionalizations +institutionalize +institutionalized +institutionalizes +institutionalizing +institutionally +institutions +institutor +institutors +instroke +instrokes +instruct +instructed +instructing +instruction +instructional +instructions +instructive +instructively +instructiveness +instructor +instructors +instructorship +instructorships +instructress +instructresses +instructs +instrument +instrumental +instrumentalism +instrumentalist +instrumentalists +instrumentalities +instrumentality +instrumentally +instrumentals +instrumentation +instrumented +instrumenting +instruments +insubordinate +insubordinately +insubordinates +insubordination +insubordinations +insubstantial +insubstantiality +insufferable +insufferableness +insufferably +insufficiencies +insufficiency +insufficient +insufficiently +insufflate +insufflated +insufflates +insufflating +insufflation +insufflations +insufflator +insufflators +insulant +insulants +insular +insularism +insularity +insularly +insulate +insulated +insulates +insulating +insulation +insulations +insulative +insulator +insulators +insulin +insult +insulted +insulter +insulters +insulting +insultingly +insults +insuperability +insuperable +insuperableness +insuperably +insupportable +insupportableness +insupportably +insuppressible +insuppressibly +insurability +insurable +insurance +insurances +insure +insured +insureds +insurer +insurers +insures +insurgence +insurgencies +insurgency +insurgent +insurgently +insurgents +insuring +insurmountability +insurmountable +insurmountableness +insurmountably +insurrection +insurrectional +insurrectionary +insurrectionism +insurrectionist +insurrectionists +insurrections +insusceptibility +insusceptible +insusceptibly +intact +intactly +intactness +intaglio +intaglios +intake +intakes +intangibility +intangible +intangibleness +intangibles +intangibly +intarsia +intarsias +integer +integers +integrability +integrable +integral +integrality +integrally +integrals +integrand +integrands +integrant +integrate +integrated +integrates +integrating +integration +integrationist +integrationists +integrations +integrative +integrator +integrators +integrity +integro +integument +integumentary +intellect +intellection +intellections +intellective +intellectively +intellectronics +intellects +intellectual +intellectualism +intellectualist +intellectualistic +intellectualists +intellectuality +intellectualization +intellectualizations +intellectualize +intellectualized +intellectualizer +intellectualizers +intellectualizes +intellectualizing +intellectually +intellectualness +intellectuals +intelligam +intelligence +intelligencer +intelligencers +intelligences +intelligent +intelligential +intelligently +intelligentsia +intelligibility +intelligible +intelligibleness +intelligibly +intelligunt +intelsat +intemperance +intemperate +intemperately +intemperateness +intend +intendance +intendances +intendancies +intendancy +intendant +intendants +intended +intendedly +intender +intenders +intending +intendment +intendments +intends +intenerate +intenerated +intenerates +intenerating +inteneration +intenerations +intense +intensely +intenseness +intenser +intensest +intensification +intensifications +intensified +intensifier +intensifiers +intensifies +intensify +intensifying +intension +intensional +intensionality +intensionally +intensions +intensities +intensity +intensive +intensively +intensiveness +intensives +intent +intention +intentional +intentionality +intentionally +intentioned +intentions +intently +intentness +intents +inter +interabang +interabangs +interact +interactant +interactants +interacted +interacting +interaction +interactional +interactions +interactive +interactively +interactivity +interacts +interagency +interallelic +interallied +interanimation +interanimations +interannual +interassociation +interassociations +interatomic +interavailability +interbank +interbasin +interbed +interbehavior +interbehavioral +interborough +interbrain +interbrains +interbranch +interbred +interbreed +interbreeding +interbreeds +intercalary +intercalate +intercalated +intercalates +intercalating +intercalation +intercalations +intercalative +intercalibration +intercampus +intercaste +intercede +interceded +interceder +interceders +intercedes +interceding +intercell +intercellular +intercensal +intercept +intercepted +intercepter +intercepters +intercepting +interception +interceptions +interceptive +interceptor +interceptors +intercepts +intercession +intercessional +intercessions +intercessor +intercessors +intercessory +interchain +interchange +interchangeability +interchangeable +interchangeableness +interchangeably +interchanged +interchanger +interchangers +interchanges +interchanging +interchannel +interchromosomal +interchurch +intercity +interclan +interclass +interclavicle +interclavicles +interclavicular +interclub +intercluster +intercoastal +intercollegiate +intercolonial +intercolumniation +intercolumniations +intercom +intercommunal +intercommunicate +intercommunicated +intercommunicates +intercommunicating +intercommunication +intercommunications +intercommunicative +intercommunion +intercommunions +intercommunity +intercompany +intercomparable +intercompare +intercomparison +intercomprehensibility +intercoms +interconnect +interconnectable +interconnected +interconnectedness +interconnectible +interconnecting +interconnection +interconnections +interconnectivity +interconnects +intercontinental +interconversion +interconvert +interconverted +interconvertibility +interconvertible +interconverting +interconverts +intercool +intercooled +intercooler +intercoolers +intercooling +intercools +intercorporate +intercorrelate +intercorrelation +intercortical +intercostal +intercostals +intercountry +intercounty +intercouple +intercourse +intercrater +intercrop +intercropped +intercropping +intercrops +intercross +intercrystalline +intercultural +interculturally +interculture +intercurrent +intercut +intercuts +intercutting +interdealer +interdenominational +interdental +interdentally +interdentals +interdepartmental +interdepartmentally +interdepend +interdependence +interdependencies +interdependency +interdependent +interdependently +interdialectal +interdict +interdicted +interdicting +interdiction +interdictions +interdictive +interdictively +interdictor +interdictors +interdictory +interdicts +interdictus +interdiffuse +interdiffusion +interdigitate +interdigitated +interdigitates +interdigitating +interdigitation +interdisciplinary +interdistrict +interdivisional +interdominion +interelectrode +interelectron +interelectronic +interepidemic +interest +interested +interestedly +interestedness +interesting +interestingly +interestingness +interests +interethnic +interface +interfaced +interfaces +interfacial +interfacing +interfacings +interfaculty +interfaith +interfamilial +interfamily +interfascicular +interfere +interfered +interference +interferences +interferential +interferer +interferers +interferes +interfering +interferingly +interferogram +interferograms +interferometer +interferometers +interferometric +interferometrically +interferometry +interferon +interfertile +interfertility +interfiber +interfile +interfirm +interflow +interfluve +interfluves +interfluvial +interfold +interfraternity +interfuse +interfused +interfuses +interfusing +interfusion +intergalactic +intergalactically +intergang +intergeneration +intergenerational +intergeneric +interglacial +interglacials +intergovernmental +intergovernmentally +intergradation +intergradational +intergradations +intergrade +intergraded +intergrades +intergrading +intergraft +intergranular +intergroup +intergrowth +interhemispheric +interim +interindividual +interindustry +interinfluence +interinstitutional +interinvolve +interionic +interior +interiority +interiorization +interiorizations +interiorize +interiorized +interiorizes +interiorizing +interiorly +interiors +interisland +interject +interjected +interjecting +interjection +interjectional +interjectionally +interjections +interjector +interjectors +interjectory +interjects +interjurisdictional +interlace +interlaced +interlacement +interlaces +interlacing +interlacustrine +interlaken +interlaminar +interlaminate +interlaminated +interlaminates +interlaminating +interlamination +interlaminations +interlanguage +interlanguages +interlard +interlarded +interlarding +interlards +interlay +interlayer +interleaf +interleave +interleaved +interleaves +interleaving +interlend +interleukin +interleukins +interlibrary +interline +interlinear +interlinearly +interlineation +interlined +interliner +interlines +interlingua +interlining +interlinings +interlink +interlinked +interlinking +interlinks +interlobular +interlocal +interlock +interlocked +interlocking +interlocks +interlocution +interlocutions +interlocutor +interlocutors +interlocutory +interlope +interloped +interloper +interlopers +interlopes +interloping +interlude +interludes +interlunar +interlunary +intermale +intermarginal +intermarriage +intermarriages +intermarried +intermarries +intermarry +intermarrying +intermeddle +intermeddled +intermeddler +intermeddlers +intermeddles +intermeddling +intermediacy +intermediaries +intermediary +intermediate +intermediated +intermediately +intermediateness +intermediates +intermediating +intermediation +intermediations +intermediator +intermediators +intermedin +intermedins +intermembrane +intermenstrual +interment +interments +intermesh +intermeshed +intermeshes +intermeshing +intermetallic +intermezzi +intermezzo +intermezzos +interminability +interminable +interminableness +interminably +intermingle +intermingled +intermingles +intermingling +interministerial +intermission +intermissionless +intermissions +intermit +intermitotic +intermits +intermitted +intermittence +intermittency +intermittent +intermittently +intermitter +intermitters +intermitting +intermix +intermixed +intermixes +intermixing +intermixture +intermixtures +intermodal +intermodulation +intermodulations +intermolecular +intermolecularly +intermont +intermontane +intermountain +intern +internal +internality +internalization +internalizations +internalize +internalized +internalizes +internalizing +internally +internals +international +internationale +internationalism +internationalist +internationalists +internationality +internationalization +internationalizations +internationalize +internationalized +internationalizes +internationalizing +internationally +internationals +interne +internecine +interned +internee +internees +internet +interneuron +interneuronal +interneurons +interning +internist +internists +internment +internodal +internode +internodes +interns +internship +internships +internuclear +internucleon +internucleonic +internucleotide +internuncial +internuncially +internuncio +internuncios +interobserver +interocean +interoceanic +interoceptive +interoceptor +interoceptors +interoffice +interoperability +interoperable +interoperative +interorbital +interorgan +interorganizational +interosculate +interosculated +interosculates +interosculating +interpandemic +interparish +interparochial +interparoxysmal +interparticle +interparty +interpellate +interpellated +interpellates +interpellating +interpellation +interpellations +interpellator +interpellators +interpenetrate +interpenetrated +interpenetrates +interpenetrating +interpenetration +interpenetrations +interperceptual +interpermeate +interpersonal +interpersonally +interphalangeal +interphase +interphased +interphases +interphasing +interplanetary +interplant +interplanted +interplanting +interplants +interplay +interplayed +interplaying +interplays +interplead +interpleaded +interpleader +interpleaders +interpleading +interpleads +interpluvial +interpoint +interpol +interpolate +interpolated +interpolates +interpolating +interpolation +interpolations +interpolative +interpolator +interpolators +interpopulation +interpopulational +interposal +interpose +interposed +interposer +interposers +interposes +interposing +interposition +interpositions +interpret +interpretability +interpretable +interpretableness +interpretably +interpretation +interpretational +interpretations +interpretative +interpretatively +interpreted +interpreter +interpreters +interpreting +interpretive +interpretively +interprets +interprofessional +interprovincial +interproximal +interpsychic +interpupillary +interracial +interracially +interred +interregional +interregna +interregnal +interregnum +interregnums +interrelate +interrelated +interrelatedly +interrelatedness +interrelates +interrelating +interrelation +interrelations +interrelationship +interrelationships +interreligious +interrenal +interring +interrobang +interrobangs +interrogate +interrogated +interrogatee +interrogatees +interrogates +interrogating +interrogation +interrogational +interrogations +interrogative +interrogatively +interrogatives +interrogator +interrogatories +interrogatorily +interrogators +interrogatory +interrogee +interrogees +interrow +interrupt +interrupted +interrupter +interrupters +interruptible +interrupting +interruption +interruptions +interruptive +interruptor +interruptors +interrupts +interruptus +inters +interscholastic +interscholastically +interschool +intersect +intersected +intersecting +intersection +intersectional +intersections +intersects +intersegment +intersegmental +intersensory +interservice +intersession +intersessional +intersessions +intersex +intersexes +intersexual +intersexuality +intersexually +intersocietal +intersociety +interspace +interspaced +interspaces +interspacing +interspatial +interspecies +interspecific +intersperse +interspersed +interspersedly +intersperses +interspersing +interspersion +interspersions +interstadial +interstage +interstate +interstates +interstation +interstellar +intersterile +intersterility +interstice +interstices +interstimulation +interstimulus +interstitial +interstitially +interstrain +interstrand +interstratification +interstratify +intersubjective +intersubjectively +intersubjectivity +intersubstitutability +intersubstitutable +intersystem +interterm +interterminal +interterritorial +intertestamental +intertexture +intertextures +intertidal +intertidally +intertie +interties +intertill +intertillage +intertilled +intertilling +intertills +intertranslatable +intertransmutation +intertrial +intertribal +intertroop +intertropical +intertwine +intertwined +intertwinement +intertwinements +intertwines +intertwining +intertwist +intertwisted +intertwisting +intertwists +interunion +interunit +interuniversity +interurban +interval +intervale +intervales +intervalic +intervalley +intervallic +intervalometer +intervalometers +intervals +intervene +intervened +intervener +interveners +intervenes +intervening +intervenor +intervenors +intervention +interventional +interventionism +interventionist +interventionists +interventions +interventricular +intervertebral +intervertebrally +interview +interviewable +interviewed +interviewee +interviewees +interviewer +interviewers +interviewing +interviews +intervillage +intervisibility +intervisible +intervisitation +intervocalic +intervocalically +interwar +interweave +interweaves +interweaving +interwired +interwork +interworking +interwove +interwoven +interzonal +interzone +intestacies +intestacy +intestate +intestates +intestinal +intestinally +intestine +intestines +inthrall +inthralled +inthralling +inthrallingly +inthrallment +inthralls +inthrone +inthroned +inthronement +inthronements +inthrones +inthroning +inti +intima +intimacies +intimacy +intimae +intimal +intimas +intimate +intimated +intimately +intimateness +intimater +intimaters +intimates +intimating +intimation +intimations +intime +intimidate +intimidated +intimidates +intimidating +intimidatingly +intimidation +intimidations +intimidator +intimidators +intimidatory +intinction +intinctions +intine +intines +intis +intitule +intituled +intitules +intituling +into +intolerability +intolerable +intolerableness +intolerably +intolerance +intolerant +intolerantly +intolerantness +intonate +intonated +intonates +intonating +intonation +intonational +intonations +intone +intoned +intonement +intonements +intoner +intoners +intones +intoning +intoxicant +intoxicants +intoxicate +intoxicated +intoxicatedly +intoxicates +intoxicating +intoxicatingly +intoxication +intoxications +intoxicative +intoxicator +intoxicators +intra +intracardiac +intracardial +intracardially +intracellular +intracellularly +intracerebral +intracerebrally +intracoastal +intracompany +intracranial +intracranially +intractability +intractable +intractableness +intractably +intracutaneous +intracutaneously +intracytoplasmic +intraday +intradepartmental +intradermal +intradermally +intrados +intradoses +intraepithelial +intragalactic +intragenic +intralingual +intramolecular +intramolecularly +intramural +intramurally +intramuscular +intramuscularly +intranasal +intranasally +intransigeance +intransigeant +intransigeantly +intransigence +intransigency +intransigent +intransigently +intransigents +intransitive +intransitively +intransitiveness +intransitives +intransitivity +intranuclear +intraocular +intraocularly +intraperitoneal +intraperitoneally +intrapersonal +intrapersonally +intraplate +intrapopulation +intrapreneur +intrapreneurial +intrapreneurialism +intrapreneurially +intrapreneurs +intrapsychic +intrapsychically +intrapulmonary +intraspecies +intraspecific +intrastate +intrathecal +intrathecally +intrathoracic +intrathoracically +intrauterine +intravasation +intravasations +intravascular +intravascularly +intravenous +intravenouses +intravenously +intraventricular +intraventricularly +intravital +intravitally +intravitam +intrazonal +intreat +intreated +intreating +intreatingly +intreatment +intreats +intrench +intrenched +intrenches +intrenching +intrenchment +intrenchments +intrepid +intrepidity +intrepidly +intrepidness +intricacies +intricacy +intricate +intricately +intricateness +intrigant +intrigants +intriguant +intriguants +intrigue +intrigued +intriguer +intriguers +intrigues +intriguing +intriguingly +intrinsic +intrinsical +intrinsically +intro +introduce +introduced +introducer +introducers +introduces +introducible +introducing +introduction +introductions +introductorily +introductory +introgressant +introgressants +introgression +introgressions +introgressive +introit +introits +introject +introjected +introjecting +introjection +introjections +introjects +intromission +intromissions +intromissive +intromit +intromits +intromitted +intromittent +intromitter +intromitters +intromitting +intron +introns +introrse +intros +introspect +introspected +introspecting +introspection +introspectional +introspectionism +introspectionist +introspectionistic +introspectionists +introspective +introspectively +introspectiveness +introspects +introversion +introversions +introversive +introversively +introvert +introverted +introverting +introverts +intrude +intruded +intruder +intruders +intrudes +intruding +intrusion +intrusions +intrusive +intrusively +intrusiveness +intrust +intrusted +intrusting +intrusts +intubate +intubated +intubates +intubating +intubation +intubational +intubationally +intubations +intuit +intuitable +intuited +intuiting +intuition +intuitional +intuitionally +intuitionism +intuitionist +intuitionists +intuitions +intuitive +intuitively +intuitiveness +intuits +intumesce +intumesced +intumescence +intumescences +intumescent +intumesces +intumescing +intussuscept +intussuscepted +intussuscepting +intussusception +intussusceptions +intussusceptive +intussuscepts +intwine +intwined +intwinement +intwinements +intwines +intwining +intwist +intwisted +intwisting +intwists +inuit +inuits +inuktitut +inulase +inulases +inulin +inulins +inunction +inunctions +inundate +inundated +inundates +inundating +inundation +inundations +inundator +inundators +inundatory +inupiaq +inupiaqs +inupiat +inupiats +inure +inured +inurement +inurements +inures +inuring +inurn +inurned +inurning +inurns +inutile +inutilely +inutility +inuvik +invade +invaded +invader +invaders +invades +invading +invaginate +invaginated +invaginates +invaginating +invagination +invaginations +invalid +invalidate +invalidated +invalidates +invalidating +invalidation +invalidations +invalidator +invalidators +invalided +invaliding +invalidism +invalidity +invalidly +invalids +invaluable +invaluableness +invaluably +invariability +invariable +invariableness +invariably +invariance +invariant +invariantly +invariants +invasion +invasions +invasive +invasively +invasiveness +invective +invectively +invectiveness +invectives +inveigh +inveighed +inveigher +inveighers +inveighing +inveighs +inveigle +inveigled +inveiglement +inveiglements +inveigler +inveiglers +inveigles +inveigling +invenient +invenit +invent +invented +inventible +inventing +invention +inventional +inventions +inventive +inventively +inventiveness +inventor +inventorial +inventorially +inventoried +inventories +inventors +inventory +inventorying +inventress +inventresses +invents +inveracities +inveracity +invercargill +inverness +invernesses +inverse +inversely +inverses +inversion +inversions +inversive +invert +invertase +invertases +invertebrate +invertebrates +inverted +inverter +inverters +invertible +inverting +inverts +invest +investable +invested +investigable +investigate +investigated +investigates +investigating +investigation +investigational +investigations +investigative +investigator +investigatorial +investigators +investigatory +investing +investiture +investitures +investment +investments +investor +investors +invests +inveteracy +inveterate +inveterately +inveterateness +inviability +inviable +invidia +invidious +invidiously +invidiousness +invigilate +invigilated +invigilates +invigilating +invigilation +invigilations +invigilator +invigilators +invigorant +invigorants +invigorate +invigorated +invigorates +invigorating +invigoratingly +invigoration +invigorations +invigorative +invigorator +invigorators +invincibility +invincible +invincibleness +invincibly +inviolability +inviolable +inviolableness +inviolably +inviolacy +inviolate +inviolately +inviolateness +inviscid +invisibility +invisible +invisibleness +invisibles +invisibly +invita +invitation +invitational +invitationals +invitations +invitatories +invitatory +invite +invited +invitee +invitees +inviter +inviters +invites +inviting +invitingly +invocate +invocated +invocates +invocating +invocation +invocational +invocations +invocatory +invoice +invoiced +invoices +invoicing +invoke +invoked +invoker +invokers +invokes +invoking +involucel +involucels +involucra +involucral +involucrate +involucre +involucres +involucrum +involuntarily +involuntariness +involuntary +involute +involuted +involutely +involutes +involuting +involution +involutional +involutions +involve +involved +involvedly +involvement +involvements +involver +involvers +involves +involving +invulnerability +invulnerable +invulnerableness +invulnerably +inward +inwardly +inwardness +inwards +inweave +inweaved +inweaves +inweaving +inwind +inwinding +inwinds +inwound +inwove +inwoven +inwrap +inwrapped +inwrapping +inwraps +inwreathe +inwreathed +inwreathes +inwreathing +inwrought +io +iodate +iodated +iodates +iodating +iodation +iodations +iodic +iodide +iodides +iodinate +iodinated +iodinates +iodinating +iodination +iodinations +iodine +iodization +iodizations +iodize +iodized +iodizes +iodizing +iodoform +iodoforms +iodophor +iodophors +iodopsin +iodopsins +ion +iona +ionia +ionian +ionians +ionic +ionicity +ionics +ionium +ionizable +ionization +ionize +ionized +ionizer +ionizers +ionizes +ionizing +ionone +ionones +ionophore +ionophores +ionosphere +ionospheric +ionospherically +ions +iontophoreses +iontophoresis +iontophoretic +iontophoretically +iota +iotacism +iowa +iowan +iowans +iowas +ipecac +ipecacuanha +iphigenia +iproniazid +iproniazids +ipse +ipsilateral +ipsilaterally +ipsissima +ipso +ipsos +ipsum +iran +iranian +iranians +iraq +iraqi +iraqis +irascibility +irascible +irascibleness +irascibly +irate +irately +irateness +ire +ireful +irefully +ireland +irelands +irenic +irenical +irenically +ireton +iridaceous +iridectomies +iridectomy +irides +iridescence +iridescent +iridescently +iridic +iridium +iridologist +iridologists +iridology +iridosmine +iridosmines +iris +irises +irish +irishism +irishisms +irishman +irishmen +irishness +irishries +irishry +irishwoman +irishwomen +iritic +iritis +irk +irked +irking +irks +irksome +irksomely +irksomeness +irkutsk +iroko +irokos +iron +ironbark +ironbarks +ironbound +ironclad +ironclads +irondequoit +ironed +ironer +ironers +ironfisted +ironhanded +ironhandedness +ironhearted +ironic +ironical +ironically +ironicalness +ironies +ironing +ironings +ironist +ironists +ironize +ironized +ironizes +ironizing +ironmaster +ironmasters +ironmonger +ironmongeries +ironmongers +ironmongery +ironness +irons +ironside +ironsides +ironsmith +ironsmiths +ironstone +ironstones +ironware +ironweed +ironweeds +ironwood +ironwoods +ironwork +ironworker +ironworkers +ironworks +irony +iroquoian +iroquoians +iroquois +irradiance +irradiances +irradiancy +irradiant +irradiate +irradiated +irradiates +irradiating +irradiation +irradiations +irradiative +irradiator +irradiators +irradicable +irradicably +irrational +irrationalism +irrationalist +irrationalistic +irrationalists +irrationalities +irrationality +irrationalize +irrationalized +irrationalizes +irrationalizing +irrationally +irrationalness +irrawaddy +irreal +irreality +irreclaimability +irreclaimable +irreclaimableness +irreclaimably +irreconcilability +irreconcilable +irreconcilableness +irreconcilables +irreconcilably +irrecoverable +irrecoverableness +irrecoverably +irrecusable +irrecusably +irredeemable +irredeemably +irredenta +irredentism +irredentist +irredentists +irreducibility +irreducible +irreducibleness +irreducibly +irreflexive +irreformability +irreformable +irrefragability +irrefragable +irrefragably +irrefrangible +irrefrangibly +irrefutability +irrefutable +irrefutably +irregardless +irregular +irregularities +irregularity +irregularly +irregulars +irrelative +irrelatively +irrelevance +irrelevancies +irrelevancy +irrelevant +irrelevantly +irreligion +irreligionist +irreligionists +irreligions +irreligious +irreligiously +irreligiousness +irremeable +irremediable +irremediableness +irremediably +irremissibility +irremissible +irremissibly +irremovability +irremovable +irremovably +irreparability +irreparable +irreparableness +irreparably +irrepealability +irrepealable +irreplaceability +irreplaceable +irreplaceableness +irreplaceably +irrepressibility +irrepressible +irrepressibleness +irrepressibly +irreproachability +irreproachable +irreproachableness +irreproachably +irreproducibility +irreproducible +irresistibility +irresistible +irresistibleness +irresistibly +irresoluble +irresolute +irresolutely +irresoluteness +irresolution +irresolvable +irrespective +irrespectively +irrespirable +irresponsibility +irresponsible +irresponsibleness +irresponsibles +irresponsibly +irresponsive +irresponsively +irresponsiveness +irretrievability +irretrievable +irretrievableness +irretrievably +irreverence +irreverences +irreverent +irreverently +irreversibility +irreversible +irreversibleness +irreversibly +irrevocability +irrevocable +irrevocableness +irrevocably +irridenta +irrigable +irrigate +irrigated +irrigates +irrigating +irrigation +irrigational +irrigations +irrigator +irrigators +irritabilities +irritability +irritable +irritableness +irritably +irritant +irritants +irritate +irritated +irritatedly +irritates +irritating +irritatingly +irritation +irritations +irritative +irritator +irritators +irrotational +irrupt +irrupted +irrupting +irruption +irruptions +irruptive +irruptively +irrupts +irving +iráklion +is +isaac +isabella +isaiah +isaias +isallobar +isallobaric +isallobars +iscariot +ischaemia +ischemia +ischemic +ischia +ischial +ischium +isentropic +isentropically +iseult +isfahan +ishmael +ishmaelite +ishmaelites +ishmaelitish +ishmaelitism +ishmaels +ishtar +isinglass +isis +iskenderun +islam +islamabad +islamic +islamics +islamism +islamist +islamists +islamization +islamize +islamized +islamizes +islamizing +island +islanded +islander +islanders +islanding +islands +islay +isle +isled +isles +islet +islets +isling +ism +ismaili +ismailian +ismailians +ismailis +ismene +isms +isn +isn't +isoagglutination +isoagglutinations +isoagglutinin +isoagglutinins +isoagglutinogen +isoagglutinogens +isoalloxazine +isoantibodies +isoantibody +isoantigen +isoantigenic +isoantigenicity +isoantigens +isobar +isobaric +isobars +isobutane +isobutanes +isobutylene +isobutylenes +isocaloric +isocarboxazid +isocarboxazids +isochromatic +isochromosome +isochromosomes +isochron +isochronal +isochronally +isochrone +isochrones +isochronism +isochronize +isochronized +isochronizes +isochronizing +isochronous +isochronously +isochrons +isochroous +isocitric +isoclinal +isoclinally +isoclinals +isoclinic +isocrates +isocyanate +isocyanates +isocyclic +isodiametric +isodimorphism +isodose +isodynamic +isoelectric +isoelectronic +isoelectronically +isoenzymatic +isoenzyme +isoenzymes +isoenzymic +isogamete +isogametes +isogametic +isogamies +isogamous +isogamy +isogeneic +isogenic +isogenous +isogeny +isogloss +isoglossal +isoglosses +isoglossic +isogon +isogonal +isogonic +isogons +isogony +isograft +isografts +isogram +isograms +isohel +isohels +isohyet +isohyetal +isohyets +isokinetic +isolable +isolatable +isolate +isolated +isolates +isolating +isolation +isolationism +isolationist +isolationistic +isolationists +isolations +isolator +isolators +isolde +isolecithal +isoleucine +isoleucines +isoline +isolines +isomagnetic +isomer +isomerase +isomerases +isomeric +isomerism +isomerisms +isomerization +isomerizations +isomerize +isomerized +isomerizes +isomerizing +isomerous +isomers +isometric +isometrical +isometrically +isometrics +isometropia +isometropias +isometry +isomorph +isomorphic +isomorphically +isomorphism +isomorphous +isomorphs +isoniazid +isoniazids +isooctane +isopach +isophotal +isophote +isophotes +isopiestic +isopiestics +isopleth +isoplethic +isopleths +isopod +isopods +isoprenaline +isoprenalines +isoprene +isoprenoid +isopropyl +isoproterenol +isopycnic +isosceles +isoseismal +isoseismic +isosmotic +isosmotically +isospin +isospins +isostasy +isostatic +isostatically +isotach +isotactic +isotherm +isothermal +isothermally +isothermals +isotherms +isotone +isotones +isotonic +isotonically +isotonicity +isotope +isotopes +isotopic +isotopically +isotretinoin +isotretinoins +isotropic +isotropism +isotropy +isozyme +isozymes +isozymic +ispahan +israel +israeli +israelis +israelite +israelites +israelitic +issachar +issei +isseis +issuable +issuably +issuance +issuant +issue +issued +issueless +issuer +issuers +issues +issuing +istanbul +isthmi +isthmian +isthmic +isthmus +isthmuses +istle +istles +istria +istrian +istrians +it +it'd +it'll +it's +itacolumite +itacolumites +itaconic +italian +italianate +italianism +italianisms +italianization +italianizations +italianize +italianized +italianizes +italianizing +italians +italic +italicism +italicisms +italicization +italicizations +italicize +italicized +italicizes +italicizing +italics +italophile +italophiles +italophilia +italophobe +italophobes +italophobia +italy +itasca +itch +itched +itches +itchier +itchiest +itchiness +itching +itchy +item +itemed +iteming +itemization +itemizations +itemize +itemized +itemizer +itemizers +itemizes +itemizing +items +iterance +iterances +iterant +iterate +iterated +iterates +iterating +iteration +iterations +iterative +iteratively +ithaca +ithaka +ithyphallic +itháki +itineracy +itinerancies +itinerancy +itinerant +itinerantly +itinerants +itineraries +itinerary +itinerate +itinerated +itinerates +itinerating +itineration +itinerations +its +itself +itsukushima +itsy +itty +ituraea +ituraean +ituraeans +ivanhoe +ivermectin +ivermectins +ivied +ivies +iviza +ivories +ivory +ivorybill +ivorybills +ivy +iwis +ixion +ixodid +ixtle +ixtles +iyar +iyyar +izalco +izar +izars +izzard +j +jab +jabbed +jabber +jabbered +jabberer +jabberers +jabbering +jabbers +jabberwocky +jabbing +jabiru +jabirus +jaborandi +jaborandis +jabot +jaboticaba +jabots +jabs +jacal +jacales +jacals +jacamar +jacamars +jacana +jacanas +jacaranda +jacarandas +jacinth +jacinths +jacinto +jack +jackal +jackals +jackanapes +jackanapeses +jackass +jackassery +jackasses +jackboot +jackbooted +jackboots +jackdaw +jackdaws +jacked +jacker +jackers +jacket +jacketed +jacketing +jacketless +jackets +jackfruit +jackfruits +jackhammer +jackhammered +jackhammering +jackhammers +jacking +jackknife +jackknifed +jackknifes +jackknifing +jackknives +jackleg +jacklegs +jacklight +jacklighted +jacklighting +jacklights +jackplane +jackplanes +jackpot +jackpots +jackrabbit +jackrabbited +jackrabbiting +jackrabbits +jacks +jackscrew +jackscrews +jackshaft +jackshafts +jacksmelt +jacksnipe +jacksnipes +jackson +jacksonian +jacksonianism +jacksonians +jackstay +jackstays +jackstone +jackstones +jackstraw +jackstraws +jacob +jacobean +jacobeans +jacobian +jacobians +jacobin +jacobinic +jacobinical +jacobinism +jacobinize +jacobinized +jacobinizes +jacobinizing +jacobins +jacobite +jacobites +jacobitical +jacobitism +jacobus +jaconet +jaconets +jacquard +jacquards +jacquerie +jacqueries +jactitation +jactitations +jacuzzi +jade +jaded +jadedly +jadedness +jadeite +jadeites +jades +jadestone +jadestones +jading +jaditic +jaeger +jaegers +jaffa +jaffas +jag +jagatai +jagged +jaggedly +jaggedness +jagger +jaggeries +jaggers +jaggery +jaggier +jaggiest +jagging +jaggy +jagless +jags +jaguar +jaguarondi +jaguarondis +jaguars +jaguarundi +jaguarundis +jah +jahveh +jahweh +jai +jail +jailbait +jailbird +jailbirds +jailbreak +jailbreaks +jailed +jailer +jailers +jailhouse +jailhouses +jailing +jailor +jailors +jails +jain +jaina +jainas +jainism +jainisms +jains +jaipur +jakarta +jake +jakes +jakob +jalalabad +jalap +jalapeño +jalapeños +jalaps +jalopies +jalopy +jalousie +jalousies +jam +jamaica +jamaican +jamaicans +jamb +jambalaya +jambe +jambeau +jambeaux +jambes +jamboree +jamborees +jambs +james +jamesian +jammable +jammed +jammer +jammers +jammies +jamming +jammu +jammy +jams +jamshid +jamshyd +jane +janeiro +janeite +janeites +jangle +jangled +jangler +janglers +jangles +jangling +jangly +janissaries +janissary +janitor +janitorial +janitors +janizaries +janizary +jansenism +jansenist +jansenistic +jansenists +januaries +january +januarys +janus +jap +japan +japanese +japanization +japanize +japanized +japanizes +japanizing +japanned +japanner +japanners +japanning +japans +jape +japed +japer +japers +japery +japes +japheth +japhetic +japing +japlish +japonaiserie +japonaiseries +japonica +japonicas +japonism +japonisms +japs +japurá +jar +jardiniere +jardinieres +jardinière +jardinières +jarful +jarfuls +jargon +jargoned +jargoneer +jargoneers +jargoning +jargonish +jargonist +jargonistic +jargonists +jargonize +jargonized +jargonizes +jargonizing +jargons +jargoon +jargoons +jarhead +jarheads +jarl +jarls +jarlsberg +jarrah +jarrahs +jarred +jarring +jarringly +jars +jasmine +jasmines +jason +jasper +jaspers +jasperware +jaspery +jassid +jassids +jat +jato +jatos +jats +jaunce +jaunced +jaunces +jauncing +jaundice +jaundiced +jaundices +jaundicing +jaunt +jaunted +jauntier +jauntiest +jauntily +jauntiness +jaunting +jaunts +jaunty +java +javanese +javarí +javas +javelin +javelina +javelinas +javelins +javelle +jaw +jawbone +jawboned +jawboner +jawboners +jawbones +jawboning +jawbreaker +jawbreakers +jawbreaking +jawbreakingly +jawed +jawing +jawless +jawline +jawlines +jaws +jay +jaybird +jaybirds +jaycee +jaycees +jaygee +jaygees +jayhawker +jayhawkers +jays +jayvee +jayvees +jaywalk +jaywalked +jaywalker +jaywalkers +jaywalking +jaywalks +jazz +jazzed +jazzer +jazzers +jazzes +jazzier +jazziest +jazzily +jazziness +jazzing +jazzish +jazzlike +jazzman +jazzmen +jazzy +jaçana +jaçanas +je +jealous +jealousies +jealously +jealousness +jealousy +jean +jeaned +jeans +jeddah +jee +jeebies +jeep +jeepers +jeepney +jeepneys +jeeps +jeer +jeered +jeerer +jeerers +jeering +jeeringly +jeers +jeez +jefe +jefes +jefferson +jeffersonian +jeffersonianism +jeffersonians +jeffrey +jehad +jehads +jehoshaphat +jehovah +jehu +jehus +jejuna +jejunal +jejune +jejunely +jejuneness +jejunum +jekyll +jell +jellaba +jellabas +jelled +jellicoe +jellied +jellies +jellified +jellifies +jellify +jellifying +jelling +jells +jelly +jellybean +jellybeans +jellyfish +jellyfishes +jellying +jellylike +jellyroll +jellyrolls +jelutong +jemmied +jemmies +jemmy +jemmying +jena +jenner +jennet +jennets +jennies +jenny +jeon +jeopard +jeoparded +jeopardies +jeoparding +jeopardize +jeopardized +jeopardizes +jeopardizing +jeopardous +jeopards +jeopardy +jequirity +jequitinhonha +jerboa +jerboas +jeremiad +jeremiads +jeremiah +jeremiahs +jeremias +jerez +jericho +jerk +jerked +jerker +jerkers +jerkier +jerkiest +jerkily +jerkin +jerkiness +jerking +jerkingly +jerkins +jerks +jerkwater +jerky +jeroboam +jeroboams +jerome +jerrican +jerricans +jerries +jerry +jerrybuild +jerrybuilder +jerrybuilders +jerrybuilding +jerrybuilds +jerrybuilt +jersey +jerseys +jerusalem +jess +jessamine +jessamines +jesse +jessed +jesses +jessing +jest +jested +jester +jesters +jesting +jestingly +jests +jesuit +jesuitic +jesuitical +jesuitically +jesuitism +jesuitry +jesuits +jesus +jet +jetavator +jetavators +jetbead +jetbeads +jetfighter +jetfighters +jetfoil +jetfoils +jetful +jetlike +jetliner +jetliners +jetpack +jetpacks +jetport +jetports +jets +jetsam +jetted +jettied +jetties +jettiness +jetting +jettison +jettisonable +jettisoned +jettisoning +jettisons +jetty +jettying +jetway +jeté +jeu +jeunesse +jeux +jew +jewel +jeweled +jeweler +jewelers +jewelfish +jewelfishes +jeweling +jewelled +jeweller +jewellers +jewellery +jewellike +jewelling +jewelry +jewels +jewelweed +jewelweeds +jewess +jewesses +jewfish +jewfishes +jewish +jewishly +jewishness +jewries +jewry +jews +jezebel +jezebels +jiao +jib +jibaro +jibaros +jibbed +jibber +jibbers +jibbing +jibboom +jibbooms +jibe +jibed +jibes +jibing +jibs +jicama +jicamas +jicarilla +jicarillas +jiff +jiffies +jiffs +jiffy +jig +jigged +jigger +jiggers +jiggery +jigging +jiggle +jiggled +jiggles +jiggling +jiggly +jigs +jigsaw +jigsaws +jihad +jihads +jill +jillion +jillionaire +jillionaires +jillions +jillionth +jillionths +jills +jilt +jilted +jilter +jilters +jilting +jilts +jim +jimjams +jimmied +jimmies +jimmy +jimmying +jimsonweed +jimsonweeds +jingle +jingled +jingler +jinglers +jingles +jingling +jingly +jingo +jingoes +jingoish +jingoism +jingoist +jingoistic +jingoistically +jingoists +jink +jinked +jinking +jinks +jinmen +jinn +jinnee +jinni +jinns +jinricksha +jinrickshas +jinrikisha +jinrikishas +jinriksha +jinrikshas +jinx +jinxed +jinxes +jinxing +jipijapa +jipijapas +jitney +jitneys +jitter +jitterbug +jitterbugged +jitterbugging +jitterbugs +jittered +jitterier +jitteriest +jitteriness +jittering +jitters +jittery +jiujitsu +jiujutsu +jivaro +jivaros +jive +jived +jiver +jivers +jives +jivey +jiving +jivy +jo +joan +job +jobbed +jobber +jobbers +jobbery +jobbing +jobholder +jobholders +jobless +joblessness +jobs +jocasta +jock +jockey +jockeyed +jockeying +jockeys +jocks +jockstrap +jockstraps +jocose +jocosely +jocoseness +jocosity +jocular +jocularity +jocularly +jocund +jocundity +jocundly +jodhpur +jodhpurs +jodrell +joe +joel +joes +joey +joeys +jog +jogged +jogger +joggers +jogging +joggle +joggled +joggles +joggling +jogjakarta +jogs +johannesburg +john +johnboat +johnboats +johnnies +johnny +johnnycake +johnnycakes +johns +johnson +johnsonian +johnsonians +johnstone +johnstown +joie +join +joinder +joinders +joined +joiner +joineries +joiners +joinery +joining +joins +joint +jointed +jointer +jointers +jointing +jointly +joints +jointure +jointures +jointworm +jointworms +joist +joisted +joisting +joists +jojoba +jojobas +joke +joked +joker +jokers +jokes +jokester +jokesters +jokey +jokier +jokiest +jokily +jokiness +joking +jokingly +joky +jolie +jollied +jollier +jollies +jolliest +jollification +jollifications +jollily +jolliness +jollities +jollity +jolly +jollyboat +jollyboats +jollying +jolt +jolted +jolter +jolters +joltily +joltiness +jolting +jolts +jolty +jomada +jonah +jonahs +jonathan +jones +jongleur +jongleurs +jonnycake +jonnycakes +jonquil +jonquils +jonson +jooal +jordan +jordanian +jordanians +jorum +jorums +joseph +josephs +josephus +josh +joshed +josher +joshers +joshes +joshing +joshingly +joshua +josiah +joss +josses +jostle +jostled +jostler +jostlers +jostles +jostling +josé +jot +jots +jotted +jotting +jottings +joual +joule +joules +jounce +jounced +jounces +jouncing +jour +journal +journalese +journalism +journalist +journalistic +journalistically +journalists +journalize +journalized +journalizer +journalizers +journalizes +journalizing +journals +journey +journeyed +journeyer +journeyers +journeying +journeyman +journeymen +journeys +journeywork +joust +jousted +jouster +jousters +jousting +jousts +jove +jovial +joviality +jovially +jovian +jowett +jowl +jowlier +jowliest +jowliness +jowls +jowly +joy +joyance +joyce +joyed +joyful +joyfully +joyfulness +joying +joyless +joylessly +joylessness +joyous +joyously +joyousness +joypop +joypopped +joypopper +joypoppers +joypopping +joypops +joyride +joyrider +joyriders +joyrides +joyriding +joys +joystick +joysticks +joão +juan +juanism +juans +juba +jubal +jubas +jubilance +jubilant +jubilantly +jubilarian +jubilarians +jubilate +jubilated +jubilates +jubilating +jubilation +jubilee +jubilees +judaea +judah +judaic +judaica +judaical +judaically +judaism +judaist +judaistic +judaists +judaization +judaizations +judaize +judaized +judaizer +judaizers +judaizes +judaizing +judas +judases +judder +juddered +juddering +judders +jude +judea +judean +judeans +judeo +judge +judged +judgement +judgements +judger +judgers +judges +judgeship +judgeships +judging +judgmatic +judgmatical +judgmatically +judgment +judgmental +judgmentally +judgments +judicable +judicata +judicator +judicatories +judicators +judicatory +judicature +judicatures +judice +judicial +judicially +judiciaries +judiciary +judicious +judiciously +judiciousness +judith +judo +judoist +judoists +judos +judy +jug +juga +jugate +jugful +jugfuls +jugged +juggernaut +juggernauts +jugging +juggle +juggled +juggler +juggleries +jugglers +jugglery +juggles +juggling +jugoslav +jugoslavs +jugs +jugular +jugulars +jugulate +jugulated +jugulates +jugulating +jugum +jugums +juice +juiced +juicehead +juiceheads +juiceless +juicer +juicers +juices +juicier +juiciest +juicily +juiciness +juicing +juicy +jujitsu +juju +jujube +jujubes +jujuism +jujus +jujutsu +juke +jukebox +jukeboxes +juked +jukes +juking +julep +juleps +julian +julienne +julienned +juliet +juliett +julius +july +julys +jumada +jumble +jumbled +jumbles +jumbling +jumbo +jumbos +jumbuck +jumbucks +jump +jumped +jumper +jumpers +jumpier +jumpiest +jumpily +jumpiness +jumping +jumpmaster +jumpmasters +jumps +jumpsuit +jumpsuits +jumpy +junco +juncoes +juncos +junction +junctional +junctions +junctural +juncture +junctures +june +juneau +juneberries +juneberry +junes +jung +jungfrau +jungian +jungians +jungle +jungled +junglelike +jungles +jungly +junior +juniorate +juniors +juniper +junipers +junius +junk +junked +junker +junkerdom +junkerism +junkers +junket +junketed +junketeer +junketeered +junketeering +junketeers +junketer +junketers +junketing +junkets +junkie +junkier +junkies +junkiest +junking +junkman +junkmen +junks +junky +junkyard +junkyards +juno +junoesque +junta +juntas +junto +juntos +jupiter +jura +jural +jurally +jurassic +jurat +jurats +jure +jureipswich +jurel +jurels +juridic +juridical +juridically +juried +juries +juris +jurisconsult +jurisconsults +jurisdiction +jurisdictional +jurisdictionally +jurisdictions +jurisprudence +jurisprudent +jurisprudential +jurisprudentially +jurisprudents +jurist +juristic +juristical +juristically +jurists +juror +jurors +jury +jurying +juryman +jurymen +jurywoman +jurywomen +jus +jussive +jussives +just +juste +justed +justes +justice +justices +justiciability +justiciable +justiciar +justiciaries +justiciars +justiciary +justifiability +justifiable +justifiableness +justifiably +justification +justifications +justificative +justificatory +justified +justifier +justifiers +justifies +justify +justifying +justing +justinian +justly +justness +justs +jut +jute +jutish +jutland +juts +jutted +juttied +jutties +jutting +jutty +juttying +juvenal +juvenescence +juvenescent +juvenile +juvenilely +juvenileness +juveniles +juvenilia +juvenilities +juvenility +juxtapose +juxtaposed +juxtaposes +juxtaposing +juxtaposition +juxtapositional +juxtapositions +juárez +jyväskylä +k +kaaba +kab +kabala +kabalas +kabbala +kabbalah +kabbalas +kabob +kabobs +kabs +kabuki +kabukis +kabul +kabyle +kabyles +kachina +kachinas +kaddish +kaffeeklatsch +kaffeeklatsches +kaffir +kaffirs +kaffiyeh +kaffiyehs +kafir +kafiri +kafirs +kafka +kafkaesque +kaftan +kaftans +kagoshima +kahn +kahoolawe +kahuna +kaiak +kaiaked +kaiaker +kaiakers +kaiaking +kaiaks +kailas +kailyard +kainit +kainite +kainites +kainits +kaiser +kaiserdom +kaiserdoms +kaiserin +kaiserins +kaiserism +kaisers +kaka +kakapo +kakapos +kakas +kakemono +kakemonos +kaki +kakiemon +kakis +kakistocracies +kakistocracy +kalahari +kalamazoo +kalanchoe +kalashnikov +kalashnikovs +kale +kaleidoscope +kaleidoscopes +kaleidoscopic +kaleidoscopical +kaleidoscopically +kalends +kalgoorlie +kalimantan +kalimba +kalimbas +kaliningrad +kallidin +kallidins +kallikrein +kallikreins +kalmar +kalmuck +kalmucks +kalmuk +kalmuks +kalmyk +kalmyks +kalpac +kalpacs +kalsomine +kalsomines +kama +kamaaina +kamala +kamalas +kamasutra +kamchatka +kame +kamehameha +kames +kamet +kamikaze +kamikazes +kampala +kampong +kampongs +kampuchea +kampuchean +kampucheans +kana +kanak +kanaka +kanakas +kanaks +kanamycin +kanamycins +kanarese +kanas +kanban +kanchenjunga +kandy +kangaroo +kangaroos +kangchenjunga +kaniapiskau +kanji +kanjis +kankakee +kannada +kano +kansa +kansan +kansans +kansas +kansu +kant +kantele +kanteles +kantian +kantians +kanuri +kanuris +kanzu +kanzus +kaolin +kaoline +kaolines +kaolinite +kaolinites +kaolinitic +kaolinize +kaolinized +kaolinizes +kaolinizing +kaolins +kaon +kaons +kapellmeister +kaph +kapok +kaposi +kaposi's +kappa +kaput +kaputt +kara +karabiner +karabiners +karachi +karaism +karaite +karaites +karakoram +karakorum +karakul +karakuls +karaoke +karaokes +karat +karate +karateist +karateists +karats +karaya +karelia +karelian +karelians +karen +karenina +karens +kari +kariba +karma +karmic +karnak +karnataka +karok +karoks +karoo +karoos +kaross +karroo +karroos +karst +karstic +karsts +kart +karting +kartings +karts +karyogamies +karyogamy +karyokinesis +karyokinetic +karyologic +karyological +karyology +karyolymph +karyolymphs +karyoplasm +karyoplasms +karyosome +karyosomes +karyotype +karyotyped +karyotypes +karyotypic +karyotypical +karyotypically +karyotyping +kasbah +kasha +kashan +kashans +kasher +kashered +kashering +kashers +kashmir +kashmiri +kashmiris +kashrut +kashruth +kashubian +kaskaskia +kaskaskias +kata +katabatic +katahdin +katakana +katakanas +katanga +katangese +katas +katchina +katcina +katharevusa +katharsis +kathiawar +kathmandu +katmai +katmandu +kattegat +katydid +katydids +katzenjammer +katzenjammers +kauai +kauri +kauris +kava +kavas +kaw +kawartha +kaws +kay +kayak +kayaked +kayaker +kayakers +kayaking +kayaks +kaybecker +kaybeckers +kayo +kayoed +kayoing +kayos +kazak +kazakh +kazakhs +kazakhstan +kazaks +kazbek +kazoo +kazoos +kea +kealakekua +kean +keas +keats +keatsian +kebab +kebabs +kebbock +kebbocks +kebbuck +kebbucks +keble +kebob +kebobs +kechua +kechuas +ked +kedge +kedged +kedgeree +kedges +kedging +keek +keeked +keeking +keeks +keel +keelboat +keelboats +keeled +keelhaul +keelhauled +keelhauling +keelhauls +keeling +keelless +keels +keelson +keelsons +keen +keened +keener +keeners +keenest +keening +keenly +keenness +keens +keep +keeper +keepers +keeping +keeps +keepsake +keepsakes +keeshond +keeshonden +keeshonds +keester +keesters +keewatin +kef +kefallinía +keffiyeh +kefir +kefirs +keflavík +kefs +keg +kegged +kegging +kegler +keglers +kegling +kegs +keister +keisters +kelim +kelims +kelly +keloid +keloidal +keloids +kelp +kelpie +kelpies +kelps +kelpy +kelson +kelsons +kelt +keltic +kelts +kelvin +kelvins +kemijoki +kemp +kempis +kempt +ken +kenaf +kenai +kendal +kendo +kendos +kenilworth +kennebec +kenned +kennedy +kennel +kenneled +kenneling +kennelled +kennelling +kennels +kenning +kennings +keno +kenos +kenosis +kenotic +kens +kenspeckle +kent +kentish +kentledge +kentledges +kentuckian +kentuckians +kentucky +kenya +kenyan +kenyans +keogh +kephalin +kephalins +kepi +kepis +kepler +kept +kerala +keratectomies +keratectomy +keratin +keratinization +keratinizations +keratinize +keratinized +keratinizes +keratinizing +keratinophilic +keratinous +keratitides +keratitis +keratoconjunctivitis +keratoplasties +keratoplasty +keratoses +keratosis +keratotic +keratotomies +keratotomy +kerb +kerbs +kerch +kerchief +kerchiefed +kerchiefs +kerchieves +keresan +keresans +kerf +kerfs +kerfuffle +kerfuffles +kerguelen +kerman +kermans +kermes +kermess +kermesse +kermesses +kermis +kermises +kern +kerne +kerned +kernel +kerneled +kernels +kernes +kerning +kernite +kernites +kerns +kerogen +kerogens +kerosene +kerosenes +kerosine +kerosines +kerria +kerrias +kerries +kerry +kersey +kerseymere +kerseymeres +kerseys +kerygma +kerygmas +kerygmatic +kestrel +kestrels +ketch +ketches +ketchup +ketene +ketenes +ketoacidosis +ketogenesis +ketogenic +ketoglutaric +ketone +ketones +ketonic +ketose +ketoses +ketosis +ketosteroid +ketosteroids +ketotic +kettle +kettledrum +kettledrums +kettles +kevel +kevels +keweenaw +kewpie +kewpies +key +keyboard +keyboarded +keyboarder +keyboarders +keyboarding +keyboardist +keyboardists +keyboards +keybutton +keybuttons +keycard +keycards +keyed +keyhole +keyholes +keying +keyless +keynes +keynesian +keynesianism +keynesians +keynote +keynoted +keynoter +keynoters +keynotes +keynoting +keypad +keypads +keypunch +keypunched +keypuncher +keypunchers +keypunches +keypunching +keys +keystone +keystones +keystroke +keystroked +keystrokes +keystroking +keyway +keyways +keyword +keywords +kg +khaddar +khaddars +khadi +khaki +khakis +khalif +khalifs +khalkha +khalkidhikí +khamsin +khamsins +khan +khanate +khanates +khans +khapra +khartoum +khartum +khat +khatanga +khats +khedival +khedive +khedives +khedivial +khi +khmer +khmerian +khmers +khoikhoi +khoikhoin +khoikhoins +khoikhois +khoisan +khoisans +khoum +khowar +khwarizmi +khyber +khíos +kiang +kiangs +kiangsi +kiangsu +kiaugh +kiaughs +kibbe +kibbi +kibbitz +kibbitzer +kibbitzers +kibble +kibbled +kibbles +kibbling +kibbutz +kibbutzim +kibbutznik +kibbutzniks +kibe +kibei +kibeis +kibes +kibitz +kibitzed +kibitzer +kibitzers +kibitzes +kibitzing +kiblah +kiblahs +kibosh +kiboshed +kiboshes +kiboshing +kick +kickable +kickapoo +kickapoos +kickback +kickbacks +kickboard +kickboards +kickboxer +kickboxers +kickboxing +kicked +kicker +kickers +kickier +kickiest +kicking +kickoff +kickoffs +kicks +kickshaw +kickshaws +kickstand +kickstands +kickup +kickups +kicky +kid +kidcom +kidcoms +kidded +kidder +kidderminster +kidderminsters +kidders +kiddie +kiddies +kidding +kiddingly +kiddish +kiddo +kiddos +kiddush +kiddushes +kiddy +kideo +kideos +kidnap +kidnaped +kidnapee +kidnapees +kidnaper +kidnapers +kidnaping +kidnapped +kidnappee +kidnappees +kidnapper +kidnappers +kidnapping +kidnappings +kidnaps +kidney +kidneys +kids +kidskin +kidvid +kidvids +kielbasa +kierkegaard +kieselguhr +kieselguhrs +kieserite +kieserites +kiev +kif +kifs +kigali +kike +kikes +kikládhes +kikongo +kikongos +kikuyu +kikuyus +kilauea +kilderkin +kilderkins +kilim +kilimanjaro +kilims +kill +killable +killarney +killdeer +killdeers +killed +killer +killers +killersat +killersats +killick +killicks +killie +killies +killifish +killifishes +killing +killingly +killings +killjoy +killjoys +killock +killocks +kills +kiln +kilned +kilning +kilns +kilo +kiloampere +kiloamperes +kilobar +kilobars +kilobase +kilobases +kilobecquerel +kilobecquerels +kilobit +kilobits +kilobyte +kilobytes +kilocalorie +kilocalories +kilocandela +kilocandelas +kilocoulomb +kilocoulombs +kilocurie +kilocuries +kilocycle +kilocycles +kilofarad +kilofarads +kilogauss +kilogausses +kilogram +kilograms +kilohenries +kilohenry +kilohenrys +kilohertz +kilojoule +kilojoules +kilokelvin +kilokelvins +kiloliter +kiloliters +kilolumen +kilolumens +kilolux +kilomegacycle +kilomegacycles +kilometer +kilometers +kilometric +kilomole +kilomoles +kilonewton +kilonewtons +kilooersted +kilooersteds +kiloohm +kiloohms +kiloparsec +kiloparsecs +kilopascal +kilopascals +kilorad +kiloradian +kiloradians +kilorads +kilos +kilosecond +kiloseconds +kilosiemens +kilosievert +kilosieverts +kilosteradian +kilosteradians +kilotesla +kiloteslas +kiloton +kilotons +kilovolt +kilovolts +kilowatt +kilowatts +kiloweber +kilowebers +kilt +kilted +kilter +kiltie +kilties +kilting +kilts +kilty +kimberley +kimberlite +kimberlites +kimberlitic +kimbundu +kimbundus +kimchee +kimchees +kimchi +kimchis +kimono +kimonoed +kimonos +kin +kina +kinas +kinase +kinases +kind +kinder +kindergarten +kindergartener +kindergarteners +kindergartens +kindergartner +kindergartners +kindersley +kindest +kindhearted +kindheartedly +kindheartedness +kindle +kindled +kindler +kindlers +kindles +kindless +kindlessly +kindlier +kindliest +kindliness +kindling +kindlings +kindly +kindness +kindnesses +kindred +kindredness +kinds +kine +kinema +kinematic +kinematical +kinematically +kinematics +kinescope +kinescoped +kinescopes +kinescoping +kineses +kinesic +kinesics +kinesiologist +kinesiologists +kinesiology +kinesis +kinestheses +kinesthesia +kinesthesias +kinesthesis +kinesthetic +kinesthetically +kinetic +kinetically +kineticism +kineticist +kineticists +kinetics +kinetin +kinetins +kinetochore +kinetochores +kinetoplast +kinetoplasts +kinetoscope +kinetoscopes +kinetosome +kinetosomes +kinfolk +kinfolks +king +king's +kingbird +kingbirds +kingbolt +kingbolts +kingcraft +kingcrafts +kingcup +kingcups +kingdom +kingdoms +kinged +kingfish +kingfisher +kingfishers +kingfishes +kinging +kinglet +kinglets +kinglier +kingliest +kingliness +kingly +kingmaker +kingmakers +kingmaking +kingpin +kingpins +kings +kingship +kingships +kingside +kingsides +kingsley +kingstown +kingwood +kingwoods +kinin +kinins +kink +kinkajou +kinkajous +kinked +kinkier +kinkiest +kinkily +kinkiness +kinking +kinks +kinky +kinnikinnic +kinnikinnick +kinnikinnicks +kinnikinnics +kino +kinos +kinsfolk +kinshasa +kinship +kinsman +kinsmen +kinswoman +kinswomen +kinyarwanda +kioga +kiosk +kiosks +kiowa +kiowas +kip +kipling +kipped +kipper +kippered +kipperer +kipperers +kippering +kippers +kipping +kippur +kips +kir +kirche +kirchhoff +kirghiz +kirghizes +kirghizia +kirghizstan +kirgiz +kirgizes +kirgizia +kirgizstan +kiri +kiribati +kirigami +kirin +kirk +kirkpatrick +kirks +kirlian +kirman +kirmans +kirmess +kirmesses +kirs +kirsch +kirschwasser +kirschwassers +kirtland +kirtle +kirtles +kirundi +kirundis +kishka +kishkas +kishke +kishkes +kiska +kislev +kismet +kiss +kissable +kissed +kisser +kissers +kisses +kissimmee +kissing +kist +kists +kiswahili +kit +kitchen +kitchenette +kitchenettes +kitchens +kitchenware +kite +kited +kitelike +kites +kith +kithara +kitharas +kithe +kithed +kithing +kitikmeot +kiting +kits +kitsch +kitschified +kitschifies +kitschifing +kitschify +kitschy +kitted +kitten +kittened +kittening +kittenish +kittenishly +kittenishness +kittens +kitties +kitting +kittiwake +kittiwakes +kittle +kittled +kittles +kittling +kitts +kitty +kiva +kivas +kiwanian +kiwanians +kiwi +kiwifruit +kiwis +klagenfurt +klamath +klamaths +klan +klanism +klansman +klansmen +klatch +klatches +klatsch +klavern +klaverns +klaxon +klaxons +klebsiella +klebsiellas +klee +kleenex +kleenexes +kleig +klein +klemperer +klepht +klephtic +klephts +kleptocracies +kleptocracy +kleptocratic +kleptomania +kleptomaniac +kleptomaniacal +kleptomaniacs +klezmer +klezmorim +klieg +kliegs +klinefelter +klingon +klingons +klipspringer +klipspringers +klister +klisters +klondike +kloof +kloofs +klosters +kludge +kludged +kludges +kludging +kludgy +kluge +kluged +kluges +kluging +klugy +klutz +klutzes +klutziness +klutzy +klux +kluxer +kluxism +klystron +klystrons +km +knack +knacker +knackered +knackers +knackery +knacks +knackwurst +knackwursts +knap +knapped +knapper +knappers +knapping +knaps +knapsack +knapsacked +knapsacks +knapweed +knapweeds +knar +knars +knaur +knaurs +knave +knaveries +knavery +knaves +knavish +knavishly +knavishness +knawe +knawel +knawels +knawes +knead +kneadable +kneaded +kneader +kneaders +kneading +kneads +knee +kneeboard +kneeboarded +kneeboarding +kneeboards +kneecap +kneecapped +kneecapping +kneecaps +kneed +kneehole +kneeholes +kneeing +kneel +kneeled +kneeler +kneelers +kneeling +kneels +kneepad +kneepads +kneepan +kneepans +knees +kneesock +kneesocks +knell +knelled +knelling +knells +knelt +knesset +knessets +knew +knickerbocker +knickerbockers +knickers +knickknack +knickknacks +knife +knifed +knifelike +knifeman +knifemen +knifepoint +knifepoints +knifer +knifers +knifes +knifing +knifings +knight +knighted +knighthood +knighting +knightliness +knightly +knights +knish +knishes +knit +knits +knitted +knitter +knitters +knitting +knitwear +knives +knob +knobbed +knobbier +knobbiest +knobblier +knobbliest +knobbly +knobby +knobkerrie +knobkerries +knobs +knock +knockabout +knockabouts +knockdown +knockdowns +knocked +knocker +knockers +knocking +knockings +knockoff +knockoffs +knockout +knockouts +knocks +knockwurst +knockwursts +knoll +knolled +knolling +knolls +knop +knopped +knops +knossos +knot +knotgrass +knotgrasses +knothole +knotholes +knots +knotted +knotter +knotters +knottier +knottiest +knottiness +knotting +knotty +knotweed +knotweeds +knout +knouted +knouting +knouts +know +knowable +knower +knowers +knowing +knowingly +knowingness +knowledge +knowledgeability +knowledgeable +knowledgeableness +knowledgeably +known +knows +knox +knoxville +knubby +knuckle +knuckleball +knuckleballer +knuckleballers +knuckleballs +knucklebone +knucklebones +knuckled +knucklehead +knuckleheaded +knuckleheads +knuckler +knucklers +knuckles +knuckling +knur +knurl +knurled +knurling +knurls +knurly +knurs +ko +koa +koala +koalas +koan +koans +koas +kob +kobo +kobold +kobolds +kobs +koch +kodak +kodiak +kohl +kohlrabi +kohlrabies +koi +koine +koines +kokanee +kokanees +kola +kolache +kolacky +kolas +kolinskies +kolinsky +kolkhoz +kolkhozes +kolkhoznik +kolkhozniki +kolkhozniks +kolkhozy +kolo +kolos +kolyma +komandorski +komati +komatik +komatiks +kombu +kombus +komodo +komondor +komondorok +komondors +komsomol +kong +kongo +kongos +konkani +koodoo +koodoos +kook +kookaburra +kookaburras +kookie +kookier +kookiest +kookiness +kooks +kooky +kootchy +kootenay +kopeck +kopecks +kopek +kopeks +koph +kopje +kopjes +koppie +koppies +kor +korai +koran +koranic +korat +korats +kordofanian +kordofanians +kore +korea +korean +koreans +kors +korsakoff +korsakov +korun +koruna +korunas +koruny +kos +kosciusko +kosher +koshered +koshering +koshers +kosovo +koto +kotos +koumiss +koumisses +kouprey +kouroi +kouros +kowloon +kowtow +kowtowed +kowtowing +kowtows +kra +kraal +kraals +kraft +krait +kraits +krakatau +krakatoa +kraken +krakens +kraków +krater +kraters +kraut +krauts +krebs +kremlin +kremlinological +kremlinologist +kremlinologists +kremlinology +kreplach +kreutzer +kreutzers +kreuzer +kreuzers +krewe +krewes +kriemhild +kriemhilde +krill +krimmer +krimmers +kringle +krio +kris +krises +krishna +krishnaism +krishnas +kriss +kroenecker +krona +krone +kronecker +kronen +kroner +kronor +kronos +kronur +krugerrand +krugerrands +krumhorn +krumhorns +krummholz +krummhorn +krummhorns +krummkake +krummkakes +krypton +kshatriya +kshatriyas +ku +kuala +kublai +kuchean +kuchen +kuchens +kudo +kudos +kudu +kudus +kudzu +kufic +kugel +kugels +kulak +kulaks +kultur +kulturkampf +kulturkampfs +kulturs +kumiss +kumisses +kumquat +kumquats +kundalini +kung +kunlun +kunming +kunzite +kunzites +kuoyu +kuoyus +kurchatovium +kurd +kurdish +kurdistan +kurds +kurgan +kurgans +kuril +kurile +kurilian +kurilians +kurland +kuroshio +kurrajong +kurrajongs +kurtoses +kurtosis +kuru +kurus +kush +kuskokwim +kutch +kutenai +kutenais +kuwait +kuwaiti +kuwaitis +kvass +kvasses +kvetch +kvetched +kvetches +kvetching +kvetchy +kwa +kwacha +kwachas +kwajalein +kwakiutl +kwakiutls +kwangtung +kwantung +kwanza +kwanzaa +kwanzas +kwas +kwashiorkor +kweichow +kyack +kyacks +kyanite +kyanites +kyanize +kyanized +kyanizes +kyanizing +kyat +kyats +kybosh +kylikes +kylix +kymogram +kymograms +kymograph +kymographic +kymographs +kymography +kymric +kyoga +kyoto +kyphosis +kyphotic +kyrgyz +kyrgyzstan +kyrie +kyries +kyte +kythe +kyushu +kárpathos +kérkira +kíthira +kórinthos +köln +königsberg +küche +kümmel +kümmelweck +l +l'oeil +l'oeils +l'évêque +la +laager +laagered +laagering +laagers +laari +lab +laban +labanotation +labanotations +labara +labarum +labdanum +labdanums +label +labelable +labeled +labeler +labelers +labeling +labella +labellate +labelled +labeller +labellers +labelling +labellum +labels +labia +labial +labialization +labializations +labialize +labialized +labializes +labializing +labially +labials +labiate +labiates +labile +lability +labiodental +labiodentals +labionasal +labionasals +labiovelar +labiovelars +labium +lablab +lablabs +labor +laboratories +laboratory +labored +laborer +laborers +laboring +laborious +laboriously +laboriousness +laborite +laborites +labors +laborsaving +labour +labourite +labourites +labours +labra +labrador +labradorean +labradoreans +labradorian +labradorians +labradorite +labradorites +labradors +labret +labrets +labrum +labs +labuan +laburnum +laburnums +labyrinth +labyrinthian +labyrinthine +labyrinthodont +labyrinthodonts +labyrinths +lac +laccadive +laccolith +laccolithic +laccoliths +lace +laced +lacedaemon +lacedaemonian +laceless +lacelike +lacer +lacerate +lacerated +lacerates +lacerating +laceration +lacerations +lacerative +lacers +lacerta +lacertilian +laces +lacewing +lacewings +lacework +lacey +laches +lachesis +lachrymal +lachrymation +lachrymations +lachrymator +lachrymators +lachrymatory +lachrymose +lachrymosely +lachrymosity +lacier +laciest +laciness +lacing +lacings +lacinia +lacinias +laciniate +laciniation +laciniations +lack +lackadaisical +lackadaisically +lackadaisicalness +lackaday +lacked +lackey +lackeyed +lackeying +lackeys +lacking +lackluster +lacks +laconia +laconic +laconically +laconism +laconisms +lacquer +lacquered +lacquerer +lacquerers +lacquering +lacquers +lacquerware +lacquerwork +lacrimal +lacrimation +lacrimations +lacrimator +lacrimators +lacrosse +lacs +lactalbumin +lactalbumins +lactamase +lactase +lactate +lactated +lactates +lactating +lactation +lactational +lactations +lacteal +lacteally +lactescence +lactescent +lactic +lactiferous +lactiferousness +lactobacilli +lactobacillus +lactoflavin +lactoflavins +lactogenic +lactoglobulin +lactoglobulins +lactometer +lactometers +lactone +lactones +lactonic +lactoprotein +lactoproteins +lactose +lacuna +lacunae +lacunal +lacunar +lacunaria +lacunars +lacunas +lacunate +lacustrine +lacy +lad +ladanum +ladanums +ladder +laddered +laddering +ladderlike +ladders +laddie +laddies +lade +laded +laden +ladened +ladening +ladens +lades +ladies +ladin +lading +ladino +ladinos +ladins +ladle +ladled +ladler +ladlers +ladles +ladling +ladoga +lads +lady +ladybird +ladybirds +ladybug +ladybugs +ladyfinger +ladyfingers +ladyfish +ladyfishes +ladykin +ladykins +ladylike +ladylikeness +ladylove +ladyloves +ladysfinger +ladysfingers +ladyship +ladyships +ladysmith +laertes +laetare +laetrile +lafayette +lag +lagan +lagans +lagend +lagends +lager +lagers +laggard +laggardly +laggardness +laggards +lagged +lagger +laggers +lagging +laggings +lagniappe +lagniappes +lagomorph +lagomorphic +lagomorphous +lagomorphs +lagoon +lagoonal +lagoons +lagos +lagrangian +lagrangians +lags +lahar +lahars +lahnda +lahontan +lahore +laic +laical +laically +laicals +laicism +laicization +laicizations +laicize +laicized +laicizes +laicizing +laics +laid +laide +lain +lair +laird +lairdly +lairds +lairs +laisser +laissez +lait +laitance +laity +laius +lake +lakebed +lakebeds +laked +lakefront +lakefronts +lakeland +lakelike +laker +lakers +lakes +lakeshore +lakeshores +lakeside +lakesides +lakh +laking +lakota +lakotas +lakshadweep +lakshmi +laky +lalapalooza +lalapaloozas +lallan +lalland +lallands +lallans +lallapalooza +lallapaloozas +lallation +lallations +lally +lallygag +lallygagged +lallygagging +lallygags +lam +lama +lamaism +lamaist +lamaistic +lamaists +lamarck +lamarckian +lamarckianism +lamarckians +lamarckism +lamas +lamaseries +lamasery +lamaze +lamb +lambast +lambaste +lambasted +lambastes +lambasting +lambasts +lambda +lambdoid +lambed +lambency +lambent +lambently +lamber +lambers +lambert +lamberts +lambing +lambkill +lambkills +lamblike +lambrequin +lambrequins +lambrusco +lambs +lambskin +lamby +lame +lamebrain +lamebrained +lamebrains +lamed +lamedh +lamella +lamellae +lamellar +lamellarly +lamellas +lamellate +lamellated +lamellately +lamellation +lamellations +lamellibranch +lamellibranchs +lamellicorn +lamellicorns +lamelliform +lamely +lameness +lament +lamentable +lamentableness +lamentably +lamentation +lamentations +lamented +lamentedly +lamenter +lamenters +lamenting +laments +lamer +lames +lamest +lamia +lamiae +lamian +lamians +lamias +lamina +laminae +laminal +laminar +laminaria +laminarian +laminarians +laminarin +laminarins +laminas +laminate +laminated +laminates +laminating +lamination +laminations +laminator +laminators +laminectomies +laminectomy +laming +laminitis +lamister +lamisters +lammas +lammases +lammastide +lammed +lammergeier +lammergeiers +lammergeyer +lammergeyers +lammermoor +lamming +lamp +lampblack +lampbrush +lamper +lampion +lampions +lamplight +lamplighter +lamplighters +lampoon +lampooned +lampooner +lampooners +lampoonery +lampooning +lampoonist +lampoonists +lampoons +lamppost +lampposts +lamprey +lampreys +lamprophyre +lamprophyres +lamps +lampshade +lampshades +lampshell +lampshells +lampworking +lampworkings +lams +lamster +lamsters +lamé +lamés +lanai +lanais +lanate +lancashire +lancaster +lancasters +lancastrian +lancastrians +lance +lanced +lancelet +lancelets +lancelot +lanceolate +lanceolately +lancer +lancers +lances +lancet +lanceted +lancets +lancewood +lancewoods +lancinating +lancing +land +landau +landaulet +landaulets +landaus +landed +lander +landers +landes +landfall +landfalls +landfill +landfilled +landfilling +landfills +landform +landforms +landgrab +landgrabs +landgrave +landgraves +landgraviate +landgraviates +landgravine +landgravines +landholder +landholders +landholding +landholdings +landing +landings +landladies +landlady +landless +landlessness +landline +landlines +landlocked +landlord +landlordism +landlords +landlubber +landlubberliness +landlubberly +landlubbers +landlubbing +landmark +landmarks +landmass +landmasses +landmine +landmines +landowner +landowners +landownership +landowning +landrace +landraces +lands +landscape +landscaped +landscaper +landscapers +landscapes +landscaping +landscapist +landscapists +landseer +landside +landsides +landsleit +landslide +landslides +landslip +landslips +landsmaal +landsmal +landsman +landsmen +landsmål +landtag +landtags +landward +landwards +lane +lanes +laneway +laneways +lanfranc +lang +langbeinite +langbeinites +langerhans +langlauf +langlaufer +langlaufers +langlaufs +langley +langleys +langobard +langobardic +langobards +langostino +langostinos +langouste +langoustes +langoustine +langoustines +langrage +langrages +langsyne +language +languages +langue +languedoc +langues +languet +languets +languid +languidly +languidness +languish +languished +languisher +languishers +languishes +languishing +languishingly +languishment +languishments +languor +languorous +languorously +languorousness +langur +langurs +laniard +laniards +laniferous +lank +lanka +lankan +lankans +lanker +lankest +lankier +lankiest +lankily +lankiness +lankly +lankness +lanky +lanner +lanneret +lannerets +lanners +lanolin +lanose +lanosity +lansing +lantana +lantanas +lantern +lanterns +lanthanide +lanthanum +lanthorn +lanthorns +lanuginose +lanuginous +lanuginousness +lanugo +lanugos +lanyard +lanyards +lanzarote +lao +laocoon +laodicea +laodicean +laodiceans +laomedon +laos +laotian +laotians +lap +laparoscope +laparoscopes +laparoscopic +laparoscopies +laparoscopist +laparoscopists +laparoscopy +laparotomies +laparotomy +lapboard +lapboards +lapdog +lapdogs +lapel +lapeled +lapelled +lapels +lapful +lapfuls +lapidarian +lapidaries +lapidary +lapilli +lapillus +lapin +lapis +lapith +lapiths +laplace +lapland +laplander +laplanders +lapp +lapped +lapper +lappers +lappet +lappets +lapping +lappish +lapps +laps +lapsang +lapse +lapsed +lapser +lapsers +lapses +lapsing +lapstrake +lapstreak +laptev +laptop +laptops +laputa +laputan +laputans +lapwing +lapwings +lar +laramie +larboard +larboards +larcener +larceners +larcenies +larcenist +larcenists +larcenous +larcenously +larceny +larch +larches +lard +larded +larder +larders +larding +lardon +lardons +lardoon +lardoons +lards +lardy +laree +larees +lares +large +largehearted +largeheartedness +largely +largemouth +largeness +larger +largess +largesse +largesses +largest +larghetto +larghettos +largish +largo +largos +lariat +lariats +lark +larked +larker +larkers +larkier +larkiest +larkiness +larking +larkish +larks +larkspur +larkspurs +larky +larmoyante +larnaca +larrigan +larrigans +larrikin +larrikins +larrup +larruped +larruping +larrups +larum +larums +larva +larvae +larval +larvas +larvicidal +larvicide +larvicides +laryngal +laryngals +laryngeal +laryngeals +laryngectomies +laryngectomized +laryngectomy +larynges +laryngitic +laryngitis +laryngologist +laryngologists +laryngology +laryngopharynx +laryngopharynxs +laryngoscope +laryngoscopes +laryngoscopic +laryngoscopical +laryngoscopically +laryngoscopy +larynx +larynxes +lasagna +lasagnas +lasagne +lascar +lascars +lascivious +lasciviously +lasciviousness +lase +lased +laser +laserlike +lasers +lases +lash +lashed +lasher +lashers +lashes +lashing +lashings +lashins +lasing +lass +lassa +lassen +lasses +lassie +lassies +lassitude +lasso +lassoed +lassoer +lassoers +lassoes +lassoing +lassos +last +lasted +laster +lasters +lastex +lasting +lastingly +lastingness +lastly +lasts +latakia +latch +latched +latches +latchet +latchets +latching +latchkey +latchkeys +latchstring +latchstrings +late +latecomer +latecomers +lated +lateen +lateener +lateeners +lateens +latelies +lately +laten +latencies +latency +latened +lateness +latening +latens +latensification +latensifications +latent +latently +later +laterad +lateral +lateraled +lateraling +laterality +lateralization +lateralizations +lateralize +lateralized +lateralizes +lateralizing +lateralled +lateralling +laterally +laterals +laterite +laterites +lateritic +laterization +laterizations +latest +latests +latewood +latewoods +latex +latexes +lath +lathe +lathed +lather +lathered +latherer +latherers +lathering +lathers +lathery +lathes +lathing +lathings +laths +lathyrism +lathyrisms +lathyritic +latices +laticifer +laticiferous +laticifers +latifundia +latifundio +latifundios +latifundium +latigo +latigoes +latigos +latimer +latin +latina +latinate +latinism +latinisms +latinist +latinists +latinity +latinization +latinizations +latinize +latinized +latinizer +latinizers +latinizes +latinizing +latino +latinos +latins +latish +latissimi +latissimus +latitude +latitudes +latitudinal +latitudinally +latitudinarian +latitudinarianism +latitudinarians +latium +latke +latkes +latosol +latosolic +latosols +latrine +latrines +latten +lattens +latter +latterly +lattermost +lattice +latticed +lattices +latticework +latticing +latus +latvia +latvian +latvians +lauan +lauans +laud +laudability +laudable +laudableness +laudably +laudanum +laudation +laudations +laudative +laudatory +laude +lauded +lauder +lauderdale +lauders +lauding +lauds +laugh +laughable +laughableness +laughably +laughed +laugher +laughers +laughing +laughingly +laughingstock +laughingstocks +laughs +laughter +launce +launces +launch +launched +launcher +launchers +launches +launching +launchings +launchpad +launchpads +launder +laundered +launderer +launderers +launderette +launderettes +laundering +launderings +launders +laundress +laundresses +laundrette +laundrettes +laundries +laundromat +laundromats +laundry +laundryman +laundrymen +launfal +laura +lauras +laurasia +laureate +laureates +laureateship +laureateships +laureation +laureations +laurel +laureled +laureling +laurelled +laurelling +laurels +laurent +laurentian +lauric +lauryl +lausanne +lautrec +lava +lavabo +lavaboes +lavage +lavages +lavalava +lavalavas +lavalier +lavaliere +lavalieres +lavalike +lavallière +lavallières +lavas +lavation +lavations +lavatories +lavatory +lave +laved +lavender +lavendered +lavendering +lavenders +laver +laverock +laverocks +lavers +laves +laving +lavinia +lavish +lavished +lavisher +lavishers +lavishes +lavishing +lavishly +lavishness +lavoisier +lavrock +lavrocks +law +lawbreaker +lawbreakers +lawbreaking +lawed +lawful +lawfully +lawfulness +lawgiver +lawgivers +lawing +lawless +lawlessly +lawlessness +lawmaker +lawmakers +lawmaking +lawman +lawmen +lawn +lawnmower +lawnmowers +lawns +lawny +lawrence +lawrencian +lawrencium +lawrentian +laws +lawsuit +lawsuits +lawyer +lawyering +lawyerings +lawyerlike +lawyerly +lawyers +lax +laxation +laxations +laxative +laxatives +laxer +laxest +laxities +laxity +laxly +laxness +lay +layabout +layabouts +layaway +layaways +layback +laybacks +layer +layerage +layerages +layered +layering +layerings +layers +layette +layettes +laying +layman +laymen +layoff +layoffs +layout +layouts +layover +layovers +laypeople +layperson +laypersons +lays +layup +layups +laywoman +laywomen +lazar +lazaret +lazarets +lazarette +lazarettes +lazaretto +lazarettos +lazarist +lazarists +lazars +lazarus +laze +lazed +lazes +lazied +lazier +lazies +laziest +lazily +laziness +lazing +lazuli +lazulite +lazulites +lazurite +lazurites +lazy +lazybones +lazying +lazyish +lb +lea +leach +leachability +leachable +leachate +leachates +leached +leacher +leachers +leaches +leaching +lead +leaded +leaden +leadenly +leadenness +leader +leaderless +leaders +leadership +leaderships +leadier +leadiest +leading +leadingly +leadless +leadman +leadmen +leadoff +leadoffs +leadplant +leadplants +leads +leadscrew +leadscrews +leadsman +leadsmen +leadwork +leadwort +leadworts +leady +leaf +leafage +leafed +leafhopper +leafhoppers +leafier +leafiest +leafiness +leafing +leafless +leaflet +leafleted +leafleteer +leafleteers +leafleting +leaflets +leafletted +leafletting +leaflike +leafs +leafstalk +leafstalks +leafy +league +leagued +leaguer +leaguered +leaguering +leaguers +leagues +leaguing +leah +leak +leakage +leakages +leaked +leaker +leakers +leakier +leakiest +leakily +leakiness +leaking +leakproof +leaks +leaky +leal +leally +lean +leander +leaned +leaner +leanest +leaning +leanings +leanly +leanness +leans +leant +leap +leaped +leaper +leapers +leapfrog +leapfrogged +leapfrogging +leapfrogs +leaping +leaps +leapt +lear +learn +learnable +learned +learnedly +learnedness +learner +learners +learning +learns +learnt +leary +leas +leasable +lease +leaseback +leased +leasehold +leaseholder +leaseholders +leaseholds +leaser +leasers +leases +leash +leashed +leashes +leashing +leasing +leasings +least +leastways +leastwise +leather +leatherback +leatherbacks +leathered +leatherette +leatherettes +leatherhead +leatherheads +leatheriness +leathering +leatherjacket +leatherjackets +leatherleaf +leatherlike +leathern +leatherneck +leathernecks +leathers +leatherwear +leatherwood +leatherwoods +leatherwork +leatherworker +leatherworkers +leatherworking +leatherworks +leathery +leave +leaved +leaven +leavened +leavening +leavenings +leavens +leaver +leavers +leaves +leaving +leavings +leavis +leavisite +lebanese +lebanon +lebensraum +lebenswelt +lebkuchen +lecce +lech +leched +lecher +lecheries +lecherous +lecherously +lecherousness +lechers +lechery +leches +leching +lechwe +lechwes +lecithin +lecithinase +lecithinases +lectern +lecterns +lectin +lectins +lection +lectionaries +lectionary +lections +lector +lectors +lectotype +lectotypes +lecture +lectured +lecturer +lecturers +lectures +lectureship +lectureships +lecturing +led +leda +lederhosen +ledge +ledger +ledgers +ledges +ledgy +lee +leeboard +leeboards +leech +leeched +leeches +leeching +leechlike +leek +leeks +leer +leered +leerier +leeriest +leerily +leeriness +leering +leeringly +leers +leery +lees +leeuwenhoek +leeward +leeway +left +lefties +leftish +leftism +leftist +leftists +leftmost +leftover +leftovers +lefts +leftward +leftwards +leftwing +lefty +leg +legacies +legacy +legal +legalese +legaleses +legalism +legalisms +legalist +legalistic +legalistically +legalists +legalities +legality +legalization +legalizations +legalize +legalized +legalizer +legalizers +legalizes +legalizing +legally +legals +legate +legated +legatee +legatees +legates +legateship +legateships +legatine +legating +legation +legationary +legations +legato +legator +legators +legatos +legend +legendarily +legendary +legendries +legendry +legends +leger +legerdemain +legerdemains +legerity +legers +leges +legged +legger +leggers +leggier +leggiest +leggin +legginess +legging +leggings +leggins +leggy +leghold +leghorn +leghorns +legibility +legible +legibleness +legibly +legion +legionaries +legionary +legionella +legionellae +legionnaire +legionnaires +legions +legislate +legislated +legislates +legislating +legislation +legislative +legislatively +legislatives +legislator +legislatorial +legislators +legislatorship +legislatorships +legislature +legislatures +legist +legists +legit +legitimacy +legitimate +legitimated +legitimately +legitimateness +legitimates +legitimating +legitimation +legitimations +legitimatize +legitimatized +legitimatizes +legitimatizing +legitimator +legitimators +legitimism +legitimist +legitimists +legitimization +legitimizations +legitimize +legitimized +legitimizer +legitimizers +legitimizes +legitimizing +legless +legman +legmen +legomena +legomenon +legroom +legs +legume +legumes +leguminous +legwork +lehar +lehigh +lehua +lehuas +lei +leibnitz +leicester +leicesters +leicestershire +leiden +leipzig +leis +leishmania +leishmanial +leishmanias +leishmaniasis +leister +leistered +leistering +leisters +leisure +leisured +leisureliness +leisurely +leisurewear +leitmotif +leitmotifs +leitmotiv +leitmotivs +lek +leke +leks +leku +lekvar +lekvars +lely +leman +lemans +lemma +lemmas +lemmata +lemming +lemminglike +lemmings +lemniscal +lemniscate +lemnisci +lemniscus +lemnos +lemon +lemonade +lemonades +lemongrass +lemongrasses +lemons +lemony +lempira +lempiras +lemur +lemures +lemurlike +lemurs +lenape +lenapes +lend +lendable +lender +lenders +lending +lends +length +lengthen +lengthened +lengthener +lengtheners +lengthening +lengthens +lengthier +lengthiest +lengthily +lengthiness +lengths +lengthways +lengthwise +lengthy +lenience +leniencies +leniency +lenient +leniently +lenin +leningrad +leninism +leninist +leninists +leninite +leninites +lenis +lenition +lenitions +lenitive +lenitively +lenitives +lenity +lennon +lennox +leno +lenos +lens +lense +lensed +lenses +lensing +lensless +lensman +lensmen +lent +lentamente +lentando +lenten +lentic +lenticel +lenticellate +lenticels +lenticular +lenticule +lenticules +lentigines +lentiginose +lentiginous +lentigo +lentil +lentils +lentisk +lentisks +lentissimo +lentivirus +lentiviruses +lento +lentos +lents +leo +leonardo +leone +leones +leonian +leonians +leonid +leonides +leonids +leonine +leopard +leopardess +leopardesses +leopardi +leopards +leopold +leos +leotard +leotarded +leotards +lepanto +lepcha +lepchas +leper +lepers +lepidolite +lepidolites +lepidoptera +lepidopteran +lepidopterans +lepidopterist +lepidopterists +lepidopterological +lepidopterologist +lepidopterologists +lepidopterology +lepidopterous +lepidote +lepontic +lepontine +leporine +leprechaun +leprechaunish +leprechauns +lepromatous +leprosaria +leprosarium +leprosariums +leprose +leprosy +leprotic +leprous +leprously +leprousness +lepta +leptocephali +leptocephalus +lepton +leptonic +leptons +leptosomatic +leptosome +leptosomes +leptospiral +leptospire +leptospires +leptospirosis +leptotene +leptotenes +lepus +lerici +lesbian +lesbianism +lesbians +lesbos +lese +lesion +lesioned +lesions +lesotho +lespedeza +lespedezas +less +lessee +lessees +lessen +lessened +lessening +lessens +lesser +lesson +lessoned +lessoning +lessons +lessor +lessors +lest +let +let's +letch +letches +letdown +letdowns +lethal +lethality +lethally +lethalness +lethargic +lethargically +lethargies +lethargy +lethe +lethean +leto +lets +lett +letted +letter +letterbox +letterboxed +letterboxes +letterboxing +lettered +letterer +letterers +letterform +letterforms +lettergram +lettergrams +letterhead +letterheads +lettering +letterings +letterman +lettermen +letterpress +letterpresses +letters +letterspacing +lettic +letting +lettings +lettish +letts +lettuce +lettuces +letup +letups +leu +leucine +leucines +leucite +leucites +leucitic +leucocidin +leucocidins +leucocyte +leucocytes +leucocytic +leucocytoid +leucocytoses +leucocytosis +leucocytotic +leucoderma +leucodermal +leucodermas +leucodermic +leucopenia +leucopenias +leucopenic +leucoplast +leucoplastid +leucoplastids +leucoplasts +leucorrhea +leucorrheal +leucorrheas +leucotomies +leucotomy +leukemia +leukemic +leukemics +leukemogenesis +leukemogenic +leukemoid +leukocyte +leukocytes +leukocytic +leukocytoid +leukocytoses +leukocytosis +leukocytotic +leukoderma +leukodermal +leukodermas +leukodermic +leukodystrophy +leukopenia +leukopenias +leukopenic +leukoplakia +leukoplakias +leukoplakic +leukoplasia +leukoplasias +leukopoiesis +leukopoietic +leukorrhea +leukorrheal +leukorrheas +leukoses +leukosis +leukotomies +leukotomy +leukotriene +leukotrienes +lev +leva +levalloisian +levant +levanted +levanter +levanters +levantine +levantines +levanting +levants +levas +levator +levatores +levators +levee +leveed +leveeing +levees +level +leveled +leveler +levelers +levelheaded +levelheadedly +levelheadedness +leveling +levelled +leveller +levellers +levelling +levelly +levelness +levels +lever +leverage +leveraged +leverages +leveraging +levered +leveret +leverets +leverhulme +levering +leverkusen +levers +levi +levi's +leviable +leviathan +leviathans +levied +levier +leviers +levies +levigate +levigated +levigates +levigating +levigation +levigations +levin +levins +levirate +levirates +leviratic +leviratical +levis +levitate +levitated +levitates +levitating +levitation +levitational +levitations +levitator +levitators +levite +levites +levitic +levitical +leviticus +levities +levity +levo +levodopa +levodopas +levorotary +levorotation +levorotations +levorotatory +levs +levulose +levuloses +levy +levying +lewd +lewder +lewdest +lewdly +lewdness +lewis +lewises +lewisite +lewisites +lewisson +lewissons +lex +lexeme +lexemes +lexemic +lexes +lexica +lexical +lexicality +lexicalization +lexicalizations +lexicalize +lexicalized +lexicalizes +lexicalizing +lexically +lexicographer +lexicographers +lexicographic +lexicographical +lexicographically +lexicography +lexicological +lexicologically +lexicologist +lexicologists +lexicology +lexicon +lexicons +lexington +lexis +lexises +ley +leyden +león +lhasa +lhotse +li +liabilities +liability +liable +liaise +liaised +liaises +liaising +liaison +liaisons +liana +lianas +liane +lianes +liang +liao +liaodong +liaoning +liaotung +liar +liars +liassic +lib +libation +libationary +libations +libbed +libber +libbers +libbing +libecchio +libeccio +libel +libelant +libelants +libeled +libelee +libelees +libeler +libelers +libeling +libelist +libelists +libellant +libellants +libelled +libellee +libellees +libelling +libellous +libelous +libelously +libels +libera +liberace +liberal +liberalism +liberalist +liberalistic +liberalists +liberalities +liberality +liberalization +liberalizations +liberalize +liberalized +liberalizer +liberalizers +liberalizes +liberalizing +liberally +liberalness +liberals +liberate +liberated +liberates +liberating +liberatingly +liberation +liberationist +liberationists +liberations +liberator +liberators +liberia +liberian +liberians +libertarian +libertarianism +libertarians +liberties +libertinage +libertinages +libertine +libertines +libertinism +liberty +libidinal +libidinally +libidinous +libidinously +libidinousness +libido +libidos +libitum +libra +librae +libran +librans +librarian +librarians +librarianship +librarianships +libraries +library +libration +librational +librations +libratory +libre +libres +libretti +librettist +librettists +libretto +librettos +libriform +libris +librist +librists +librium +libs +libya +libyan +libyans +lice +licence +licenced +licences +licencing +licensable +license +licensed +licensee +licensees +licenser +licensers +licenses +licensing +licensor +licensors +licensure +licensures +licente +licentiate +licentiates +licentious +licentiously +licentiousness +lich +lichee +lichees +lichen +lichened +lichening +lichenological +lichenologist +lichenologists +lichenology +lichenous +lichens +licit +licitly +licitness +lick +licked +licker +lickerish +lickerishly +lickerishness +lickers +lickety +licking +lickings +licks +lickspittle +lickspittles +licorice +lictor +lictors +lid +lidar +lidded +lidding +lidless +lido +lidocaine +lidos +lids +lie +liebfraumilch +liebig +liechtenstein +liechtensteiner +liechtensteiners +lied +lieder +liederkranz +lief +liefer +liefest +liege +liegeman +liegemen +lieges +lien +liens +lier +lierne +liernes +liers +lies +lieu +lieutenancies +lieutenancy +lieutenant +lieutenants +life +lifeblood +lifeboat +lifeboats +lifeful +lifeguard +lifeguarded +lifeguarding +lifeguards +lifejacket +lifejackets +lifeless +lifelessly +lifelessness +lifelike +lifelikeness +lifeline +lifelines +lifelong +lifer +lifers +lifes +lifesaver +lifesavers +lifesaving +lifestyle +lifestyles +lifetime +lifetimes +lifeway +lifework +lifo +lift +liftable +lifted +lifter +lifters +liftgate +liftgates +lifting +liftman +liftmen +liftoff +liftoffs +lifts +ligament +ligamental +ligamentary +ligamentous +ligaments +ligan +ligand +ligands +ligans +ligase +ligases +ligate +ligated +ligates +ligating +ligation +ligations +ligature +ligatured +ligatures +ligaturing +liger +ligers +light +lightbulb +lightbulbs +lighted +lighten +lightened +lightener +lighteners +lightening +lightens +lighter +lighterage +lighterages +lighters +lightest +lightface +lightfaced +lightfast +lightfastness +lightheaded +lightheadedly +lightheadedness +lighthearted +lightheartedly +lightheartedness +lighthouse +lighthouses +lighting +lightings +lightish +lightless +lightlessness +lightly +lightness +lightning +lightninged +lightninglike +lightnings +lightplane +lightplanes +lightproof +lights +lightship +lightships +lightsome +lightsomely +lightsomeness +lighttight +lightweight +lightweights +lightwood +lightwoods +ligneous +lignification +lignifications +lignified +lignifies +lignify +lignifying +lignin +lignite +lignitic +lignocellulose +lignocelluloses +lignocellulosic +lignosulfonate +lignosulfonates +lignum +ligroin +ligula +ligulae +ligulas +ligulate +ligule +ligules +ligure +ligures +liguria +ligurian +ligurians +likability +likable +likableness +like +likeable +likeableness +liked +likelier +likeliest +likelihood +likeliness +likely +liken +likened +likeness +likenesses +likening +likens +likes +likewise +liking +likings +likker +likuta +lilac +lilacs +lilangeni +lilied +lilies +lilith +lille +lilliput +lilliputian +lilliputians +lilt +lilted +lilting +liltingly +liltingness +lilts +lily +lima +limacine +limacon +limacons +limas +limassol +limb +limba +limbas +limbate +limbeck +limbecks +limbed +limber +limbered +limbering +limberly +limberness +limbers +limbi +limbic +limbing +limbless +limbo +limbos +limbs +limburg +limburger +limburgers +limbus +limby +lime +limeade +limeades +limed +limekiln +limekilns +limelight +limen +limens +limerick +limericks +limes +limestone +limewater +limewaters +limey +limeys +limicoline +limicolous +limier +limiest +limina +liminal +liming +limit +limitability +limitable +limitary +limitation +limitational +limitations +limitative +limited +limitedly +limitedness +limiteds +limiter +limiters +limites +limiting +limitingly +limitless +limitlessly +limitlessness +limitrophe +limits +limmer +limmers +limn +limned +limner +limners +limnetic +limning +limnologic +limnological +limnologically +limnologist +limnologists +limnology +limns +limo +limoges +limonene +limonenes +limonite +limonitic +limos +limousin +limousine +limousines +limp +limpa +limped +limper +limpest +limpet +limpets +limpid +limpidity +limpidly +limpidness +limping +limpkin +limpkins +limply +limpness +limpopo +limps +limuli +limulus +limy +linac +linacs +linage +linages +linalool +linalools +linchpin +linchpins +lincoln +lincolnesque +lincolniana +lincolnshire +lincomycin +lincomycins +lindane +lindanes +lindbergh +lindemann +linden +lindens +lindesnes +lindies +lindisfarne +lindy +line +lineage +lineages +lineal +lineality +lineally +lineament +lineamental +lineaments +linear +linearity +linearization +linearizations +linearize +linearized +linearizes +linearizing +linearly +lineation +lineations +linebacker +linebackers +linebacking +linebred +linebreeding +linecaster +linecasters +linecasting +linecut +linecuts +lined +linefeed +linefeeds +lineman +linemen +linen +linens +lineolate +liner +linerboard +linerboards +linerless +liners +lines +linesman +linesmen +lineswoman +lineswomen +lineup +lineups +liney +ling +linga +lingala +lingalas +lingam +lingams +lingas +lingayat +lingayats +lingayen +lingberries +lingberry +lingcod +lingcods +linger +lingered +lingerer +lingerers +lingerie +lingering +lingeringly +lingers +lingo +lingoes +lingonberries +lingonberry +lings +lingua +linguae +lingual +lingually +linguals +linguine +linguini +linguist +linguistic +linguistical +linguistically +linguistician +linguisticians +linguistics +linguists +lingulate +liniment +liniments +linin +lining +linings +linins +link +linkage +linkages +linkboy +linkboys +linked +linker +linkers +linking +linkings +linkman +linkmen +links +linksman +linksmen +linkup +linkups +linn +linnaean +linnaeus +linnean +linnet +linnets +linnhe +linns +linocut +linocuts +linoleate +linoleates +linoleic +linolenic +linoleum +linotype +linotypes +linsang +linsangs +linseed +linseeds +linsey +linstock +linstocks +lint +lintel +lintels +linter +linters +lintless +lintwhite +lintwhites +linty +linuron +linurons +lion +lioness +lionesses +lionfish +lionfishes +lionheart +lionhearted +lionization +lionizations +lionize +lionized +lionizer +lionizers +lionizes +lionizing +lionlike +lions +lip +lipan +lipans +lipari +lipase +lipases +lipectomies +lipectomy +lipid +lipide +lipides +lipidic +lipids +lipizzan +lipizzaner +lipizzaners +lipizzans +lipless +liplike +lipogenesis +lipoic +lipoid +lipoidal +lipoids +lipolyses +lipolysis +lipolytic +lipoma +lipomas +lipomata +lipomatous +lipophilic +lipopolysaccharide +lipopolysaccharides +lipoprotein +lipoproteins +liposomal +liposome +liposomes +liposuction +liposuctions +lipotropic +lipotropin +lipotropins +lipotropism +lipotropy +lipped +lippes +lippi +lippier +lippiest +lipping +lippizan +lippizaner +lippizaners +lippizans +lippy +lipreading +lips +lipstick +lipsticked +lipsticks +liptauer +liptauers +lipton +liquate +liquated +liquates +liquating +liquation +liquations +liquefacient +liquefaction +liquefactions +liquefactive +liquefiable +liquefied +liquefier +liquefiers +liquefies +liquefy +liquefying +liquescence +liquescency +liquescent +liqueur +liqueurs +liquid +liquidambar +liquidambars +liquidate +liquidated +liquidates +liquidating +liquidation +liquidations +liquidator +liquidators +liquidity +liquidize +liquidized +liquidizes +liquidizing +liquidly +liquidness +liquids +liquified +liquifies +liquify +liquifying +liquor +liquored +liquorice +liquoring +liquors +lira +liras +lire +liri +liripipe +liripipes +lirot +liroth +lisbon +lisente +lisle +lisp +lisped +lisper +lispers +lisping +lisps +lissom +lissome +lissomely +lissomeness +list +listed +listee +listees +listel +listels +listen +listenability +listenable +listened +listener +listeners +listenership +listenerships +listening +listens +lister +listeria +listerias +listeriosis +listers +listing +listings +listless +listlessly +listlessness +lists +liszt +lit +litanies +litany +litchi +litchis +lite +liter +literacy +literal +literalism +literalist +literalistic +literalists +literality +literalization +literalizations +literalize +literalized +literalizes +literalizing +literally +literalness +literals +literarily +literariness +literary +literate +literately +literateness +literates +literati +literatim +literation +literations +literator +literators +literature +literatures +literatus +liters +litharge +litharges +lithe +lithely +litheness +lither +lithesome +lithest +lithia +lithias +lithiases +lithiasis +lithic +lithification +lithifications +lithified +lithifies +lithify +lithifying +lithium +litho +lithoed +lithoes +lithograph +lithographed +lithographer +lithographers +lithographic +lithographical +lithographically +lithographing +lithographs +lithography +lithoing +lithologic +lithological +lithologically +lithologist +lithologists +lithology +lithophane +lithophanes +lithophyte +lithophytes +lithophytic +lithopone +lithopones +lithos +lithosol +lithosols +lithosphere +lithospheres +lithospheric +lithostratigraphic +lithostratigraphy +lithotomies +lithotomy +lithotripsies +lithotripsy +lithotripter +lithotripters +lithotriptor +lithotriptors +lithotrities +lithotrity +lithuania +lithuanian +lithuanians +litigable +litigant +litigants +litigate +litigated +litigates +litigating +litigation +litigations +litigator +litigators +litigious +litigiously +litigiousness +litmus +litotes +litre +litres +litten +litter +litterateur +litterateurs +litterbag +litterbags +litterbug +litterbugs +littered +litterer +litterers +littering +littermate +littermates +litters +littery +little +littleneck +littlenecks +littleness +littler +littlest +littoral +littorals +littérateur +littérateurs +liturgic +liturgical +liturgically +liturgics +liturgies +liturgiologist +liturgiologists +liturgiology +liturgist +liturgists +liturgy +livability +livable +livableness +live +liveability +liveable +livebearer +livebearers +lived +livelier +liveliest +livelihood +livelihoods +livelily +liveliness +livelong +lively +liven +livened +liveness +livening +livens +liver +livered +liveried +liveries +liverish +liverishness +liverleaf +liverleaves +liverpudlian +liverpudlians +livers +liverwort +liverworts +liverwurst +livery +liveryman +liverymen +lives +livestock +livetrap +livetraps +livid +lividity +lividly +lividness +living +livingly +livingness +livings +livingstone +livonia +livonian +livonians +livorno +livre +livres +livy +lixiviate +lixiviated +lixiviates +lixiviating +lixiviation +lixiviations +lizard +lizardfish +lizardfishes +lizardlike +lizards +lizzie +liège +ljubljana +ll +llama +llamas +llano +llanos +lloyd +llullaillaco +lo +loach +loaches +load +loaded +loader +loaders +loading +loadings +loadmaster +loadmasters +loads +loadstar +loadstars +loadstone +loadstones +loaf +loafed +loafer +loafers +loafing +loafs +loam +loamed +loaming +loams +loamy +loan +loanable +loanda +loaned +loaner +loaners +loaning +loans +loansharking +loansharkings +loanword +loanwords +loath +loathe +loathed +loather +loathers +loathes +loathing +loathingly +loathings +loathly +loathness +loathsome +loathsomely +loathsomeness +loaves +lob +lobar +lobate +lobated +lobately +lobation +lobations +lobbed +lobber +lobbers +lobbied +lobbies +lobbing +lobby +lobbyer +lobbyers +lobbygow +lobbygows +lobbying +lobbyism +lobbyist +lobbyists +lobe +lobectomies +lobectomy +lobed +lobefin +lobefinned +lobefins +lobelia +lobelias +lobeline +lobelines +lobes +loblollies +loblolly +lobo +lobola +lobolas +lobos +lobotomies +lobotomize +lobotomized +lobotomizes +lobotomizing +lobotomy +lobs +lobscouse +lobscouses +lobster +lobstered +lobsterer +lobsterers +lobstering +lobsterlike +lobsterman +lobstermen +lobsters +lobular +lobularly +lobulate +lobulated +lobulation +lobulations +lobule +lobules +lobulose +lobworm +lobworms +loc +local +locale +locales +localism +localisms +localist +localists +localite +localites +localities +locality +localizability +localizable +localization +localizations +localize +localized +localizer +localizers +localizes +localizing +locally +localness +locals +locarno +locatable +locate +located +locater +locaters +locates +locating +location +locational +locationally +locations +locative +locatives +locator +locators +loch +lochia +lochial +lochs +loci +lock +lockable +lockage +lockages +lockbox +lockboxes +lockdown +lockdowns +locke +locked +locker +lockers +locket +lockets +locking +lockjaw +lockkeeper +lockkeepers +lockmaster +lockmasters +locknut +locknuts +lockout +lockouts +lockram +locks +lockset +locksets +locksmith +locksmithing +locksmiths +lockstep +lockstitch +lockstitched +lockstitches +lockstitching +lockup +lockups +loco +locoed +locoes +locofoco +locofocos +locoing +locoism +locoisms +locomote +locomoted +locomotes +locomoting +locomotion +locomotive +locomotives +locomotor +locomotory +locos +locoweed +locoweeds +locular +loculate +loculated +loculation +loculations +locule +loculed +locules +loculi +loculicidal +loculus +locum +locus +locust +locusts +locution +locutions +lode +loden +lodens +lodes +lodestar +lodestars +lodestone +lodestones +lodge +lodged +lodgement +lodgements +lodgepole +lodger +lodgers +lodges +lodging +lodgings +lodgment +lodgments +lodicule +lodicules +loeb +loess +loessial +loft +lofted +loftier +loftiest +loftily +loftiness +lofting +loftlike +lofts +lofty +log +loganberries +loganberry +logarithm +logarithmic +logarithmical +logarithmically +logarithms +logbook +logbooks +loge +loges +logged +logger +loggerhead +loggerheads +loggers +loggia +loggias +logging +loggings +logia +logic +logical +logicality +logically +logicalness +logician +logicians +logics +logier +logiest +login +logins +logion +logistic +logistical +logistically +logistician +logisticians +logistics +logjam +logjams +lognormal +lognormality +lognormally +logo +logogram +logogrammatic +logogrammatically +logograms +logograph +logographic +logographically +logographs +logography +logogriph +logogriphs +logoi +logomachies +logomachy +logorrhea +logorrheic +logos +logotype +logotypes +logout +logroll +logrolled +logroller +logrollers +logrolling +logrollings +logrolls +logs +logwood +logwoods +logy +lohengrin +loin +loincloth +loincloths +loins +loire +loiter +loitered +loiterer +loiterers +loitering +loiters +loki +lolita +lolitas +loll +lolland +lollapalooza +lollapaloozas +lollard +lollardism +lollards +lollardy +lolled +loller +lollers +lollies +lolling +lollingly +lollipop +lollipops +lollop +lolloped +lolloping +lollops +lollopy +lolls +lolly +lollygag +lollygagged +lollygagging +lollygags +lollypop +lollypops +lombard +lombardian +lombardic +lombards +lombardy +lombok +loment +loments +lomond +lomé +london +londonderry +londoner +londoners +lone +lonelier +loneliest +lonelily +loneliness +lonely +loneness +loner +loners +lonesome +lonesomely +lonesomeness +lonesomes +long +longan +longanimity +longans +longboat +longboats +longbow +longbowman +longbowmen +longbows +longcase +longed +longer +longeron +longerons +longest +longevities +longevity +longevous +longfellow +longhair +longhaired +longhairs +longhand +longhead +longheaded +longheadedness +longheads +longhorn +longhorns +longhouse +longhouses +longicorn +longicorns +longing +longingly +longings +longish +longitude +longitudes +longitudinal +longitudinally +longleaf +longlegs +longline +longlines +longman +longneck +longnecks +longness +longobard +longobardi +longobardic +longobards +longs +longship +longships +longshore +longshoreman +longshoremen +longshoring +longsighted +longsightedness +longsome +longsomely +longsomeness +longspur +longspurs +longstanding +longsuffering +longtime +longue +longues +longueur +longueurs +longwinded +longwindedly +longwise +longyi +longyis +lonsdale +loo +loobies +looby +loofa +loofah +loofahs +loofas +look +lookalike +lookalikes +lookdown +lookdowns +looked +looker +lookers +looking +lookout +lookouts +looks +lookup +lookups +loom +loomed +looming +looms +loon +looney +looneys +loonier +loonies +looniest +loonily +looniness +loons +loony +loop +looped +looper +loopers +loophole +loopholes +loopier +loopiest +looping +loops +loopy +loos +loose +loosed +loosely +loosen +loosened +looseness +loosening +loosens +looser +looses +loosest +loosestrife +loosestrifes +loosey +loosing +loot +looted +looter +looters +looting +loots +lop +lope +loped +loper +lopers +lopes +lophophore +lophophores +loping +lopped +lopper +loppers +loppier +loppiest +lopping +loppy +lops +lopsided +lopsidedly +lopsidedness +loquacious +loquaciously +loquaciousness +loquacity +loquat +loquats +loran +lorca +lord +lorded +lording +lordings +lordlier +lordliest +lordliness +lordling +lordlings +lordly +lordoses +lordosis +lordotic +lords +lordship +lordships +lordy +lore +loreal +lorelei +loreleis +lorentz +lorenz +lorgnette +lorgnettes +lorgnon +lorgnons +lorica +loricae +loricate +loricated +lories +lorikeet +lorikeets +loris +lorises +lorn +lorne +lornness +lorraine +lorries +lorry +lory +los +losable +losableness +lose +losel +losels +loser +losers +loses +losing +losingest +losings +loss +losses +lossless +lossy +lost +lostness +lot +lota +lotah +lotahs +lotas +loth +lothario +lotharios +lothian +loti +lotic +lotion +lotions +lotos +lotoses +lots +lotte +lotted +lotteries +lottery +lotting +lotto +lottos +lotus +lotuses +lotusland +louche +loud +louden +loudened +loudening +loudens +louder +loudest +loudly +loudmouth +loudmouthed +loudmouths +loudness +loudspeaker +loudspeakers +loudun +lough +loughs +louis +louise +louisiana +louisville +lounge +lounged +lounger +loungers +lounges +loungewear +lounging +loupe +loupes +lour +lourdes +loured +lourenço +louring +lours +loury +louse +loused +louses +lousewort +louseworts +lousier +lousiest +lousily +lousiness +lousing +lousy +lout +louted +louting +loutish +loutishly +loutishness +louts +louvain +louver +louvered +louvers +louvre +louvred +louvres +lovability +lovable +lovableness +lovably +lovage +lovages +lovastatin +lovat +lovats +love +loveable +lovebird +lovebirds +lovebug +lovebugs +loved +lovelace +loveless +lovelessly +lovelessness +lovelier +lovelies +loveliest +lovelily +loveliness +lovelock +lovelocks +lovelorn +lovelornness +lovely +lovemaking +lover +loverly +lovers +loves +loveseat +loveseats +lovesick +lovesickness +lovesome +lovey +loving +lovingly +lovingness +low +lowball +lowballed +lowballing +lowballs +lowborn +lowboy +lowboys +lowbred +lowbrow +lowbrowed +lowbrows +lowdown +lowed +lower +lowercase +lowercased +lowercases +lowercasing +lowerclassman +lowerclassmen +lowered +lowering +loweringly +lowermost +lowers +lowery +lowest +lowing +lowland +lowlander +lowlanders +lowlands +lowlier +lowliest +lowlife +lowlifes +lowlight +lowlights +lowlihead +lowliheads +lowliness +lowlives +lowly +lown +lowness +lows +lox +loxes +loxodrome +loxodromes +loxodromic +loxodromical +loxodromically +loyal +loyalism +loyalist +loyalists +loyally +loyalties +loyalty +loyola +lozenge +lozenges +lsd +luanda +luau +luaus +luba +lubas +lubavitcher +lubavitchers +lubber +lubberliness +lubberly +lubbers +lube +lubed +lubes +lubing +lubricant +lubricants +lubricate +lubricated +lubricates +lubricating +lubrication +lubrications +lubricative +lubricator +lubricators +lubricious +lubriciously +lubriciousness +lubricities +lubricity +lubricous +lucania +lucarne +lucarnes +lucca +lucency +lucent +lucently +lucerne +luces +lucia +lucian +lucians +lucid +lucida +lucidas +lucidity +lucidly +lucidness +lucifer +luciferase +luciferases +luciferin +luciferins +lucina +lucinas +lucite +luck +lucked +luckier +luckiest +luckily +luckiness +lucking +luckless +lucknow +lucks +lucky +lucrative +lucre +lucrece +lucretian +lucretius +lucubrate +lucubrated +lucubrates +lucubrating +lucubration +lucubrations +luculent +lucullan +luddism +luddite +luddites +lude +ludes +ludicrous +ludicrously +ludicrousness +lues +luetic +luetically +luff +luffa +luffas +luffed +luffing +luffs +lufthansa +luftwaffe +lug +lugano +luge +luged +luger +lugers +luges +luggage +lugged +lugger +luggers +lugging +luging +lugs +lugsail +lugsails +lugubrious +lugubriously +lugubriousness +lugworm +lugworms +luichow +luiseño +luiseños +luke +lukewarm +lukewarmly +lukewarmness +lull +lullabied +lullabies +lullaby +lullabying +lulled +lulling +lulls +lully +lulu +lulus +lumbago +lumbar +lumber +lumbered +lumberer +lumberers +lumbering +lumberingly +lumberjack +lumberjacks +lumberman +lumbermen +lumbers +lumberyard +lumberyards +lumbricoid +lumeloid +lumen +lumenal +lumens +lumina +luminal +luminance +luminaria +luminarias +luminaries +luminary +luminesce +luminesced +luminescence +luminescent +luminesces +luminescing +luminiferous +luminism +luminist +luminists +luminosities +luminosity +luminous +luminously +luminousness +lumière +lummox +lummoxes +lump +lumpectomies +lumpectomy +lumped +lumpen +lumpenproletariat +lumpenproletariats +lumpfish +lumpfishes +lumpier +lumpiest +lumpily +lumpiness +lumping +lumpish +lumpishly +lumpishness +lumps +lumpur +lumpy +luna +lunacies +lunacy +lunar +lunarscape +lunarscapes +lunate +lunated +lunates +lunatic +lunatics +lunation +lunch +lunched +luncheon +luncheonette +luncheonettes +luncheons +luncher +lunchers +lunches +lunching +lunchmeat +lunchmeats +lunchroom +lunchrooms +lunchtime +lunchtimes +lundy +lune +lunes +lunette +lunettes +lung +lunge +lunged +lunger +lungers +lunges +lungfish +lungfishes +lungi +lunging +lungis +lungs +lungworm +lungworms +lungwort +lungworts +lungyi +lungyis +lunisolar +lunitidal +lunker +lunkers +lunkhead +lunkheaded +lunkheads +lunula +lunulae +lunular +lunulate +lunulated +lunule +lunules +luny +lupercalia +lupercalian +lupin +lupine +lupines +lupins +lupulin +lupulins +lupus +lurch +lurched +lurcher +lurchers +lurches +lurching +lurchingly +lure +lured +lurer +lurers +lures +lurex +lurid +luridly +luridness +luring +luringly +lurk +lurked +lurker +lurkers +lurking +lurkingly +lurks +lusaka +lusatia +lusatian +lusatians +luscious +lusciously +lusciousness +lush +lushed +lusher +lushes +lushest +lushing +lushly +lushness +lusitania +lusitanian +lusitanians +lust +lusted +luster +lustered +lustering +lusterless +lusters +lusterware +lustful +lustfully +lustfulness +lustier +lustiest +lustily +lustiness +lusting +lustra +lustral +lustrate +lustrated +lustrates +lustrating +lustration +lustrations +lustrative +lustrous +lustrously +lustrousness +lustrum +lustrums +lusts +lusty +lusus +lutanist +lutanists +lute +luteal +lutecium +luted +lutefisk +lutefisks +lutein +luteinization +luteinizations +luteinize +luteinized +luteinizes +luteinizing +luteins +lutenist +lutenists +luteous +lutes +lutetium +lutfisk +lutfisks +luther +lutheran +lutheranism +lutheranize +lutheranized +lutheranizes +lutheranizing +lutherans +lutherism +luthier +luthiers +luting +lutist +lutists +lutyens +lutz +lutzes +luwian +luwians +lux +luxate +luxated +luxates +luxating +luxation +luxations +luxe +luxembourg +luxembourger +luxembourgers +luxemburg +luxes +luxor +luxuriance +luxuriant +luxuriantly +luxuriate +luxuriated +luxuriates +luxuriating +luxuries +luxurious +luxuriously +luxuriousness +luxury +luzon +lwei +lyam +lyase +lyases +lycanthrope +lycanthropes +lycanthropies +lycanthropy +lyceum +lyceums +lych +lychee +lychees +lychnis +lychnises +lycia +lycian +lycians +lycopene +lycopenes +lycopod +lycopodium +lycopodiums +lycopods +lycra +lycée +lycées +lyddite +lyddites +lydia +lydian +lydians +lye +lygus +lying +lyings +lyme +lymph +lymphadenitis +lymphadenopathies +lymphadenopathy +lymphangiogram +lymphangiograms +lymphangiographic +lymphangiographies +lymphangiography +lymphatic +lymphatically +lymphatics +lymphoblast +lymphoblastic +lymphoblasts +lymphocyte +lymphocytes +lymphocytic +lymphocytosis +lymphocytotic +lymphogram +lymphograms +lymphogranuloma +lymphogranulomatoses +lymphogranulomatosis +lymphographic +lymphography +lymphoid +lymphokine +lymphokines +lymphoma +lymphomas +lymphomata +lymphomatoid +lymphomatoses +lymphomatosis +lymphomatous +lymphopoieses +lymphopoiesis +lymphopoietic +lymphosarcoma +lymphosarcomas +lymphosarcomata +lymphotoxin +lymphotoxins +lymphotropic +lynch +lynched +lyncher +lynchers +lynches +lynching +lynchings +lynchpin +lynchpins +lynx +lynxes +lyon +lyonnais +lyonnaise +lyonnesse +lyons +lyophile +lyophiled +lyophilic +lyophilization +lyophilizations +lyophilize +lyophilized +lyophilizer +lyophilizers +lyophilizes +lyophilizing +lyophobic +lyra +lyrate +lyre +lyrebird +lyrebirds +lyres +lyric +lyrical +lyrically +lyricalness +lyricism +lyricist +lyricists +lyricize +lyricized +lyricizes +lyricizing +lyrics +lyrism +lyrist +lyrists +lysander +lysate +lysates +lyse +lysed +lysenko +lysenkoism +lysergic +lyses +lysimeter +lysimeters +lysimetric +lysin +lysine +lysing +lysins +lysis +lysistrata +lysithea +lysogen +lysogenic +lysogenicity +lysogenies +lysogenization +lysogenizations +lysogenize +lysogenized +lysogenizes +lysogenizing +lysogens +lysogeny +lysol +lysolecithin +lysolecithins +lysosomal +lysosome +lysosomes +lysozyme +lysozymes +lytic +lytically +lytta +lyttae +lytton +lázne +lésvos +lèse +límnos +lübeck +m +m1 +m16 +ma +ma'am +maar +maars +maasai +maasais +maastricht +mab +mabe +mac +macabre +macabrely +macaco +macacos +macadam +macadamia +macadamias +macadamization +macadamizations +macadamize +macadamized +macadamizer +macadamizers +macadamizes +macadamizing +macanese +macao +macaque +macaques +macaroni +macaronic +macaronics +macaronies +macaronis +macaroon +macaroons +macassar +macau +macaulay +macaw +macaws +macbeth +maccabean +maccabees +macduff +mace +macebearer +macebearers +maced +macedon +macedonia +macedonian +macedonians +macer +macerate +macerated +macerater +maceraters +macerates +macerating +maceration +macerations +macerator +macerators +macers +maces +mach +machabees +mache +maches +machete +machetes +machiavelli +machiavellian +machiavellianism +machiavellians +machiavellism +machiavellist +machiavellists +machicolate +machicolated +machicolates +machicolating +machicolation +machicolations +machina +machinability +machinable +machinate +machinated +machinates +machinating +machination +machinations +machinator +machinators +machine +machineability +machineable +machined +machineless +machinelike +machineries +machinery +machines +machining +machinist +machinists +machismo +machmeter +machmeters +macho +machoism +machos +machzor +macing +macintosh +macintoshes +mack +mackenzie +mackerel +mackerels +mackinac +mackinaw +mackinaws +mackintosh +mackintoshes +mackle +mackled +mackles +macklin +mackling +maclaurin +macle +macled +macles +macmillan +macon +macpherson +macramé +macready +macro +macroaggregate +macroaggregated +macroaggregates +macrobiotic +macrobiotics +macrocephalia +macrocephalic +macrocephalous +macrocephaly +macroclimate +macroclimates +macroclimatic +macrocode +macrocodes +macrocosm +macrocosmic +macrocosmically +macrocosms +macrocyclic +macrocyte +macrocytes +macrocytic +macrocytoses +macrocytosis +macrocytotic +macrodome +macrodomes +macroeconomic +macroeconomics +macroeconomist +macroeconomists +macroevolution +macroevolutionary +macroevolutions +macrofossil +macrofossils +macrogamete +macrogametes +macroglobulin +macroglobulinemia +macroglobulinemias +macroglobulinemic +macroglobulins +macrograph +macrographs +macrography +macroinstruction +macroinstructions +macrolepidoptera +macromere +macromeres +macromolecular +macromolecule +macromolecules +macron +macrons +macronuclear +macronuclei +macronucleus +macronutrient +macronutrients +macrophage +macrophages +macrophagic +macrophotograph +macrophotographs +macrophotography +macrophysics +macrophyte +macrophytes +macrophytic +macropterous +macros +macroscale +macroscales +macroscopic +macroscopical +macroscopically +macrosporangia +macrosporangium +macrospore +macrospores +macrostructural +macrostructure +macrostructures +macs +macula +maculae +macular +maculas +maculate +maculated +maculates +maculating +maculation +macule +maculed +macules +maculing +macumba +macédoine +mad +madagascan +madagascans +madagascar +madam +madame +madames +madams +madcap +madcaps +madded +madden +maddened +maddening +maddeningly +maddens +madder +madders +maddest +madding +maddish +made +madeira +madeiran +madeirans +madeiras +madeleine +madeleines +mademoiselle +mademoiselles +madhouse +madhouses +madhya +madison +madly +madman +madmen +madness +madnesses +madonna +madonnas +madras +madrepore +madrepores +madreporian +madreporic +madreporite +madreporites +madrid +madrigal +madrigalian +madrigalist +madrigalists +madrigals +madrilene +madrilenes +madrilène +madrilènes +madrona +madrone +madrones +madrono +madroña +madroñas +madroño +madroños +mads +maduro +maduros +madwoman +madwomen +madwort +madworts +mae +maecenas +maecenases +maelstrom +maelstroms +maenad +maenadic +maenads +maestoso +maestri +maestro +maestros +mafeking +maffick +mafficked +mafficking +mafficks +mafia +mafic +mafiosi +mafioso +mafiosos +mag +magadha +magazine +magazines +magazinist +magazinists +magdalen +magdalene +magdalenes +magdalenian +magdalens +magdeburg +mage +magellan +magellanic +magen +magenta +magentas +mages +maggiore +maggot +maggots +maggoty +maghreb +maghrib +magi +magian +magianism +magic +magical +magically +magician +magicians +magicked +magicking +magics +maginot +magisterial +magisterially +magisterium +magisteriums +magistracies +magistracy +magistral +magistrally +magistrate +magistrates +magistratical +magistratically +magistrature +magistratures +maglemosian +maglev +maglevs +magma +magmas +magmata +magmatic +magna +magnanimities +magnanimity +magnanimous +magnanimously +magnanimousness +magnate +magnates +magnesia +magnesian +magnesite +magnesites +magnesium +magnet +magnetar +magnetars +magnetic +magnetically +magnetism +magnetisms +magnetite +magnetizable +magnetization +magnetizations +magnetize +magnetized +magnetizer +magnetizers +magnetizes +magnetizing +magneto +magnetoelectric +magnetoelectricity +magnetofluiddynamic +magnetofluiddynamics +magnetogasdynamic +magnetogasdynamics +magnetograph +magnetographs +magnetohydrodynamic +magnetohydrodynamics +magnetometer +magnetometers +magnetometric +magnetometry +magnetomotive +magneton +magnetons +magnetopause +magnetopauses +magnetoplasmadynamic +magnetoplasmadynamics +magnetoresistance +magnetoresistances +magnetos +magnetosphere +magnetospheres +magnetospheric +magnetostatic +magnetostriction +magnetostrictions +magnetostrictive +magnetostrictively +magnetron +magnetrons +magnets +magnifiable +magnific +magnifical +magnifically +magnificat +magnification +magnifications +magnificats +magnificence +magnificent +magnificently +magnifico +magnificoes +magnified +magnifier +magnifiers +magnifies +magnify +magnifying +magniloquence +magniloquent +magniloquently +magnitude +magnitudes +magnolia +magnolias +magnon +magnum +magnums +magnus +magot +magots +magpie +magpies +mags +maguey +magueys +magus +magyar +magyars +mah +mahabharata +mahal +mahaleb +mahalebs +mahalo +maharaja +maharajah +maharajahs +maharajas +maharanee +maharanees +maharani +maharanis +maharashtra +maharishi +maharishis +mahatma +mahatmas +mahayana +mahayanas +mahayanist +mahayanistic +mahayanists +mahdi +mahdis +mahdism +mahdist +mahdists +mahi +mahican +mahicans +mahimahi +mahis +mahjong +mahjongg +mahjonggs +mahjongs +mahler +mahlstick +mahlsticks +mahoe +mahoes +mahoganies +mahogany +mahomet +mahonia +mahout +mahouts +mahrati +mahratta +mahratti +mahuang +mahuangs +mahzor +mahzorim +mahzors +maia +maid +maiden +maidenhair +maidenhairs +maidenhead +maidenheads +maidenhood +maidenliness +maidenly +maidens +maidhood +maidish +maidishness +maids +maidservant +maidservants +maidu +maidus +maieutic +maieutical +mail +mailability +mailable +mailbag +mailbags +mailbox +mailboxes +maile +mailed +mailer +mailers +mailgram +mailing +mailings +maillot +maillots +mailman +mailmen +mailroom +mailrooms +mails +maim +maimed +maimer +maimers +maiming +maims +main +maine +mainframe +mainframes +mainland +mainlander +mainlanders +mainline +mainlined +mainliner +mainliners +mainlines +mainlining +mainly +mainmast +mainmasts +mains +mainsail +mainsails +mainsheet +mainsheets +mainspring +mainsprings +mainstay +mainstays +mainstream +mainstreamed +mainstreamer +mainstreamers +mainstreaming +mainstreams +maintain +maintainability +maintainable +maintained +maintainer +maintainers +maintaining +maintains +maintenance +maintop +maintops +mainz +maiolica +maisonette +maisonettes +maitre +maitres +maize +maizes +majeste +majestic +majestical +majestically +majesties +majesty +majesté +majeure +majolica +major +majora +majorca +majorcan +majorcans +majordomo +majordomos +majored +majorette +majorettes +majoring +majoritarian +majoritarianism +majoritarians +majorities +majority +majorly +majors +majuscular +majuscule +majuscules +makable +makalu +makar +makars +makassar +make +makeable +makebate +makebates +makefast +makefasts +makeover +makeovers +maker +makereadies +makeready +makers +makes +makeshift +makeshifts +makeup +makeups +makeweight +makeweights +makimono +makimonos +making +makings +mako +makos +makuta +mal +malabar +malabo +malabsorption +malabsorptions +malacca +malaccas +malachi +malachias +malachite +malacological +malacologist +malacologists +malacology +malacostracan +malacostracans +maladaptation +maladaptations +maladapted +maladaptive +maladies +maladjusted +maladjustive +maladjustment +maladjustments +maladminister +maladministered +maladministering +maladministers +maladministration +maladministrations +maladroit +maladroitly +maladroitness +maladroits +malady +malaga +malagas +malagasies +malagasy +malagueña +malaise +malamute +malamutes +malapert +malapertly +malapertness +malaperts +malapportioned +malapportionment +malapportionments +malaprop +malapropian +malapropism +malapropisms +malapropist +malapropists +malapropos +malaprops +malar +malaria +malarial +malarian +malariologist +malariologists +malariology +malarious +malarkey +malarky +malars +malassimilation +malassimilations +malate +malates +malathion +malawi +malawian +malawians +malay +malaya +malayalam +malayalams +malayan +malayans +malays +malaysia +malaysian +malaysians +malcontent +malcontented +malcontentedly +malcontentedness +malcontents +maldistribution +maldistributions +maldivan +maldivans +maldive +maldives +maldivian +maldivians +male +maleate +maleates +malebranche +malecite +malecites +maledict +maledicted +maledicting +malediction +maledictions +maledictory +maledicts +malefaction +malefactions +malefactor +malefactors +malefic +maleficence +maleficent +maleic +malemute +malemutes +maleness +malentendu +malentendus +males +malevolence +malevolent +malevolently +malfeasance +malfeasant +malfeasants +malfi +malformation +malformations +malformed +malfunction +malfunctioned +malfunctioning +malfunctions +malgre +mali +malian +malians +malic +malice +malicious +maliciously +maliciousness +malign +malignance +malignancies +malignancy +malignant +malignantly +maligned +maligner +maligners +maligning +malignities +malignity +malignly +maligns +malihini +malihinis +maline +malines +malinger +malingered +malingerer +malingerers +malingering +malingers +malinke +malinkes +malinois +maliseet +maliseets +malison +malisons +malkin +malkins +mall +mallard +mallards +malleability +malleable +malleableness +malleably +malled +mallee +mallees +mallei +mallemuck +mallemucks +mallet +mallets +malleus +malling +mallorca +mallow +mallows +malls +malmsey +malmseys +malnourish +malnourished +malnourishes +malnourishing +malnourishment +malnourishments +malnutrition +malo +malocclusion +malocclusions +malodor +malodorous +malodorously +malodorousness +malodors +malolactic +malonic +maloti +malpighian +malplaquet +malposition +malpositions +malpractice +malpractitioner +malpractitioners +malt +malta +maltase +malted +maltese +maltha +malthas +malthus +malthusian +malthusianism +malthusians +malting +maltose +maltreat +maltreated +maltreater +maltreaters +maltreating +maltreatment +maltreatments +maltreats +malts +maltster +maltsters +malty +malvasia +malvasias +malversation +malversations +malvinas +malvoisie +malvoisies +mama +mamas +mamba +mambas +mamberamo +mambo +mamboed +mamboing +mambos +mameluke +mamelukes +mamey +mameys +mamluk +mamluks +mamma +mammae +mammal +mammalian +mammalians +mammalogical +mammalogist +mammalogists +mammalogy +mammals +mammaplasties +mammaplasty +mammary +mammas +mammate +mammee +mammer +mammered +mammering +mammers +mammies +mammiferous +mammilla +mammillae +mammillary +mammillate +mammillated +mammillation +mammillations +mammock +mammocked +mammocking +mammocks +mammogram +mammograms +mammographic +mammographies +mammography +mammon +mammonism +mammonist +mammonists +mammoplasties +mammoplasty +mammoth +mammoths +mammy +mamoré +man +mana +manacle +manacled +manacles +manacling +manage +manageability +manageable +manageableness +manageably +managed +management +managemental +managements +manager +manageress +manageresses +managerial +managerially +managers +managership +managerships +manages +managing +managua +managuan +managuans +manakin +manakins +manama +manamah +manas +manasseh +manatee +manatees +manchester +manchineel +manchineels +manchu +manchuguo +manchukuo +manchuria +manchurian +manchurians +manchus +manciple +manciples +mancunian +mancunians +mandaean +mandaeans +mandala +mandalas +mandalay +mandalic +mandamus +mandamused +mandamuses +mandamusing +mandan +mandans +mandarin +mandarinate +mandarinates +mandarinic +mandarinism +mandarins +mandataries +mandatary +mandate +mandated +mandates +mandating +mandator +mandatories +mandatorily +mandators +mandatory +mande +mandean +mandeans +mandekan +mandekans +mandelbrot +mandes +mandible +mandibles +mandibular +mandibulate +mandibulates +mandingo +mandingoes +mandingos +mandinka +mandinkas +mandioca +mandola +mandolas +mandolin +mandoline +mandolines +mandolinist +mandolinists +mandolins +mandragora +mandragoras +mandrake +mandrakes +mandrel +mandrels +mandril +mandrill +mandrills +mandrils +mane +maned +manege +maneges +manes +manet +maneuver +maneuverability +maneuverable +maneuvered +maneuverer +maneuverers +maneuvering +maneuverings +maneuvers +manful +manfully +manfulness +mangabey +mangabeys +manganate +manganates +manganese +manganesian +manganic +manganite +manganites +manganous +mange +mangel +manger +mangers +mangier +mangiest +mangily +manginess +mangle +mangled +mangler +manglers +mangles +mangling +mango +mangoes +mangonel +mangonels +mangos +mangosteen +mangosteens +mangrove +mangroves +mangy +manhandle +manhandled +manhandles +manhandling +manhattan +manhattanite +manhattanites +manhattanization +manhattanizations +manhattanize +manhattanized +manhattanizes +manhattanizing +manhattans +manhole +manholes +manhood +manhunt +manhunts +mania +maniac +maniacal +maniacally +maniacs +manias +manic +manically +manichaean +manichaeanism +manichaeanisms +manichaeans +manichaeism +manichaeisms +manichean +manicheans +manichee +manichees +manicheism +manicotti +manics +manicure +manicured +manicures +manicuring +manicurist +manicurists +manifest +manifestant +manifestants +manifestation +manifestations +manifested +manifester +manifesters +manifesting +manifestly +manifesto +manifestoed +manifestoes +manifestoing +manifestos +manifests +manifold +manifolded +manifolding +manifoldly +manifoldness +manifolds +manikin +manikins +manila +manilas +manilla +manillas +manille +maninka +maninkas +manioc +manioca +maniocas +maniocs +maniple +maniples +manipulability +manipulable +manipular +manipulars +manipulatable +manipulate +manipulated +manipulates +manipulating +manipulation +manipulations +manipulative +manipulatively +manipulativeness +manipulator +manipulators +manipulatory +manipur +manito +manitoba +manitoban +manitobans +manitos +manitou +manitoulin +manitous +manitu +manitus +mankind +manless +manlier +manliest +manlike +manliness +manly +manmade +manna +mannan +mannans +mannar +manned +mannequin +mannequins +manner +mannered +mannerism +mannerisms +mannerist +manneristic +mannerists +mannerless +mannerliness +mannerly +manners +mannheim +mannikin +mannikins +manning +mannish +mannishly +mannishness +mannite +mannites +mannitol +mannitols +mannose +mannoses +mano +manometer +manometers +manometric +manometrical +manometrically +manometry +manor +manorial +manorialism +manors +manos +manpack +manpower +manqué +manrope +manropes +mans +mansard +mansarded +mansards +manse +manservant +manses +mansfield +mansion +mansions +manslaughter +manslayer +manslayers +mansuetude +mansuetudes +manta +mantas +manteau +manteaus +manteaux +mantegna +mantel +mantelet +mantelets +mantelletta +mantellettas +mantelpiece +mantelpieces +mantels +mantelshelf +mantelshelfs +manteltree +manteltrees +mantes +mantic +mantically +manticore +mantid +mantids +mantilla +mantillas +mantis +mantises +mantissa +mantissas +mantle +mantled +mantles +mantlet +mantlets +mantling +mantoux +mantova +mantra +mantrap +mantraps +mantras +mantric +mantua +mantuan +mantuans +mantuas +manu +manual +manually +manuals +manubria +manubrium +manufactories +manufactory +manufacturable +manufactural +manufacture +manufactured +manufacturer +manufacturers +manufactures +manufacturing +manumission +manumissions +manumit +manumits +manumitted +manumitter +manumitters +manumitting +manure +manured +manurer +manurers +manures +manurial +manuring +manus +manuscript +manuscripts +manward +manwards +manwise +manx +manxman +manxmen +manxwoman +manxwomen +many +manyfold +manyplies +manzanilla +manzanillas +manzanita +manzanitas +manzoni +manège +manèges +mao +maoism +maoist +maoists +maori +maoris +map +maple +maples +maplike +mapmaker +mapmakers +mapmaking +mappable +mapped +mapper +mappers +mapping +mappings +maps +maputo +maquette +maquettes +maqui +maquila +maquiladora +maquiladoras +maquilas +maquillage +maquillages +maquis +maquisard +maquisards +mar +mara +marabou +marabous +marabout +marabouts +maraca +maracaibo +maracas +maraging +marajó +maranta +marantas +maras +marasca +marascas +maraschino +maraschinos +marasmic +marasmus +marat +maratha +marathas +marathi +marathon +marathoner +marathoners +marathoning +marathons +marattas +maraud +marauded +marauder +marauders +marauding +marauds +marañón +marbella +marble +marbled +marbleize +marbleized +marbleizes +marbleizing +marbles +marblewood +marblewoods +marbling +marbly +marburg +marc +marcasite +marcasites +marcasitical +marcato +marcatos +marcel +marcelled +marcelling +marcels +marcescent +march +marchand +marche +marched +marchen +marcher +marchers +marches +marchesa +marchese +marchesi +marching +marchioness +marchionesses +marchland +marchlands +marchlike +marchpane +marchpanes +marcionism +marcionite +marcionites +marconi +marcs +mardi +marduk +mare +marek +marengo +mares +marfan +margarine +margarines +margarita +margaritas +margarite +margarites +margay +marge +margent +margents +margin +marginal +marginalia +marginality +marginalization +marginalizations +marginalize +marginalized +marginalizes +marginalizing +marginally +marginate +marginated +marginates +marginating +margination +marginations +margined +margining +margins +margravate +margravates +margrave +margraves +margravial +margraviate +margraviates +margravine +margravines +marguerite +marguerites +maria +mariachi +mariachis +marian +mariana +marianas +marianist +marianists +maricopa +maricopas +maricultural +mariculture +maricultures +mariculturist +mariculturists +marie +marienberg +marienbourg +marienburg +marigold +marigolds +marihuana +marijuana +marimba +marimbas +marimbist +marimbists +marina +marinade +marinaded +marinades +marinading +marinara +marinaras +marinas +marinate +marinated +marinates +marinating +marination +marinations +marine +mariner +mariners +marines +marino +mariolater +mariolaters +mariolatrous +mariolatry +mariological +mariology +marionette +marionettes +mariposa +marish +marishes +marist +marists +marital +maritally +maritime +mariánské +marjoram +mark +markdown +markdowns +marked +markedly +markedness +marker +markers +market +marketability +marketable +marketed +marketeer +marketeering +marketeers +marketer +marketers +marketing +marketings +marketplace +marketplaces +markets +marketwise +markham +markhor +markhors +marking +markings +markka +markkaa +markkas +markoff +markov +markovian +marks +marksman +marksmanship +marksmen +markswoman +markswomen +markup +markups +marl +marled +marlin +marline +marlines +marlinespike +marlinespikes +marling +marlingspike +marlingspikes +marlins +marlinspike +marlinspikes +marlite +marlites +marlitic +marls +marlstone +marlstones +marly +marmalade +marmalades +marmara +marmite +marmites +marmolada +marmoreal +marmoreally +marmorean +marmoset +marmosets +marmot +marmots +marne +marocain +marocains +maronite +maronites +maroon +marooned +marooning +maroons +marplot +marplots +marque +marquee +marquees +marques +marquesan +marquesans +marquess +marquessate +marquessates +marquesses +marqueterie +marqueteries +marquetries +marquetry +marquette +marquis +marquisate +marquisates +marquise +marquises +marquisette +marquisettes +marrakech +marrakesh +marram +marrams +marrano +marranos +marred +marriage +marriageability +marriageable +marriageableness +marriages +married +marrieds +marries +marring +marron +marrons +marrow +marrowbone +marrowbones +marrowfat +marrowfats +marrowy +marry +marrying +mars +marsala +marsalas +marse +marseillaise +marseille +marseilles +marsh +marshal +marshalcy +marshaled +marshaling +marshall +marshalled +marshalling +marshals +marshalship +marshalships +marshes +marshier +marshiest +marshiness +marshland +marshlands +marshmallow +marshmallows +marshmallowy +marshy +marston +marsupia +marsupial +marsupials +marsupium +mart +martaban +martagon +martagons +marted +martel +martello +marten +martens +martensite +martensites +martensitic +martensitically +martha +martial +martialed +martialing +martialism +martialist +martialists +martialled +martialling +martially +martials +martian +martians +martin +martinet +martinets +marting +martingal +martingale +martingales +martingals +martini +martinique +martinis +martinmas +martinmases +martins +martlet +martlets +marts +martyr +martyrdom +martyred +martyries +martyring +martyrization +martyrizations +martyrize +martyrized +martyrizes +martyrizing +martyrologies +martyrologist +martyrologists +martyrology +martyrs +martyry +martí +marvel +marveled +marveling +marvelled +marvelling +marvellous +marvelous +marvelously +marvelousness +marvels +marx +marxian +marxianism +marxians +marxism +marxist +marxists +mary +maryknoller +maryknollers +maryland +marylander +marylanders +maryology +marys +marzipan +mas +masaccio +masachusetts +masada +masai +masais +masala +masalas +masbate +mascara +mascaraed +mascaraing +mascaras +mascarpone +mascarpones +mascon +mascons +mascot +mascots +masculine +masculinely +masculineness +masculines +masculinities +masculinity +masculinization +masculinizations +masculinize +masculinized +masculinizes +masculinizing +masefield +maser +masers +maseru +mash +mashed +masher +masherbrum +mashers +mashes +mashgiach +mashgiah +mashgichim +mashgihim +mashie +mashies +mashing +mashy +masjid +masjids +mask +maskable +masked +maskeg +maskegs +masker +maskers +masking +maskings +maskinonge +maskinonges +masklike +masks +masochism +masochist +masochistic +masochistically +masochists +mason +masoned +masonic +masoning +masonite +masonries +masonry +masons +masora +masorah +masorahs +masoras +masorete +masoretes +masoretic +masque +masquer +masquerade +masqueraded +masquerader +masqueraders +masquerades +masquerading +masquers +masques +mass +massachuset +massachusets +massachusett +massachusetts +massacre +massacred +massacrer +massacrers +massacres +massacring +massage +massaged +massager +massagers +massages +massaging +massasauga +massasaugas +masscult +masscults +masse +massed +massena +masses +masseter +masseteric +masseters +masseur +masseurs +masseuse +masseuses +massicot +massicots +massier +massiest +massif +massifs +massing +massinger +massive +massively +massiveness +massless +massorete +massoretes +massy +massé +mast +mastaba +mastabah +mastabahs +mastabas +mastectomies +mastectomy +masted +master +masterdom +mastered +masterful +masterfully +masterfulness +masteries +mastering +masterliness +masterly +mastermind +masterminded +masterminding +masterminds +masterpiece +masterpieces +masters +mastership +masterships +mastersinger +mastersingers +masterstroke +masterstrokes +masterwork +masterworks +mastery +masthead +mastheads +mastic +masticate +masticated +masticates +masticating +mastication +mastications +masticator +masticatories +masticators +masticatory +mastics +mastiff +mastiffs +mastigophoran +mastigophorans +mastitic +mastitis +mastodon +mastodonic +mastodons +mastodont +mastoid +mastoidectomies +mastoidectomy +mastoiditis +mastoids +masts +masturbate +masturbated +masturbates +masturbating +masturbation +masturbational +masturbator +masturbators +masturbatory +masuria +masurian +mat +matabele +matabeleland +matabeles +matador +matadors +matagorda +matapan +match +matchability +matchable +matchboard +matchboards +matchbook +matchbooks +matchbox +matchboxes +matched +matcher +matchers +matches +matching +matchless +matchlessly +matchlessness +matchlock +matchlocks +matchmaker +matchmakers +matchmaking +matchstick +matchsticks +matchup +matchups +matchwood +matchwoods +mate +mated +matelot +matelote +matelotes +matelots +matelotte +matelottes +mater +materfamilias +materfamiliases +materia +material +materialism +materialist +materialistic +materialistically +materialists +materialities +materiality +materialization +materializations +materialize +materialized +materializer +materializers +materializes +materializing +materially +materialness +materials +materiel +maternal +maternalism +maternally +maternities +maternity +maters +mates +matey +mateyness +math +mathematic +mathematical +mathematically +mathematician +mathematicians +mathematics +mathematization +mathematizations +mathematize +mathematized +mathematizes +mathematizing +maths +matilda +matilija +matin +matinal +matinee +matinees +mating +matins +matinée +matinées +matisse +matjes +matriarch +matriarchal +matriarchalism +matriarchate +matriarchates +matriarchic +matriarchies +matriarchs +matriarchy +matrices +matricidal +matricide +matricides +matriclinous +matriculant +matriculants +matriculate +matriculated +matriculates +matriculating +matriculation +matriculations +matrilineage +matrilineages +matrilineal +matrilineally +matrilocal +matrilocally +matrimonial +matrimonially +matrimonies +matrimony +matrix +matrixes +matron +matronal +matronliness +matronly +matrons +matronymic +matronymics +mats +matsu +matte +matted +matter +mattered +matterhorn +mattering +matters +mattery +mattes +matthaean +matthean +matthew +matthias +matting +mattings +mattock +mattocks +mattress +mattresses +maturate +maturated +maturates +maturating +maturation +maturational +maturations +maturative +mature +matured +maturely +matureness +maturer +matures +maturest +maturing +maturities +maturity +matutinal +matutinally +matzo +matzoh +matzohs +matzos +matzot +matzoth +maté +matériel +mau +maud +maudlin +maudlinly +maudlinness +maued +maugham +maugre +maui +mauing +maul +mauled +mauler +maulers +mauling +mauls +maulstick +maulsticks +maund +maunder +maundered +maunderer +maunderers +maundering +maunders +maunds +maundy +maupassant +mauretania +mauretanian +mauretanians +maurice +mauritania +mauritanian +mauritanians +mauritian +mauritians +mauritius +mauser +mausolea +mausolean +mausoleum +mausoleums +mauve +mauves +maven +mavens +maverick +mavericks +mavin +mavins +mavis +mavises +mavourneen +mavourneens +mavournin +mavournins +maw +mawkish +mawkishly +mawkishness +maws +max +maxed +maxes +maxi +maxilla +maxillae +maxillaries +maxillary +maxillas +maxilliped +maxillipeds +maxillofacial +maxim +maxima +maximal +maximalist +maximalists +maximally +maximals +maximi +maximilian +maximin +maximization +maximizations +maximize +maximized +maximizer +maximizers +maximizes +maximizing +maxims +maximum +maximums +maximus +maxing +maxis +maxixe +maxixes +maxwell +may +maya +mayagüez +mayan +mayanist +mayanists +mayans +mayapple +mayapples +mayas +maybe +maybes +mayday +maydays +mayest +mayflies +mayflower +mayflowers +mayfly +mayhap +mayhem +mayhems +maying +mayings +maymyo +mayn +mayn't +mayo +mayon +mayonnaise +mayor +mayoral +mayoralties +mayoralty +mayoress +mayoresses +mayors +mayorship +mayorships +mayos +mayotte +maypole +maypoles +maypop +maypops +mays +mayst +maytime +mayweed +mayweeds +mazaedia +mazaedium +mazal +mazard +mazards +mazatlán +mazda +mazdaism +mazdeism +maze +mazed +mazel +mazelike +mazer +mazers +mazes +mazier +maziest +mazily +maziness +mazing +mazourka +mazourkas +mazuma +mazumas +mazurka +mazurkas +mazy +mazzard +mazzards +maître +mañana +mbabane +mbira +mbiras +mbundu +mbundus +mccarthyism +mccarthyist +mccarthyists +mccarthyite +mccarthyites +mcclure +mccoy +mccoys +mcintosh +mcintoshes +mckinley +mdewakanton +mdewakantons +me +mea +mead +meadow +meadowfoam +meadowland +meadowlands +meadowlark +meadowlarks +meadows +meadowsweet +meadowsweets +meadowy +meager +meagerly +meagerness +meagre +meal +mealie +mealier +mealies +mealiest +mealiness +meals +mealtime +mealtimes +mealworm +mealworms +mealy +mealybug +mealybugs +mealymouthed +mean +meander +meandered +meanderer +meanderers +meandering +meanderingly +meanders +meandrous +meaner +meanest +meanie +meanies +meaning +meaningful +meaningfully +meaningfulness +meaningless +meaninglessly +meaninglessness +meaningly +meanings +meanly +meanness +means +meant +meantime +meanwhile +meany +measle +measles +measlier +measliest +measly +measurability +measurable +measurably +measure +measured +measuredly +measuredness +measureless +measurelessly +measurelessness +measurement +measurements +measurer +measurers +measures +measuring +meat +meatball +meatballs +meated +meathead +meatheads +meatier +meatiest +meatiness +meatless +meatloaf +meatloaves +meatpacker +meatpackers +meatpacking +meatpackings +meats +meatus +meatuses +meaty +mecamylamine +mecamylamines +mecca +meccas +mechanic +mechanical +mechanically +mechanicalness +mechanicals +mechanician +mechanicians +mechanics +mechanism +mechanisms +mechanist +mechanistic +mechanistically +mechanists +mechanizable +mechanization +mechanizations +mechanize +mechanized +mechanizer +mechanizers +mechanizes +mechanizing +mechanochemical +mechanochemistry +mechanoreception +mechanoreceptions +mechanoreceptive +mechanoreceptor +mechanoreceptors +mechanotherapies +mechanotherapist +mechanotherapists +mechanotherapy +mechlin +mechlins +mecklenburg +meclizine +meclizines +meconium +meconiums +mecopteran +mecopterans +mecopterous +mecum +mecums +med +medaillon +medaillons +medaka +medakas +medal +medaled +medaling +medalist +medalists +medalled +medallic +medalling +medallion +medallions +medallist +medallists +medals +meddle +meddled +meddler +meddlers +meddles +meddlesome +meddlesomely +meddlesomeness +meddling +mede +medea +medellín +medes +medevac +medevaced +medevacing +medevacs +medflies +medfly +media +mediacy +mediad +mediae +mediaeval +mediaevalism +mediaevalisms +mediaevalist +mediaevalists +mediagenic +medial +medially +medials +median +medianly +medians +mediant +mediants +medias +mediastina +mediastinal +mediastinum +mediate +mediated +mediately +mediates +mediating +mediation +mediational +mediations +mediative +mediatization +mediatizations +mediatize +mediatized +mediatizes +mediatizing +mediator +mediators +mediatory +mediatrix +medic +medica +medicable +medicaid +medical +medically +medicals +medicament +medicamentous +medicaments +medicare +medicate +medicated +medicates +medicating +medication +medications +medicative +medicatrix +medicean +medici +medicinable +medicinal +medicinally +medicine +medicines +medick +medicks +medico +medicolegal +medicos +medics +medieval +medievalism +medievalisms +medievalist +medievalists +medievally +medina +medinas +mediocre +mediocrities +mediocritization +mediocritizations +mediocritize +mediocritized +mediocritizes +mediocritizing +mediocrity +meditate +meditated +meditates +meditating +meditation +meditational +meditations +meditative +meditatively +meditativeness +meditator +meditators +mediterranean +mediterraneans +medium +mediumistic +mediums +mediumship +medlar +medlars +medley +medleys +medoc +medocs +medulla +medullae +medullar +medullary +medullas +medullated +medullization +medullizations +medulloblastoma +medulloblastomas +medulloblastomata +medusa +medusae +medusan +medusans +medusas +medusoid +medusoids +meed +meeds +meek +meeker +meekest +meekly +meekness +meemies +meerkat +meerkats +meerschaum +meerschaums +meet +meeter +meeters +meeting +meetinghouse +meetinghouses +meetings +meetly +meets +mefenamic +megaampere +megaamperes +megabar +megabars +megabecquerel +megabecquerels +megabit +megabits +megabuck +megabucks +megabyte +megabytes +megacandela +megacandelas +megacephalic +megacephalies +megacephalous +megacephaly +megacities +megacity +megacorporation +megacorporations +megacoulomb +megacoulombs +megacycle +megacycles +megadeal +megadeals +megadeath +megadeaths +megadose +megadoses +megaera +megafarad +megafarads +megafauna +megafaunal +megaflop +megaflops +megagamete +megagametes +megagametophyte +megagametophytes +megagram +megagrams +megahenries +megahenry +megahenrys +megahertz +megahit +megahits +megajoule +megajoules +megakaryocyte +megakaryocytes +megakaryocytic +megakelvin +megakelvins +megalith +megalithic +megaliths +megaloblast +megaloblastic +megaloblasts +megalocardia +megalocardias +megalocephalic +megalocephalies +megalocephalous +megalocephaly +megalomania +megalomaniac +megalomaniacal +megalomaniacally +megalomaniacs +megalomanic +megalopolis +megalopolises +megalopolistic +megalopolitan +megalosaur +megalosaurian +megalosaurians +megalosaurs +megalumen +megalumens +megalux +megameter +megameters +megamole +megamoles +meganewton +meganewtons +megaohm +megaohms +megaparsec +megaparsecs +megapascal +megapascals +megaphone +megaphoned +megaphones +megaphonic +megaphonically +megaphoning +megapode +megapodes +megapolis +megaproject +megaprojects +megara +megaradian +megaradians +megarian +megarians +megaric +megarics +megaron +megarons +megascopic +megascopically +megasecond +megaseconds +megasiemens +megasievert +megasieverts +megasporangia +megasporangium +megaspore +megaspores +megasporic +megasporocyte +megasporocytes +megasporogeneses +megasporogenesis +megasporophyll +megasporophylls +megastar +megastars +megasteradian +megasteradians +megastructure +megastructures +megatesla +megateslas +megathere +megatheres +megatherian +megaton +megatonnage +megatons +megavitamin +megavitamins +megavolt +megavoltage +megavoltages +megavolts +megawatt +megawattage +megawattages +megawatts +megaweber +megawebers +meghalaya +megillah +megillahs +megilp +megilps +megohm +megohms +megrez +megrim +megrims +meiji +mein +meioses +meiosis +meiotic +meiotically +meissen +meissens +meistersinger +meistersingers +meitnerium +mekong +melamine +melancholia +melancholiac +melancholiacs +melancholic +melancholically +melancholics +melancholily +melancholiness +melancholy +melanchthon +melanesia +melanesian +melanesians +melange +melanges +melanic +melanin +melanism +melanistic +melanite +melanites +melanitic +melanization +melanizations +melanize +melanized +melanizes +melanizing +melanoblast +melanoblastic +melanoblasts +melanocyte +melanocytes +melanogenesis +melanoid +melanoids +melanoma +melanomas +melanomata +melanophore +melanophores +melanoses +melanosis +melanosity +melanosome +melanosomes +melanotic +melanous +melaphyre +melaphyres +melatonin +melatonins +melba +melbourne +melchior +melchite +melchites +melchizedek +melchizedeks +meld +melded +melding +melds +melee +melees +melena +melenas +melic +melilot +melilots +meliorable +meliorate +meliorated +meliorates +meliorating +melioration +meliorations +meliorative +melioratives +meliorator +meliorators +meliorism +meliorist +melioristic +meliorists +melisma +melismas +melismata +melismatic +melkite +melkites +mell +melled +melliferous +mellific +mellifluence +mellifluent +mellifluently +mellifluous +mellifluously +mellifluousness +melling +mellitus +mellophone +mellophones +mellotron +mellotrons +mellow +mellowed +mellower +mellowest +mellowing +mellowly +mellowness +mellows +mells +melodeon +melodeons +melodic +melodically +melodies +melodious +melodiously +melodiousness +melodist +melodists +melodize +melodized +melodizer +melodizers +melodizes +melodizing +melodrama +melodramas +melodramatic +melodramatically +melodramatics +melodramatist +melodramatists +melodramatization +melodramatizations +melodramatize +melodramatized +melodramatizes +melodramatizing +melody +meloid +meloids +melon +melongene +melongenes +melons +melos +melphalan +melphalans +melpomene +melt +meltability +meltable +meltage +meltages +meltdown +meltdowns +melted +melter +melters +melting +meltingly +melton +meltons +melts +meltwater +melty +melville +mem +member +membered +members +membership +memberships +membranal +membrane +membraned +membranes +membranous +membranously +memento +mementoes +mementos +memnon +memo +memoir +memoire +memoirist +memoirists +memoirs +memorabilia +memorability +memorable +memorableness +memorably +memoranda +memorandum +memorandums +memorial +memorialist +memorialists +memorialization +memorializations +memorialize +memorialized +memorializer +memorializers +memorializes +memorializing +memorially +memorials +memoriam +memories +memoriter +memorizable +memorization +memorizations +memorize +memorized +memorizer +memorizers +memorizes +memorizing +memory +memos +memphis +memsahib +memsahibs +men +menace +menaced +menacer +menacers +menaces +menacing +menacingly +menad +menadione +menadiones +menads +menage +menagerie +menageries +menages +menander +menarche +menarcheal +menazon +menazons +mencken +menckenian +mend +mendable +mendacious +mendaciously +mendaciousness +mendacities +mendacity +mende +mended +mendel +mendeleev +mendelevium +mendelian +mendelianism +mendelianisms +mendelians +mendelism +mendelisms +mendelist +mendelists +mendelssohn +mender +menders +mendes +mendicancy +mendicant +mendicants +mendicity +mending +mendings +mends +meneer +meneers +menelaus +menenius +menfolk +menfolks +menhaden +menhadens +menhir +menhirs +menial +menially +menials +meniere +meningeal +meninges +meningioma +meningiomas +meningiomata +meningitic +meningitides +meningitis +meningococcal +meningococci +meningococcic +meningococcus +meningoencephalitic +meningoencephalitis +meninx +meniscal +meniscate +meniscectomy +menisci +meniscoid +meniscoidal +meniscus +meniscuses +mennonite +mennonites +meno +menology +menominee +menominees +menopausal +menopause +menorah +menorahs +menorca +menorrhagia +menorrhagias +menorrhagic +mens +mensa +mensal +mensch +menschen +mensches +mensem +menservants +menses +mensh +menshevik +mensheviki +mensheviks +menshevism +menshevist +menshevists +menstrua +menstrual +menstruate +menstruated +menstruates +menstruating +menstruation +menstruous +menstruum +menstruums +mensurability +mensurable +mensurableness +mensural +mensuration +mensurations +mensurative +menswear +menta +mental +mentalism +mentalisms +mentalist +mentalistic +mentalists +mentalities +mentality +mentally +mentation +mentations +menthe +menthol +mentholated +menthols +mention +mentionable +mentioned +mentioner +mentioners +mentioning +mentions +mentis +mentor +mentored +mentoring +mentors +mentorship +mentorships +mentum +menu +menuhin +menus +meo +meos +meow +meowed +meowing +meows +meperidine +meperidines +mephistophelean +mephistopheles +mephistophelian +mephitic +mephitical +mephitically +mephitis +mephitises +meprobamate +meprobamates +mer +meramec +merbromin +merbromins +mercalli +mercantile +mercantilism +mercantilist +mercantilistic +mercantilists +mercaptan +mercaptans +mercaptopurine +mercaptopurines +mercator +mercedario +mercedes +mercenaries +mercenarily +mercenariness +mercenary +mercer +merceries +mercerization +mercerizations +mercerize +mercerized +mercerizes +mercerizing +mercers +mercery +merchandisable +merchandise +merchandised +merchandiser +merchandisers +merchandises +merchandising +merchandisings +merchandize +merchandized +merchandizes +merchandizing +merchandizings +merchant +merchantability +merchantable +merchantman +merchantmen +merchants +mercia +mercian +mercians +mercies +merciful +mercifully +mercifulness +merciless +mercilessly +mercilessness +mercurate +mercurated +mercurates +mercurating +mercuration +mercurations +mercurial +mercurialism +mercurialisms +mercurially +mercurialness +mercurials +mercuric +mercurochrome +mercurous +mercury +mercutio +mercy +merde +mere +meredith +merely +merengue +merengues +merest +meretricious +meretriciously +meretriciousness +merganser +mergansers +merge +merged +mergence +merger +mergers +merges +merging +meridian +meridians +meridiem +meridional +meridionally +meridionals +meringue +meringues +merino +merinos +meristem +meristematic +meristematically +meristems +meristic +meristically +merit +merited +meriting +meritless +meritocracies +meritocracy +meritocrat +meritocratic +meritocrats +meritorious +meritoriously +meritoriousness +merits +merl +merle +merles +merlin +merlins +merlon +merlons +merlot +merlots +merls +mermaid +mermaids +merman +mermen +meroblastic +meroblastically +merocrine +meromorphic +meromyosin +meromyosins +merope +meropia +meropic +meroplankton +meroplanktonic +meroplanktons +merovingian +merovingians +merowe +merozoite +merozoites +meroë +merrier +merriest +merrily +merrimack +merriment +merriness +merry +merrymaker +merrymakers +merrymaking +merrythought +merrythoughts +merseyside +merthiolate +mesa +mesabi +mesarch +mesas +mescal +mescalero +mescaleros +mescaline +mescals +mesdames +mesdemoiselles +meseemed +meseems +mesembryanthemum +mesembryanthemums +mesencephalic +mesencephalon +mesenchymal +mesenchymatous +mesenchyme +mesenchymes +mesenteric +mesenteries +mesenteritis +mesenteritises +mesenteron +mesenteronic +mesenterons +mesentery +mesh +meshach +meshed +meshes +meshing +meshuga +meshugaas +meshugah +meshugga +meshuggah +meshugge +meshuggener +meshuggeners +meshwork +meshy +mesial +mesially +mesic +mesityl +mesitylene +mesitylenes +mesmer +mesmeric +mesmerically +mesmerism +mesmerist +mesmerists +mesmerization +mesmerizations +mesmerize +mesmerized +mesmerizer +mesmerizers +mesmerizes +mesmerizing +mesne +mesoamerica +mesoamerican +mesoamericans +mesoblast +mesoblastic +mesoblasts +mesocarp +mesocarps +mesocephalic +mesocephally +mesocyclone +mesocyclones +mesoderm +mesodermal +mesodermic +mesogastria +mesogastric +mesogastrium +mesoglea +mesogleal +mesogloea +mesolithic +mesomere +mesomeres +mesomorph +mesomorphic +mesomorphism +mesomorphous +mesomorphs +mesomorphy +meson +mesonephric +mesonephros +mesonephroses +mesonic +mesons +mesopause +mesopauses +mesopelagic +mesophyll +mesophyllic +mesophyllous +mesophylls +mesophyte +mesophytes +mesophytic +mesopotamia +mesopotamian +mesopotamians +mesoscale +mesosome +mesosomes +mesosphere +mesospheric +mesothelia +mesothelial +mesothelioma +mesotheliomas +mesotheliomata +mesothelium +mesothoraces +mesothoracic +mesothorax +mesothoraxes +mesothorium +mesothoriums +mesotrophic +mesozoic +mesquite +mesquites +mess +message +messaged +messages +messaging +messaline +messalines +messed +messeigneurs +messenger +messengered +messengering +messengers +messenia +messenian +messenians +messes +messiah +messiahs +messiahship +messianic +messianism +messianisms +messianist +messianists +messias +messier +messiest +messieurs +messily +messina +messiness +messing +messmate +messmates +messrs +messuage +messuages +messy +mestiza +mestizas +mestizo +mestizoes +mestizos +mestranol +mestranols +met +metabolic +metabolically +metabolism +metabolisms +metabolite +metabolites +metabolizable +metabolize +metabolized +metabolizes +metabolizing +metacarpal +metacarpally +metacarpals +metacarpi +metacarpus +metacenter +metacenters +metacentric +metacentricity +metacentrics +metacercaria +metacercarial +metacercarias +metachromatic +metachromatism +metachromatisms +metaethical +metaethics +metafiction +metafictional +metafictionist +metafictionists +metafictions +metagalactic +metagalaxies +metagalaxy +metagenesis +metagenetic +metagnathism +metagnathous +metal +metalanguage +metalanguages +metaled +metaling +metalinguistic +metalinguistics +metalize +metalized +metalizes +metalizing +metalled +metallic +metallically +metallics +metalliferous +metalline +metalling +metallization +metallizations +metallize +metallized +metallizes +metallizing +metallographer +metallographers +metallographic +metallographically +metallography +metalloid +metalloidal +metalloids +metallophone +metallophones +metallurgic +metallurgical +metallurgically +metallurgist +metallurgists +metallurgy +metalmark +metalmarks +metals +metalsmith +metalsmiths +metalware +metalwork +metalworker +metalworkers +metalworking +metamathematical +metamathematician +metamathematicians +metamathematics +metamere +metameres +metameric +metamerically +metamerism +metamerisms +metamorphic +metamorphically +metamorphism +metamorphose +metamorphosed +metamorphoses +metamorphosing +metamorphosis +metamorphous +metanalyses +metanalysis +metanephric +metanephros +metanephroses +metaphase +metaphases +metaphor +metaphoric +metaphorical +metaphorically +metaphors +metaphosphate +metaphosphates +metaphosphoric +metaphrase +metaphrased +metaphrases +metaphrasing +metaphrast +metaphrastic +metaphrasts +metaphysic +metaphysical +metaphysically +metaphysician +metaphysicians +metaphysics +metaplasia +metaplasias +metaplasm +metaplasmic +metaplasms +metaplastic +metapontum +metaprotein +metaproteins +metapsychological +metapsychology +metasequoia +metasilicate +metasomatic +metasomatically +metasomatism +metasomatosis +metastability +metastable +metastably +metastases +metastasis +metastasize +metastasized +metastasizes +metastasizing +metastatic +metastatically +metatarsal +metatarsally +metatarsals +metatarsi +metatarsus +metate +metates +metatheses +metathesis +metathesize +metathesized +metathesizes +metathesizing +metathetic +metathetical +metathetically +metathoraces +metathoracic +metathorax +metathoraxes +metaxylem +metaxylems +metazoal +metazoan +metazoans +metazoic +mete +meted +metempsychoses +metempsychosis +metencephala +metencephalic +metencephalon +meteor +meteoric +meteorically +meteorite +meteorites +meteoritic +meteoritical +meteoriticist +meteoriticists +meteoritics +meteorograph +meteorographs +meteoroid +meteoroidal +meteoroids +meteorologic +meteorological +meteorologically +meteorologist +meteorologists +meteorology +meteors +meter +metered +metering +meters +meterstick +metersticks +metes +metestrous +metestrus +metestruses +meth +methacrylate +methacrylates +methacrylic +methadon +methadone +methamphetamine +methamphetamines +methanation +methanations +methane +methanol +methaqualone +methaqualones +methedrine +metheglin +metheglins +methemoglobin +methemoglobinemia +methemoglobins +methenamine +methenamines +methicillin +methicillins +methinks +methionine +methionines +method +methodic +methodical +methodically +methodicalness +methodism +methodist +methodistic +methodistical +methodists +methodization +methodizations +methodize +methodized +methodizer +methodizers +methodizes +methodizing +methodological +methodologically +methodologies +methodologist +methodologists +methodology +methods +methotrexate +methotrexates +methought +methoxychlor +methoxychlors +methoxyflurane +methuen +methuselah +methyl +methylal +methylals +methylamine +methylamines +methylase +methylases +methylate +methylated +methylates +methylating +methylation +methylations +methylator +methylators +methylbenzene +methylbenzenes +methylcellulose +methylcelluloses +methylcholanthrene +methyldopa +methyldopas +methylene +methylenes +methylic +methylmercury +methylnaphthalene +methylnaphthalenes +methylphenidate +methylphenidates +methylprednisolone +methylxanthine +methylxanthines +methysergide +methysergides +meticais +metical +meticals +meticulosity +meticulous +meticulously +meticulousness +metier +metiers +meting +metis +metonic +metonym +metonymic +metonymical +metonymically +metonymies +metonyms +metonymy +metoo +metope +metopes +metopic +metopon +metopons +metralgia +metralgias +metrazol +metric +metrical +metrically +metricate +metricated +metricates +metricating +metrication +metricize +metricized +metricizes +metricizing +metrics +metrification +metrifications +metrified +metrifies +metrify +metrifying +metrist +metrists +metritis +metritises +metro +metrological +metrologically +metrologies +metrologist +metrologists +metrology +metronidazole +metronidazoles +metronome +metronomes +metronomic +metronomical +metronomically +metronymic +metroplex +metroplexs +metropolis +metropolises +metropolitan +metropolitans +metrorrhagia +metrorrhagias +metrorrhagic +metros +metternich +mettle +mettled +mettles +mettlesome +metz +meunière +meursault +meuse +mew +mewed +mewing +mewl +mewled +mewling +mewls +mews +mex +mexicali +mexican +mexicans +mexico +meyerbeer +meze +mezereon +mezereons +mezereum +mezereums +mezes +mezuza +mezuzah +mezuzahs +mezuzas +mezuzot +mezza +mezzanine +mezzanines +mezzo +mezzos +mezzotint +mezzotints +mi +miami +miamis +miao +miaos +miaow +miasma +miasmal +miasmas +miasmata +miasmatic +miasmic +miasmically +mica +micaceous +micah +micas +micawber +micawberish +micawbers +miccosukee +miccosukees +mice +micellar +micelle +micelles +mich +michael +michaelis +michaelmas +michaelmases +micheas +michelangelo +michelin +michigan +michigander +michiganders +mick +mickey +mickeys +mickle +micks +micmac +micmacs +micra +micro +microampere +microamperes +microanalyses +microanalysis +microanalyst +microanalysts +microanalytic +microanalytical +microanatomical +microanatomy +microbalance +microbalances +microbar +microbarograph +microbarographs +microbars +microbe +microbeam +microbeams +microbecquerel +microbecquerels +microbes +microbial +microbic +microbiologic +microbiological +microbiologically +microbiologist +microbiologists +microbiology +microbrewer +microbreweries +microbrewers +microbrewery +microbrewing +microburst +microbursts +microbus +microbuses +microbusses +microcalorimeter +microcalorimeters +microcalorimetric +microcalorimetry +microcandela +microcandelas +microcapsule +microcapsules +microcassette +microcassettes +microcavity +microcephalic +microcephalics +microcephalies +microcephalous +microcephaly +microchemical +microchemist +microchemistries +microchemistry +microchemists +microchip +microchips +microcircuit +microcircuitry +microcircuits +microcirculation +microcirculations +microcirculatory +microclimate +microclimates +microclimatic +microclimatologic +microclimatological +microclimatology +microcline +microclines +micrococcal +micrococci +micrococcus +microcode +microcomputer +microcomputers +microcopied +microcopies +microcopy +microcopying +microcosm +microcosmic +microcosmical +microcosmically +microcosmos +microcosms +microcoulomb +microcoulombs +microcrystal +microcrystalline +microcrystallinity +microcrystals +microcultural +microculture +microcultures +microcurie +microcuries +microcyte +microcytes +microcytic +microdensitometer +microdensitometers +microdensitometric +microdensitometry +microdissection +microdissections +microdot +microdots +microearthquake +microearthquakes +microeconomic +microeconomics +microelectrode +microelectrodes +microelectromechanical +microelectronic +microelectronically +microelectronics +microelectrophoresis +microelectrophoretic +microelectrophoretically +microelement +microelements +microencapsulate +microencapsulated +microencapsulates +microencapsulating +microencapsulation +microencapsulations +microenvironment +microenvironmental +microenvironments +microevolution +microevolutionary +microevolutions +microfabrication +microfarad +microfarads +microfauna +microfaunal +microfibril +microfibrillar +microfibrils +microfiche +microfiches +microfilament +microfilamentous +microfilaments +microfilaria +microfilariae +microfilarial +microfilm +microfilmable +microfilmed +microfilmer +microfilmers +microfilming +microfilms +microfloppies +microfloppy +microflora +microfloral +microform +microforms +microfossil +microfossils +microfungi +microfungus +microfunguses +microgamete +microgametes +microgametocyte +microgametocytes +microgram +micrograms +micrograph +micrographic +micrographically +micrographics +micrographs +micrography +microgravity +microgroove +microgrooves +microhabitat +microhabitats +microhenries +microhenry +microhenrys +microhertz +microimage +microimages +microinch +microinches +microinject +microinjected +microinjecting +microinjection +microinjections +microinjects +microinstruction +microinstructions +microjet +microjets +microjoule +microjoules +microkelvin +microkelvins +microlepidoptera +microlepidopterous +microliter +microliters +microlith +microlithic +microlithography +microliths +microlumen +microlumens +microlux +micromachining +micromanage +micromanaged +micromanagement +micromanager +micromanagers +micromanages +micromanaging +micromanipulation +micromanipulations +micromanipulative +micromanipulator +micromanipulators +micromere +micromeres +micrometeorite +micrometeorites +micrometeoritic +micrometeoroid +micrometeoroids +micrometeorological +micrometeorologist +micrometeorologists +micrometeorology +micrometer +micrometers +micromethod +micromethods +micrometric +micrometrical +micrometrically +micrometry +micromini +microminiature +microminiaturization +microminiaturizations +microminiaturize +microminiaturized +microminiaturizes +microminiaturizing +microminis +micromolar +micromole +micromoles +micromorphological +micromorphology +micron +microneedle +microneedles +micronesia +micronesian +micronesians +micronewton +micronewtons +micronize +micronized +micronizes +micronizing +microns +micronuclear +micronuclei +micronucleus +micronucleuses +micronutrient +micronutrients +microohm +microohms +microorganism +microorganisms +micropaleontologic +micropaleontological +micropaleontologist +micropaleontologists +micropaleontology +microparticle +microparticles +micropascal +micropascals +microphage +microphages +microphagic +microphone +microphones +microphonic +microphonics +microphotograph +microphotographer +microphotographers +microphotographic +microphotographs +microphotography +microphotometer +microphotometers +microphotometric +microphotometrically +microphotometry +microphyll +microphyllous +microphylls +microphysical +microphysically +microphysicist +microphysicists +microphysics +microphyte +microphytes +microphytic +micropipet +micropipets +micropipette +micropipettes +microplankton +microplanktons +micropore +micropores +microporosity +microporous +microprint +microprints +microprism +microprisms +microprobe +microprobes +microprocessor +microprocessors +microprogram +microprogramming +microprogrammings +microprograms +microprojection +microprojections +microprojector +microprojectors +micropublisher +micropublishers +micropublishing +micropublishings +micropulsation +micropulsations +micropuncture +micropunctures +micropylar +micropyle +micropyles +microquake +microquakes +microradian +microradians +microradiograph +microradiographic +microradiographs +microradiography +microreader +microreaders +microreproduction +microreproductions +micros +microscale +microscales +microscope +microscopes +microscopic +microscopical +microscopically +microscopies +microscopist +microscopists +microscopium +microscopy +microsecond +microseconds +microseism +microseismic +microseismicity +microseisms +microsensor +microsensors +microsiemens +microsievert +microsieverts +microsoft +microsomal +microsome +microsomes +microsomic +microspectrophotometer +microspectrophotometers +microspectrophotometric +microspectrophotometry +microsphere +microspheres +microspherical +microsporangia +microsporangiate +microsporangium +microspore +microspores +microsporic +microsporocyte +microsporocytes +microsporogenesis +microsporophyll +microsporophylls +microsporous +microstate +microstates +microsteradian +microsteradians +microstructural +microstructure +microstructures +microsurgeries +microsurgery +microsurgical +microswitch +microswitches +microsystems +microteaching +microteachings +microtechnic +microtechnics +microtechnique +microtechniques +microtesla +microteslas +microtome +microtomes +microtomic +microtomies +microtomy +microtonal +microtonality +microtonally +microtone +microtones +microtubular +microtubule +microtubules +microvascular +microvasculature +microvasculatures +microvillar +microvilli +microvillous +microvillus +microvolt +microvolts +microwatt +microwatts +microwavable +microwave +microwaveable +microwaved +microwaves +microwaving +microweber +microwebers +microworld +microworlds +micturate +micturated +micturates +micturating +micturition +micturitions +mid +midair +midas +midbrain +midbrains +midcourse +midcult +midcults +midday +midden +middens +middies +middle +middlebrow +middlebrows +middled +middleman +middlemen +middlemost +middler +middlers +middles +middleton +middleweight +middleweights +middling +middlingly +middlings +middorsal +middy +mideast +mideasterner +mideasterners +midfield +midfielder +midfielders +midfields +midgard +midge +midges +midget +midgets +midgut +midguts +midi +midianite +midianites +midiron +midirons +midis +midland +midlander +midlanders +midlands +midlatitude +midlatitudes +midlevel +midlevels +midlife +midline +midlines +midlives +midlothian +midmonth +midmorning +midmost +midnight +midnightly +midpoint +midpoints +midrange +midranges +midrash +midrashic +midrashim +midrib +midribs +midriff +midriffs +midsagittal +midseason +midsection +midsections +midship +midshipman +midshipmen +midships +midsize +midsized +midsole +midsoles +midst +midstream +midsummer +midterm +midterms +midtown +midtowns +midway +midways +midweek +midweekly +midwest +midwestern +midwesterner +midwesterners +midwife +midwifed +midwifery +midwifes +midwifing +midwinter +midwinters +midwived +midwives +midwiving +midyear +midyears +mien +miens +mieux +miff +miffed +miffier +miffiest +miffiness +miffing +miffs +miffy +might +mightier +mightiest +mightily +mightiness +mightn't +mighty +mignon +mignonette +mignonettes +mignons +migraine +migraines +migrainous +migrant +migrants +migrate +migrated +migrates +migrating +migration +migrational +migrations +migrator +migrators +migratory +mihrab +mihrabs +mikado +mikados +mikasuki +mikasukis +mike +miked +mikes +miking +mikra +mikron +mikrons +mikvah +mikvos +mikvot +mikvoth +mil +miladies +milady +milage +milages +milah +milan +milanese +milano +milch +milchig +mild +milder +mildest +mildew +mildewed +mildewing +mildews +mildewy +mildly +mildness +mile +mileage +mileages +milepost +mileposts +miler +milers +miles +milesian +milesians +milestone +milestones +miletus +milfoil +milfoils +milia +miliaria +miliarial +miliarias +miliary +milieu +milieus +milieux +militance +militancy +militant +militantly +militantness +militants +militaria +militaries +militarily +militarism +militarist +militaristic +militaristically +militarists +militarization +militarizations +militarize +militarized +militarizes +militarizing +military +militate +militated +militates +militating +milites +militia +militiaman +militiamen +militias +milium +milk +milked +milker +milkers +milkfish +milkfishes +milkier +milkiest +milkiness +milking +milkmaid +milkmaids +milkman +milkmen +milks +milkshake +milkshakes +milksop +milksoppy +milksops +milkweed +milkweeds +milkwort +milkworts +milky +mill +millage +millages +millais +millboard +millboards +milldam +milldams +mille +milled +millefiori +millefleur +millefleurs +millenarian +millenarianism +millenarians +millenaries +millenary +millennia +millennial +millennialism +millennialist +millennialists +millennially +millennium +millenniums +millepede +millepedes +millepore +millepores +miller +millerite +millerites +millers +millesimal +millesimally +millesimals +millet +millets +millhouse +millhouses +milliammeter +milliammeters +milliampere +milliamperes +milliard +milliards +milliary +millibar +millibars +millibecquerel +millibecquerels +millicandela +millicandelas +millicoulomb +millicoulombs +millicurie +millicuries +millidegree +millidegrees +millieme +milliemes +millifarad +millifarads +milligal +milligals +milligram +milligrams +millihenries +millihenry +millihenrys +millihertz +millijoule +millijoules +millikelvin +millikelvins +millilambert +millilamberts +milliliter +milliliters +millilitre +millilitres +millilumen +millilumens +millilux +millime +millimeter +millimeters +millimetre +millimetres +millimicron +millimicrons +millimolar +millimole +millimoles +milline +milliner +millineries +milliners +millinery +millines +millinewton +millinewtons +milling +millings +milliohm +milliohms +million +millionaire +millionaires +millionairess +millionairesses +millionfold +millions +millionth +millionths +milliosmol +milliosmols +millipascal +millipascals +millipede +millipedes +milliradian +milliradians +millirem +millirems +milliroentgen +milliroentgens +millisecond +milliseconds +millisiemens +millisievert +millisieverts +millisteradian +millisteradians +millitesla +milliteslas +millivolt +millivoltmeter +millivoltmeters +millivolts +milliwatt +milliwatts +milliweber +milliwebers +millpond +millponds +millrace +millraces +millrun +millruns +mills +millstone +millstones +millstream +millstreams +millwork +millworks +millwright +millwrights +milo +milord +milos +milpa +milpas +milquetoast +milquetoasts +milquetoasty +milreis +milrinone +mils +milt +milted +milter +milters +miltiades +milting +milton +miltonian +miltonic +milts +milwaukee +mim +mimas +mimbres +mime +mimed +mimeo +mimeoed +mimeograph +mimeographed +mimeographing +mimeographs +mimeoing +mimeos +mimer +mimers +mimes +mimeses +mimesis +mimetic +mimetically +mimic +mimicked +mimicker +mimickers +mimicking +mimicries +mimicry +mimics +miming +mimosa +mimosas +min +mina +minable +minacious +minaciously +minaciousness +minacity +minae +minamata +minaret +minarets +minas +minatorial +minatorily +minatory +minaudière +minaudières +mince +minced +mincemeat +mincer +mincers +minces +minch +mincing +mincingly +mind +mindanao +mindblower +mindblowers +minded +mindedly +mindedness +minden +minder +minders +mindful +mindfully +mindfulness +minding +mindless +mindlessly +mindlessness +mindoro +minds +mindscape +mindscapes +mindset +mindsets +mine +mineable +mined +minefield +minefields +minelayer +minelayers +miner +mineral +mineralizable +mineralization +mineralizations +mineralize +mineralized +mineralizer +mineralizers +mineralizes +mineralizing +mineralocorticoid +mineralocorticoids +mineralogic +mineralogical +mineralogically +mineralogies +mineralogist +mineralogists +mineralogy +minerals +miners +minerva +mines +mineshaft +mineshafts +minestrone +minestrones +minesweeper +minesweepers +minesweeping +mineworker +mineworkers +ming +mingier +mingiest +mingle +mingled +mingler +minglers +mingles +mingling +mingy +minho +mini +miniature +miniatures +miniaturist +miniaturistic +miniaturists +miniaturization +miniaturizations +miniaturize +miniaturized +miniaturizes +miniaturizing +minibar +minibars +minibike +minibiker +minibikers +minibikes +minibus +minibuses +minibusses +minicab +minicabs +minicam +minicamp +minicamps +minicams +minicar +minicars +minicomputer +minicomputers +miniconjou +miniconjous +miniconvention +miniconventions +minicourse +minicourses +minicoy +minicycle +minicycles +minidisk +minidisks +minie +minified +minifies +minify +minifying +minikin +minikins +minilab +minilabs +minim +minima +minimal +minimalism +minimalist +minimalists +minimality +minimalization +minimalizations +minimalize +minimalized +minimalizes +minimalizing +minimally +minimax +minimill +minimills +minimization +minimizations +minimize +minimized +minimizer +minimizers +minimizes +minimizing +minims +minimum +minimums +mining +minings +minion +minions +minipark +miniparks +minis +minischool +minischools +miniscule +miniseries +miniski +miniskirt +miniskirted +miniskirts +miniskis +ministate +ministates +minister +ministered +ministerial +ministerially +ministering +ministers +ministership +ministrant +ministrants +ministration +ministrations +ministrative +ministries +ministroke +ministrokes +ministry +minitrack +minitracks +minium +miniums +minivan +minivans +miniver +minivers +minié +mink +minke +minks +minn +minnan +minneapolis +minneconjou +minneconjous +minnesinger +minnesingers +minnesota +minnesotan +minnesotans +minnow +minnows +minoan +minoans +minor +minora +minorca +minorcan +minorcans +minored +minoring +minorite +minorites +minorities +minority +minors +minos +minotaur +minoxidil +minsk +minster +minsters +minstrel +minstrels +minstrelsies +minstrelsy +mint +mintage +minted +minter +minters +minting +mintmark +mintmarks +minton +mints +minty +minuend +minuends +minuet +minuets +minus +minuscular +minuscule +minuses +minute +minuted +minutely +minuteman +minutemen +minuteness +minuter +minutes +minutest +minutia +minutiae +minuting +minx +minxes +minxish +minyan +minyanim +minyans +miocene +mioses +miosis +miotic +miotics +miquelet +miquelets +miquelon +mir +mirabile +mirabiles +mirabilia +mirabilis +miracidia +miracidial +miracidium +miracle +miracles +miraculous +miraculously +miraculousness +mirador +miradors +mirage +mirages +miranda +mirandize +mirandized +mirandizes +mirandizing +mire +mired +mirepoix +mirepoixs +mires +mirex +mirexes +mirier +miriest +mirin +miriness +miring +mirins +mirk +mirks +mirky +mirliton +mirlitons +mirror +mirrored +mirroring +mirrorlike +mirrors +mirs +mirth +mirthful +mirthfully +mirthfulness +mirthless +mirthlessly +mirthlessness +mirv +mirved +mirving +mirvs +miry +miró +misact +misacts +misaddress +misaddressed +misaddresses +misaddressing +misadjust +misadjusted +misadjusting +misadjusts +misadministration +misadministrations +misadventure +misadventures +misadvise +misadvised +misadvises +misadvising +misaim +misaimed +misaiming +misaims +misalign +misaligned +misaligning +misalignment +misalignments +misaligns +misalliance +misalliances +misallied +misallies +misallocate +misallocated +misallocates +misallocating +misallocation +misallocations +misally +misallying +misanalyses +misanalysis +misanthrope +misanthropes +misanthropic +misanthropically +misanthropist +misanthropists +misanthropy +misapplication +misapplications +misapplied +misapplies +misapply +misapplying +misappraisal +misappraisals +misapprehend +misapprehended +misapprehending +misapprehends +misapprehension +misapprehensions +misappropriate +misappropriated +misappropriates +misappropriating +misappropriation +misappropriations +misarrange +misarranged +misarranges +misarranging +misarticulate +misarticulated +misarticulates +misarticulating +misassemble +misassembled +misassembles +misassembling +misassumption +misassumptions +misattribute +misattributed +misattributes +misattributing +misattribution +misattributions +misbalance +misbalanced +misbalances +misbalancing +misbecame +misbecome +misbecomes +misbecoming +misbegotten +misbehave +misbehaved +misbehaver +misbehavers +misbehaves +misbehaving +misbehavior +misbehaviors +misbelief +misbeliefs +misbelieve +misbelieved +misbeliever +misbelievers +misbelieves +misbelieving +misbound +misbrand +misbranded +misbranding +misbrands +misbutton +misbuttoned +misbuttoning +misbuttons +misc +miscalculate +miscalculated +miscalculates +miscalculating +miscalculation +miscalculations +miscall +miscalled +miscalling +miscalls +miscaption +miscaptioned +miscaptioning +miscaptions +miscarriage +miscarriages +miscarried +miscarries +miscarry +miscarrying +miscast +miscasting +miscasts +miscatalog +miscataloged +miscataloging +miscatalogs +miscegenation +miscegenational +miscegenations +miscellanea +miscellaneous +miscellaneously +miscellaneousness +miscellanies +miscellanist +miscellanists +miscellany +misch +mischance +mischannel +mischanneled +mischanneling +mischannels +mischaracterization +mischaracterizations +mischaracterize +mischaracterized +mischaracterizes +mischaracterizing +mischarge +mischarged +mischarges +mischarging +mischief +mischievous +mischievously +mischievousness +mischoice +mischoices +miscibility +miscible +miscitation +miscitations +misclassification +misclassifications +misclassified +misclassifies +misclassify +misclassifying +miscode +miscoded +miscodes +miscoding +miscommunication +miscommunications +miscomprehend +miscomprehended +miscomprehending +miscomprehends +miscomprehension +miscomprehensions +miscomputation +miscomputations +miscompute +miscomputed +miscomputes +miscomputing +misconceive +misconceived +misconceiver +misconceivers +misconceives +misconceiving +misconception +misconceptions +misconduct +misconducted +misconducting +misconducts +misconnect +misconnected +misconnecting +misconnection +misconnections +misconnects +misconstruction +misconstructions +misconstrue +misconstrued +misconstrues +misconstruing +miscopied +miscopies +miscopy +miscopying +miscorrelation +miscorrelations +miscount +miscounted +miscounting +miscounts +miscreant +miscreants +miscreate +miscreated +miscreates +miscreating +miscreation +miscreations +miscue +miscued +miscueing +miscues +miscuing +miscut +misdate +misdated +misdates +misdating +misdeal +misdealer +misdealers +misdealing +misdeals +misdealt +misdeed +misdeeds +misdeem +misdeemed +misdeeming +misdeems +misdefine +misdefined +misdefines +misdefining +misdemeanant +misdemeanants +misdemeanor +misdemeanors +misdemeanour +misdemeanours +misdescribe +misdescribed +misdescribes +misdescribing +misdescription +misdescriptions +misdevelop +misdeveloped +misdeveloping +misdevelops +misdiagnose +misdiagnosed +misdiagnoses +misdiagnosing +misdiagnosis +misdial +misdialed +misdialing +misdialled +misdialling +misdials +misdid +misdirect +misdirected +misdirecting +misdirection +misdirects +misdistribution +misdistributions +misdivision +misdivisions +misdo +misdoer +misdoers +misdoes +misdoing +misdone +misdoubt +misdoubted +misdoubting +misdoubts +misdraw +misdrawing +misdrawn +misdrew +mise +miseducate +miseducated +miseducates +miseducating +miseducation +miseducations +misemphases +misemphasis +misemphasize +misemphasized +misemphasizes +misemphasizing +misemploy +misemployed +misemploying +misemployment +misemployments +misemploys +miser +miserable +miserableness +miserably +miserere +misereres +misericord +misericorde +misericordes +misericords +miseries +miserliness +miserly +misers +misery +misesteem +misesteemed +misesteeming +misesteems +misestimate +misestimated +misestimates +misestimating +misestimation +misestimations +misevaluate +misevaluated +misevaluates +misevaluating +misevaluation +misevaluations +misfeasance +misfeasor +misfeasors +misfield +misfielded +misfielding +misfields +misfile +misfiled +misfiles +misfiling +misfire +misfired +misfires +misfiring +misfit +misfits +misfocus +misfocused +misfocuses +misfocusing +misfortune +misfortunes +misfuel +misfueled +misfueling +misfuelled +misfuelling +misfuels +misfunction +misfunctioned +misfunctioning +misfunctions +misgauge +misgauged +misgauges +misgauging +misgave +misgive +misgiven +misgives +misgiving +misgivings +misgovern +misgoverned +misgoverning +misgovernment +misgovernments +misgovernor +misgovernors +misgoverns +misgrade +misgraded +misgrades +misgrading +misguidance +misguide +misguided +misguidedly +misguidedness +misguider +misguiders +misguides +misguiding +mishandle +mishandled +mishandles +mishandling +mishanter +mishanters +mishap +mishaps +mishear +misheard +mishearing +mishears +mishegaas +mishegoss +mishit +mishits +mishitting +mishmash +mishmashes +mishna +mishnah +mishnaic +misidentification +misidentifications +misidentified +misidentifies +misidentify +misidentifying +misimpression +misimpressions +misinform +misinformant +misinformants +misinformation +misinformed +misinformer +misinformers +misinforming +misinforms +misinterpret +misinterpretation +misinterpretations +misinterpreted +misinterpreter +misinterpreters +misinterpreting +misinterprets +misjoinder +misjoinders +misjudge +misjudged +misjudges +misjudging +misjudgment +misjudgments +miskick +miskicked +miskicking +miskicks +miskito +miskitos +misknew +misknow +misknowing +misknowledge +misknown +misknows +mislabel +mislabeled +mislabeling +mislabelled +mislabelling +mislabels +mislaid +mislay +mislayer +mislayers +mislaying +mislays +mislead +misleader +misleaders +misleading +misleadingly +misleads +mislearn +mislearned +mislearning +mislearns +mislearnt +misled +mislike +misliked +mislikes +misliking +mislocate +mislocated +mislocates +mislocating +mislocation +mislocations +mismanage +mismanaged +mismanagement +mismanages +mismanaging +mismark +mismarked +mismarking +mismarks +mismarriage +mismarriages +mismatch +mismatched +mismatches +mismatching +mismate +mismated +mismates +mismating +misname +misnamed +misnames +misnaming +misnomer +misnomered +misnomers +miso +misogamic +misogamist +misogamists +misogamy +misogynic +misogynist +misogynistic +misogynists +misogynous +misogyny +misologist +misologists +misology +misoneism +misoneist +misoneists +misorder +misordered +misordering +misorders +misorient +misorientation +misoriented +misorienting +misorients +misos +mispackage +mispackaged +mispackages +mispackaging +misperceive +misperceived +misperceives +misperceiving +misperception +misperceptions +mispickel +mispickels +misplace +misplaced +misplacement +misplacements +misplaces +misplacing +misplan +misplanned +misplanning +misplans +misplay +misplayed +misplaying +misplays +misposition +mispositioned +mispositioning +mispositions +misprint +misprinted +misprinting +misprints +misprision +misprisions +misprize +misprized +misprizer +misprizers +misprizes +misprizing +misprogram +misprogramed +misprograming +misprogrammed +misprogramming +misprograms +mispronounce +mispronounced +mispronounces +mispronouncing +mispronunciation +mispronunciations +misquotation +misquotations +misquote +misquoted +misquoter +misquoters +misquotes +misquoting +misread +misreading +misreads +misreckon +misreckoned +misreckoning +misreckons +misrecollection +misrecollections +misrecord +misrecorded +misrecording +misrecords +misreference +misreferenced +misreferences +misreferencing +misregister +misregistered +misregistering +misregisters +misregistration +misregistrations +misrelate +misrelated +misrelates +misrelating +misremember +misremembered +misremembering +misremembers +misrender +misrendered +misrendering +misrenders +misreport +misreported +misreporter +misreporters +misreporting +misreports +misrepresent +misrepresentation +misrepresentations +misrepresentative +misrepresented +misrepresenter +misrepresenters +misrepresenting +misrepresents +misroute +misrouted +misroutes +misrouting +misrule +misruled +misrules +misruling +miss +missa +missable +missal +missals +missed +missend +missending +missends +missense +missenses +missent +misses +misset +missets +missetting +misshape +misshaped +misshapen +misshapenly +misshaper +misshapers +misshapes +misshaping +missies +missile +missileer +missileers +missileman +missilemen +missileries +missilery +missiles +missilries +missilry +missing +missiol +mission +missional +missionaries +missionary +missioned +missioner +missioners +missioning +missionization +missionizations +missionize +missionized +missionizer +missionizers +missionizes +missionizing +missions +missis +missises +mississippi +mississippian +mississippians +missive +missives +missolonghi +missort +missorted +missorting +missorts +missouri +missourian +missourians +missouris +missout +missouts +misspeak +misspeaking +misspeaks +misspell +misspelled +misspelling +misspellings +misspells +misspelt +misspend +misspending +misspends +misspent +misspoke +misspoken +misstate +misstated +misstatement +misstatements +misstates +misstating +misstep +missteps +misstricken +misstrike +misstrikes +misstriking +misstruck +missus +missuses +missy +mist +mistakable +mistakably +mistake +mistaken +mistakenly +mistaker +mistakers +mistakes +mistaking +mistassini +misted +mister +misters +mistflower +mistflowers +misthink +misthinking +misthinks +misthought +misthrew +misthrow +misthrowing +misthrown +misthrows +mistier +mistiest +mistily +mistime +mistimed +mistimes +mistiming +mistiness +misting +mistitle +mistitled +mistitles +mistitling +mistletoe +mistletoes +misto +mistook +mistrain +mistrained +mistraining +mistrains +mistral +mistrals +mistranscribe +mistranscribed +mistranscribes +mistranscribing +mistranscription +mistranscriptions +mistranslate +mistranslated +mistranslates +mistranslating +mistranslation +mistranslations +mistreat +mistreated +mistreating +mistreatment +mistreatments +mistreats +mistress +mistresses +mistrial +mistrials +mistrust +mistrusted +mistrustful +mistrustfully +mistrustfulness +mistrusting +mistrusts +mistruth +mistruths +mists +mistune +mistuned +mistunes +mistuning +misty +mistype +mistyped +mistypes +mistyping +misunderstand +misunderstanding +misunderstandings +misunderstands +misunderstood +misusage +misusages +misuse +misused +misuser +misusers +misuses +misusing +misutilization +misutilizations +misvalue +misvalued +misvalues +misvaluing +misvocalization +misvocalizations +misword +misworded +miswording +miswords +miswrite +miswrites +miswriting +miswritten +miswrote +mitanni +mitannian +mitannians +mitchell +mite +miter +mitered +miterer +miterers +mitering +miters +miterwort +miterworts +mites +mithraic +mithraism +mithraist +mithraists +mithras +mithridate +mithridates +mithridatic +mithridatism +mithridatisms +miticidal +miticide +miticides +mitigable +mitigate +mitigated +mitigates +mitigating +mitigation +mitigations +mitigative +mitigator +mitigators +mitigatory +mitochondria +mitochondrial +mitochondrion +mitogen +mitogenic +mitogenicity +mitogens +mitomycin +mitomycins +mitoses +mitosis +mitotic +mitotically +mitral +mitre +mitred +mitres +mitrewort +mitreworts +mitring +mitsubishi +mitsubishis +mitt +mitten +mittens +mittimus +mitts +mitty +mittyish +mitzvah +mitzvahed +mitzvahing +mitzvahs +mitzvoth +miwok +miwoks +mix +mixable +mixed +mixer +mixers +mixes +mixing +mixologist +mixologists +mixology +mixt +mixtec +mixtecs +mixture +mixtures +mizar +mizen +mizenmast +mizenmasts +mizens +mizoram +mizzen +mizzenmast +mizzenmasts +mizzens +mizzle +mizzled +mizzles +mizzling +mizzly +miño +ml +mlle +mlles +mm +mme +mmes +mnemonic +mnemonically +mnemonics +mnemosyne +moa +moab +moabite +moabites +moabitish +moan +moaned +moaner +moaners +moaning +moans +moas +moat +moated +moating +moatlike +moats +mob +mobbed +mobbing +mobbish +mobbishly +mobcap +mobcaps +mobe +mobil +mobile +mobiles +mobility +mobilization +mobilizations +mobilize +mobilized +mobilizes +mobilizing +mobled +mobocracies +mobocracy +mobocrat +mobocratic +mobocratical +mobocrats +mobs +mobster +mobsters +mobuto +moc +moccasin +moccasins +mocha +mochas +moche +mochica +mock +mocked +mocker +mockeries +mockers +mockery +mocking +mockingbird +mockingbirds +mockingly +mocks +mockup +mockups +mocs +mod +modacrylic +modacrylics +modal +modalities +modality +modally +mode +model +modeled +modeler +modelers +modeless +modeling +modelings +modelled +modelling +models +modem +modems +modena +moderate +moderated +moderately +moderateness +moderates +moderating +moderation +moderations +moderato +moderator +moderators +moderatorship +moderatorships +moderatos +modern +moderne +modernism +modernisms +modernist +modernistic +modernists +modernities +modernity +modernization +modernizations +modernize +modernized +modernizer +modernizers +modernizes +modernizing +modernly +modernness +moderns +modes +modest +modesties +modestly +modesty +modi +modica +modicum +modicums +modifiability +modifiable +modification +modifications +modificative +modificator +modificators +modificatory +modified +modifier +modifiers +modifies +modify +modifying +modigliani +modillion +modillions +modioli +modiolus +modish +modishly +modishness +modiste +modistes +modoc +modocs +modred +mods +modulability +modular +modularity +modularization +modularizations +modularize +modularized +modularizes +modularizing +modularly +modulars +modulate +modulated +modulates +modulating +modulation +modulations +modulative +modulator +modulators +modulatory +module +modules +moduli +modulo +modulus +modus +moesia +mofette +mofettes +moffette +moffettes +mogadishu +mogen +moggie +moggies +moggy +moghul +moghuls +mogollon +mogul +moguls +mohair +mohammed +mohammedan +mohammedanism +mohammedanisms +mohammedans +moharram +mohave +mohaves +mohawk +mohawks +mohegan +mohegans +mohenjo +mohican +mohicans +moho +mohock +mohockism +mohorovicic +mohos +mohs +mohur +mohurs +moidore +moidores +moieties +moiety +moil +moiled +moiler +moilers +moiling +moilingly +moils +moines +moirai +moire +moires +moiré +moist +moisten +moistened +moistener +moisteners +moistening +moistens +moister +moistest +moistly +moistness +moisture +moistures +moisturize +moisturized +moisturizer +moisturizers +moisturizes +moisturizing +mojarra +mojarras +mojave +mojaves +mojo +mojoes +mojos +moke +mokes +mol +mola +molal +molalities +molality +molar +molarities +molarity +molars +molas +molasses +mold +moldable +moldavia +moldavian +moldavians +moldboard +moldboards +molded +molder +moldered +moldering +molders +moldier +moldiest +moldiness +molding +moldings +moldova +moldovan +moldovans +molds +moldy +mole +molecular +molecularity +molecularly +molecule +molecules +molehill +molehills +moles +moleskin +moleskins +molest +molestation +molestations +molested +molester +molesters +molesting +molests +molies +moline +molise +molière +moll +mollie +mollies +mollifiable +mollification +mollifications +mollified +mollifier +mollifiers +mollifies +mollify +mollifying +mollifyingly +molls +mollusc +mollusca +molluscan +molluscicidal +molluscicide +molluscicides +molluscoid +molluscous +molluscs +molluscum +mollusk +molluskan +mollusks +molly +mollycoddle +mollycoddled +mollycoddler +mollycoddlers +mollycoddles +mollycoddling +moloch +molokai +molopo +molotov +mols +molt +molted +molten +molter +molters +molting +molto +molts +moluccan +moluccans +moluccas +moly +molybdate +molybdates +molybdenite +molybdenites +molybdenum +molybdic +molybdous +mom +mombasa +mome +moment +momenta +momentarily +momentariness +momentary +momently +momento +momentous +momentously +momentousness +moments +momentum +momentums +momes +momma +mommas +mommies +mommy +moms +momus +mon +mona +monacan +monacans +monachal +monachism +monachisms +monaco +monad +monadelphous +monadic +monadical +monadically +monadism +monadnock +monadnocks +monads +monandries +monandrous +monandry +monanthous +monarch +monarchal +monarchally +monarchial +monarchian +monarchianism +monarchic +monarchical +monarchically +monarchies +monarchism +monarchist +monarchistic +monarchists +monarchs +monarchy +monarda +monardas +monasterial +monasteries +monasterries +monastery +monastic +monastical +monastically +monasticism +monastics +monatomic +monatomically +monaural +monaurally +monaxial +monazite +monazites +monday +mondays +monde +mondrian +monecious +monel +monensin +monensins +moneran +monerans +monestrous +monet +monetarily +monetarism +monetarist +monetarists +monetary +monetization +monetizations +monetize +monetized +monetizes +monetizing +money +moneybag +moneybags +moneybox +moneyboxes +moneychanger +moneychangers +moneyed +moneyer +moneyers +moneygrubber +moneygrubbers +moneygrubbing +moneylender +moneylenders +moneymaker +moneymakers +moneymaking +moneyman +moneymen +moneys +moneysaving +moneywort +moneyworts +mongeese +monger +mongered +mongering +mongers +mongo +mongol +mongolia +mongolian +mongolians +mongolic +mongolism +mongoloid +mongoloids +mongols +mongoose +mongooses +mongrel +mongrelism +mongrelization +mongrelizations +mongrelize +mongrelized +mongrelizes +mongrelizing +mongrelly +mongrels +monicker +monickers +monied +monies +moniker +monikers +monilial +moniliasis +moniliform +moniliformly +monish +monished +monishes +monishing +monism +monist +monistic +monistically +monists +monition +monitions +monitor +monitored +monitorial +monitorially +monitories +monitoring +monitors +monitorship +monitorships +monitory +monk +monkeries +monkery +monkey +monkeyed +monkeying +monkeylike +monkeypod +monkeypods +monkeys +monkeyshine +monkeyshines +monkfish +monkfishes +monkhood +monkhoods +monkish +monkishly +monkishness +monks +monkshood +monkshoods +mono +monoacid +monoacidic +monoacids +monoamine +monoaminergic +monoamines +monobasic +monocarboxylic +monocarp +monocarpellary +monocarpic +monocarpous +monocarps +monocausal +monocephalic +monocephalous +monoceros +monochasia +monochasial +monochasium +monochord +monochords +monochromat +monochromatic +monochromatically +monochromaticity +monochromatism +monochromator +monochromators +monochromats +monochrome +monochromes +monochromic +monochromist +monochromists +monocle +monocled +monocles +monoclinal +monocline +monoclines +monoclinic +monoclinous +monoclonal +monocoque +monocoques +monocot +monocots +monocotyledon +monocotyledonous +monocotyledons +monocracies +monocracy +monocrat +monocratic +monocrats +monocrystal +monocrystalline +monocrystals +monocular +monocularly +monocultural +monoculture +monocultures +monocycle +monocycles +monocyclic +monocyte +monocytes +monocytic +monocytoid +monocytoses +monocytosis +monodactyl +monodactylous +monodactyls +monodic +monodical +monodically +monodies +monodisperse +monodist +monodists +monodrama +monodramas +monodramatic +monody +monoecious +monoeciously +monoecism +monoester +monoesters +monofilament +monofilaments +monogamic +monogamist +monogamists +monogamous +monogamously +monogamy +monogastric +monogenean +monogeneans +monogenesis +monogenetic +monogenic +monogenically +monogenism +monogenist +monogenistic +monogenists +monogenous +monogerm +monoglot +monoglots +monoglyceride +monoglycerides +monogram +monogramed +monograming +monogrammatic +monogrammed +monogrammer +monogrammers +monogramming +monograms +monograph +monographed +monographer +monographers +monographic +monographically +monographing +monographs +monogynist +monogynists +monogynous +monogyny +monohull +monohulls +monohybrid +monohybrids +monohydrate +monohydrated +monohydrates +monohydric +monohydroxy +monoicous +monolayer +monolayers +monolingual +monolingualism +monolinguals +monolith +monolithic +monolithically +monoliths +monolog +monologged +monologging +monologic +monological +monologist +monologists +monologize +monologized +monologizes +monologizing +monologs +monologue +monologued +monologues +monologuing +monologuist +monologuists +monomania +monomaniac +monomaniacal +monomaniacally +monomaniacs +monomer +monomeric +monomers +monometallic +monometallism +monometallist +monometallists +monometer +monometers +monomial +monomials +monomolecular +monomolecularly +monomorphemic +monomorphic +monomorphism +monomorphous +monongahela +mononuclear +mononucleate +mononucleated +mononucleosis +mononucleotide +mononucleotides +monopetalous +monophagous +monophagy +monophobia +monophobias +monophobic +monophonic +monophonically +monophonies +monophony +monophosphate +monophthong +monophthongal +monophthongs +monophyletic +monophyletically +monophyly +monophysite +monophysites +monophysitic +monophysitism +monoplane +monoplanes +monoplegia +monoplegias +monoplegic +monoploid +monoploids +monopod +monopode +monopodes +monopodia +monopodial +monopodially +monopodium +monopods +monopole +monopoles +monopolies +monopolism +monopolist +monopolistic +monopolistically +monopolists +monopolization +monopolizations +monopolize +monopolized +monopolizer +monopolizers +monopolizes +monopolizing +monopoly +monopropellant +monopropellants +monoprotic +monopsonies +monopsonist +monopsonistic +monopsonists +monopsony +monorail +monorails +monorchid +monorchidism +monorchids +monorhyme +monorhymed +monorhymes +monos +monosaccharide +monosaccharides +monosepalous +monosodium +monosome +monosomes +monosomic +monosomy +monospecific +monospecificity +monospermal +monospermous +monostele +monosteles +monostelic +monostely +monostich +monostiches +monostichous +monostome +monostomous +monostylous +monosyllabic +monosyllabically +monosyllabicity +monosyllable +monosyllables +monosynaptic +monosynaptically +monoterpene +monoterpenes +monotheism +monotheist +monotheistic +monotheistical +monotheistically +monotheists +monothematic +monotint +monotints +monotone +monotones +monotonic +monotonically +monotonicity +monotonies +monotonous +monotonously +monotonousness +monotony +monotrematous +monotreme +monotremes +monotrichate +monotrichic +monotrichous +monotype +monotypes +monotypic +monounsaturate +monounsaturated +monounsaturates +monovalence +monovalency +monovalent +monovular +monoxide +monoxides +monozygotic +monroe +monrovia +mons +monseigneur +monsieur +monsignor +monsignori +monsignorial +monsignors +monsoon +monsoonal +monsoons +monster +monsters +monstrance +monstrances +monstrosities +monstrosity +monstrous +monstrously +monstrousness +montadale +montadales +montage +montaged +montages +montaging +montagnais +montagnard +montagnards +montague +montagues +montaigne +montan +montana +montanan +montanans +montane +montanism +montanist +montanists +montargis +montauk +montauks +monte +montecristo +montego +monteith +monteiths +montenegrin +montenegrins +montenegro +monterey +montero +monteros +monterrey +montes +montesquieu +montessori +montessorian +monteverdi +montevideo +montezuma +montferrat +montfort +montgolfier +montgomery +month +monthlies +monthlong +monthly +months +monticello +monticule +monticules +montmartre +montmorency +montmorillonite +montmorillonites +montmorillonitic +montparnasse +montpelier +montpellier +montrachet +montreal +montreux +montréal +montserrat +monument +monumental +monumentality +monumentalize +monumentalized +monumentalizes +monumentalizing +monumentally +monuments +monuron +monurons +monzonite +monzonites +monzonitic +monégasque +monégasques +moo +mooch +mooched +moocher +moochers +mooches +mooching +mood +moodier +moodiest +moodily +moodiness +moods +moody +mooed +mooing +moola +moolah +moon +moonbeam +moonbeams +moonblind +mooncalf +mooncalves +moonchild +moonchildren +moondust +mooned +mooneye +mooneyed +mooneyes +moonfaced +moonfish +moonfishes +moonflower +moonflowers +moonie +moonier +moonies +mooniest +mooning +moonish +moonishly +moonless +moonlet +moonlets +moonlight +moonlighted +moonlighter +moonlighters +moonlighting +moonlights +moonlike +moonlit +moonquake +moonquakes +moonrise +moonrises +moons +moonscape +moonscapes +moonseed +moonseeds +moonset +moonsets +moonshine +moonshined +moonshiner +moonshiners +moonshines +moonshining +moonstone +moonstones +moonstricken +moonstruck +moonwalk +moonwalked +moonwalker +moonwalkers +moonwalking +moonwalks +moonward +moonwort +moonworts +moony +moor +moorage +moore +moorea +moored +moorfowl +moorfowls +moorhen +moorhens +mooring +moorings +moorish +moorland +moorlands +moors +moos +moose +moosebird +moosebirds +moosehead +mooser +moosewood +moosewoods +moot +mooted +mooting +mootness +moots +mop +mopboard +mopboards +mope +moped +mopeds +moper +mopers +mopes +mopey +moping +mopish +mopishly +mopped +mopper +moppers +moppet +moppets +mopping +mops +moquette +moquettes +mor +mora +morae +morainal +moraine +moraines +morainic +moral +morale +moralism +moralisms +moralist +moralistic +moralistically +moralists +moralities +morality +moralization +moralizations +moralize +moralized +moralizer +moralizers +moralizes +moralizing +morally +morals +moras +morass +morasses +morassy +moratoria +moratorium +moratoriums +moratory +moravia +moravian +moravians +moray +morays +morbid +morbidities +morbidity +morbidly +morbidness +morbific +morbus +morceau +morceaux +mordacious +mordaciously +mordacity +mordancy +mordant +mordanted +mordanting +mordantly +mordants +mordecai +mordent +mordents +mordovia +mordvinia +more +moreen +moreens +morel +morello +morellos +morels +moreover +mores +moresque +moresques +morgan +morgana +morganatic +morganatically +morganite +morganites +morgans +morgen +morgens +morgue +morgues +mori +moribund +moribundity +moribundly +morion +morions +morisco +moriscoes +moriscos +moritz +mormon +mormonism +mormons +morn +mornay +morning +mornings +morns +morny +moro +moroccan +moroccans +morocco +moroccos +moron +moronic +moronically +moronism +moronity +morons +moros +morose +morosely +moroseness +morosity +morph +morphactin +morphactins +morphallaxes +morphallaxis +morphean +morpheme +morphemes +morphemic +morphemically +morphemics +morpheus +morphia +morphias +morphine +morphing +morphinism +morphinisms +morphinist +morphinists +morpho +morphogen +morphogenesis +morphogenetic +morphogenetically +morphogenic +morphogens +morphologic +morphological +morphologically +morphologies +morphologist +morphologists +morphology +morphometric +morphometrically +morphometry +morphophonemic +morphophonemics +morphos +morphoses +morphosis +morphs +morris +morrow +morrows +morse +morsel +morsels +mort +mortadella +mortadellas +mortal +mortalities +mortality +mortally +mortals +mortar +mortarboard +mortarboards +mortared +mortaring +mortarless +mortars +mortem +mortems +mortgage +mortgaged +mortgagee +mortgagees +mortgager +mortgagers +mortgages +mortgaging +mortgagor +mortgagors +mortice +morticed +mortices +mortician +morticians +morticing +mortification +mortifications +mortified +mortifier +mortifiers +mortifies +mortify +mortifying +mortifyingly +mortimer +mortis +mortise +mortised +mortises +mortising +mortmain +mortola +morton +morts +mortuaries +mortuary +morula +morulae +morular +morulation +morulations +mosaic +mosaically +mosaicism +mosaicisms +mosaicist +mosaicists +mosaicked +mosaicking +mosaiclike +mosaics +mosasaur +mosasaurs +moschatel +moschatels +moscow +moselle +moselles +moses +mosey +moseyed +moseying +moseys +mosfet +moshav +moshavim +moslem +moslems +mosotho +mosque +mosques +mosquito +mosquitoes +mosquitoey +mosquitos +moss +mossback +mossbacked +mossbacks +mossbunker +mossbunkers +mossed +mosses +mossgrown +mossier +mossiest +mossiness +mossing +mosslike +mosso +mossy +most +mostaccioli +mostly +mot +mote +motel +motels +motes +motet +motets +moth +mothball +mothballed +mothballing +mothballs +mother +motherboard +motherboards +mothered +motherfucker +motherfuckers +motherfucking +motherhood +motherhouse +motherhouses +mothering +motherings +motherland +motherlands +motherless +motherlessness +motherliness +motherly +mothers +motherwort +motherworts +mothier +mothiest +mothlike +mothproof +mothproofed +mothproofer +mothproofers +mothproofing +mothproofs +moths +mothy +motif +motific +motifs +motile +motility +motion +motional +motioned +motioning +motionless +motionlessly +motionlessness +motions +motivate +motivated +motivates +motivating +motivation +motivational +motivationally +motivations +motivative +motivator +motivators +motive +motived +motiveless +motivelessly +motives +motivic +motiving +motivities +motivity +motley +motleys +motmot +motmots +motocross +motocrosses +motoneuron +motoneurons +motor +motorbike +motorbikes +motorboat +motorboater +motorboaters +motorboating +motorboats +motorbus +motorbuses +motorbusses +motorcade +motorcaded +motorcades +motorcading +motorcar +motorcars +motorcycle +motorcycled +motorcycles +motorcycling +motorcyclist +motorcyclists +motordom +motored +motoric +motorically +motoring +motorist +motorists +motorization +motorizations +motorize +motorized +motorizes +motorizing +motorless +motorman +motormen +motormouth +motormouths +motorola +motors +motortruck +motortrucks +motorway +motorways +mots +mott +motte +mottes +mottle +mottled +mottler +mottlers +mottles +mottling +motto +mottoes +mottos +motts +moue +moues +moufflon +moufflons +mouflon +mouflons +mouillé +moujik +moujiks +moulage +moulages +moulin +moulins +mound +moundbird +moundbirds +mounded +mounding +mounds +mount +mountable +mountain +mountaineer +mountaineered +mountaineering +mountaineers +mountainous +mountainously +mountainousness +mountains +mountainside +mountainsides +mountaintop +mountaintops +mountainy +mountbatten +mountebank +mountebanked +mountebankery +mountebanking +mountebanks +mounted +mounter +mounters +mountie +mounties +mounting +mountings +mounts +mounty +mourn +mourned +mourner +mourners +mournful +mournfully +mournfulness +mourning +mourningly +mourns +mouse +moused +mouser +mousers +mouses +mousetrap +mousetrapped +mousetrapping +mousetraps +mousey +mousier +mousiest +mousily +mousiness +mousing +mousings +mousquetaire +mousquetaires +moussaka +mousse +moussed +mousseline +mousselines +mousses +moussing +moustache +moustaches +moustachio +moustachioed +moustachios +mousterian +mousy +mouth +mouthbreeder +mouthbreeders +mouthed +mouther +mouthers +mouthful +mouthfuls +mouthier +mouthiest +mouthiness +mouthing +mouthings +mouthlike +mouthpart +mouthparts +mouthpiece +mouthpieces +mouths +mouthwash +mouthwashes +mouthwatering +mouthwateringly +mouthy +mouton +moutonnée +moutonnéed +moutonnées +moutons +movability +movable +movableness +movables +movably +move +moveable +moved +moveless +movelessly +movelessness +movement +movements +mover +movers +moves +movie +moviedom +moviedoms +moviegoer +moviegoers +moviegoing +moviemaker +moviemakers +moviemaking +movies +moving +movingly +moviola +moviolas +mow +mowed +mower +mowers +mowing +mown +mows +moxie +moyen +mozambican +mozambicans +mozambique +mozarab +mozarabic +mozarabs +mozart +mozartian +mozartians +mozetta +mozettas +mozo +mozos +mozzarella +mozzetta +mozzettas +mpg +mph +mr +mri +mridanga +mridangam +mrs +ms +msg +mu +much +muchacho +muchachos +muchness +muciferous +mucilage +mucilaginous +mucilaginously +mucin +mucinous +mucins +muck +muckamuck +muckamucks +mucked +mucker +muckers +muckety +muckier +muckiest +muckily +mucking +muckluck +mucklucks +muckrake +muckraked +muckraker +muckrakers +muckrakes +muckraking +mucks +muckworm +muckworms +mucky +mucocutaneous +mucoid +mucoids +mucolytic +mucopeptide +mucopeptides +mucopolysaccharide +mucopolysaccharides +mucoprotein +mucoproteins +mucopurulent +mucosa +mucosae +mucosal +mucosas +mucous +mucoviscidosis +mucro +mucronate +mucronation +mucronations +mucrones +mucus +mud +mudbug +mudbugs +mudded +mudder +mudders +muddied +muddier +muddies +muddiest +muddily +muddiness +mudding +muddle +muddled +muddleheaded +muddleheadedly +muddleheadedness +muddler +muddlers +muddles +muddling +muddly +muddy +muddying +mudfish +mudfishes +mudflat +mudflats +mudflow +mudflows +mudguard +mudguards +mudpack +mudpacks +mudra +mudras +mudroom +mudrooms +muds +mudsill +mudsills +mudskipper +mudskippers +mudslide +mudslides +mudslinger +mudslingers +mudslinging +mudstone +mudstones +mudéjar +mudéjares +muenster +muensters +muesli +mueslis +muezzin +muezzins +muff +muffed +muffin +muffing +muffins +muffle +muffled +muffler +mufflered +mufflers +muffles +muffling +muffs +muffuletta +muffulettas +mufti +muftis +mug +mugful +mugged +muggee +muggees +mugger +muggers +muggier +muggiest +mugginess +mugging +muggings +muggy +mughal +mughals +mugho +mugo +mugs +mugwump +mugwumpery +mugwumps +muhammad +muhammadan +muhammadanism +muhammadanisms +muhammadans +muhammedan +muhammedans +muharram +muharrum +mujahedeen +mujahedeens +mujahedin +mujahedins +mujahideen +mujahideens +mujahidin +mujahidins +mujik +mujiks +mukluk +mukluks +muktuk +mulatto +mulattoes +mulattos +mulberries +mulberry +mulch +mulched +mulches +mulching +mulct +mulcted +mulcting +mulcts +mule +mules +muleskinner +muleskinners +muleta +muletas +muleteer +muleteers +muley +muleys +mulhacén +muliebrity +mulish +mulishly +mulishness +mull +mulla +mullah +mullahism +mullahs +mullas +mulled +mullein +mulleins +mullen +mullens +muller +mullerian +mullers +mullet +mullets +mulligan +mulligans +mulligatawnies +mulligatawny +mulling +mullion +mullioned +mullions +mullite +mullites +mulls +multi +multiaddress +multiage +multiagency +multiarmed +multiatom +multiauthor +multiaxial +multiband +multibank +multibarrel +multibarreled +multibillion +multibillionaire +multibillionaires +multibladed +multibranched +multibuilding +multicampus +multicar +multicarbon +multicausal +multicell +multicelled +multicellular +multicellularity +multicellulocentric +multicenter +multichain +multichambered +multichannel +multicharacter +multicity +multiclient +multicoated +multicolor +multicolored +multicolumn +multicomponent +multiconductor +multicopy +multicounty +multicourse +multicultural +multiculturalism +multicurie +multicurrency +multidentate +multidialectal +multidimensional +multidimensionality +multidirectional +multidisciplinary +multidiscipline +multidivisional +multidomain +multidrug +multielectrode +multielement +multiemployer +multiengine +multienzyme +multiethnic +multifaceted +multifactor +multifactorial +multifactorially +multifamily +multifarious +multifariously +multifariousness +multifid +multifilament +multiflash +multiflora +multiflorous +multifocal +multifoil +multifoils +multifold +multiform +multiformity +multifrequency +multifunction +multifunctional +multigenerational +multigenic +multigerm +multigrade +multigrain +multigravida +multigravidas +multigrid +multigrooved +multigroup +multihandicapped +multiheaded +multihospital +multihued +multihull +multilane +multilateral +multilateralism +multilateralist +multilateralists +multilaterally +multilayer +multilayered +multilevel +multileveled +multiline +multilingual +multilingualism +multilingually +multilobed +multilocular +multimanned +multimedia +multimegaton +multimegawatt +multimember +multimetallic +multimillennial +multimillion +multimillionaire +multimillionaires +multimodal +multimode +multimolecular +multination +multinational +multinationalism +multinationals +multinomial +multinomials +multinuclear +multinucleate +multinucleated +multiorgasmic +multipack +multipacks +multipage +multipaned +multipara +multiparae +multiparameter +multiparas +multiparity +multiparous +multipart +multiparticle +multipartite +multiparty +multipath +multiped +multipede +multiphase +multiphasic +multiphoton +multipicture +multipiece +multipion +multipiston +multiplant +multiplayer +multiple +multiples +multiplet +multiplets +multiplex +multiplexed +multiplexer +multiplexers +multiplexes +multiplexing +multiplexor +multiplexors +multipliable +multiplicable +multiplicand +multiplicands +multiplicate +multiplication +multiplicational +multiplications +multiplicative +multiplicatively +multiplicities +multiplicity +multiplied +multiplier +multipliers +multiplies +multiply +multiplying +multipoint +multipolar +multipolarity +multipole +multiport +multipotential +multipower +multiproblem +multiprocessing +multiprocessor +multiprocessors +multiproduct +multiprogramming +multipronged +multipurpose +multiracial +multiracialism +multiracialisms +multirange +multiregional +multireligious +multiroom +multiscreen +multisense +multisensory +multiservice +multisided +multisite +multisize +multiskilled +multisource +multispecies +multispectral +multispeed +multisport +multisports +multistage +multistate +multistemmed +multistep +multistoried +multistory +multistranded +multisyllabic +multisystem +multitalented +multitask +multitasked +multitasking +multitasks +multiterminal +multithreaded +multitiered +multiton +multitone +multitowered +multitrack +multitracked +multitracking +multitrillion +multitude +multitudes +multitudinous +multitudinously +multitudinousness +multiunion +multiunit +multiuse +multiuser +multivalence +multivalent +multivariable +multivariate +multiversities +multiversity +multivitamin +multivitamins +multivoltine +multivolume +multiwall +multiwarhead +multiwavelength +multiword +multiyear +multnomah +multure +multures +mum +mumble +mumbled +mumbler +mumblers +mumbles +mumblety +mumbling +mumbly +mumbo +mummed +mummer +mummeries +mummers +mummery +mummichog +mummichogs +mummies +mummification +mummifications +mummified +mummifies +mummify +mummifying +mumming +mummy +mump +mumped +mumps +mums +munch +munchausen +munched +muncher +munchers +munches +munchhausen +munchies +munching +munchkin +munchkins +munda +mundane +mundanely +mundaneness +mundanity +mundungus +mung +mungo +mungos +muni +munich +municipal +municipalities +municipality +municipalization +municipalizations +municipalize +municipalized +municipalizes +municipalizing +municipally +municipals +munificence +munificent +munificently +muniment +muniments +munis +munition +munitioned +munitioning +munitions +munsee +munsees +munster +munsters +muntin +muntins +muntjac +muntjacs +muntjak +muntjaks +muon +muonic +muonium +muons +muppie +muppies +mural +muraled +muralist +muralists +muralled +murals +muramic +murat +murchison +murder +murdered +murderee +murderees +murderer +murderers +murderess +murderesses +murdering +murderous +murderously +murderousness +murders +murein +mureins +murex +murexes +muriate +muriates +muriatic +muricate +muricated +murices +murid +murids +murine +murines +murk +murkier +murkiest +murkily +murkiness +murks +murky +murmansk +murmur +murmured +murmurer +murmurers +murmuring +murmuringly +murmurous +murmurously +murmurs +murphies +murphy +murrain +murrains +murray +murre +murres +murrey +murreys +murrumbidgee +murther +murthered +murthering +murthers +musca +muscadet +muscadets +muscadine +muscadines +muscae +muscarine +muscarines +muscarinic +muscat +muscatel +muscatels +muscats +muscid +muscids +muscle +musclebound +muscled +muscleman +musclemen +muscles +muscling +muscly +muscovite +muscovites +muscovy +muscular +muscularity +muscularly +musculature +musculoskeletal +muse +mused +museological +museologically +museologist +museologists +museology +muser +musers +muses +musette +musettes +museum +museumgoer +museumgoers +museums +mush +mushed +musher +mushers +mushes +mushier +mushiest +mushily +mushiness +mushing +mushroom +mushroomed +mushrooming +mushrooms +mushy +music +musical +musicale +musicales +musicality +musicalization +musicalizations +musicalize +musicalized +musicalizes +musicalizing +musically +musicals +musician +musicianly +musicians +musicianship +musicological +musicologically +musicologist +musicologists +musicology +musing +musingly +musings +musique +musk +muskeg +muskegs +muskellunge +muskellunges +muskelunge +muskelunges +musket +musketeer +musketeers +musketry +muskets +muskhogean +muskhogeans +muskie +muskier +muskies +muskiest +muskiness +muskingum +muskmelon +muskmelons +muskogean +muskogeans +muskogee +muskogees +muskox +muskoxen +muskrat +muskrats +muskroot +muskroots +musky +muslim +muslims +muslin +muslins +musquash +musquashes +musquashs +muss +mussalman +mussed +mussel +mussels +musses +mussier +mussiest +mussily +mussiness +mussing +mussolini +mussorgsky +mussulman +mussulmans +mussulmen +mussy +must +mustache +mustached +mustaches +mustachio +mustachioed +mustachios +mustang +mustangs +mustard +mustards +mustardy +musteline +muster +mustered +mustering +musters +musth +musths +mustier +mustiest +mustily +mustiness +mustn +mustn't +musts +musty +mutability +mutable +mutableness +mutably +mutagen +mutageneses +mutagenesis +mutagenic +mutagenically +mutagenicity +mutagenize +mutagenized +mutagenizes +mutagenizing +mutagens +mutandis +mutant +mutants +mutase +mutases +mutate +mutated +mutates +mutating +mutation +mutational +mutationally +mutations +mutatis +mutative +mutchkin +mutchkins +mute +muted +mutedly +mutely +muteness +muter +mutes +mutest +mutilate +mutilated +mutilates +mutilating +mutilation +mutilations +mutilative +mutilator +mutilators +mutine +mutined +mutineer +mutineers +mutines +muting +mutinied +mutinies +mutining +mutinous +mutinously +mutinousness +mutiny +mutinying +mutism +mutisms +muton +mutons +mutt +mutter +muttered +mutterer +mutterers +muttering +mutterings +mutters +mutton +muttonchops +muttonfish +muttonfishes +muttonhead +muttonheaded +muttonheads +muttons +muttony +mutts +mutual +mutualism +mutualisms +mutualist +mutualistic +mutualists +mutuality +mutualization +mutualizations +mutualize +mutualized +mutualizes +mutualizing +mutually +mutuals +mutuel +mutuels +muumuu +muumuus +muzak +muzhik +muzhiks +muzjik +muzjiks +muztag +muztagata +muztagh +muzzier +muzziest +muzzily +muzziness +muzzle +muzzled +muzzleloader +muzzleloaders +muzzleloading +muzzler +muzzlers +muzzles +muzzling +muzzy +mv +my +myalgia +myalgic +myanmar +myasthenia +myasthenic +myc +mycelia +mycelial +mycelium +mycenae +mycenaean +mycenaeans +mycenian +mycenians +mycetoma +mycetomas +mycetomata +mycetomatous +mycetophagous +mycetozoan +mycetozoans +mycobacteria +mycobacterial +mycobacterium +mycoflora +mycologic +mycological +mycologically +mycologies +mycologist +mycologists +mycology +mycophagist +mycophagists +mycophagous +mycophagy +mycophile +mycophiles +mycoplasma +mycoplasmal +mycoplasmas +mycorhiza +mycorrhiza +mycorrhizae +mycorrhizal +mycorrhizas +mycoses +mycosis +mycotic +mycotoxicoses +mycotoxicosis +mycotoxin +mycotoxins +mycs +mydriasis +mydriatic +mydriatics +myelencephalic +myelencephalon +myelencephalons +myelin +myelinated +myelination +myelinations +myeline +myelines +myelinic +myelinization +myelinizations +myelinize +myelinized +myelinizes +myelinizing +myelins +myelitis +myeloblast +myeloblastic +myeloblasts +myelocyte +myelocytes +myelocytic +myelofibroses +myelofibrosis +myelofibrotic +myelogenic +myelogenous +myelogram +myelograms +myelography +myeloid +myeloma +myelomas +myelomata +myelomatoid +myelomatous +myelopathic +myelopathy +myeloproliferative +myiases +myiasis +mykonos +mylar +mylonite +mylonites +myna +mynah +mynahs +mynas +mynheer +mynheers +myoblast +myoblasts +myocardia +myocardial +myocarditis +myocarditises +myocardium +myoclonic +myoclonus +myoclonuses +myoelectric +myoelectrical +myofibril +myofibrillar +myofibrils +myofilament +myofilaments +myogenetic +myogenic +myoglobin +myoglobins +myograph +myographs +myoinositol +myoinositols +myologic +myologist +myologists +myology +myoma +myomas +myomata +myomatous +myoneural +myopathic +myopathies +myopathy +myope +myopes +myopia +myopic +myopically +myosin +myosis +myositis +myositises +myosotis +myosotises +myotic +myotome +myotomes +myotonia +myotonias +myotonic +myriad +myriads +myriapod +myriapodous +myriapods +myriopod +myriopods +myristic +myrmecological +myrmecologist +myrmecologists +myrmecology +myrmecophile +myrmecophiles +myrmecophilous +myrmecophily +myrmidon +myrmidons +myrobalan +myrobalans +myrrh +myrtle +myself +mysia +mysian +mysians +mysid +mysids +mysophobia +mysophobias +mysore +mystagogic +mystagogue +mystagogues +mystagogy +mysteries +mysterious +mysteriously +mysteriousness +mystery +mystic +mystical +mystically +mysticalness +mysticete +mysticetes +mysticetous +mysticism +mystics +mystification +mystified +mystifier +mystifiers +mystifies +mystify +mystifying +mystifyingly +mystique +mystiques +myth +mythic +mythical +mythically +mythicize +mythicized +mythicizer +mythicizers +mythicizes +mythicizing +mythmaker +mythmakers +mythmaking +mythographer +mythographers +mythographies +mythography +mythoi +mythologer +mythologers +mythologic +mythological +mythologically +mythologies +mythologist +mythologists +mythologize +mythologized +mythologizer +mythologizers +mythologizes +mythologizing +mythology +mythomania +mythomaniac +mythomanias +mythopeic +mythopoeia +mythopoeic +mythopoesis +mythopoetic +mythopoetical +mythos +myths +mythy +myxameba +myxamoeba +myxamoebae +myxamoebas +myxedema +myxedemas +myxedematous +myxedemic +myxobacteria +myxobacterium +myxoedema +myxoedemas +myxoid +myxoma +myxomas +myxomata +myxomatoses +myxomatosis +myxomatous +myxomycete +myxomycetes +myxoviral +myxovirus +myxoviruses +málaga +mâche +mâches +mâché +mâcon +mälaren +märchen +médaillon +médaillons +médoc +mélange +mélanges +ménage +ménages +ménière +mérida +mérite +mésalliance +mésalliances +métier +métiers +métis +mêlée +mêlées +même +míkonos +mílos +möbius +mössbauer +müller +müllerian +münster +n +n'djamena +n'gana +n'ganas +naan +nab +nabataea +nabataean +nabataeans +nabatean +nabateans +nabbed +nabber +nabbers +nabbing +nabe +nabes +nabob +nabobs +nabokov +naboth +nabs +nacelle +nacelles +nacho +nachos +nacre +nacred +nacreous +nacres +nada +nadir +nadirs +nadu +naff +naffed +naffing +naffs +nag +naga +nagaland +nagana +naganas +nagar +nagas +nagasaki +nagged +nagger +naggers +nagging +naggingly +nags +nah +nahuatl +nahuatlan +nahuatls +nahum +naiad +naiades +naiads +naif +naifs +nail +nailbrush +nailbrushes +nailed +nailer +nailers +nailing +nails +nainsook +naipaul +naira +nairas +nairobi +naive +naively +naiveness +naiveties +naivety +naiveté +naked +nakedly +nakedness +naled +naleds +nalidixic +nalorphine +nalorphines +naloxone +naloxones +naltrexone +naltrexones +nam +nama +namable +namaland +namaqualand +namas +namaycush +namaycushes +namby +name +nameable +named +nameless +namelessly +namelessness +namely +nameplate +nameplates +namer +namers +names +namesake +namesakes +nametag +nametags +nametape +nametapes +namib +namibia +namibian +namibians +naming +nan +nana +nanak +nanas +nance +nances +nancy +nandina +nanism +nanisms +nankeen +nankeens +nankin +nanking +nankins +nannie +nannies +nannofossil +nannofossils +nannoplankton +nannoplanktons +nanny +nannyberries +nannyberry +nannyish +nanoampere +nanoamperes +nanobecquerel +nanobecquerels +nanocandela +nanocandelas +nanocoulomb +nanocoulombs +nanoengineering +nanofarad +nanofarads +nanofossil +nanofossils +nanogram +nanograms +nanohenries +nanohenry +nanohenrys +nanohertz +nanojoule +nanojoules +nanokelvin +nanokelvins +nanolumen +nanolumens +nanolux +nanometer +nanometers +nanomole +nanomoles +nanonewton +nanonewtons +nanoohm +nanoohms +nanopascal +nanopascals +nanoplankton +nanoplanktons +nanoradian +nanoradians +nanosecond +nanoseconds +nanosiemens +nanosievert +nanosieverts +nanosteradian +nanosteradians +nanotechnology +nanotesla +nanoteslas +nanovolt +nanovolts +nanowatt +nanowatts +nanoweber +nanowebers +nansen +nanterre +nantes +nanticoke +nanticokes +nantua +nantucket +nantucketer +nantucketers +naoise +naomi +nap +napa +napalm +napalmed +napalming +napalms +napas +nape +naperies +naperville +napery +napes +naphtali +naphtha +naphthalene +naphthalenes +naphthalenic +naphthalin +naphthaline +naphthalines +naphthalins +naphthas +naphthene +naphthenes +naphthenic +naphthol +naphthols +naphthous +naphthylamine +naphthylamines +naphtol +naphtols +napier +napierian +napiform +napkin +napkins +naples +napless +napoleon +napoleonic +napoleons +napoli +napoléon +nappa +nappas +nappe +napped +nappes +nappier +nappies +nappiest +napping +nappy +naprapath +naprapathies +naprapaths +naprapathy +naproxen +naproxens +naps +naptime +naptimes +narbonne +narc +narceine +narceines +narcism +narcisms +narcissi +narcissism +narcissisms +narcissist +narcissistic +narcissistically +narcissists +narcissus +narcissuses +narco +narcoanalyses +narcoanalysis +narcoanalytic +narcodollar +narcodollars +narcokleptocracies +narcokleptocracy +narcolepsies +narcolepsy +narcoleptic +narcoma +narcomas +narcomata +narcos +narcoses +narcosis +narcosyntheses +narcosynthesis +narcotic +narcotically +narcotics +narcotism +narcotisms +narcotization +narcotizations +narcotize +narcotized +narcotizes +narcotizing +narcs +nard +nards +nares +narghile +narghiles +nargileh +nargilehs +narial +naris +nark +narked +narking +narks +narraganset +narragansets +narragansett +narragansetts +narratability +narratable +narrate +narrated +narrater +narraters +narrates +narrating +narration +narrational +narrationally +narrations +narrative +narratively +narratives +narratological +narratologist +narratologists +narratology +narrator +narrators +narrow +narrowback +narrowbacks +narrowband +narrowcast +narrowcaster +narrowcasters +narrowcasting +narrowcasts +narrowed +narrower +narrowest +narrowing +narrowish +narrowly +narrowness +narrows +narthex +narthexes +narváez +narwal +narwals +narwhal +narwhale +narwhales +narwhals +nary +nasal +nasality +nasalization +nasalizations +nasalize +nasalized +nasalizes +nasalizing +nasally +nasals +nascence +nascency +nascent +naseberries +naseberry +naseby +nashville +nasion +nasions +naskapi +naskapis +nasofrontal +nasogastric +nasopharyngeal +nasopharynges +nasopharynx +nasopharynxes +nassau +nastic +nastier +nasties +nastiest +nastily +nastiness +nasturtium +nasturtiums +nasty +natal +natalities +natality +natant +natation +natations +natatorial +natatorium +natatory +natch +natchez +nates +nathan +nathanael +natheless +nathless +natick +naticks +nation +national +nationalism +nationalist +nationalistic +nationalistically +nationalists +nationalities +nationality +nationalization +nationalizations +nationalize +nationalized +nationalizer +nationalizers +nationalizes +nationalizing +nationally +nationals +nationhood +nationless +nations +nationwide +native +natively +nativeness +natives +nativism +nativisms +nativist +nativistic +nativists +nativities +nativity +nato +natriureses +natriuresis +natriuretic +natrolite +natrolites +natron +natrons +natter +nattered +nattering +natters +nattier +nattiest +nattily +nattiness +natty +naturae +natural +naturalism +naturalist +naturalistic +naturalistically +naturalists +naturalizable +naturalization +naturalizations +naturalize +naturalized +naturalizes +naturalizing +naturally +naturalness +naturals +nature +natured +naturedly +naturedness +naturel +natures +naturism +naturist +naturists +naturopath +naturopathic +naturopathies +naturopaths +naturopathy +naugahyde +naught +naughtier +naughties +naughtiest +naughtily +naughtiness +naughts +naughty +naumachia +naumachiae +naumachias +nauplial +nauplii +nauplius +nauru +nauruan +nauruans +nausea +nauseam +nauseant +nauseants +nauseate +nauseated +nauseates +nauseating +nauseatingly +nauseation +nauseations +nauseous +nauseously +nauseousness +nausicaa +nautch +nautical +nautically +nautili +nautiloid +nautiloids +nautilus +nautiluses +navaho +navahos +navaid +navaids +navajo +navajos +naval +navarre +nave +navel +navels +navelwort +navelworts +naves +navicular +naviculars +navies +navigability +navigable +navigableness +navigably +navigate +navigated +navigates +navigating +navigation +navigational +navigationally +navigations +navigator +navigators +navvies +navvy +navy +nawab +nawabs +naxos +nay +nays +naysaid +naysay +naysayer +naysayers +naysaying +naysays +nazarene +nazarenes +nazareth +nazarite +nazarites +naze +nazi +nazification +nazifications +nazify +naziism +nazirite +nazirites +naziritism +nazis +nazism +naïf +naïfs +naïve +naïvely +naïver +naïvest +naïvety +naïveté +naïvetés +nco +ncos +ncr +ndebele +ndebeles +ndjamena +ndongo +ndongos +ne +ne'er +neandertal +neanderthal +neanderthaloid +neanderthals +neanthropic +neap +neapolitan +neapolitans +neaps +near +nearby +nearctic +neared +nearer +nearest +nearing +nearly +nearness +nears +nearshore +nearside +nearsighted +nearsightedly +nearsightedness +neat +neaten +neatened +neatening +neatens +neater +neatest +neath +neatherd +neatly +neatness +neats +neb +nebbish +nebbishes +nebbishy +nebenkern +nebenkerns +nebraska +nebraskan +nebraskans +nebs +nebuchadnezzar +nebuchadnezzars +nebula +nebulae +nebular +nebulas +nebulization +nebulizations +nebulize +nebulized +nebulizer +nebulizers +nebulizes +nebulizing +nebulosities +nebulosity +nebulous +nebulously +nebulousness +necessaries +necessarily +necessary +necessitarian +necessitarianism +necessitarians +necessitate +necessitated +necessitates +necessitating +necessitation +necessitations +necessitative +necessities +necessitous +necessitously +necessitousness +necessity +neck +neckband +neckbands +necked +neckerchief +neckerchiefs +neckerchieves +necking +neckings +necklace +necklaces +neckless +neckline +necklines +neckpiece +neckpieces +necks +necktie +neckties +neckwear +necrobiosis +necrobiotic +necrologic +necrological +necrologies +necrologist +necrologists +necrology +necromancer +necromancers +necromancy +necromantic +necromantically +necrophagia +necrophagias +necrophagous +necrophile +necrophiles +necrophilia +necrophiliac +necrophiliacs +necrophilic +necrophilism +necrophobia +necrophobias +necrophobic +necropoleis +necropolis +necropolises +necropsied +necropsies +necropsing +necropsy +necrose +necrosed +necroses +necrosing +necrosis +necrotic +necrotize +necrotized +necrotizes +necrotizing +necrotomies +necrotomy +nectar +nectarial +nectaries +nectarine +nectarines +nectarous +nectars +nectary +nee +need +needed +needful +needfully +needfulness +needier +neediest +neediness +needing +needle +needlecraft +needlecrafts +needled +needlefish +needlefishes +needlelike +needlepoint +needlepointed +needlepointing +needlepoints +needler +needlers +needles +needless +needlessly +needlessness +needlewoman +needlewomen +needlework +needleworker +needleworkers +needling +needn +needn't +needs +needy +neem +neems +nefarious +nefariously +nefariousness +nefertiti +nefyn +negate +negated +negater +negaters +negates +negating +negation +negational +negations +negative +negatived +negatively +negativeness +negatives +negativing +negativism +negativist +negativistic +negativists +negativity +negator +negators +negatory +negatron +negatrons +negev +neglect +neglected +neglecter +neglecters +neglectful +neglectfully +neglectfulness +neglecting +neglects +negligee +negligees +negligence +negligent +negligently +negligibility +negligible +negligibleness +negligibly +negligé +negligée +negligées +negligés +negotiability +negotiable +negotiably +negotiant +negotiants +negotiate +negotiated +negotiates +negotiating +negotiation +negotiations +negotiator +negotiators +negotiatory +negress +negresses +negrillo +negrilloes +negrillos +negrito +negritoes +negritos +negritude +negro +negroes +negroid +negroids +negroness +negrophile +negrophiles +negrophilism +negrophobe +negrophobes +negrophobia +negros +negus +neguses +nehemiah +nehemias +nehru +neigh +neighbor +neighbored +neighborhood +neighborhoods +neighboring +neighborliness +neighborly +neighbors +neighed +neighing +neighs +neither +nekton +nektonic +nektons +nellie +nellies +nelly +nellyism +nelson +nelsons +nem +nematic +nematicidal +nematicide +nematicides +nematocidal +nematocide +nematocides +nematocyst +nematocystic +nematocysts +nematode +nematodes +nematological +nematologist +nematologists +nematology +nembutal +nemean +nemeans +nemertean +nemerteans +nemertine +nemertines +nemeses +nemesis +nemophila +nemophilas +nene +nenes +nenets +nennius +neo +neoarsphenamine +neoarsphenamines +neoclassic +neoclassical +neoclassicism +neoclassicist +neoclassicists +neocolonial +neocolonialism +neocolonialist +neocolonialists +neocon +neocons +neoconservatism +neoconservative +neoconservatives +neocortex +neocortexes +neocortical +neocortices +neodymium +neofascism +neofascist +neofascists +neogaea +neogaean +neogaeas +neogea +neogeas +neogenesis +neogenetic +neoimpressionism +neoimpressionist +neoimpressionists +neoliberal +neoliberalism +neoliberals +neolith +neolithic +neoliths +neological +neologically +neologies +neologism +neologisms +neologist +neologistic +neologistical +neologists +neologize +neologized +neologizes +neologizing +neology +neomycin +neon +neonatal +neonatally +neonate +neonates +neonatologist +neonatologists +neonatology +neoned +neoorthodox +neoorthodoxy +neopallia +neopallium +neopalliums +neophilia +neophiliac +neophiliacs +neophyte +neophytes +neoplasia +neoplasias +neoplasm +neoplasms +neoplastic +neoplasticism +neoplasticist +neoplasticists +neoplatonic +neoplatonism +neoplatonist +neoplatonists +neoprene +neoptolemus +neorealism +neorealist +neorealistic +neorealists +neorican +neoricans +neostigmine +neostigmines +neotenic +neotenies +neotenous +neoteny +neoteric +neoterics +neotropic +neotropical +neotropics +neotype +neotypes +nepal +nepalese +nepali +nepalis +nepenthe +nepenthean +nepenthes +nepheline +nephelines +nephelinic +nephelinite +nephelinites +nephelinitic +nephelite +nephelites +nephelometer +nephelometers +nephelometric +nephelometrically +nephelometry +nephew +nephews +nephological +nephology +nephoscope +nephoscopes +nephrectomies +nephrectomize +nephrectomized +nephrectomizes +nephrectomizing +nephrectomy +nephric +nephridia +nephridial +nephridium +nephrite +nephrites +nephritic +nephritides +nephritis +nephritises +nephrogenic +nephrogenous +nephrologist +nephrologists +nephrology +nephron +nephrons +nephropathic +nephropathies +nephropathy +nephroses +nephrosis +nephrostome +nephrostomes +nephrotic +nephrotomies +nephrotomy +nephrotoxic +nephrotoxicity +nepotism +nepotist +nepotistic +nepotistical +nepotists +neptune +neptunian +neptunium +neral +nerals +nerd +nerdish +nerds +nerdy +nereid +nereides +nereids +nereis +nereus +neritic +nero +nerol +neroli +nerols +neronian +nerts +nervate +nervation +nervations +nerve +nerved +nerveless +nervelessly +nervelessness +nerves +nervier +nerviest +nervily +nerviness +nerving +nervosa +nervosity +nervous +nervously +nervousness +nervure +nervures +nervy +nescience +nesciences +nescient +nescients +ness +nesselrode +nesselrodes +nesses +nessus +nest +nested +nester +nesters +nesting +nestle +nestled +nestler +nestlers +nestles +nestling +nestlings +nestor +nestorian +nestorianism +nestorians +nestorius +nestors +nests +net +netback +netbacks +nether +netherlander +netherlanders +netherlandish +netherlands +nethermost +netherworld +netherworldly +netherworlds +netkeeper +netkeepers +netless +netlike +netminder +netminders +nets +netsuke +netsukes +netted +netter +netters +netting +nettle +nettled +nettles +nettlesome +nettling +netty +network +networked +networker +networkers +networking +networkings +networks +netzahualcóyotl +neuchâtel +neufchâtel +neum +neumatic +neume +neumes +neums +neural +neuralgia +neuralgic +neurally +neuraminidase +neuraminidases +neurasthenia +neurasthenic +neurasthenically +neurasthenics +neurectomies +neurectomy +neurilemma +neurilemmal +neurilemmas +neuristor +neuristors +neuritic +neuritis +neuroanatomical +neuroanatomies +neuroanatomist +neuroanatomists +neuroanatomy +neurobiological +neurobiologist +neurobiologists +neurobiology +neuroblast +neuroblastoma +neuroblastomas +neuroblastomata +neuroblasts +neurochemical +neurochemist +neurochemistry +neurochemists +neuroendocrine +neuroendocrinological +neuroendocrinologist +neuroendocrinologists +neuroendocrinology +neurofibril +neurofibrillary +neurofibrils +neurofibroma +neurofibromas +neurofibromata +neurofibromatoses +neurofibromatosis +neurofilament +neurofilamentous +neurofilaments +neurogeneses +neurogenesis +neurogenetics +neurogenic +neurogenically +neuroglia +neuroglial +neurohormonal +neurohormone +neurohormones +neurohypophyseal +neurohypophyses +neurohypophysial +neurohypophysis +neuroimaging +neuroleptic +neuroleptics +neurologic +neurological +neurologically +neurologist +neurologists +neurology +neuroma +neuromas +neuromata +neuromuscular +neuron +neuronal +neurone +neurones +neuronic +neuronically +neurons +neuropath +neuropathic +neuropathically +neuropathies +neuropathologic +neuropathological +neuropathologist +neuropathologists +neuropathology +neuropaths +neuropathy +neuropharmacological +neuropharmacologist +neuropharmacologists +neuropharmacology +neurophysiologic +neurophysiological +neurophysiologist +neurophysiologists +neurophysiology +neuropsychiatric +neuropsychiatrist +neuropsychiatrists +neuropsychiatry +neuropsychological +neuropsychologist +neuropsychologists +neuropsychology +neuropteran +neuropterans +neuropterous +neuroradiological +neuroradiologist +neuroradiologists +neuroradiology +neuroscience +neuroscientific +neuroscientist +neuroscientists +neurosecretion +neurosecretions +neurosecretory +neurosensory +neuroses +neurosis +neurospora +neurosurgeon +neurosurgeons +neurosurgeries +neurosurgery +neurosurgical +neurotic +neurotically +neuroticism +neurotics +neurotomies +neurotomy +neurotoxic +neurotoxicity +neurotoxin +neurotoxins +neurotransmission +neurotransmissions +neurotransmitter +neurotransmitters +neurotropic +neurotropism +neurula +neurulae +neurulas +neurulation +neurulations +neustadt +neuston +neustons +neustria +neustrian +neustrians +neuter +neutered +neutering +neuters +neutral +neutralism +neutralist +neutralistic +neutralists +neutrality +neutralization +neutralizations +neutralize +neutralized +neutralizer +neutralizers +neutralizes +neutralizing +neutrally +neutralness +neutrals +neutrino +neutrinoless +neutrinos +neutron +neutronic +neutrons +neutrophil +neutrophile +neutrophilic +neutrophils +nevada +nevadan +nevadans +nevadian +nevadians +never +neverland +nevermore +nevertheless +nevi +neville +nevilles +nevis +nevoid +nevus +new +newark +newborn +newborns +newburg +newburgh +newcastle +newcomen +newcomer +newcomers +newel +newels +newer +newest +newfangled +newfangledness +newfound +newfoundland +newfoundlander +newfoundlanders +newie +newies +newish +newly +newlywed +newlyweds +newmarket +newmarkets +newness +newport +news +newsagent +newsagents +newsboy +newsboys +newsbreak +newsbreaks +newscast +newscaster +newscasters +newscasts +newsdealer +newsdealers +newsgathering +newsgatherings +newsgirl +newsgirls +newsgroup +newsgroups +newshound +newshounds +newsier +newsiest +newsiness +newsless +newsletter +newsletters +newsmagazine +newsmagazines +newsmaker +newsmakers +newsman +newsmen +newsmonger +newsmongers +newspaper +newspapering +newspaperings +newspaperman +newspapermen +newspapers +newspaperwoman +newspaperwomen +newspeak +newspeople +newsperson +newspersons +newsprint +newsreader +newsreaders +newsreel +newsreels +newsroom +newsrooms +newsstand +newsstands +newsweeklies +newsweekly +newswire +newswires +newswoman +newswomen +newsworthier +newsworthiest +newsworthiness +newsworthy +newswriting +newsy +newt +newton +newtonian +newtons +newts +next +nexus +nexuses +nez +ngorongoro +ngultrum +ngultrums +nguni +ngunis +ngwee +niacin +niacinamide +niagara +nialamide +niamey +nib +nibble +nibbled +nibbler +nibblers +nibbles +nibbling +nibelung +nibelungen +nibelungenlied +nibelungs +niblick +niblicks +nibs +nicad +nicads +nicaea +nicaragua +nicaraguan +nicaraguans +niccolite +niccolites +nice +nicely +nicene +niceness +nicer +nicest +niceties +nicety +niche +niched +niches +niching +nicholas +nichrome +nick +nicked +nickel +nickeled +nickelic +nickeliferous +nickeling +nickelled +nickelling +nickelodeon +nickelodeons +nickelous +nickels +nicker +nickered +nickering +nickers +nicking +nickle +nickles +nicknack +nicknacks +nickname +nicknamed +nicknamer +nicknamers +nicknames +nicknaming +nicks +nicobar +nicodemus +nicomedia +nicosia +nicotiana +nicotianas +nicotinamide +nicotine +nicotinic +nicotinism +nictate +nictated +nictates +nictating +nictitate +nictitated +nictitates +nictitating +nictitation +nictitations +nidate +nidated +nidates +nidating +nidation +nidations +niddering +nidderings +nide +nides +nidi +nidicolous +nidificate +nidificated +nidificates +nidificating +nidification +nidifications +nidified +nidifies +nidifugous +nidify +nidifying +nidus +niduses +niece +nieces +nielli +niellist +niellists +niello +nielloed +nielloing +niellos +nielsbohrium +niente +nietzsche +nietzschean +nietzscheans +nifedipine +nifedipines +niflheim +niftier +nifties +niftiest +niftily +niftiness +nifty +nigella +nigellas +niger +nigeria +nigerian +nigerians +niggard +niggardliness +niggardly +niggards +nigger +niggers +niggle +niggled +niggler +nigglers +niggles +niggling +nigglingly +nigglings +nigh +nighed +nigher +nighest +nighing +nighs +night +nightcap +nightcaps +nightclothes +nightclub +nightclubber +nightclubbers +nightclubby +nightclubs +nightdress +nightdresses +nighter +nighters +nightfall +nightglow +nightglows +nightgown +nightgowns +nighthawk +nighthawks +nightie +nighties +nightingale +nightingales +nightjar +nightjars +nightless +nightlife +nightlong +nightly +nightmare +nightmares +nightmarish +nightmarishly +nightmarishness +nightrider +nightriders +nights +nightscape +nightscapes +nightscope +nightscopes +nightshade +nightshades +nightshirt +nightshirts +nightside +nightsides +nightspot +nightspots +nightstand +nightstands +nightstick +nightsticks +nighttime +nightwalker +nightwalkers +nightwear +nighty +nigra +nigrae +nigrescence +nigrescences +nigrescent +nigrosine +nigrosines +nihil +nihilism +nihilist +nihilistic +nihilistically +nihilists +nihilities +nihility +niihau +nijinsky +nike +nikkei +nil +nile +niles +nilgai +nilgais +nill +nilled +nilling +nills +nilly +nilotic +nilpotency +nilpotent +nilpotents +nim +nimbi +nimble +nimbleness +nimbler +nimblest +nimbly +nimbostrati +nimbostratus +nimbus +nimbuses +nimes +nimieties +nimiety +niminy +nimmed +nimming +nimrod +nimrods +nims +nincompoop +nincompoopery +nincompoops +nine +ninebark +ninebarks +ninefold +ninepin +ninepins +niner +niners +nines +nineteen +nineteenfold +nineteens +nineteenth +nineteenths +nineties +ninetieth +ninetieths +ninety +ninetyfold +nineveh +ninhydrin +ninhydrins +ninja +ninjas +ninnies +ninny +ninnyhammer +ninnyhammers +ninon +ninons +ninth +ninthly +ninths +niobate +niobates +niobe +niobite +niobites +niobium +nip +nipa +nipas +niping +nipped +nipper +nippers +nippier +nippiest +nippily +nippiness +nipping +nippingly +nipple +nippled +nipples +nipplewort +nippleworts +nippon +nipponese +nippy +nips +nirvana +nirvanas +nirvanic +nisan +nisei +niseis +nisi +nissan +nissans +nissen +nisus +nit +niter +niterie +niteries +niters +nitery +nitid +nitinol +nitpick +nitpicked +nitpicker +nitpickers +nitpicking +nitpickings +nitpicks +nitpicky +nitrate +nitrated +nitrates +nitrating +nitration +nitrations +nitrator +nitrators +nitric +nitride +nitrided +nitrides +nitriding +nitrifiable +nitrification +nitrifications +nitrified +nitrifier +nitrifiers +nitrifies +nitrify +nitrifying +nitril +nitrile +nitriles +nitrils +nitrite +nitrites +nitro +nitrobacteria +nitrobacterium +nitrobenzene +nitrocellulose +nitrocellulosic +nitrochloroform +nitrochloroforms +nitrofuran +nitrofurans +nitrofurantoin +nitrofurantoins +nitrogen +nitrogenase +nitrogenases +nitrogenize +nitrogenized +nitrogenizes +nitrogenizing +nitrogenous +nitroglycerin +nitroglycerine +nitrohydrochloric +nitromethane +nitromethanes +nitroparaffin +nitroparaffins +nitroreductase +nitros +nitrosamine +nitrosamines +nitrostarch +nitrostarches +nitrous +nits +nitty +nitwit +nitwits +nitwitted +niue +nival +niveous +nivernais +nix +nixed +nixes +nixie +nixies +nixing +nixy +nizam +nizamate +nizams +niño +niños +no +noachian +noachic +noachical +noah +noah's +nob +nobbier +nobbiest +nobble +nobbled +nobbler +nobblers +nobbles +nobbling +nobby +nobel +nobelist +nobelists +nobelium +nobiliary +nobilities +nobility +noble +nobleman +noblemen +nobleness +nobler +nobles +noblesse +noblest +noblewoman +noblewomen +nobly +nobodies +nobody +nobs +nocent +nociceptive +nociceptor +nociceptors +nock +nocked +nocking +nocks +noctambulation +noctambulations +noctambulism +noctambulisms +noctambulist +noctambulists +noctiluca +noctilucas +noctilucent +noctuid +noctuids +noctule +noctules +nocturn +nocturnal +nocturnally +nocturne +nocturnes +nocturns +nocuous +nocuously +nod +nodal +nodality +nodally +nodded +nodder +nodders +noddies +nodding +noddle +noddles +noddy +node +nodes +nodi +nodose +nodosity +nods +nodular +nodulation +nodulations +nodule +nodules +nodulose +nodulous +nodus +noel +noels +noes +noesis +noetic +nog +noggin +nogging +noggins +nogs +noh +nohow +noil +noils +noir +noire +noires +noirish +noise +noised +noiseless +noiselessly +noiselessness +noisemaker +noisemakers +noisemaking +noises +noisette +noisettes +noisier +noisiest +noisily +noisiness +noising +noisome +noisomely +noisomeness +noisy +nolens +nolle +nolo +nolos +nom +noma +nomad +nomadic +nomadically +nomadism +nomads +nomarchies +nomarchy +nomas +nombril +nombrils +nome +nomen +nomenclator +nomenclatorial +nomenclators +nomenclatural +nomenclature +nomenclatures +nomenklatura +nomenklaturas +nomes +nomina +nominal +nominalism +nominalist +nominalistic +nominalists +nominalization +nominalize +nominalized +nominalizes +nominalizing +nominally +nominals +nominate +nominated +nominates +nominating +nomination +nominations +nominative +nominatives +nominator +nominators +nominee +nominees +nomogram +nomograms +nomograph +nomographic +nomographs +nomography +nomologic +nomological +nomologically +nomologist +nomologists +nomology +nomothetic +nomothetical +nomothetically +noms +non +nonabrasive +nonabsorbable +nonabsorbent +nonabsorptive +nonabstract +nonacademic +nonacceptance +nonaccountable +nonaccredited +nonaccrual +nonachievement +nonacid +nonacidic +nonacquisitive +nonacting +nonaction +nonactivated +nonactor +nonadaptive +nonaddict +nonaddictive +nonadditive +nonadditivity +nonadhesive +nonadiabatic +nonadjacent +nonadjustable +nonadmirer +nonadmission +nonaesthetic +nonaffiliated +nonaffluent +nonage +nonagenarian +nonagenarians +nonages +nonaggression +nonaggressive +nonagon +nonagons +nonagricultural +nonalcoholic +nonalcoholics +nonaligned +nonalignment +nonallelic +nonallergenic +nonallergic +nonalphabetic +nonaluminum +nonambiguous +nonanalytic +nonanatomic +nonanimal +nonanoic +nonanswer +nonantagonistic +nonanthropological +nonanthropologist +nonantibiotic +nonantigenic +nonappearance +nonappearances +nonaquatic +nonaqueous +nonarable +nonarbitrariness +nonarbitrary +nonarchitect +nonarchitecture +nonargument +nonaristocratic +nonaromatic +nonart +nonartist +nonartistic +nonary +nonascetic +nonaspirin +nonassertive +nonassessable +nonassociated +nonastronomical +nonathlete +nonathletic +nonatomic +nonattached +nonattachment +nonattendance +nonattender +nonauditory +nonauthor +nonauthoritarian +nonautomated +nonautomatic +nonautomotive +nonautonomous +nonavailability +nonbacterial +nonbank +nonbanking +nonbarbiturate +nonbaryonic +nonbasic +nonbearing +nonbehavioral +nonbeing +nonbeings +nonbelief +nonbeliever +nonbelievers +nonbelligerency +nonbelligerent +nonbelligerents +nonbetting +nonbibliographic +nonbinary +nonbinding +nonbiodegradable +nonbiographical +nonbiological +nonbiologically +nonbiologist +nonbiting +nonblack +nonblacks +nonblank +nonbody +nonbonded +nonbonding +nonbook +nonbooks +nonbotanist +nonbrand +nonbreakable +nonbreathing +nonbreeder +nonbreeding +nonbroadcast +nonbuilding +nonburnable +nonbusiness +nonbuying +noncabinet +noncaking +noncallable +noncaloric +noncampus +noncancelable +noncancerous +noncandidacy +noncandidate +noncandidates +noncannibalistic +noncapital +noncapitalist +noncarcinogen +noncarcinogenic +noncardiac +noncareer +noncarrier +noncash +noncasual +noncausal +nonce +noncelebration +noncelebrity +noncellular +noncellulosic +noncentral +noncertificated +noncertified +nonchalance +nonchalant +nonchalantly +noncharacter +noncharismatic +nonchauvinist +nonchemical +nonchromosomal +nonchronological +nonchurch +nonchurchgoer +noncircular +noncirculating +noncitizen +noncitizens +nonclandestine +nonclass +nonclassical +nonclassified +nonclassroom +nonclearing +nonclerical +noncling +nonclinical +nonclogging +noncoercive +noncognitive +noncoherent +noncoincidence +noncoital +noncoking +noncola +noncollector +noncollege +noncollegiate +noncollinear +noncolor +noncolored +noncolorfast +noncom +noncombat +noncombatant +noncombatants +noncombative +noncombustible +noncommercial +noncommissioned +noncommitment +noncommittal +noncommittally +noncommitted +noncommunicating +noncommunication +noncommunicative +noncommunist +noncommunists +noncommunity +noncommutative +noncommutativity +noncomparability +noncomparable +noncompatible +noncompetition +noncompetitive +noncompetitor +noncomplementary +noncomplex +noncompliance +noncompliances +noncompliant +noncompliants +noncomplicated +noncomplying +noncomposer +noncompound +noncomprehension +noncompressible +noncompulsory +noncomputer +noncomputerized +noncoms +nonconceptual +nonconcern +nonconclusion +nonconcur +nonconcured +nonconcuring +nonconcurrence +nonconcurrent +nonconcurring +nonconcurs +noncondensable +nonconditioned +nonconducting +nonconduction +nonconductive +nonconductor +nonconductors +nonconference +nonconfidence +nonconfidential +nonconflicting +nonconform +nonconformance +nonconformances +nonconformed +nonconformer +nonconformers +nonconforming +nonconformism +nonconformist +nonconformists +nonconformity +nonconforms +nonconfrontation +nonconfrontational +noncongruent +nonconjugated +nonconnection +nonconscious +nonconsecutive +nonconsensual +nonconservation +nonconservative +nonconsolidated +nonconstant +nonconstitutional +nonconstruction +nonconstructive +nonconsumer +nonconsuming +nonconsumption +nonconsumptive +noncontact +noncontagious +noncontemporary +noncontiguous +noncontingent +noncontinuous +noncontract +noncontractual +noncontradiction +noncontradictory +noncontributing +noncontributory +noncontrollable +noncontrolled +noncontrolling +noncontroversial +nonconventional +nonconvertible +noncooperation +noncooperationist +noncooperationists +noncooperations +noncooperative +noncooperator +noncooperators +noncoplanar +noncorporate +noncorrelation +noncorrodible +noncorroding +noncorrosive +noncountry +noncounty +noncoverage +noncreative +noncreativity +noncredentialed +noncredit +noncrime +noncriminal +noncrisis +noncritical +noncrossover +noncrushable +noncrystalline +nonculinary +noncultivated +noncultivation +noncultural +noncumulative +noncurrent +noncustodial +noncustomer +noncyclic +noncyclical +nondairy +nondance +nondancer +nondeceptive +nondecision +nondecreasing +nondeductibility +nondeductible +nondeductive +nondefense +nondeferrable +nondeforming +nondegenerate +nondegradable +nondegree +nondelegate +nondeliberate +nondelinquent +nondelivery +nondemanding +nondemocratic +nondenominational +nondenominationalism +nondepartmental +nondependent +nondepletable +nondepleting +nondeposition +nondepressed +nonderivative +nondescript +nondescriptive +nondescriptly +nondescripts +nondesert +nondestructive +nondestructively +nondestructiveness +nondetachable +nondeterministic +nondevelopment +nondeviant +nondiabetic +nondialyzable +nondiapausing +nondidactic +nondiffusible +nondimensional +nondiplomatic +nondirected +nondirectional +nondirective +nondisabled +nondisclosure +nondisclosures +nondiscount +nondiscretionary +nondiscrimination +nondiscriminatory +nondiscursive +nondisjunction +nondisjunctional +nondisjunctions +nondispersive +nondisruptive +nondistinctive +nondiversified +nondividing +nondoctor +nondoctrinaire +nondocumentary +nondogmatic +nondollar +nondomestic +nondominant +nondormant +nondramatic +nondrinker +nondrinkers +nondrinking +nondriver +nondrug +nondrying +nondurable +nondurables +none +nonearning +nonecclesiastical +noneconomic +noneconomist +nonedible +noneditorial +noneducation +noneducational +noneffective +nonego +nonelastic +nonelected +nonelection +nonelective +nonelectric +nonelectrical +nonelectrolyte +nonelectrolytes +nonelectronic +nonelementary +nonelite +nonemergency +nonemotional +nonemphatic +nonempirical +nonemployee +nonemployment +nonempty +nonencapsulated +nonending +nonenergy +nonenforceability +nonenforcement +nonengagement +nonengineering +nonentertainment +nonentities +nonentity +nonenzymatic +nonenzymic +nonequilibrium +nonequivalence +nonequivalent +nonerotic +nones +nonessential +nonessentials +nonestablished +nonestablishment +nonesterified +nonesuch +nonesuches +nonet +nonetheless +nonethical +nonethnic +nonets +nonevaluative +nonevent +nonevents +nonevidence +nonexclusive +nonexecutive +nonexempt +nonexistence +nonexistent +nonexistential +nonexotic +nonexpendable +nonexperimental +nonexpert +nonexplanatory +nonexploitation +nonexploitative +nonexploitive +nonexplosive +nonexplosives +nonexposed +nonextant +nonfact +nonfactor +nonfactual +nonfaculty +nonfading +nonfamilial +nonfamily +nonfan +nonfarm +nonfarmer +nonfat +nonfatal +nonfattening +nonfatty +nonfeasance +nonfederal +nonfederated +nonfeminist +nonferrous +nonfiction +nonfictional +nonfigurative +nonfilamentous +nonfilterable +nonfinal +nonfinancial +nonfinite +nonfissionable +nonflammability +nonflammable +nonflowering +nonfluency +nonfluorescent +nonflying +nonfood +nonforfeitable +nonforfeiture +nonformal +nonfossil +nonfraternization +nonfreezing +nonfrivolous +nonfrozen +nonfuel +nonfulfillment +nonfunctional +nonfunctioning +nongame +nongaseous +nongay +nongenetic +nongenital +nongeometrical +nonghetto +nonglamorous +nonglare +nongolfer +nongonococcal +nongovernment +nongovernmental +nongraded +nongraduate +nongrammatical +nongranular +nongravitational +nongreasy +nongreen +nongregarious +nongrowing +nongrowth +nonguest +nonhalogenated +nonhandicapped +nonhappening +nonhardy +nonharmonic +nonhazardous +nonheme +nonhemolytic +nonhereditary +nonhero +nonheroes +nonhierarchical +nonhistone +nonhistorical +nonhome +nonhomogeneous +nonhomologous +nonhomosexual +nonhormonal +nonhospital +nonhospitalized +nonhostile +nonhousing +nonhuman +nonhumans +nonhunter +nonhunting +nonhygroscopic +nonhysterical +nonideal +nonidentical +nonidentity +nonideological +nonillion +nonillions +nonillionth +nonillionths +nonimage +nonimitative +nonimmigrant +nonimmigrants +nonimmune +nonimpact +nonimplication +nonimportation +noninclusion +nonincreasing +nonincumbent +nonindependence +nonindigenous +nonindividual +noninductive +nonindustrial +nonindustrialized +nonindustry +noninfected +noninfectious +noninfective +noninfested +noninflammable +noninflammatory +noninflationary +noninflectional +noninfluence +noninformation +noninitial +noninitiate +noninjury +noninsect +noninsecticidal +noninstallment +noninstitutional +noninstitutionalized +noninstructional +noninstrumental +noninsurance +noninsured +nonintegral +nonintegrated +nonintellectual +noninteracting +noninteractive +noninterchangeable +nonintercourse +noninterest +noninterference +nonintersecting +nonintervention +noninterventionist +noninterventionists +nonintimidating +nonintoxicant +nonintoxicating +nonintrospective +nonintrusive +nonintuitive +noninvasive +noninvolved +noninvolvement +nonionic +nonionizing +nonirradiated +nonirrigated +nonirritant +nonirritating +nonissue +nonissues +nonjoinder +nonjoinders +nonjoiner +nonjudgmental +nonjudicial +nonjuring +nonjuror +nonjurors +nonjury +nonjusticiable +nonkosher +nonlabor +nonlandowner +nonlanguage +nonlawyer +nonleaded +nonleague +nonlegal +nonlegume +nonleguminous +nonlethal +nonlexical +nonlibrarian +nonlibrary +nonlife +nonlineal +nonlinear +nonlinearities +nonlinearity +nonlinearly +nonlinguistic +nonliquid +nonliteral +nonliterary +nonliterate +nonliterates +nonliving +nonlocal +nonlogical +nonluminous +nonmagnetic +nonmainstream +nonmajor +nonmalignant +nonmalleable +nonmammalian +nonmanagement +nonmanagerial +nonmandatory +nonmanual +nonmanufacturing +nonmarital +nonmarket +nonmarketable +nonmaterial +nonmaterialistic +nonmathematical +nonmatriculated +nonmeaningful +nonmeasurable +nonmeat +nonmechanical +nonmechanistic +nonmedical +nonmeeting +nonmember +nonmembers +nonmembership +nonmental +nonmercurial +nonmetal +nonmetallic +nonmetals +nonmetameric +nonmetaphorical +nonmetric +nonmetrical +nonmetro +nonmetropolitan +nonmicrobial +nonmigrant +nonmigratory +nonmilitant +nonmilitary +nonmimetic +nonminority +nonmobile +nonmolecular +nonmonetarist +nonmonetary +nonmoney +nonmonogamous +nonmoral +nonmotile +nonmotility +nonmotorized +nonmoving +nonmunicipal +nonmusic +nonmusical +nonmusician +nonmutant +nonmyelinated +nonmystical +nonnarrative +nonnational +nonnative +nonnatural +nonnecessity +nonnegative +nonnegligent +nonnegotiable +nonnetwork +nonneural +nonnews +nonnitrogenous +nonnormative +nonnovel +nonnuclear +nonnucleated +nonnumeric +nonnumerical +nonnumerically +nonnutritious +nonnutritive +nonobjective +nonobjectivism +nonobjectivist +nonobjectivists +nonobjectivity +nonobligatory +nonobscene +nonobservance +nonobservances +nonobservant +nonobservantly +nonobvious +nonoccupational +nonoccurrence +nonofficial +nonohmic +nonoily +nonoperatic +nonoperating +nonoperational +nonoperative +nonoptimal +nonorganic +nonorgasmic +nonorthodox +nonoverlapping +nonowner +nonoxidizing +nonoxynol +nonpaid +nonpainful +nonparallel +nonparametric +nonparasitic +nonpareil +nonpareils +nonparticipant +nonparticipating +nonparticipation +nonparticipatory +nonpartisan +nonpartisans +nonpartisanship +nonpartisanships +nonparty +nonpasserine +nonpassive +nonpast +nonpathogenic +nonpaying +nonpayment +nonpeak +nonperformance +nonperformer +nonperforming +nonperishable +nonpermanent +nonpermissive +nonpersistent +nonperson +nonpersonal +nonpersons +nonpetroleum +nonphilosopher +nonphilosophical +nonphonemic +nonphonetic +nonphosphate +nonphotographic +nonphysical +nonphysician +nonplanar +nonplastic +nonplay +nonplaying +nonplus +nonplused +nonpluses +nonplusing +nonplussed +nonplusses +nonplussing +nonpoetic +nonpoint +nonpoisonous +nonpolar +nonpolarizable +nonpolice +nonpolitical +nonpolitically +nonpolitician +nonpolluting +nonpoor +nonporous +nonpossession +nonpractical +nonpracticing +nonpregnant +nonprescription +nonprime +nonprint +nonprinting +nonproblem +nonprocedural +nonproducing +nonproductive +nonproductively +nonproductiveness +nonproductives +nonprofessional +nonprofessionally +nonprofessionals +nonprofessorial +nonprofit +nonprogram +nonprogrammer +nonprogressive +nonproliferation +nonproprietary +nonpros +nonprossed +nonprosses +nonprossing +nonprotein +nonpsychiatric +nonpsychiatrist +nonpsychological +nonpsychotic +nonpublic +nonpunitive +nonpurposive +nonquantifiable +nonquantitative +nonracial +nonracially +nonradioactive +nonrailroad +nonrandom +nonrandomness +nonrated +nonrational +nonreactive +nonreactor +nonreader +nonreaders +nonreading +nonrealistic +nonreappointment +nonreceipt +nonreciprocal +nonrecognition +nonrecombinant +nonrecourse +nonrecoverable +nonrectangular +nonrecurrent +nonrecurring +nonrecursive +nonrecyclable +nonreducing +nonredundant +nonrefillable +nonreflecting +nonrefundable +nonregulated +nonregulation +nonrelative +nonrelativistic +nonrelativistically +nonrelevant +nonreligious +nonrenewable +nonrenewal +nonrepayable +nonrepresentational +nonrepresentationalism +nonrepresentative +nonreproductive +nonresidence +nonresidency +nonresident +nonresidential +nonresidents +nonresistance +nonresistances +nonresistant +nonresistants +nonresonant +nonrespondent +nonresponder +nonresponse +nonresponsive +nonrestricted +nonrestrictive +nonretractile +nonretroactive +nonreturnable +nonreusable +nonreversible +nonrevolutionary +nonrigid +nonrioter +nonrioting +nonromantic +nonrotating +nonroutine +nonroyal +nonrubber +nonruling +nonruminant +nonsalable +nonsaline +nonsaponifiable +nonscheduled +nonschizophrenic +nonschool +nonscience +nonscientific +nonscientist +nonscientists +nonseasonal +nonsecretor +nonsecretors +nonsecretory +nonsectarian +nonsectarianism +nonsecure +nonsedimentable +nonsegregated +nonsegregation +nonselected +nonselective +nonself +nonsensational +nonsense +nonsensical +nonsensicality +nonsensically +nonsensicalness +nonsensitive +nonsensuous +nonsentence +nonseptate +nonsequential +nonserious +nonsexist +nonsexual +nonshrink +nonshrinkable +nonsigner +nonsignificance +nonsignificant +nonsignificantly +nonsimultaneous +nonsingular +nonsinkable +nonskater +nonsked +nonskeds +nonskeletal +nonskid +nonskier +nonslip +nonsmoker +nonsmokers +nonsmoking +nonsocial +nonsocialist +nonsolar +nonsolid +nonsolution +nonspatial +nonspeaker +nonspeaking +nonspecialist +nonspecialists +nonspecific +nonspecifically +nonspectacular +nonspeculative +nonspeech +nonspherical +nonsporting +nonstandard +nonstarter +nonstarters +nonstationary +nonstatistical +nonsteady +nonsteroid +nonsteroidal +nonstick +nonstop +nonstory +nonstrategic +nonstructural +nonstructured +nonstudent +nonstyle +nonsubject +nonsubjective +nonsubsidized +nonsuccess +nonsuch +nonsuches +nonsugar +nonsuit +nonsuited +nonsuiting +nonsuits +nonsuperimposable +nonsupervisory +nonsupport +nonsurgical +nonswimmer +nonswimmers +nonsyllabic +nonsymbolic +nonsymmetric +nonsymmetrical +nonsynchronous +nonsystem +nonsystematic +nonsystemic +nonsystems +nontarget +nontariff +nontaxable +nonteaching +nontechnical +nontemporal +nontenured +nonterminal +nonterminating +nontheatrical +nontheist +nontheistic +nontheological +nontheoretical +nontherapeutic +nonthermal +nonthinking +nonthreatening +nontidal +nontitle +nontobacco +nontonal +nontotalitarian +nontoxic +nontraditional +nontraditionally +nontransferable +nontransparent +nontreatment +nontrivial +nontropical +nonturbulent +nontypical +nonunanimous +nonuniform +nonuniformity +nonunion +nonunionized +nonunique +nonuniqueness +nonuniversal +nonuniversity +nonuple +nonuples +nonurban +nonurgent +nonuse +nonuser +nonusers +nonutilitarian +nonutility +nonutopian +nonvalid +nonvalidity +nonvanishing +nonvascular +nonvector +nonvectors +nonvegetarian +nonvenomous +nonverbal +nonverbally +nonveteran +nonviable +nonviewer +nonvintage +nonviolence +nonviolent +nonviolently +nonviral +nonvirgin +nonviscous +nonvisual +nonvocal +nonvocational +nonvolatile +nonvolcanic +nonvoluntary +nonvoter +nonvoters +nonvoting +nonwar +nonwestern +nonwhite +nonwhites +nonwinning +nonwoody +nonword +nonwords +nonwork +nonworker +nonworking +nonwoven +nonwovens +nonwriter +nonyellowing +nonylphenylhydroxynonaoxyethylene +nonzero +noodle +noodled +noodles +noodling +nook +nooks +nooky +noon +noonday +nooning +noons +noontide +noontime +noose +noosed +nooses +noosing +noosphere +nootka +nootkas +nopal +nopals +nope +nor +nor'easter +nor'easters +nor'wester +nor'westers +noradrenalin +noradrenaline +noradrenalins +noradrenergic +noradrenergically +nordic +nordics +nordkyn +nordmann +norepinephrine +norepinephrines +norethindrone +norethindrones +norfolk +nori +noria +norias +noricum +noris +norite +norites +noritic +norland +norm +norma +normal +normalcy +normality +normalizable +normalization +normalizations +normalize +normalized +normalizer +normalizers +normalizes +normalizing +normally +normals +norman +normande +normandy +normans +normative +normatively +normativeness +normed +normocyte +normocytes +normotensive +normotensives +normothermia +normothermic +norms +norn +nornicotine +nornicotines +norns +norrköping +norse +norseman +norsemen +north +northamptonshire +northanger +northbound +northeast +northeaster +northeasterly +northeastern +northeasterner +northeasterners +northeasternmost +northeasters +northeastward +northeastwardly +northeastwards +norther +northerlies +northerly +northern +northerner +northerners +northernmost +northernness +northers +northing +northings +northland +northlander +northlanders +northlands +northman +northmen +northrop +northumberland +northumbria +northumbrian +northumbrians +northward +northwardly +northwards +northwest +northwester +northwesterly +northwestern +northwesterner +northwesterners +northwesternmost +northwesters +northwestward +northwestwardly +northwestwards +nortriptyline +nortriptylines +norway +norwegian +norwegians +norwich +nose +nosebag +nosebags +noseband +nosebands +nosebleed +nosebleeds +nosed +nosedive +nosedives +nosegay +nosegays +noseguard +noseguards +nosepiece +nosepieces +noser +noses +nosewheel +nosewheels +nosey +nosh +noshed +nosher +noshers +noshes +noshing +nosier +nosiest +nosily +nosiness +nosing +nosings +nosocomial +nosographer +nosographers +nosographic +nosographical +nosography +nosologic +nosological +nosologically +nosologies +nosologist +nosologists +nosology +nostalgia +nostalgic +nostalgically +nostalgist +nostalgists +nostoc +nostocs +nostra +nostradamus +nostril +nostrils +nostrum +nostrums +nosy +not +nota +notabilities +notability +notable +notableness +notables +notably +notarial +notarially +notaries +notarization +notarizations +notarize +notarized +notarizes +notarizing +notary +notate +notated +notates +notating +notation +notational +notations +notch +notchback +notchbacks +notched +notches +notching +note +notebook +notebooks +notecase +notecases +noted +notedly +notedness +noteless +notepad +notepads +notepaper +noter +noters +notes +noteworthier +noteworthiest +noteworthily +noteworthiness +noteworthy +nothing +nothingism +nothingness +nothings +notice +noticeability +noticeable +noticeably +noticed +noticer +noticers +notices +noticing +notifiable +notification +notifications +notified +notifier +notifiers +notifies +notify +notifying +noting +notion +notional +notionality +notionally +notions +notochord +notochordal +notochords +notogaea +notogea +notoriety +notorious +notoriously +notoriousness +notornis +nottinghamshire +notum +notwithstanding +nouakchott +nougat +nougats +nought +noughts +noumena +noumenal +noumenon +nouméa +noun +nouns +nourish +nourished +nourisher +nourishers +nourishes +nourishing +nourishment +nourishments +nous +nouveau +nouveaux +nouvelle +nova +novaculite +novaculites +novae +novalike +novas +novation +novations +novaya +novel +novelette +novelettes +novelettish +novelist +novelistic +novelistically +novelists +novelization +novelizations +novelize +novelized +novelizer +novelizers +novelizes +novelizing +novella +novellas +novelle +novelly +novels +novelties +novelty +november +novembers +novemdecillion +novena +novenae +novenas +novercal +novgorod +novice +novices +noviciate +noviciates +novitiate +novitiates +novo +novobiocin +novobiocins +novocain +novocaine +novocaines +now +nowadays +noway +noways +nowhere +nowhither +nowise +nowness +noxious +noxiously +noxiousness +nozzle +nozzles +noël +noëls +ns +nt +nth +nu +nuance +nuanced +nuances +nub +nuba +nubbier +nubbiest +nubbin +nubbins +nubble +nubbles +nubbly +nubby +nubia +nubian +nubians +nubile +nubility +nubs +nucellar +nucelli +nucellus +nucha +nuchal +nuchas +nuclear +nuclearization +nuclearizations +nuclearize +nuclearized +nuclearizes +nuclearizing +nuclease +nucleases +nucleate +nucleated +nucleates +nucleating +nucleation +nucleations +nucleator +nucleators +nuclei +nucleic +nuclein +nucleinic +nucleins +nucleocapsid +nucleocapsids +nucleohistone +nucleohistones +nucleoid +nucleoids +nucleolar +nucleolate +nucleolated +nucleoli +nucleolus +nucleon +nucleonic +nucleonics +nucleons +nucleophile +nucleophiles +nucleophilic +nucleophilically +nucleophilicity +nucleoplasm +nucleoplasmatic +nucleoplasmic +nucleoplasms +nucleoprotein +nucleoproteins +nucleoside +nucleosides +nucleosomal +nucleosome +nucleosomes +nucleosynthesis +nucleosynthetic +nucleotidase +nucleotidases +nucleotide +nucleotides +nucleus +nucleuses +nuclide +nuclides +nuclidic +nude +nudely +nudeness +nuder +nudes +nudest +nudge +nudged +nudger +nudgers +nudges +nudging +nudibranch +nudibranches +nudibranchian +nudibranchians +nudibranchiate +nudibranchiates +nudism +nudist +nudists +nudity +nudnick +nudnicks +nudnik +nudniks +nudzh +nudzhed +nudzhes +nudzhing +nudzhs +nugatory +nugget +nuggets +nuisance +nuisances +nuke +nuked +nukes +nuking +null +nullah +nullahs +nullarbor +nulled +nullification +nullificationist +nullificationists +nullifications +nullified +nullifier +nullifiers +nullifies +nullify +nullifying +nulling +nullipara +nulliparas +nulliparous +nullities +nullity +nulls +numb +numbed +number +numberable +numbered +numberer +numberers +numbering +numberings +numberless +numbers +numbest +numbfish +numbfishes +numbing +numbingly +numbly +numbness +numbs +numbskull +numbskulls +numen +numerable +numeracy +numeral +numerally +numerals +numerary +numerate +numerated +numerates +numerating +numeration +numerations +numerator +numerators +numeric +numerical +numerically +numerics +numero +numerological +numerologist +numerologists +numerology +numerous +numerously +numerousness +numidia +numidian +numidians +numina +numinous +numinousness +numismatic +numismatically +numismatics +numismatist +numismatists +nummular +nummulite +nummulites +nummulitic +numskull +numskulls +nun +nunatak +nunataks +nunc +nunchaku +nunchakus +nunciature +nunciatures +nuncio +nuncios +nuncle +nuncles +nuncupative +nunivak +nunlike +nunneries +nunnery +nuns +nuptial +nuptiality +nuptially +nuptials +nurd +nurds +nuremberg +nureyev +nuristan +nuristani +nuristanis +nurse +nursed +nursemaid +nursemaids +nurser +nurseries +nursers +nursery +nurseryman +nurserymen +nurses +nursing +nursling +nurslings +nurturance +nurturances +nurturant +nurture +nurtured +nurturer +nurturers +nurtures +nurturing +nut +nutate +nutated +nutates +nutating +nutation +nutational +nutations +nutcase +nutcases +nutcracker +nutcrackers +nutgall +nutgalls +nuthatch +nuthatches +nuthouse +nuthouses +nutlet +nutlets +nutlike +nutmeat +nutmeats +nutmeg +nutmegs +nutpick +nutpicks +nutria +nutrias +nutrient +nutrients +nutriment +nutrimental +nutriments +nutrition +nutritional +nutritionally +nutritionist +nutritionists +nutritious +nutritiously +nutritiousness +nutritive +nutritively +nuts +nutsedge +nutshell +nutshells +nutted +nutter +nutters +nuttier +nuttiest +nuttily +nuttiness +nutting +nutty +nux +nuzzle +nuzzled +nuzzler +nuzzlers +nuzzles +nuzzling +nw +nyala +nyalas +nyanja +nyasa +nyasaland +nyctalopia +nyctalopias +nyctalopic +nyctitropic +nyctitropism +nyctitropisms +nyctophobia +nyctophobias +nyet +nylon +nylons +nymph +nympha +nymphae +nymphal +nymphalid +nymphalids +nymphet +nymphets +nymphette +nymphettes +nympho +nympholepsies +nympholepsy +nympholept +nympholeptic +nympholepts +nymphomania +nymphomaniac +nymphomaniacal +nymphomaniacs +nymphos +nymphs +nynorsk +nystagmic +nystagmus +nystagmuses +nystatin +nystatins +náxos +née +névé +nîmes +nürnberg +o +o'clock +o'er +o'neill +o'odham +o'odhams +oaf +oafish +oafishly +oafishness +oafs +oahu +oak +oaken +oakland +oakley +oakleys +oakmoss +oakmosses +oaks +oakum +oar +oared +oarfish +oarfishes +oaring +oarless +oarlock +oarlocks +oars +oarsman +oarsmanship +oarsmen +oarswoman +oarswomen +oases +oasis +oast +oasts +oat +oatcake +oatcakes +oaten +oater +oaters +oath +oaths +oatmeal +oats +obadiah +obbligati +obbligato +obbligatos +obcompressed +obcordate +obduracy +obdurate +obdurately +obdurateness +obeah +obeahs +obedience +obedient +obediently +obeisance +obeisances +obeisant +obeisantly +obeli +obelia +obelias +obeliscal +obelisk +obeliskoid +obelisks +obelize +obelized +obelizes +obelizing +obelus +obento +obentos +oberammergau +oberon +obese +obesely +obeseness +obesity +obey +obeyed +obeyer +obeyers +obeying +obeys +obfuscate +obfuscated +obfuscates +obfuscating +obfuscation +obfuscations +obfuscatory +obi +obie +obies +obis +obit +obiter +obits +obituaries +obituarist +obituarists +obituary +object +objected +objectification +objectifications +objectified +objectifier +objectifiers +objectifies +objectify +objectifying +objecting +objection +objectionability +objectionable +objectionableness +objectionably +objections +objective +objectively +objectiveness +objectives +objectivism +objectivist +objectivistic +objectivists +objectivity +objectivization +objectivizations +objectivize +objectivized +objectivizes +objectivizing +objectless +objectlessness +objector +objectors +objects +objet +objets +objurgate +objurgated +objurgates +objurgating +objurgation +objurgations +objurgatorily +objurgatory +oblanceolate +oblast +oblasti +oblasts +oblate +oblately +oblateness +oblates +oblation +oblational +oblations +oblatory +obligable +obligate +obligated +obligately +obligates +obligati +obligating +obligation +obligational +obligations +obligato +obligator +obligatorily +obligators +obligatory +obligatos +oblige +obliged +obligee +obligees +obliger +obligers +obliges +obliging +obligingly +obligingness +obligor +obligors +oblique +obliqued +obliquely +obliqueness +obliques +obliquing +obliquities +obliquitous +obliquity +obliterate +obliterated +obliterates +obliterating +obliteration +obliterations +obliterative +obliterator +obliterators +oblivion +oblivious +obliviously +obliviousness +oblong +oblongata +oblongatae +oblongatas +oblongs +obloquies +obloquy +obnoxious +obnoxiously +obnoxiousness +obnubilate +obnubilated +obnubilates +obnubilating +obnubilation +obnubilations +oboe +oboes +oboist +oboists +obol +oboli +obols +obolus +obovate +obovoid +obscene +obscenely +obsceneness +obscener +obscenest +obscenities +obscenity +obscura +obscurant +obscurantic +obscurantism +obscurantist +obscurantists +obscurants +obscuras +obscuration +obscurations +obscure +obscured +obscurely +obscureness +obscurer +obscurers +obscures +obscurest +obscuring +obscurities +obscurity +obsequies +obsequious +obsequiously +obsequiousness +obsequy +observability +observable +observables +observably +observance +observances +observant +observantly +observants +observation +observational +observationally +observations +observatories +observatory +observe +observed +observer +observers +observes +observing +observingly +obsess +obsessed +obsesses +obsessing +obsession +obsessional +obsessionally +obsessions +obsessive +obsessively +obsessiveness +obsessives +obsessor +obsessors +obsidian +obsidians +obsolesce +obsolesced +obsolescence +obsolescent +obsolescently +obsolesces +obsolescing +obsolete +obsoleted +obsoletely +obsoleteness +obsoletes +obsoleting +obsoletism +obstacle +obstacles +obstante +obstetric +obstetrical +obstetrically +obstetrician +obstetricians +obstetrics +obstinacies +obstinacy +obstinate +obstinately +obstinateness +obstreperous +obstreperously +obstreperousness +obstruct +obstructed +obstructer +obstructers +obstructing +obstruction +obstructionism +obstructionist +obstructionistic +obstructionists +obstructions +obstructive +obstructively +obstructiveness +obstructor +obstructors +obstructs +obstruent +obstruents +obtain +obtainability +obtainable +obtained +obtainer +obtainers +obtaining +obtainment +obtainments +obtains +obtect +obtected +obtest +obtestation +obtestations +obtested +obtesting +obtests +obtrude +obtruded +obtruder +obtruders +obtrudes +obtruding +obtrusion +obtrusions +obtrusive +obtrusively +obtrusiveness +obtund +obtunded +obtundent +obtunding +obtundity +obtunds +obturate +obturated +obturates +obturating +obturation +obturations +obturator +obturators +obtuse +obtusely +obtuseness +obtuser +obtusest +obverse +obversely +obverses +obversion +obversions +obvert +obverted +obverting +obverts +obviate +obviated +obviates +obviating +obviation +obviations +obviator +obviators +obvious +obviously +obviousness +oca +ocarina +ocarinas +ocas +occam +occasion +occasional +occasionally +occasioned +occasioning +occasions +occident +occidental +occidentalism +occidentalization +occidentalizations +occidentalize +occidentalized +occidentalizes +occidentalizing +occidentally +occidentals +occipita +occipital +occipitally +occipitals +occiput +occiputs +occitan +occitanian +occitans +occlude +occluded +occludent +occludes +occluding +occlusal +occlusion +occlusions +occlusive +occlusives +occult +occultation +occultations +occulted +occulter +occulters +occulting +occultism +occultist +occultists +occultly +occultness +occults +occupancies +occupancy +occupant +occupants +occupation +occupational +occupationally +occupations +occupied +occupier +occupiers +occupies +occupy +occupying +occur +occurred +occurrence +occurrences +occurrent +occurring +occurs +ocean +oceanaria +oceanarium +oceanariums +oceanaut +oceanauts +oceanfront +oceangoing +oceania +oceanian +oceanians +oceanic +oceanid +oceanides +oceanids +oceanographer +oceanographers +oceanographic +oceanographical +oceanographically +oceanography +oceanologic +oceanological +oceanologically +oceanologist +oceanologists +oceanology +oceans +oceanus +ocellar +ocellate +ocellated +ocellation +ocellations +ocelli +ocellus +ocelot +ocelots +ocher +ocherous +ochers +ochery +ochlocracies +ochlocracy +ochlocrat +ochlocratic +ochlocratical +ochlocratically +ochlocrats +ochlophobia +ochlophobic +ochlophobics +ochre +ochreous +ochres +ockham +ocotillo +ocotillos +ocrea +ocreae +octad +octadic +octads +octagon +octagonal +octagonally +octagons +octahedra +octahedral +octahedrally +octahedron +octahedrons +octal +octamerous +octameter +octameters +octandrious +octane +octans +octant +octantal +octants +octapeptide +octapeptides +octastyle +octaval +octavalent +octave +octaves +octavian +octavius +octavo +octavos +octennial +octet +octets +octillion +octillions +octillionth +octillionths +october +octobers +octobrist +octobrists +octocentenary +octodecillion +octodecimo +octodecimos +octogenarian +octogenarians +octometer +octometers +octonaries +octonary +octopi +octoploid +octoploids +octopod +octopodous +octopods +octopus +octopuses +octoroon +octoroons +octosyllabic +octosyllabics +octosyllable +octosyllables +octothorp +octothorps +octuple +octupled +octuples +octupling +octylcyanoacrylate +ocular +ocularist +ocularists +oculars +oculi +oculist +oculists +oculogyric +oculomotor +oculus +odalisk +odalisks +odalisque +odalisques +odd +oddball +oddballs +odder +oddest +oddish +oddities +oddity +oddjobber +oddjobbers +oddly +oddment +oddments +oddness +odds +oddsmaker +oddsmakers +ode +odea +odense +odeon +oder +odes +odessa +odeum +odic +odin +odious +odiously +odiousness +odist +odists +odium +odograph +odographs +odometer +odometers +odometry +odonate +odonates +odontalgia +odontalgias +odontalgic +odontoblast +odontoblastic +odontoblasts +odontoglossum +odontoid +odontological +odontologically +odontologist +odontologists +odontology +odontophoral +odontophore +odontophores +odontophorine +odontophorous +odor +odorant +odorants +odored +odoriferous +odoriferously +odoriferousness +odorize +odorized +odorizes +odorizing +odorless +odorlessly +odorlessness +odorous +odorously +odorousness +odors +odyssean +odysseus +odyssey +odysseys +oecumenical +oedema +oedipal +oedipally +oedipus +oeil +oeillade +oeillades +oeils +oenological +oenologist +oenologists +oenology +oenomel +oenomels +oenone +oenophile +oenophiles +oersted +oersteds +oesophagi +oesophagus +oestrogen +oestrogens +oestrus +oeuvre +oeuvres +of +ofay +off +offa +offal +offbeat +offcast +offcasts +offcut +offcuts +offed +offenbach +offence +offences +offend +offended +offender +offenders +offending +offends +offense +offenseless +offenses +offensive +offensively +offensiveness +offensives +offer +offered +offerer +offerers +offering +offerings +offeror +offerors +offers +offertories +offertory +offhand +offhanded +offhandedly +offhandedness +office +officeholder +officeholders +officemate +officemates +officer +officered +officering +officers +offices +official +officialdom +officialdoms +officialese +officialeses +officialism +officially +officials +officiant +officiants +officiaries +officiary +officiate +officiated +officiates +officiating +officiation +officiations +officiator +officiators +officinal +officinally +officinals +officio +officious +officiously +officiousness +offing +offish +offishly +offishness +offline +offload +offloaded +offloading +offloads +offprint +offprinted +offprinting +offprints +offs +offscouring +offscourings +offscreen +offset +offsets +offsetting +offshoot +offshoots +offshore +offside +offsides +offspring +offsprings +offstage +offtrack +offy +oft +often +oftener +oftenest +oftentimes +ofttimes +ogam +ogams +ogee +ogees +ogham +oghamic +oghamist +oghamists +oghams +ogival +ogive +ogives +oglala +oglalas +ogle +ogled +ogler +oglers +ogles +ogling +ogre +ogreish +ogres +ogress +ogresses +oh +ohia +ohio +ohioan +ohioans +ohm +ohmic +ohmically +ohmmeter +ohmmeters +ohms +oho +oidia +oidium +oil +oilbird +oilbirds +oilcan +oilcans +oilcloth +oilcloths +oiled +oiler +oilers +oilfield +oilfields +oilier +oiliest +oilily +oiliness +oiling +oilman +oilmen +oilpaper +oilpapers +oils +oilseed +oilseeds +oilskin +oilskins +oilstone +oilstones +oily +oink +oinked +oinking +oinks +ointment +ointments +oireachtas +oiticica +oiticicas +ojibwa +ojibwas +ojibway +ojibways +ok +ok'd +ok'ing +ok's +oka +okapi +okapis +okas +okay +okayed +okaying +okays +okeechobee +okeydoke +okeydokey +okhotsk +okie +okies +okinawa +oklahoma +oklahoman +oklahomans +okra +okras +oks +oktoberfest +olaf +old +olden +oldenburg +older +oldest +oldfangled +oldie +oldies +oldish +oldness +olds +oldsquaw +oldsquaws +oldster +oldsters +oldwife +oldwives +olea +oleaginous +oleaginously +oleaginousness +oleander +oleanders +oleandomycin +oleaster +oleasters +oleate +oleates +olecranal +olecranial +olecranian +olecranon +olecranons +olefin +olefinic +olefins +oleic +olein +oleine +oleines +oleins +oleo +oleograph +oleographer +oleographers +oleographic +oleographs +oleography +oleomargarine +oleomargarines +oleoresin +oleoresinous +oleoresins +oleos +oleum +oleums +olfaction +olfactometer +olfactometers +olfactometric +olfactometry +olfactory +olicook +olicooks +oligarch +oligarchic +oligarchical +oligarchies +oligarchs +oligarchy +oligocene +oligochaete +oligochaetes +oligochaetous +oligochete +oligochetes +oligoclase +oligoclases +oligodendrocyte +oligodendrocytes +oligodendroglia +oligodendroglial +oligodendroglias +oligomer +oligomeric +oligomerization +oligomerizations +oligomers +oligonucleotide +oligonucleotides +oligophagous +oligophagy +oligopolies +oligopolistic +oligopoly +oligopsonies +oligopsonistic +oligopsony +oligosaccharide +oligosaccharides +oligotrophic +oligotrophy +olingo +olingos +olio +olios +olivaceous +olive +olivenite +olivenites +oliver +olives +olivewood +olivewoods +olivia +olivier +olivine +olivinic +olivinitic +olla +ollas +olmec +olmecs +ologies +ology +ololiuqui +oloroso +olorosos +olympia +olympiad +olympiads +olympian +olympians +olympic +olympics +olympus +olé +om +omaha +omahas +oman +omani +omanis +omar +omasa +omasum +omayyad +omber +ombre +ombudsman +ombudsmanship +ombudsmen +ombudsperson +ombudspersons +ombudspersonship +ombudswoman +ombudswomanship +ombudswomen +omdurman +omega +omegas +omelet +omelets +omelette +omelettes +omen +omened +omening +omens +omenta +omental +omentum +omentums +omer +omers +omertà +omicron +omicrons +ominous +ominously +ominousness +omissible +omission +omissions +omissive +omit +omits +omitted +omitting +ommatidia +ommatidial +ommatidium +ommatophore +ommatophores +ommatophorous +ommiad +omnibus +omnibuses +omnicompetence +omnicompetent +omnidirectional +omnifarious +omnifariously +omnifariousness +omnificent +omnipotence +omnipotency +omnipotent +omnipotently +omnipotents +omnipresence +omnipresent +omnirange +omniranges +omniscience +omnisciency +omniscient +omnisciently +omniscients +omnium +omnivore +omnivores +omnivorous +omnivorously +omnivorousness +omphali +omphalos +omphaloskepsis +omsk +on +onager +onagers +onanism +onanist +onanistic +onanists +onboard +once +onchocerciasis +oncidium +oncidiums +oncogene +oncogenes +oncogenesis +oncogenic +oncogenicity +oncologic +oncological +oncologist +oncologists +oncology +oncoming +oncornavirus +oncornaviruses +one +one's +onefold +oneida +oneidas +oneiric +oneirically +oneiromancer +oneiromancers +oneiromancy +oneness +onerous +onerously +onerousness +ones +oneself +onetime +ongoing +ongoingness +onion +onions +onionskin +onionskins +oniony +onium +onlay +onlays +online +onload +onloaded +onloading +onloads +onlooker +onlookers +onlooking +only +onomastic +onomastically +onomastician +onomasticians +onomastics +onomatologist +onomatologists +onomatology +onomatopoeia +onomatopoeias +onomatopoeic +onomatopoeically +onomatopoetic +onomatopoetically +onondaga +onondagan +onondagas +onrush +onrushes +onrushing +onset +onsets +onshore +onside +onsite +onslaught +onslaughts +onstage +onstream +ontario +ontic +ontically +onto +ontogeneses +ontogenesis +ontogenetic +ontogenetically +ontogenies +ontogeny +ontological +ontologically +ontologist +ontologists +ontology +onus +onuses +onward +onwards +onycholyses +onycholysis +onychophoran +onychophorans +onyx +onyxes +oocyst +oocysts +oocyte +oocytes +oodles +oogamete +oogametes +oogamous +oogamy +oogenesis +oogenetic +oogonia +oogonial +oogonium +oogoniums +ooh +oohed +oohing +oohs +oolemma +oolemmas +oolite +oolites +oolith +ooliths +oolitic +oologic +oological +oologically +oologist +oologists +oology +oolong +oolongs +oomiak +oomiaks +oompah +oompahs +oomph +oop +oophorectomies +oophorectomy +oophoritis +oophoritises +oops +oort +oosphere +oospheres +oospore +oospores +oosporic +oosporous +ootheca +oothecae +oothecal +ootid +ootids +ooze +oozed +oozes +oozier +ooziest +oozily +ooziness +oozing +oozy +op +opacifier +opacifiers +opacities +opacity +opah +opahs +opal +opalesce +opalesced +opalescence +opalescent +opalescently +opalesces +opalescing +opaline +opallesces +opals +opaque +opaquely +opaqueness +opaques +ope +oped +open +openability +openable +opencast +opened +opener +openers +openest +openhanded +openhandedly +openhandedness +openhearted +openheartedly +openheartedness +opening +openings +openly +openmouthed +openmouthedly +openmouthedness +openness +opens +openwork +opera +operability +operable +operably +operagoer +operagoers +operagoing +operand +operandi +operands +operant +operantly +operants +operas +operate +operated +operates +operatic +operatically +operatics +operating +operation +operational +operationalism +operationalist +operationalistic +operationalists +operationalize +operationalized +operationalizes +operationalizing +operationally +operationism +operationist +operationists +operations +operative +operatively +operativeness +operatives +operator +operatorless +operators +opercula +opercular +opercularly +operculate +operculated +operculum +operculums +operetta +operettas +operettist +operettists +operon +operons +operose +operosely +operoseness +opes +ophelia +ophidian +ophidians +ophiolite +ophiolites +ophiological +ophiologist +ophiologists +ophiology +ophiophagous +ophir +ophite +ophites +ophitic +ophiuchus +ophiuroid +ophiuroids +ophthalmia +ophthalmias +ophthalmic +ophthalmitis +ophthalmitises +ophthalmologic +ophthalmological +ophthalmologically +ophthalmologist +ophthalmologists +ophthalmology +ophthalmoscope +ophthalmoscopes +ophthalmoscopic +ophthalmoscopical +ophthalmoscopy +opiate +opiated +opiates +opiating +opine +opined +opines +oping +opining +opinion +opinionated +opinionatedly +opinionatedness +opinionative +opinionatively +opinionativeness +opinioned +opinions +opioid +opioids +opisthobranch +opisthobranchs +opisthognathism +opisthognathous +opium +oporto +opossum +opossums +opponency +opponent +opponents +opportune +opportunely +opportuneness +opportunism +opportunist +opportunistic +opportunistically +opportunists +opportunities +opportunity +opposability +opposable +oppose +opposed +opposeless +opposer +opposers +opposes +opposing +opposite +oppositely +oppositeness +opposites +opposition +oppositional +oppositionist +oppositionists +oppositions +oppress +oppressed +oppresses +oppressing +oppression +oppressions +oppressive +oppressively +oppressiveness +oppressor +oppressors +opprobrious +opprobriously +opprobriousness +opprobrium +oppugn +oppugned +oppugner +oppugners +oppugning +oppugns +opsin +opsins +opsonic +opsonin +opsonins +opsonization +opsonizations +opsonize +opsonized +opsonizes +opsonizing +opt +optative +optatively +optatives +opted +optic +optical +optically +optician +opticians +optics +optima +optimal +optimality +optimally +optimism +optimist +optimistic +optimistically +optimists +optimization +optimizations +optimize +optimized +optimizer +optimizers +optimizes +optimizing +optimum +optimums +opting +option +optional +optionality +optionally +optioned +optioning +options +optoelectronic +optoelectronics +optokinetic +optometric +optometrical +optometrist +optometrists +optometry +opts +opulence +opulency +opulent +opulently +opuntia +opuntias +opus +opuscula +opuscule +opuscules +opusculum +opuses +opéra +oquassa +oquassas +or +ora +orach +orache +oraches +oracle +oracles +oracular +oracularity +oracularly +oral +oralism +oralist +oralists +orality +orally +orals +oran +orang +orange +orangeade +orangeades +orangeism +orangeman +orangemen +orangerie +orangeries +orangeroot +orangeroots +orangery +oranges +orangewood +orangewoods +orangey +orangish +orangoutang +orangoutangs +orangs +orangutan +orangutans +orangy +orate +orated +orates +orating +oration +orations +orator +oratorial +oratorian +oratorians +oratorical +oratorically +oratories +oratorio +oratorios +orators +oratorship +oratory +orb +orbed +orbicular +orbicularity +orbicularly +orbiculate +orbiculated +orbiculately +orbing +orbit +orbital +orbitals +orbited +orbiteer +orbiteered +orbiteering +orbiteers +orbiter +orbiters +orbiting +orbits +orbs +orca +orcadian +orcadians +orcas +orchard +orchardist +orchardists +orchards +orchestra +orchestral +orchestrally +orchestras +orchestrate +orchestrated +orchestrater +orchestraters +orchestrates +orchestrating +orchestration +orchestrational +orchestrations +orchestrator +orchestrators +orchestrina +orchestrion +orchid +orchidaceous +orchidectomies +orchidectomy +orchidlike +orchids +orchiectomies +orchiectomy +orchil +orchils +orchis +orchises +orcus +ordain +ordained +ordainer +ordainers +ordaining +ordainment +ordainments +ordains +ordeal +ordeals +order +orderable +ordered +orderer +orderers +ordering +orderings +orderless +orderlies +orderliness +orderly +orders +ordinal +ordinals +ordinance +ordinances +ordinand +ordinands +ordinaries +ordinarily +ordinariness +ordinary +ordinate +ordinates +ordination +ordinations +ordines +ordnance +ordo +ordonnance +ordonnances +ordos +ordovician +ordure +ore +oread +oreads +oregano +oregon +oregonian +oregonians +oreide +oreides +oreo +oreos +ores +orestes +oresund +orfray +orfrays +organ +organa +organdie +organdies +organdy +organelle +organelles +organic +organically +organicism +organicist +organicists +organicity +organics +organism +organismal +organismic +organismically +organisms +organist +organists +organizable +organization +organizational +organizationally +organizations +organize +organized +organizer +organizers +organizes +organizing +organochlorine +organochlorines +organogeneses +organogenesis +organogenetic +organogenetically +organographic +organographically +organographies +organography +organoleptic +organoleptically +organologic +organological +organology +organomercurial +organomercurials +organometallic +organon +organons +organophosphate +organophosphates +organophosphorous +organophosphorus +organophosphoruses +organotherapeutic +organotherapies +organotherapy +organotropic +organotropically +organotropism +organotropy +organs +organum +organums +organza +organzine +organzines +orgasm +orgasmic +orgasmically +orgasms +orgastic +orgastically +orgeat +orgeats +orgiast +orgiastic +orgiastically +orgiasts +orgies +orgone +orgones +orgulous +orgy +oribatid +oribatids +oribi +oribis +oriel +oriels +orient +oriental +orientalia +orientalism +orientalist +orientalists +orientalize +orientalized +orientalizes +orientalizing +orientally +orientals +orientate +orientated +orientates +orientating +orientation +orientational +orientationally +orientations +oriented +orienteer +orienteering +orienteers +orienting +orients +orifice +orifices +orificial +oriflamme +oriflammes +origami +origamis +origanum +origanums +origin +original +originalism +originalist +originalists +originalities +originality +originally +originals +originate +originated +originates +originating +origination +originations +originative +originatively +originator +originators +origins +orinasal +orinasals +orinoco +oriole +orioles +orion +orion's +orismological +orismology +orison +orisons +orissa +oriya +orizaba +orkney +orlando +orleanian +orleanians +orleanist +orleanists +orleans +orlon +orlop +orlops +orléanais +orléans +ormazd +ormer +ormers +ormolu +ormolus +ormuz +ormuzd +ornament +ornamental +ornamentally +ornamentals +ornamentation +ornamented +ornamenter +ornamenters +ornamenting +ornaments +ornate +ornately +ornateness +ornerier +orneriest +orneriness +ornery +ornithic +ornithine +ornithines +ornithischian +ornithischians +ornithologic +ornithological +ornithologically +ornithologist +ornithologists +ornithology +ornithopod +ornithopods +ornithopter +ornithopters +ornithosis +orogenesis +orogenetic +orogenic +orogenically +orogeny +orographic +orographical +orographically +orography +oroide +oroides +orological +orologically +orologist +orologists +orology +oromo +oromos +oropharyngeal +oropharynges +oropharynx +oropharynxes +orotund +orotundity +orphan +orphanage +orphanages +orphaned +orphanhood +orphaning +orphans +orphean +orpheus +orphic +orphically +orphism +orphist +orphists +orphrey +orphreys +orpiment +orpine +orpines +orpington +orpingtons +orreries +orrery +orris +orrises +orrisroot +orrisroots +ors +ort +orthicon +orthicons +ortho +orthocenter +orthocenters +orthochromatic +orthochromatism +orthoclase +orthoclastic +orthodontia +orthodontic +orthodontically +orthodontics +orthodontist +orthodontists +orthodonture +orthodox +orthodoxes +orthodoxies +orthodoxly +orthodoxy +orthoepic +orthoepical +orthoepically +orthoepist +orthoepists +orthoepy +orthogenesis +orthogenetic +orthogenetically +orthogonal +orthogonality +orthogonalization +orthogonalizations +orthogonalize +orthogonalized +orthogonalizes +orthogonalizing +orthogonally +orthograde +orthographer +orthographers +orthographic +orthographical +orthographically +orthographies +orthographist +orthographists +orthography +orthomolecular +orthonormal +orthopaedic +orthopaedics +orthopedic +orthopedically +orthopedics +orthopedist +orthopedists +orthophosphate +orthophosphates +orthophosphoric +orthopsychiatric +orthopsychiatrical +orthopsychiatrist +orthopsychiatrists +orthopsychiatry +orthoptera +orthopteral +orthopteran +orthopterans +orthopterist +orthopterists +orthopteroid +orthopteron +orthopterons +orthopterous +orthorhombic +orthoscopic +orthoses +orthosis +orthostatic +orthotic +orthotics +orthotist +orthotists +orthotropic +orthotropically +orthotropism +orthotropous +ortler +ortles +ortolan +ortolans +orts +orvieto +orwellian +oryx +oryxes +orzo +orzos +os +osage +osages +osaka +osar +osborne +oscan +oscans +oscar +oscars +osceola +oscillate +oscillated +oscillates +oscillating +oscillation +oscillational +oscillations +oscillator +oscillators +oscillatory +oscillogram +oscillograms +oscillograph +oscillographic +oscillographically +oscillographs +oscillography +oscilloscope +oscilloscopes +oscilloscopic +oscine +oscines +oscitance +oscitances +oscitancies +oscitancy +oscitant +oscula +osculant +oscular +osculate +osculated +osculates +osculating +osculation +osculations +osculatory +oscule +oscules +osculum +osee +osier +osiers +osiris +oslo +osmanli +osmanlis +osmatic +osmeteria +osmeterium +osmic +osmically +osmics +osmious +osmiridium +osmiridiums +osmium +osmol +osmolal +osmolalities +osmolality +osmolar +osmolarities +osmolarity +osmole +osmoles +osmols +osmometer +osmometers +osmometric +osmometry +osmoregulation +osmoregulations +osmoregulatory +osmose +osmosed +osmoses +osmosing +osmosis +osmotic +osmotically +osmous +osmund +osmunda +osmundas +osmunds +osnabrück +osnaburg +osnaburgs +osprey +ospreys +osric +ossa +ossature +ossatures +ossein +osseins +osseous +osseously +osset +ossete +ossetes +ossetia +ossetian +ossetians +ossetic +ossets +ossia +ossian +ossianic +ossicle +ossicles +ossicular +ossiculate +ossific +ossification +ossified +ossifies +ossifrage +ossifrages +ossify +ossifying +osso +ossuaries +ossuary +osteal +osteitis +ostend +ostende +ostensible +ostensibly +ostensive +ostensively +ostensoria +ostensories +ostensorium +ostensory +ostentation +ostentatious +ostentatiously +ostentatiousness +osteoarthritic +osteoarthritis +osteoblast +osteoblastic +osteoblasts +osteoclases +osteoclasis +osteoclast +osteoclastic +osteoclasts +osteocyte +osteocytes +osteogeneses +osteogenesis +osteogenetic +osteogenic +osteogenous +osteoid +osteoids +osteological +osteologically +osteologies +osteologist +osteologists +osteology +osteolyses +osteolysis +osteolytic +osteoma +osteomalacia +osteomalacias +osteomas +osteomata +osteomyelitis +osteomyelitises +osteopath +osteopathic +osteopathically +osteopathist +osteopathists +osteopaths +osteopathy +osteophyte +osteophytes +osteophytic +osteoplastic +osteoplasties +osteoplasty +osteoporoses +osteoporosis +osteoporotic +osteosarcoma +osteosarcomas +osteosarcomata +osteoses +osteosis +osteotomies +osteotomist +osteotomists +osteotomy +ostia +ostiak +ostiaks +ostiaries +ostiary +ostinato +ostinatos +ostiolar +ostiole +ostioles +ostium +ostler +ostlers +ostmark +ostmarks +ostomate +ostomates +ostomies +ostomy +ostoses +ostosis +ostraca +ostracism +ostracize +ostracized +ostracizes +ostracizing +ostracod +ostracode +ostracoderm +ostracoderms +ostracodes +ostracods +ostracon +ostrich +ostriches +ostrichlike +ostrogoth +ostrogothic +ostrogoths +ostyak +ostyaks +oswego +otaheite +otalgia +otalgias +otalgic +othello +other +otherguess +otherness +others +otherwhere +otherwhile +otherwhiles +otherwise +otherworld +otherworldliness +otherworldly +otherworlds +othman +othmans +otic +otiose +otiosely +otioseness +otiosity +otitic +otitis +oto +otocyst +otocystic +otocysts +otolaryngological +otolaryngologist +otolaryngologists +otolaryngology +otolith +otolithic +otoliths +otological +otologist +otologists +otology +otophone +otorhinolaryngological +otorhinolaryngologist +otorhinolaryngologists +otorhinolaryngology +otos +otoscleroses +otosclerosis +otosclerotic +otoscope +otoscopes +ototoxic +ototoxicity +otranto +ottar +ottars +ottava +ottawa +ottawas +otter +otters +otto +ottoman +ottomans +ottos +otway +ouabain +ouabains +ouachita +ouagadougou +oubliette +oubliettes +ouch +ouches +oud +oudenarde +oudh +ouds +ought +oughtn +oughtn't +oughts +ouguiya +ouguiyas +ouija +ounce +ounces +our +ours +ourself +ourselves +ousel +ousels +oushak +oust +ousted +ouster +ousters +ousting +ousts +out +outachieve +outachieved +outachieves +outachieving +outact +outacted +outacting +outacts +outage +outages +outate +outback +outbacker +outbackers +outbalance +outbalanced +outbalances +outbalancing +outbargain +outbargained +outbargaining +outbargains +outbid +outbidden +outbidding +outbids +outbitch +outbitched +outbitches +outbitching +outbluff +outbluffed +outbluffing +outbluffs +outboard +outboards +outbought +outbound +outbox +outboxed +outboxes +outboxing +outbrag +outbraged +outbraging +outbrags +outbrave +outbraved +outbraves +outbraving +outbrawl +outbrawled +outbrawling +outbrawls +outbreak +outbreaks +outbred +outbreed +outbreeding +outbreedings +outbreeds +outbuilding +outbuildings +outbulk +outbulked +outbulking +outbulks +outburst +outbursts +outbuy +outbuying +outbuys +outcall +outcalls +outcast +outcaste +outcastes +outcasts +outcatch +outcatches +outcatching +outcaught +outcharge +outcharged +outcharges +outcharging +outclass +outclassed +outclasses +outclassing +outclimb +outclimbed +outclimbing +outclimbs +outcoach +outcoached +outcoaches +outcoaching +outcome +outcomes +outcompete +outcompeted +outcompetes +outcompeting +outcries +outcrop +outcropped +outcropping +outcroppings +outcrops +outcross +outcrossed +outcrosses +outcrossing +outcry +outcurve +outcurves +outdance +outdanced +outdances +outdancing +outdate +outdated +outdatedly +outdatedness +outdates +outdating +outdazzle +outdazzled +outdazzles +outdazzling +outdebate +outdebated +outdebates +outdebating +outdeliver +outdelivered +outdelivering +outdelivers +outdesign +outdesigned +outdesigning +outdesigns +outdid +outdistance +outdistanced +outdistances +outdistancing +outdo +outdoes +outdoing +outdone +outdoor +outdoors +outdoorsman +outdoorsmanship +outdoorsmen +outdoorswoman +outdoorswomen +outdoorsy +outdrag +outdragged +outdragging +outdrags +outdrank +outdraw +outdrawing +outdrawn +outdraws +outdress +outdressed +outdresses +outdressing +outdrew +outdrink +outdrinking +outdrinks +outdrive +outdriven +outdrives +outdriving +outdrove +outdrunk +outduel +outdueled +outdueling +outduelled +outduelling +outduels +outearn +outearned +outearning +outearns +outeat +outeaten +outeating +outeats +outed +outer +outercoat +outercoats +outermost +outers +outerwear +outface +outfaced +outfaces +outfacing +outfall +outfalls +outfield +outfielder +outfielders +outfields +outfight +outfighting +outfights +outfigure +outfigured +outfigures +outfiguring +outfish +outfished +outfishes +outfishing +outfit +outfits +outfitted +outfitter +outfitters +outfitting +outflank +outflanked +outflanking +outflanks +outflew +outflies +outflow +outflowed +outflowing +outflown +outflows +outfly +outflying +outfoot +outfooted +outfooting +outfoots +outfought +outfox +outfoxed +outfoxes +outfoxing +outfumble +outfumbled +outfumbles +outfumbling +outgain +outgained +outgaining +outgains +outgas +outgassed +outgasses +outgassing +outgeneral +outgeneraled +outgeneraling +outgenerals +outgiving +outglitter +outglittered +outglittering +outglitters +outgo +outgoes +outgoing +outgoingness +outgoings +outgone +outgrew +outgrip +outgripped +outgripping +outgrips +outgross +outgrossed +outgrosses +outgrossing +outgrow +outgrowing +outgrown +outgrows +outgrowth +outgrowths +outguess +outguessed +outguesses +outguessing +outgun +outgunned +outgunning +outguns +outhaul +outhauls +outhit +outhits +outhitting +outhomer +outhomered +outhomering +outhomers +outhouse +outhouses +outhunt +outhunted +outhunting +outhunts +outhustle +outhustled +outhustles +outhustling +outing +outings +outintrigue +outintrigued +outintrigues +outintriguing +outjump +outjumped +outjumping +outjumps +outkick +outkicked +outkicking +outkicks +outkill +outkilled +outkilling +outkills +outlaid +outland +outlander +outlanders +outlandish +outlandishly +outlandishness +outlands +outlast +outlasted +outlasting +outlasts +outlaw +outlawed +outlawing +outlawries +outlawry +outlaws +outlay +outlaying +outlays +outleap +outleaped +outleaping +outleaps +outleapt +outlearn +outlearned +outlearning +outlearns +outlearnt +outlet +outlets +outlier +outliers +outline +outlined +outliner +outliners +outlines +outlining +outlive +outlived +outlives +outliving +outlook +outlooks +outlying +outman +outmaneuver +outmaneuvered +outmaneuvering +outmaneuvers +outmanipulate +outmanipulated +outmanipulates +outmanipulating +outmanned +outmanning +outmans +outmarch +outmarched +outmarches +outmarching +outmatch +outmatched +outmatches +outmatching +outmode +outmoded +outmodes +outmoding +outmost +outmuscle +outmuscled +outmuscles +outmuscling +outness +outnumber +outnumbered +outnumbering +outnumbers +outorganize +outorganized +outorganizes +outorganizing +outpace +outpaced +outpaces +outpacing +outpass +outpassed +outpasses +outpassing +outpatient +outpatients +outperform +outperformed +outperforming +outperforms +outpitch +outpitched +outpitches +outpitching +outplace +outplaced +outplacement +outplacements +outplacer +outplacers +outplaces +outplacing +outplay +outplayed +outplaying +outplays +outplot +outplots +outplotted +outplotting +outpoint +outpointed +outpointing +outpoints +outpolitick +outpoliticked +outpoliticking +outpoliticks +outpoll +outpolled +outpolling +outpolls +outpopulate +outpopulated +outpopulates +outpopulating +outport +outports +outpost +outposts +outpour +outpoured +outpourer +outpourers +outpouring +outpourings +outpours +outpower +outpowered +outpowering +outpowers +outpray +outprayed +outpraying +outprays +outpreach +outpreached +outpreaches +outpreaching +outprice +outpriced +outprices +outpricing +outproduce +outproduced +outproduces +outproducing +outpromise +outpromised +outpromises +outpromising +outpull +outpulled +outpulling +outpulls +outpunch +outpunched +outpunches +outpunching +output +outputs +outputted +outputting +outrace +outraced +outraces +outracing +outrage +outraged +outrageous +outrageously +outrageousness +outrages +outraging +outran +outrange +outranged +outranges +outranging +outrank +outranked +outranking +outranks +outrate +outrated +outrates +outrating +outreach +outreached +outreaches +outreaching +outrebound +outrebounded +outrebounding +outrebounds +outreproduce +outreproduced +outreproduces +outreproducing +outridden +outride +outrider +outriders +outrides +outriding +outrigger +outriggers +outright +outrightly +outrightness +outrival +outrivaled +outrivaling +outrivalled +outrivalling +outrivals +outroar +outroared +outroaring +outroars +outrode +outrow +outrowed +outrowing +outrows +outrun +outrunning +outruns +outrush +outrushed +outrushes +outrushing +outré +outs +outsail +outsailed +outsailing +outsails +outsang +outsat +outscheme +outschemed +outschemes +outscheming +outscoop +outscooped +outscooping +outscoops +outscore +outscored +outscores +outscoring +outsell +outselling +outsells +outset +outsets +outshine +outshines +outshining +outshone +outshoot +outshooting +outshoots +outshot +outshout +outshouted +outshouting +outshouts +outside +outsider +outsiderness +outsiders +outsides +outsight +outsights +outsing +outsinging +outsings +outsit +outsits +outsitting +outsize +outsized +outsizes +outskate +outskated +outskates +outskating +outskirt +outskirts +outslick +outslicked +outslicking +outslicks +outsmart +outsmarted +outsmarting +outsmarts +outsoar +outsoared +outsoaring +outsoars +outsold +outsole +outsoles +outsource +outsourced +outsources +outsourcing +outsourcings +outsparkle +outsparkled +outsparkles +outsparkling +outspeak +outspeaking +outspeaks +outsped +outspeed +outspeeded +outspeeding +outspeeds +outspend +outspending +outspends +outspent +outspoke +outspoken +outspokenly +outspokenness +outspread +outspreading +outspreads +outsprint +outsprinted +outsprinting +outsprints +outstand +outstanding +outstandingly +outstands +outstare +outstared +outstares +outstaring +outstation +outstations +outstay +outstayed +outstaying +outstays +outstood +outstretch +outstretched +outstretches +outstretching +outstridden +outstride +outstrides +outstriding +outstrip +outstripped +outstripping +outstrips +outstrode +outstroke +outstrokes +outsung +outswam +outswear +outswearing +outswears +outswim +outswimming +outswims +outswore +outsworn +outswum +outtake +outtakes +outtalk +outtalked +outtalking +outtalks +outthink +outthinking +outthinks +outthought +outthrew +outthrow +outthrowing +outthrown +outthrows +outthrust +outthrusted +outthrusting +outthrusts +outtrade +outtraded +outtrades +outtrading +outturn +outturning +outturns +outvie +outvied +outvies +outvote +outvoted +outvotes +outvoting +outvying +outwait +outwaited +outwaiting +outwaits +outwalk +outwalked +outwalking +outwalks +outward +outwardly +outwardness +outwards +outwash +outwashes +outwatch +outwatched +outwatches +outwatching +outwear +outwearing +outwears +outweigh +outweighed +outweighing +outweighs +outwent +outwit +outwits +outwitted +outwitting +outwore +outwork +outworked +outworker +outworkers +outworking +outworks +outworn +outwrestle +outwrestled +outwrestles +outwrestling +outwrite +outwrites +outwriting +outwritten +outwrote +outwrought +outyell +outyelled +outyelling +outyells +outyield +outyielded +outyielding +outyields +ouzel +ouzels +ouzo +ouzos +ova +oval +ovalbumin +ovalbumins +ovality +ovally +ovalness +ovals +ovambo +ovambos +ovarial +ovarian +ovariectomies +ovariectomized +ovariectomy +ovaries +ovariole +ovarioles +ovariotomies +ovariotomy +ovaritis +ovaritises +ovary +ovate +ovately +ovation +ovational +ovations +oven +ovenable +ovenbird +ovenbirds +ovenproof +ovens +ovenware +over +overabounding +overabstract +overabundance +overabundances +overabundant +overabundantly +overaccentuate +overaccentuated +overaccentuates +overaccentuating +overachieve +overachieved +overachievement +overachievements +overachiever +overachievers +overachieves +overachieving +overact +overacted +overacting +overaction +overactions +overactive +overactivity +overacts +overadjustment +overadjustments +overadvertise +overadvertised +overadvertises +overadvertising +overage +overaged +overages +overaggressive +overaggressively +overaggressiveness +overalert +overall +overalled +overalls +overambition +overambitious +overambitiously +overambitiousness +overamplified +overanalyses +overanalysis +overanalytical +overanalyze +overanalyzed +overanalyzes +overanalyzing +overanxieties +overanxiety +overanxious +overanxiously +overanxiousness +overapplication +overapplications +overarch +overarched +overarches +overarching +overarchingly +overarm +overarmed +overarming +overarms +overarousal +overarousals +overarrange +overarranged +overarranges +overarranging +overarticulate +overassert +overasserted +overasserting +overassertion +overassertions +overassertive +overasserts +overassess +overassessed +overassesses +overassessing +overassessment +overassessments +overate +overattention +overattentions +overawe +overawed +overawes +overawing +overbake +overbaked +overbakes +overbaking +overbalance +overbalanced +overbalances +overbalancing +overbear +overbearing +overbearingly +overbearingness +overbears +overbeat +overbeaten +overbeating +overbeats +overbejeweled +overbid +overbidden +overbidder +overbidders +overbidding +overbids +overbill +overbilled +overbilling +overbills +overbite +overbites +overbleach +overbleached +overbleaches +overbleaching +overblew +overblouse +overblouses +overblow +overblowing +overblown +overblows +overboard +overboil +overboiled +overboiling +overboils +overbold +overbook +overbooked +overbooking +overbooks +overbore +overborne +overborrow +overborrowed +overborrowing +overborrows +overbought +overbreathing +overbrief +overbright +overbroad +overbrowse +overbrowsed +overbrowses +overbrowsing +overbrutal +overbuild +overbuilding +overbuilds +overbuilt +overburden +overburdened +overburdening +overburdens +overburn +overbusy +overbuy +overbuying +overbuys +overcall +overcalled +overcalling +overcalls +overcame +overcapacities +overcapacity +overcapitalization +overcapitalizations +overcapitalize +overcapitalized +overcapitalizes +overcapitalizing +overcareful +overcast +overcasting +overcastings +overcasts +overcaution +overcautious +overcautiously +overcautiousness +overcentralization +overcentralize +overcentralized +overcentralizes +overcentralizing +overcharge +overcharged +overcharges +overcharging +overchill +overchilled +overchilling +overchills +overcivilized +overclaim +overclaimed +overclaiming +overclaims +overclassification +overclassifications +overclassified +overclassifies +overclassify +overclassifying +overclean +overcleaned +overcleaning +overcleans +overclear +overcloud +overclouded +overclouding +overclouds +overcoach +overcoached +overcoaches +overcoaching +overcoat +overcoating +overcoatings +overcoats +overcome +overcomer +overcomers +overcomes +overcoming +overcommercialization +overcommercialize +overcommercialized +overcommercializes +overcommercializing +overcommit +overcommitment +overcommitments +overcommits +overcommitted +overcommitting +overcommunicate +overcommunicated +overcommunicates +overcommunicating +overcommunication +overcompensate +overcompensated +overcompensates +overcompensating +overcompensation +overcompensatory +overcomplex +overcompliance +overcomplicate +overcomplicated +overcomplicates +overcomplicating +overcompress +overcompressed +overcompresses +overcompressing +overconcentration +overconcentrations +overconcern +overconcerned +overconcerning +overconcerns +overconfidence +overconfident +overconfidently +overconscientious +overconscious +overconservative +overconstruct +overconstructed +overconstructing +overconstructs +overconsume +overconsumed +overconsumes +overconsuming +overconsumption +overcontrol +overcontrolled +overcontrolling +overcontrols +overcook +overcooked +overcooking +overcooks +overcool +overcooled +overcooling +overcools +overcorrect +overcorrected +overcorrecting +overcorrection +overcorrections +overcorrects +overcount +overcounted +overcounting +overcountings +overcounts +overcredulous +overcritical +overcritically +overcriticalness +overcrop +overcropped +overcropping +overcrops +overcrowd +overcrowded +overcrowding +overcrowds +overcultivation +overcure +overcurious +overcut +overcuts +overcutting +overdecorate +overdecorated +overdecorates +overdecorating +overdecoration +overdelicate +overdemanding +overdependence +overdependent +overdesign +overdesigned +overdesigning +overdesigns +overdetermine +overdetermined +overdetermines +overdetermining +overdevelop +overdeveloped +overdeveloping +overdevelopment +overdevelops +overdid +overdifferentiation +overdirect +overdiscount +overdiscounted +overdiscounting +overdiscounts +overdiversity +overdo +overdocument +overdocumented +overdocumenting +overdocuments +overdoer +overdoers +overdoes +overdog +overdogs +overdoing +overdominance +overdominances +overdominant +overdone +overdosage +overdosages +overdose +overdosed +overdoses +overdosing +overdraft +overdrafts +overdramatic +overdramatize +overdramatized +overdramatizes +overdramatizing +overdrank +overdraught +overdraughts +overdraw +overdrawing +overdrawn +overdraws +overdress +overdressed +overdresses +overdressing +overdrew +overdried +overdries +overdrink +overdrinking +overdrinks +overdrive +overdriven +overdrives +overdriving +overdrove +overdry +overdrying +overdub +overdubbed +overdubbing +overdubs +overdue +overeager +overeagerly +overeagerness +overearnest +overeat +overeaten +overeater +overeaters +overeating +overeats +overed +overedit +overedited +overediting +overedits +overeducate +overeducated +overeducates +overeducating +overeducation +overelaborate +overelaborated +overelaborates +overelaborating +overelaboration +overembellish +overembellished +overembellishes +overembellishing +overemote +overemotional +overemphases +overemphasis +overemphasize +overemphasized +overemphasizes +overemphasizing +overemphatic +overenamored +overencourage +overencouraged +overencourages +overencouraging +overenergetic +overengineer +overengineered +overengineering +overengineers +overenrolled +overentertained +overenthusiasm +overenthusiasms +overenthusiastic +overequip +overequipped +overequipping +overequips +overestimate +overestimated +overestimates +overestimating +overestimation +overestimations +overevaluation +overevaluations +overexaggerate +overexaggerated +overexaggerates +overexaggerating +overexaggeration +overexaggerations +overexcite +overexcited +overexcites +overexciting +overexercise +overexercised +overexercises +overexercising +overexert +overexerted +overexerting +overexertion +overexertions +overexerts +overexpand +overexpanded +overexpanding +overexpands +overexpansion +overexpectation +overexpectations +overexplain +overexplained +overexplaining +overexplains +overexplicit +overexploit +overexploitation +overexploitations +overexploited +overexploiting +overexploits +overexpose +overexposed +overexposes +overexposing +overexposure +overexposures +overextend +overextended +overextending +overextends +overextension +overextensions +overextraction +overextractions +overextrapolation +overextrapolations +overextravagant +overexuberant +overfacile +overfamiliar +overfamiliarities +overfamiliarity +overfastidious +overfat +overfatigue +overfatigued +overfavor +overfavored +overfavoring +overfavors +overfed +overfeed +overfeeding +overfeeds +overfertilization +overfertilize +overfertilized +overfertilizes +overfertilizing +overfill +overfilled +overfilling +overfills +overfish +overfished +overfishes +overfishing +overflew +overflies +overflight +overflights +overflow +overflowed +overflowing +overflown +overflows +overfly +overflying +overfocus +overfocused +overfocuses +overfocusing +overfocussed +overfocusses +overfocussing +overfond +overfulfill +overfulfilled +overfulfilling +overfulfills +overfull +overfund +overfunded +overfunding +overfunds +overfussy +overgarment +overgarments +overgeneralization +overgeneralizations +overgeneralize +overgeneralized +overgeneralizes +overgeneralizing +overgenerosity +overgenerous +overgenerously +overglamorize +overglamorized +overglamorizes +overglamorizing +overglaze +overglazed +overglazes +overglazing +overgovern +overgoverned +overgoverning +overgoverns +overgraze +overgrazed +overgrazes +overgrazing +overgrew +overgrow +overgrowing +overgrown +overgrows +overgrowth +overgrowths +overhand +overhanded +overhanding +overhandle +overhandled +overhandles +overhandling +overhands +overhang +overhanging +overhangs +overharvest +overharvested +overharvesting +overharvests +overhasty +overhaul +overhauled +overhauler +overhaulers +overhauling +overhauls +overhead +overheads +overhear +overheard +overhearer +overhearers +overhearing +overhears +overheat +overheated +overheating +overheats +overhit +overhits +overhitting +overhomogenize +overhomogenized +overhomogenizes +overhomogenizing +overhung +overhunt +overhunted +overhunting +overhunts +overhydrate +overhydrated +overhydrates +overhydrating +overhydration +overhype +overhyped +overhypes +overhyping +overidealize +overidealized +overidealizes +overidealizing +overidentification +overidentified +overidentifies +overidentify +overidentifying +overimaginative +overimpress +overimpressed +overimpresses +overimpressing +overindebtedness +overindulge +overindulged +overindulgence +overindulgences +overindulgent +overindulgently +overindulges +overindulging +overindustrialize +overindustrialized +overindustrializes +overindustrializing +overinflate +overinflated +overinflates +overinflating +overinflation +overinform +overinformed +overinforming +overinforms +overing +overingenious +overingenuity +overinsistent +overintellectualization +overintellectualize +overintellectualized +overintellectualizes +overintellectualizing +overintense +overintensity +overinterpret +overinterpretation +overinterpretations +overinterpreted +overinterpreting +overinterprets +overinvestment +overissuance +overissue +overissued +overissues +overissuing +overjoy +overjoyed +overjoying +overjoys +overkill +overkilled +overkilling +overkills +overlabor +overlabored +overlaboring +overlabors +overladen +overlaid +overlain +overland +overlap +overlapped +overlapping +overlaps +overlarge +overlavish +overlay +overlaying +overlays +overleaf +overleap +overleaped +overleaping +overleaps +overleapt +overlearn +overlearned +overlearning +overlearns +overlearnt +overlend +overlending +overlends +overlength +overlengthen +overlengthened +overlengthening +overlengthens +overlent +overlie +overlies +overlight +overliteral +overliterary +overload +overloaded +overloading +overloads +overlong +overlook +overlooked +overlooking +overlooks +overlord +overlords +overlordship +overloud +overlush +overly +overlying +overman +overmanage +overmanaged +overmanages +overmanaging +overmanned +overmannered +overmanning +overmans +overmantel +overmantels +overmaster +overmastered +overmastering +overmasters +overmatch +overmatched +overmatches +overmatching +overmature +overmaturity +overmedicate +overmedicated +overmedicates +overmedicating +overmedication +overmen +overmighty +overmilk +overmilked +overmilking +overmilks +overmine +overmined +overmines +overmining +overmix +overmixed +overmixes +overmixing +overmodest +overmodestly +overmuch +overmuscled +overnice +overnight +overnighted +overnighter +overnighters +overnighting +overnights +overnourish +overnourished +overnourishes +overnourishing +overnutrition +overobvious +overoperate +overoperated +overoperates +overoperating +overopinionated +overoptimism +overoptimist +overoptimistic +overoptimistically +overoptimists +overorchestrate +overorchestrated +overorchestrates +overorchestrating +overorganize +overorganized +overorganizes +overorganizing +overornament +overornamented +overornamenting +overornaments +overpackage +overpackaged +overpackages +overpackaging +overpaid +overparticular +overpass +overpassed +overpasses +overpassing +overpast +overpay +overpaying +overpayment +overpayments +overpays +overpedal +overpedaled +overpedaling +overpedals +overpeople +overpeopled +overpeoples +overpeopling +overpersuade +overpersuaded +overpersuades +overpersuading +overpersuasion +overplaid +overplaided +overplan +overplanned +overplanning +overplans +overplant +overplanted +overplanting +overplants +overplay +overplayed +overplaying +overplays +overplenty +overplot +overplots +overplotted +overplotting +overplus +overpluses +overpopulate +overpopulated +overpopulates +overpopulating +overpopulation +overpotent +overpower +overpowered +overpowering +overpoweringly +overpowers +overpraise +overpraised +overpraises +overpraising +overprecise +overprescribe +overprescribed +overprescribes +overprescribing +overprescription +overprescriptions +overpressure +overpressured +overpressures +overpressuring +overpressurization +overpressurizations +overprice +overpriced +overprices +overpricing +overprint +overprinted +overprinting +overprints +overprivileged +overprize +overprized +overprizes +overprizing +overprocess +overprocessed +overprocesses +overprocessing +overproduce +overproduced +overproducer +overproducers +overproduces +overproducing +overproduction +overproductions +overprogram +overprogrammed +overprogramming +overprograms +overpromise +overpromised +overpromises +overpromising +overpromote +overpromoted +overpromotes +overpromoting +overproof +overproportion +overproportionate +overproportionately +overproportioned +overproportioning +overproportions +overprotect +overprotected +overprotecting +overprotection +overprotections +overprotective +overprotectiveness +overprotects +overpump +overpumped +overpumping +overpumps +overqualified +overran +overrate +overrated +overrates +overrating +overreach +overreached +overreacher +overreachers +overreaches +overreaching +overreact +overreacted +overreacting +overreaction +overreactions +overreactive +overreacts +overrefine +overrefined +overrefinement +overrefinements +overrefines +overrefining +overregulate +overregulated +overregulates +overregulating +overregulation +overregulations +overreliance +overreport +overreported +overreporting +overreports +overrepresentation +overrepresentations +overrepresented +overrespond +overresponded +overresponding +overresponds +overrich +overridden +override +overrides +overriding +overridingly +overrigid +overripe +overripely +overripeness +overrode +overruff +overruffed +overruffing +overruffs +overrule +overruled +overrules +overruling +overrun +overrunning +overruns +overs +oversalt +oversalted +oversalting +oversalts +oversanguine +oversaturate +oversaturated +oversaturates +oversaturating +oversaturation +oversauce +oversauced +oversauces +oversaucing +oversaw +overscale +overscaled +overscore +overscored +overscores +overscoring +overscrupulous +oversea +overseas +oversecretion +oversee +overseeing +overseen +overseer +overseers +oversees +oversell +overselling +oversells +oversensitive +oversensitiveness +oversensitivities +oversensitivity +overserious +overseriously +overservice +overserviced +overservices +overservicing +overset +oversets +oversetting +oversew +oversewed +oversewing +oversewn +oversews +oversexed +overshadow +overshadowed +overshadowing +overshadows +overshirt +overshirts +overshoe +overshoes +overshoot +overshooting +overshoots +overshot +oversight +oversights +oversimple +oversimplification +oversimplifications +oversimplified +oversimplifier +oversimplifiers +oversimplifies +oversimplify +oversimplifying +oversimplistic +oversimply +oversize +oversized +oversizes +overskirt +overskirts +overslaugh +overslaughed +overslaughing +overslaughs +oversleep +oversleeping +oversleeps +overslept +overslip +overslipped +overslipping +overslips +oversmoke +oversmoked +oversmokes +oversmoking +oversold +oversolicitous +oversophisticated +oversoul +oversouls +overspecialization +overspecializations +overspecialize +overspecialized +overspecializes +overspecializing +overspeculate +overspeculated +overspeculates +overspeculating +overspeculation +overspeculations +overspend +overspender +overspenders +overspending +overspends +overspent +overspill +overspilled +overspilling +overspills +overspilt +overspread +overspreading +overspreads +overstability +overstaff +overstaffed +overstaffing +overstaffs +overstate +overstated +overstatement +overstatements +overstates +overstating +overstay +overstayed +overstaying +overstays +oversteer +oversteers +overstep +overstepped +overstepping +oversteps +overstimulate +overstimulated +overstimulates +overstimulating +overstimulation +overstimulations +overstitch +overstitched +overstitches +overstitching +overstock +overstocked +overstocking +overstocks +overstories +overstory +overstrain +overstrained +overstraining +overstrains +overstress +overstressed +overstresses +overstressing +overstretch +overstretched +overstretches +overstretching +overstrew +overstrewed +overstrewing +overstrews +overstridden +overstride +overstrides +overstriding +overstrike +overstrikes +overstrode +overstructured +overstrung +overstuff +overstuffed +overstuffing +overstuffs +oversubscribe +oversubscribed +oversubscribes +oversubscribing +oversubscription +oversubscriptions +oversubtle +oversuds +oversupplied +oversupplies +oversupply +oversupplying +oversuspicious +oversweet +oversweeten +oversweetened +oversweetening +oversweetens +oversweetness +overswing +overt +overtake +overtaken +overtakes +overtaking +overtalk +overtalkative +overtalked +overtalking +overtalks +overtax +overtaxation +overtaxations +overtaxed +overtaxes +overtaxing +overthin +overthink +overthinking +overthinks +overthinned +overthinning +overthins +overthought +overthrew +overthrow +overthrowing +overthrown +overthrows +overthrust +overtighten +overtightened +overtightening +overtightens +overtime +overtimed +overtimes +overtiming +overtip +overtipped +overtipping +overtips +overtire +overtired +overtires +overtiring +overtly +overtness +overtone +overtones +overtook +overtop +overtopped +overtopping +overtops +overtrade +overtraded +overtrades +overtrading +overtrain +overtrained +overtraining +overtrains +overtreat +overtreated +overtreating +overtreatment +overtreats +overtrick +overtricks +overtrump +overtrumped +overtrumping +overtrumps +overture +overtured +overtures +overturing +overturn +overturned +overturning +overturns +overtype +overtyped +overtyping +overuse +overused +overuses +overusing +overutilization +overutilize +overutilized +overutilizes +overutilizing +overvaluation +overvaluations +overvalue +overvalued +overvalues +overvaluing +overview +overviews +overviolent +overvivid +overvoltage +overvoltages +overwater +overwatered +overwatering +overwaters +overwear +overwearied +overwearies +overwearing +overwears +overweary +overwearying +overweening +overweeningly +overweigh +overweighed +overweighing +overweighs +overweight +overweighted +overweighting +overweights +overwhelm +overwhelmed +overwhelming +overwhelmingly +overwhelms +overwind +overwinding +overwinds +overwinter +overwintered +overwintering +overwinters +overwithheld +overwithhold +overwithholding +overwithholds +overwore +overwork +overworked +overworking +overworks +overworn +overwound +overwrite +overwrites +overwriting +overwritten +overwrote +overwrought +overzealous +overzealously +overzealousness +ovicidal +ovicide +ovicides +ovid +ovidian +oviduct +oviductal +oviducts +oviferous +oviform +ovimbundu +ovimbundus +ovine +ovines +ovipara +oviparity +oviparous +oviparously +oviposit +oviposited +ovipositing +oviposition +ovipositional +ovipositions +ovipositor +ovipositors +oviposits +ovisac +ovisacs +ovoid +ovoidal +ovoidals +ovoids +ovolactovegetarian +ovolactovegetarians +ovoli +ovolo +ovonic +ovonics +ovotestes +ovotestis +ovoviviparity +ovoviviparous +ovoviviparously +ovoviviparousness +ovular +ovulary +ovulate +ovulated +ovulates +ovulating +ovulation +ovulations +ovulatory +ovule +ovules +ovum +ow +owe +owed +owes +owing +owl +owlet +owlets +owlish +owlishly +owlishness +owls +own +owned +owner +ownerless +owners +ownership +owning +owns +owyheei +ox +oxacillin +oxacillins +oxalacetate +oxalacetates +oxalacetic +oxalate +oxalated +oxalates +oxalating +oxalic +oxalis +oxalises +oxaloacetate +oxaloacetates +oxaloacetic +oxalosuccinic +oxazepam +oxazepams +oxblood +oxbow +oxbows +oxbridge +oxcart +oxcarts +oxen +oxeye +oxeyes +oxford +oxfords +oxfordshire +oxheart +oxhearts +oxidant +oxidants +oxidase +oxidases +oxidasic +oxidation +oxidations +oxidative +oxidatively +oxide +oxides +oxidic +oxidizable +oxidization +oxidizations +oxidize +oxidized +oxidizer +oxidizers +oxidizes +oxidizing +oxidoreductase +oxidoreductases +oxime +oximes +oximeter +oximeters +oximetric +oximetrically +oximetry +oxlip +oxlips +oxo +oxon +oxonian +oxonians +oxpecker +oxpeckers +oxtail +oxtails +oxter +oxters +oxtongue +oxtongues +oxus +oxyacetylene +oxyacid +oxyacids +oxycephalic +oxycephalies +oxycephalous +oxycephaly +oxycodone +oxycodones +oxygen +oxygenase +oxygenases +oxygenate +oxygenated +oxygenates +oxygenating +oxygenation +oxygenations +oxygenator +oxygenators +oxygenic +oxygenically +oxygenize +oxygenized +oxygenizes +oxygenizing +oxygenless +oxygenous +oxyhemoglobin +oxyhemoglobins +oxyhydrogen +oxymetazoline +oxymetazolines +oxymora +oxymoron +oxymoronic +oxymoronically +oxymorons +oxyphenbutazone +oxyphenbutazones +oxyphilic +oxysulfide +oxysulfides +oxytetracycline +oxytetracyclines +oxytocia +oxytocias +oxytocic +oxytocics +oxytocin +oxytocins +oxytone +oxytones +oxyuriasis +oyer +oyes +oyesses +oyez +oyster +oystercatcher +oystercatchers +oystered +oystering +oysterman +oystermen +oysters +oz +ozark +ozarkian +ozarkians +ozarks +ozocerite +ozocerites +ozokerite +ozokerites +ozonate +ozonated +ozonates +ozonating +ozonation +ozonations +ozone +ozonic +ozonide +ozonides +ozonization +ozonizations +ozonize +ozonized +ozonizer +ozonizers +ozonizes +ozonizing +ozonosphere +ozonospheric +ozonospherical +ozonous +ozostomia +ozostomias +p +pa +pa'anga +pablum +pablums +pabulum +pac +paca +pacas +pace +paced +pacemaker +pacemakers +pacemaking +pacer +pacers +paces +pacesetter +pacesetters +pacesetting +pacha +pachas +pachinko +pachinkos +pachisi +pachisis +pachouli +pachoulis +pachuco +pachucos +pachyderm +pachydermal +pachydermatous +pachydermic +pachydermous +pachyderms +pachysandra +pachysandras +pachytene +pachytenes +pacifarin +pacifarins +pacifiable +pacific +pacifical +pacifically +pacification +pacifications +pacificator +pacificators +pacificatory +pacificism +pacificisms +pacificist +pacificists +pacified +pacifier +pacifiers +pacifies +pacifism +pacifist +pacifistic +pacifistically +pacifists +pacify +pacifying +pacing +pacinian +pack +packability +packable +package +packaged +packager +packagers +packages +packaging +packagings +packboard +packboards +packed +packer +packers +packet +packets +packhorse +packhorses +packing +packinghouse +packinghouses +packings +packman +packmen +packs +packsack +packsacks +packsaddle +packsaddles +packthread +packthreads +pacs +pact +pacts +pad +padauk +padauks +padded +padder +padders +paddies +padding +paddings +paddle +paddleball +paddleballs +paddleboard +paddleboards +paddleboat +paddleboats +paddled +paddlefish +paddlefishes +paddler +paddlers +paddles +paddling +paddlings +paddock +paddocked +paddocking +paddocks +paddy +paderborn +padi +padis +padishah +padishahs +padless +padlock +padlocked +padlocking +padlocks +padouk +padouks +padova +padre +padres +padrone +padrones +padroni +padronism +pads +padua +paduan +paduans +paduasoy +paduasoys +paean +paeanistic +paeans +paedogeneses +paedogenesis +paedogenetic +paedogenetically +paedogenic +paedomorph +paedomorphic +paedomorphism +paedomorphisms +paedomorphoses +paedomorphosis +paedomorphs +paella +paellas +paeon +paeons +pagan +pagandom +pagandoms +paganini +paganish +paganism +paganization +paganizations +paganize +paganized +paganizer +paganizers +paganizes +paganizing +pagans +page +pageant +pageantries +pageantry +pageants +pageboy +pageboys +paged +pageful +pagefuls +pager +pagers +pages +paginal +paginate +paginated +paginates +paginating +pagination +paginations +paging +pagoda +pagodas +pah +pahlavi +pahlavis +paid +pail +pailful +pailfuls +paillard +paillards +paillasse +paillasses +paillette +pailletted +paillettes +pails +pain +pained +painful +painfuller +painfullest +painfully +painfulness +paining +painkiller +painkillers +painkilling +painless +painlessly +painlessness +pains +painstaking +painstakingly +paint +paintability +paintable +paintbrush +paintbrushes +painted +painter +painterliness +painterly +painters +painting +paintings +paints +paintwork +pair +paired +pairing +pairings +pairs +paisa +paisan +paisano +paisanos +paisans +paisas +paise +paisley +paisleys +paiute +paiutes +pajama +pajamaed +pajamas +pakeha +pakehas +pakistan +pakistani +pakistanis +pal +palace +palaces +paladin +paladins +palaestra +palankeen +palankeens +palanquin +palanquins +palapa +palapas +palatability +palatable +palatableness +palatably +palatal +palatalization +palatalizations +palatalize +palatalized +palatalizes +palatalizing +palatally +palatals +palate +palates +palatial +palatially +palatialness +palatinate +palatinates +palatine +palatines +palatino +palau +palaver +palavered +palavering +palavers +palawan +palazzi +palazzo +palazzos +pale +palea +paleae +paleal +palearctic +paled +paleethnologic +paleethnological +paleethnologies +paleethnology +paleface +palefaces +palely +paleness +paleoanthropic +paleoanthropologic +paleoanthropological +paleoanthropologist +paleoanthropologists +paleoanthropology +paleobiochemical +paleobiochemistries +paleobiochemistry +paleobiogeographic +paleobiogeographical +paleobiogeography +paleobiologic +paleobiological +paleobiologist +paleobiologists +paleobiology +paleobotanic +paleobotanical +paleobotanically +paleobotanist +paleobotanists +paleobotany +paleocene +paleoclimatologist +paleoclimatologists +paleoclimatology +paleoecologic +paleoecological +paleoecologist +paleoecologists +paleoecology +paleogene +paleogeographic +paleogeographical +paleogeographically +paleogeography +paleographer +paleographers +paleographic +paleographical +paleographically +paleography +paleolith +paleolithic +paleoliths +paleomagnetic +paleomagnetically +paleomagnetism +paleomagnetist +paleomagnetists +paleontologic +paleontological +paleontologist +paleontologists +paleontology +paleopathological +paleopathologist +paleopathologists +paleopathology +paleozoic +paleozoological +paleozoologist +paleozoologists +paleozoology +paler +palermo +pales +palest +palestine +palestinian +palestinians +palestra +palestrae +palestral +palestras +palestrian +palestrina +palette +palettes +paley +palfrey +palfreys +pali +palier +paliest +palimony +palimpsest +palimpsests +palindrome +palindromes +palindromic +palindromist +palindromists +paling +palingeneses +palingenesis +palingenetic +palingenetically +palings +palinode +palinodes +palisade +palisaded +palisades +palisading +palish +pall +palladia +palladian +palladianism +palladic +palladio +palladium +palladiums +palladous +pallas +pallbearer +pallbearers +palled +pallet +palletization +palletizations +palletize +palletized +palletizer +palletizers +palletizes +palletizing +pallets +pallette +pallettes +pallia +pallial +palliasse +palliasses +palliate +palliated +palliates +palliating +palliation +palliations +palliative +palliatively +palliatives +palliator +palliators +pallid +pallidly +pallidness +pallier +palliest +palling +pallium +palliums +pallor +pallors +palls +pally +palm +palma +palmar +palmary +palmas +palmate +palmated +palmately +palmatifid +palmation +palmations +palmatisect +palmed +palmer +palmers +palmerston +palmerworm +palmerworms +palmette +palmettes +palmetto +palmettoes +palmettos +palmful +palmfuls +palmier +palmiest +palming +palmist +palmister +palmisters +palmistry +palmists +palmitate +palmitates +palmitic +palmitin +palmitins +palmlike +palms +palmy +palmyra +palmyras +palomar +palomino +palominos +palooka +palookas +palouse +palouses +paloverde +paloverdes +palp +palpability +palpable +palpably +palpal +palpate +palpated +palpates +palpating +palpation +palpations +palpator +palpators +palpatory +palpebra +palpebrae +palpebral +palpebras +palpi +palpitant +palpitate +palpitated +palpitates +palpitating +palpitatingly +palpitation +palpitations +palps +palpus +pals +palsgrave +palsgraves +palship +palships +palsied +palsies +palsy +palsying +palter +paltered +palterer +palterers +paltering +palters +paltrier +paltriest +paltrily +paltriness +paltry +paludal +paludism +paludisms +paly +palynologic +palynological +palynologically +palynologist +palynologists +palynology +pam +pamby +pamir +pamlico +pampa +pampas +pampean +pamper +pampered +pamperer +pamperers +pampering +pampero +pamperos +pampers +pamphlet +pamphletary +pamphleteer +pamphleteered +pamphleteering +pamphleteers +pamphlets +pamplona +pamprodactylous +pan +panacea +panacean +panaceas +panache +panaches +panada +panadas +panama +panamanian +panamanians +panamint +panatela +panatelas +panay +pancake +pancaked +pancakes +pancaking +pancetta +pancettas +panchax +panchaxes +panchen +panchromatic +panchromatism +pancratium +pancratiums +pancreas +pancreases +pancreatectomies +pancreatectomized +pancreatectomy +pancreatic +pancreatin +pancreatins +pancreatitis +pancreozymin +pancreozymins +pancytopenia +pancytopenias +panda +pandaemonium +pandanaceous +pandanus +pandanuses +pandar +pandarus +pandas +pandean +pandect +pandects +pandemic +pandemics +pandemoniac +pandemonium +pander +pandered +panderer +panderers +pandering +panders +pandied +pandies +pandit +pandits +pandora +pandore +pandores +pandowdies +pandowdy +pandurate +panduriform +pandy +pandying +pane +paned +panegyric +panegyrical +panegyrically +panegyrics +panegyrist +panegyrists +panegyrize +panegyrized +panegyrizes +panegyrizing +panel +paneled +paneling +panelings +panelist +panelists +panelization +panelizations +panelize +panelized +panelizes +panelizing +panelled +panelling +panellings +panels +panencephalitis +panes +panetela +panetelas +panetella +panetellas +panettone +panettones +panettoni +panfish +panfishes +panfried +panfries +panfry +panfrying +panful +panfuls +pang +panga +pangaea +pangas +pangea +panged +pangenesis +pangenetic +pangenetically +panging +pangloss +panglossian +pangola +pangolin +pangolins +pangram +pangrammatic +pangrams +pangs +panhandle +panhandled +panhandler +panhandlers +panhandles +panhandling +panhellenic +panhuman +panic +panicked +panicking +panicky +panicle +panicled +panicles +panics +paniculate +paniculated +paniculately +panicum +panicums +panier +paniers +panini +panjabi +panjandrum +panjandrums +panky +panleucopenia +panleukopenia +panmictic +panmixia +panmixias +panmixis +panne +panned +pannes +pannier +panniered +panniers +pannikin +pannikins +panning +pannonia +pannonian +pannonians +panocha +panochas +panoche +panoches +panoplied +panoplies +panoply +panoptic +panoptical +panorama +panoramas +panoramic +panoramically +panpipe +panpipes +pans +pansexual +pansexuality +pansies +panspermia +panspermias +pansy +pant +pantagruel +pantagruelian +pantagruelism +pantagruelist +pantagruelists +pantalet +pantalets +pantalette +pantalettes +pantalone +pantalones +pantaloon +pantaloons +pantdress +pantdresses +pantechnicon +pantechnicons +panted +pantheism +pantheist +pantheistic +pantheistical +pantheistically +pantheists +pantheon +pantheons +panther +panthers +pantie +panties +pantile +pantiled +pantiles +panting +pantingly +pantisocracies +pantisocracy +pantisocratic +pantisocratical +pantisocratist +pantisocratists +panto +pantoffle +pantoffles +pantofle +pantofles +pantograph +pantographic +pantographs +pantomime +pantomimed +pantomimes +pantomimic +pantomiming +pantomimist +pantomimists +pantos +pantothenate +pantothenates +pantothenic +pantoum +pantoums +pantries +pantropic +pantropical +pantry +pantryman +pantrymen +pants +pantsuit +pantsuited +pantsuits +panty +pantyhose +pantywaist +pantywaists +panzer +panzers +pap +papa +papacies +papacy +papago +papagos +papain +papains +papal +papally +papanicolaou +paparazzi +paparazzo +papas +papaverine +papaverines +papaw +papaws +papaya +papayas +papeete +paper +paperback +paperbacked +paperbacks +paperboard +paperboards +paperbound +paperboy +paperboys +paperclip +paperclips +papercraft +papered +paperer +paperers +papergirl +papergirls +paperhanger +paperhangers +paperhanging +paperiness +papering +paperings +paperknife +paperknives +paperless +papermaker +papermakers +papermaking +papers +paperweight +paperweights +paperwork +papery +papeterie +papeteries +paphian +paphians +paphos +papiamento +papiamentu +papier +papilionaceous +papilla +papillae +papillary +papillate +papilloma +papillomas +papillomata +papillomatous +papillomavirus +papillomaviruses +papillon +papillons +papillose +papillote +papillotes +papist +papistic +papistry +papists +papoose +papooses +papovavirus +papovaviruses +pappataci +pappi +pappier +pappies +pappiest +pappose +pappous +pappus +pappy +paprika +paprikas +paps +papua +papuan +papuans +papula +papulae +papular +papule +papules +papyri +papyrologic +papyrological +papyrologist +papyrologists +papyrology +papyrus +papyruses +par +para +parabioses +parabiosis +parabiotic +parabiotically +parablast +parablastic +parablasts +parable +parables +parabola +parabolas +parabolic +parabolical +parabolically +paraboloid +paraboloidal +paraboloids +paracelsus +parachute +parachuted +parachuter +parachuters +parachutes +parachutic +parachuting +parachutist +parachutists +paraclete +parade +paraded +parader +paraders +parades +paradichlorobenzene +paradichlorobenzenes +paradiddle +paradiddles +paradigm +paradigmatic +paradigmatically +paradigms +parading +paradisaic +paradisaical +paradisaically +paradisal +paradisally +paradise +paradises +paradisiac +paradisiacal +paradisiacally +paradisial +paradisical +parador +paradores +paradors +paradox +paradoxes +paradoxical +paradoxicality +paradoxically +paradoxicalness +paradrop +paradropped +paradropping +paradrops +paraesthesia +paraffin +paraffined +paraffinic +paraffining +paraffins +parafoil +parafoils +paraformaldehyde +paraformaldehydes +paragenesia +paragenesis +paragenetic +paragenetically +paragon +paragoned +paragoning +paragons +paragraph +paragraphed +paragrapher +paragraphers +paragraphic +paragraphical +paragraphing +paragraphs +paraguay +paraguayan +paraguayans +parainfluenza +parajournalism +parajournalist +parajournalistic +parajournalists +parakeet +parakeets +paralanguage +paraldehyde +paralegal +paralegals +paralinguistic +paralinguistics +paralipomenon +parallactic +parallax +parallaxes +parallel +paralleled +parallelepiped +parallelepipeds +paralleling +parallelism +parallelisms +parallelled +parallelling +parallelogram +parallelograms +parallels +paralogism +paralogisms +paralogist +paralogistic +paralogists +paralympian +paralympians +paralympic +paralyses +paralysis +paralytic +paralytically +paralytics +paralyzation +paralyzations +paralyze +paralyzed +paralyzer +paralyzers +paralyzes +paralyzing +paralyzingly +paramagnet +paramagnetic +paramagnetically +paramagnetism +paramagnets +paramaribo +paramatta +paramattas +paramecia +paramecium +parameciums +paramedic +paramedical +paramedics +parament +paramenta +paraments +parameter +parameterization +parameterizations +parameterize +parameterized +parameterizes +parameterizing +parameters +parametric +parametrical +parametrically +parametrization +parametrizations +parametrize +parametrized +parametrizes +parametrizing +paramilitaries +paramilitary +paramnesia +paramo +paramorph +paramorphic +paramorphine +paramorphines +paramorphism +paramorphisms +paramorphous +paramorphs +paramos +paramount +paramountcy +paramountly +paramour +paramours +paramylon +paramylons +paramylum +paramylums +paramyxovirus +paramyxoviruses +parang +parangs +paranoia +paranoiac +paranoiacs +paranoic +paranoically +paranoics +paranoid +paranoidal +paranoids +paranormal +paranormality +paranormally +paranymph +paranymphs +parapareses +paraparesis +parapet +parapeted +parapets +paraph +paraphernalia +paraphrasable +paraphrase +paraphrased +paraphraser +paraphrasers +paraphrases +paraphrasing +paraphrastic +paraphrastical +paraphrastically +paraphs +paraphyses +paraphysis +paraplegia +paraplegic +paraplegics +parapodia +parapodial +parapodium +parapraxes +parapraxis +paraprofessional +paraprofessionals +parapsychological +parapsychologist +parapsychologists +parapsychology +paraquat +paraquats +pararosaniline +pararosanilines +paras +parasail +parasailed +parasailer +parasailers +parasailing +parasails +parasang +parasangs +paraselenae +paraselene +paraselenic +parasensorily +parasensory +parasexual +parasexuality +parashah +parasite +parasites +parasitic +parasitical +parasitically +parasiticidal +parasiticide +parasiticides +parasitism +parasitization +parasitizations +parasitize +parasitized +parasitizes +parasitizing +parasitoid +parasitoids +parasitologic +parasitological +parasitologically +parasitologist +parasitologists +parasitology +parasitoses +parasitosis +parasol +parasoled +parasols +parasomnia +parasomnias +parastatal +parastatals +parasympathetic +parasympathetically +parasympathetics +parasympathomimetic +parasympathomimetics +parasyntheses +parasynthesis +parasynthetic +paratactic +paratactical +paratactically +parataxis +parathion +parathions +parathormone +parathormones +parathyroid +parathyroidectomies +parathyroidectomized +parathyroidectomy +parathyroids +paratroop +paratrooper +paratroopers +paratroops +paratyphoid +paravane +paravanes +paraxial +parboil +parboiled +parboiling +parboils +parbuckle +parbuckled +parbuckles +parbuckling +parcae +parcel +parceled +parceling +parcelled +parcelling +parcels +parcenaries +parcenary +parcener +parceners +parch +parched +parchedness +parcheesi +parches +parching +parchment +parchments +pard +pardi +pardie +pardner +pardners +pardon +pardonable +pardonableness +pardonably +pardoned +pardoner +pardoners +pardoning +pardons +pards +pardy +pare +pared +paregoric +paregorics +parenchyma +parenchymal +parenchymatous +parenchymatously +parent +parentage +parental +parentally +parented +parenteral +parenterally +parentheses +parenthesis +parenthesize +parenthesized +parenthesizes +parenthesizing +parenthetic +parenthetical +parenthetically +parenthood +parenting +parentis +parentless +parents +parenty +pareo +pareos +parer +parers +pares +pareses +paresis +paresthesia +paresthetic +paretic +paretically +paretics +pareu +pareus +pareve +parfait +parfaits +parfleche +parfleches +parfocal +parfocality +parfocalize +parfocalized +parfocalizes +parfocalizing +parge +parged +parges +parget +pargeted +pargeting +pargets +pargetted +pargetting +parging +pargyline +pargylines +parhelia +parhelic +parhelion +pari +pariah +pariahs +parian +parians +paribus +paricutin +paries +parietal +parietals +parietes +paring +parings +paripinnate +paris +parish +parishes +parishioner +parishioners +parisian +parisians +parisienne +parities +parity +park +parka +parkas +parked +parker +parkers +parking +parkinson +parkinson's +parkinsonian +parkinsonism +parkinsonisms +parkland +parklands +parklike +parks +parkway +parkways +parlance +parlances +parlando +parlante +parlay +parlayed +parlaying +parlays +parle +parled +parles +parley +parleyed +parleying +parleys +parliament +parliamentarian +parliamentarians +parliamentary +parliaments +parling +parlor +parlors +parlous +parlously +parma +parmenides +parmesan +parmesans +parmigiana +parmigiano +parnassian +parnassians +parnassus +parnassós +parnell +parochial +parochialism +parochialist +parochialists +parochially +parodic +parodical +parodied +parodies +parodist +parodistic +parodists +parody +parodying +parol +parole +paroled +parolee +parolees +paroles +paroling +parols +paronomasia +paronomasial +paronomasias +paronomastic +paronomastically +paronychia +paronychial +paronychias +paronym +paronymic +paronymous +paronyms +paros +parosmia +parosmias +parotid +parotidectomies +parotidectomy +parotiditis +parotids +parotitic +parotitis +parous +parousia +paroxysm +paroxysmal +paroxysmally +paroxysms +paroxytone +paroxytones +parquet +parqueted +parqueting +parquetries +parquetry +parquets +parr +parrakeet +parrakeets +parral +parrals +parramatta +parramattas +parred +parrel +parrels +parricidal +parricidally +parricide +parricides +parried +parries +parring +parrot +parroted +parroter +parroters +parrotfish +parrotfishes +parroting +parrots +parrs +parry +parrying +pars +parse +parsec +parsecs +parsed +parsee +parseeism +parsees +parser +parsers +parses +parsi +parsifal +parsiism +parsimonious +parsimoniously +parsimoniousness +parsimony +parsing +parsis +parsley +parsleyed +parsleys +parslied +parsnip +parsnips +parson +parsonage +parsonages +parsons +part +partake +partaken +partaker +partakers +partakes +partaking +parte +parted +parterre +parterres +parthenocarpic +parthenocarpically +parthenocarpy +parthenogenesis +parthenogenetic +parthenogenetically +parthenogenone +parthenogenones +parthenon +parthia +parthian +parthians +parti +partial +partialities +partiality +partially +partialness +partials +partibility +partible +participance +participant +participants +participate +participated +participates +participating +participation +participational +participations +participative +participator +participators +participatory +participial +participially +participials +participle +participles +particle +particleboard +particles +particular +particularism +particularist +particularistic +particularists +particularities +particularity +particularization +particularizations +particularize +particularized +particularizer +particularizers +particularizes +particularizing +particularly +particulars +particulate +particulates +partied +parties +parting +partings +partis +partisan +partisanly +partisans +partisanship +partisanships +partita +partitas +partite +partition +partitioned +partitioner +partitioners +partitioning +partitionings +partitionist +partitionists +partitionment +partitionments +partitions +partitive +partitively +partitives +partizan +partizans +partlet +partlets +partly +partner +partnered +partnering +partnerless +partners +partnership +partnerships +parton +partons +partook +partout +partridge +partridgeberry +partridges +parts +parturiency +parturient +parturifacient +parturifacients +parturition +parturitions +partway +party +partyer +partyers +partygoer +partygoers +partying +parure +parures +parvati +parve +parvenu +parvenue +parvenues +parvenus +parvis +parvise +parvises +parvo +parvos +parvovirus +parvoviruses +pará +pas +pasadena +pascal +pascals +pasch +pascha +paschal +pase +paseo +paseos +pases +pash +pasha +pashas +pashes +pashto +pashtun +pashtuns +pasiphaë +paso +pasqueflower +pasqueflowers +pasquinade +pasquinaded +pasquinader +pasquinaders +pasquinades +pasquinading +pass +passable +passableness +passably +passacaglia +passacaglias +passade +passades +passado +passadoes +passados +passage +passaged +passages +passageway +passageways +passagework +passageworks +passaging +passamaquoddies +passamaquoddy +passant +passband +passbands +passbook +passbooks +passchendaele +passe +passed +passel +passels +passementerie +passementeries +passenger +passengers +passepied +passepieds +passer +passerby +passerine +passerines +passers +passersby +passes +passibility +passible +passim +passing +passingly +passings +passion +passional +passionals +passionate +passionately +passionateness +passionflower +passionflowers +passionist +passionists +passionless +passionlessly +passions +passiontide +passiontides +passivate +passivated +passivates +passivating +passivation +passivations +passivator +passivators +passive +passively +passiveness +passives +passivism +passivisms +passivist +passivists +passivity +passkey +passkeys +passover +passovers +passport +passports +passu +password +passwords +passé +past +pasta +pastas +paste +pasteboard +pasteboards +pasted +pastedown +pastedowns +pastel +pastelist +pastelists +pastellist +pastellists +pastels +paster +pastern +pasternak +pasterns +pasters +pastes +pasteup +pasteups +pasteur +pasteurization +pasteurizations +pasteurize +pasteurized +pasteurizer +pasteurizers +pasteurizes +pasteurizing +pasticci +pasticcio +pasticcios +pastiche +pastiches +pasticheur +pasticheurs +pastier +pasties +pastiest +pastil +pastille +pastilles +pastils +pastime +pastimes +pastina +pastiness +pasting +pastis +pastises +pastless +pastness +pastor +pastoral +pastorale +pastorales +pastorali +pastoralism +pastoralisms +pastoralist +pastoralists +pastoralization +pastoralizations +pastoralize +pastoralized +pastoralizes +pastoralizing +pastorally +pastoralness +pastorals +pastorate +pastorates +pastored +pastoring +pastorium +pastoriums +pastors +pastorship +pastorships +pastrami +pastramis +pastries +pastromi +pastromis +pastry +pasts +pasturable +pasturage +pasture +pastured +pastureland +pasturelands +pasturer +pasturers +pastures +pasturing +pasty +pat +pataca +patacas +patagia +patagial +patagium +patagonia +patagonian +patagonians +pataphysics +patas +patch +patchable +patchboard +patchboards +patched +patcher +patchers +patches +patchier +patchiest +patchily +patchiness +patching +patchouli +patchoulies +patchoulis +patchouly +patchwork +patchworks +patchy +pate +pated +patella +patellae +patellar +patellate +patelliform +paten +patency +patens +patent +patentability +patentable +patented +patentee +patentees +patenting +patently +patentor +patentors +patents +pater +paterfamilias +paterfamiliases +paternal +paternalism +paternalist +paternalistic +paternalistically +paternalists +paternally +paternities +paternity +paternoster +paternosters +paters +pates +path +pathan +pathans +pathbreaking +pathetic +pathetical +pathetically +pathfinder +pathfinders +pathfinding +pathless +pathlessness +pathname +pathobiology +pathogen +pathogeneses +pathogenesis +pathogenetic +pathogenic +pathogenically +pathogenicity +pathogenies +pathogens +pathogeny +pathognomonic +pathography +pathologic +pathological +pathologically +pathologies +pathologist +pathologists +pathology +pathophysiologic +pathophysiological +pathophysiologist +pathophysiologists +pathophysiology +pathos +paths +pathway +pathways +pathétique +patience +patient +patiently +patients +patin +patina +patinae +patinaed +patinas +patinate +patinated +patinates +patinating +patination +patinations +patine +patined +patines +patining +patins +patio +patios +patisserie +patisseries +patissier +patissiers +patly +patmos +patna +patness +patois +patresfamilias +patriarch +patriarchal +patriarchalism +patriarchally +patriarchate +patriarchates +patriarchic +patriarchies +patriarchs +patriarchy +patricia +patrician +patricianly +patricians +patriciate +patriciates +patricidal +patricide +patricides +patrick +patriclinous +patrilineage +patrilineages +patrilineal +patrilocal +patrilocally +patrimonial +patrimonially +patrimonies +patrimony +patriot +patriotic +patriotically +patriotism +patriots +patristic +patristical +patristically +patristics +patroclinous +patroclus +patrol +patrolled +patroller +patrollers +patrolling +patrolman +patrolmen +patrols +patrolwoman +patrolwomen +patron +patronage +patronal +patroness +patronesses +patronization +patronizations +patronize +patronized +patronizer +patronizers +patronizes +patronizing +patronizingly +patrons +patronymic +patronymically +patronymics +patroon +patroons +pats +patsies +patsy +patted +patten +pattens +patter +pattered +patterer +patterers +pattering +pattern +patterned +patterning +patternings +patternless +patternmaker +patternmakers +patternmaking +patterns +patters +pattie +patties +patting +patty +pattypan +pattypans +patulent +patulous +patulously +patulousness +patzer +patzers +paucity +paul +pauline +paulist +paulists +paulo +paulownia +paulownias +paunch +paunches +paunchier +paunchiest +paunchiness +paunchy +pauper +pauperism +pauperization +pauperizations +pauperize +pauperized +pauperizes +pauperizing +paupers +paupiette +paupiettes +pausanias +pause +paused +pauses +pausing +pavan +pavane +pavanes +pavans +pavarotti +pave +paved +paveed +pavement +pavements +paver +pavers +paves +pavia +pavid +pavilion +pavilioned +pavilioning +pavilions +paving +pavings +pavis +pavises +pavisse +pavisses +pavlov +pavlova +pavlovian +pavo +pavonine +pavé +paw +pawed +pawer +pawers +pawing +pawkier +pawkiest +pawky +pawl +pawls +pawn +pawnable +pawnage +pawnages +pawnbroker +pawnbrokers +pawnbroking +pawned +pawnee +pawnees +pawner +pawners +pawning +pawnor +pawnors +pawns +pawnshop +pawnshops +pawpaw +pawpaws +paws +pax +pay +payable +payables +payback +paybacks +paycheck +paychecks +payday +paydays +payed +payee +payees +payer +payers +paying +payload +payloader +payloads +paymaster +paymasters +payment +payments +paynim +paynims +payoff +payoffs +payola +payolas +payor +payors +payout +payouts +payphone +payphones +payroll +payrolls +pays +pc +pcs +pe +pea +peabody +peace +peaceable +peaceableness +peaceably +peaceful +peacefully +peacefulness +peacekeeper +peacekeepers +peacekeeping +peacemaker +peacemakers +peacemaking +peacenik +peaceniks +peacetime +peacetimes +peach +peached +peaches +peachick +peachicks +peachier +peachiest +peachiness +peaching +peachy +peacock +peacocked +peacocking +peacockish +peacocks +peacocky +peafowl +peafowls +peag +peage +peages +peags +peahen +peahens +peak +peaked +peakedness +peaking +peaks +peaky +peal +pealed +pealike +pealing +peals +pean +peans +peanut +peanuts +pear +pearl +pearled +pearler +pearlers +pearlescence +pearlescent +pearlier +pearliest +pearliness +pearling +pearlite +pearlites +pearlitic +pearlized +pearls +pearly +pears +peart +peartly +peas +peasant +peasantry +peasants +peascod +peascods +pease +peasecod +peasecods +peashooter +peashooters +peat +peats +peaty +peavey +peaveys +peavies +peavy +peavys +pebble +pebbled +pebbles +pebbling +pebbly +pec +pecan +pecans +peccability +peccable +peccadillo +peccadilloes +peccadillos +peccancies +peccancy +peccant +peccantly +peccaries +peccary +peccavi +peccavis +peck +pecked +pecker +peckers +peckerwood +peckerwoods +pecking +peckish +pecks +pecksniffian +pecky +pecorino +pecorinos +pecs +pectase +pectases +pectate +pectates +pecten +pectens +pectic +pectin +pectinaceous +pectinate +pectinated +pectination +pectinations +pectines +pectinesterase +pectinesterases +pectinous +pectins +pectoral +pectorals +pectoris +peculate +peculated +peculates +peculating +peculation +peculations +peculator +peculators +peculiar +peculiarities +peculiarity +peculiarly +peculiars +pecuniarily +pecuniary +ped +pedagog +pedagogic +pedagogical +pedagogically +pedagogics +pedagogs +pedagogue +pedagogues +pedagoguish +pedagogy +pedal +pedaled +pedaler +pedalers +pedalfer +pedalfers +pedaling +pedalled +pedaller +pedallers +pedalling +pedalo +pedalos +pedals +pedant +pedantic +pedantically +pedantries +pedantry +pedants +pedate +peddle +peddled +peddler +peddlers +peddles +peddling +pederast +pederastic +pederasties +pederasts +pederasty +pedes +pedestal +pedestaled +pedestaling +pedestalled +pedestalling +pedestals +pedestrian +pedestrianism +pedestrianization +pedestrianizations +pedestrianize +pedestrianized +pedestrianizes +pedestrianizing +pedestrians +pediatric +pediatrician +pediatricians +pediatrics +pediatrist +pediatrists +pedicab +pedicabs +pedicel +pedicellar +pedicellate +pedicels +pedicle +pedicled +pedicles +pedicular +pediculate +pediculates +pediculosis +pediculous +pedicure +pedicured +pedicures +pedicuring +pedicurist +pedicurists +pediform +pedigree +pedigreed +pedigrees +pediment +pedimental +pedimented +pediments +pedipalp +pedipalps +pedlar +pedlars +pedocal +pedocalic +pedocals +pedodontia +pedodontias +pedodontics +pedodontists +pedogeneses +pedogenesis +pedogenetic +pedogenic +pedologic +pedological +pedologically +pedologist +pedologists +pedology +pedometer +pedometers +pedomorph +pedomorphism +pedomorphisms +pedomorphoses +pedomorphosis +pedomorphs +pedophile +pedophiles +pedophilia +pedophiliac +pedophiliacs +pedophilic +peduncle +peduncled +peduncles +peduncular +pedunculate +pedunculated +pee +peed +peeing +peek +peekaboo +peeked +peeking +peeks +peel +peelable +peeled +peeler +peelers +peeling +peelings +peels +peen +peened +peening +peens +peep +peeped +peeper +peepers +peephole +peepholes +peeping +peeps +peepshow +peepshows +peepul +peepuls +peer +peerage +peerages +peered +peeress +peeresses +peering +peerless +peerlessly +peerlessness +peers +pees +peetweet +peetweets +peeve +peeved +peeves +peeving +peevish +peevishly +peevishness +peewee +peewees +peewit +peewits +peg +pegasus +pegboard +pegboards +pegged +pegging +pegmatite +pegmatitic +pegs +pehlevi +peignoir +peignoirs +pein +peined +peining +peins +pejoration +pejorations +pejorative +pejoratively +pejoratives +pekan +pekans +peke +pekes +pekin +pekinese +peking +pekingese +pekins +pekoe +pekoes +pelage +pelages +pelagian +pelagianism +pelagians +pelagic +pelargonic +pelargonium +pelargoniums +pelasgian +pelasgians +pelasgic +pelecypod +pelecypods +pelerine +pelerines +pelew +pelf +pelican +pelicans +pelion +pelisse +pelisses +pelite +pelites +pelitic +pell +pellagra +pellagrin +pellagrins +pellagrous +pellet +pelletal +pelleted +pelleting +pelletization +pelletizations +pelletize +pelletized +pelletizer +pelletizers +pelletizes +pelletizing +pellets +pellicle +pellicles +pellicular +pellitories +pellitory +pellucid +pellucida +pellucidae +pellucidity +pellucidly +pellucidness +pelmet +pelmets +peloponnese +peloponnesian +peloponnesians +peloponnesos +peloponnesus +peloria +pelorias +peloric +pelorus +peloruses +pelota +pelotas +pelt +peltate +peltately +pelted +pelter +pelters +pelting +peltries +peltry +pelts +pelves +pelvic +pelvimeter +pelvimeters +pelvimetry +pelvis +pelvises +pelycosaur +pelycosaurs +pelée +pemba +pembroke +pemican +pemicans +pemmican +pemmicans +pemoline +pemolines +pemphigous +pemphigus +pemphiguses +pen +penal +penalization +penalizations +penalize +penalized +penalizes +penalizing +penally +penalties +penalty +penance +penanced +penances +penancing +penang +penates +pence +pencel +pencels +penchant +penchants +pencil +penciled +penciler +pencilers +penciling +pencilled +penciller +pencillers +pencilling +pencils +pendant +pendants +pendelikón +pendency +pendent +pendentive +pendently +pendents +pending +pendular +pendulous +pendulously +pendulousness +pendulum +pendulums +penelope +peneplain +peneplains +peneplane +peneplanes +penes +penetrability +penetrable +penetrably +penetralia +penetrameter +penetrameters +penetrance +penetrances +penetrant +penetrants +penetrate +penetrated +penetrates +penetrating +penetratingly +penetration +penetrations +penetrative +penetrator +penetrators +penetrometer +penetrometers +penghu +pengo +pengos +penguin +penguins +penh +penholder +penholders +penicillamine +penicillamines +penicillate +penicillately +penicillation +penicillations +penicillia +penicillin +penicillinase +penicillinases +penicillium +penicilliums +penicuik +penile +peninsula +peninsular +peninsulas +penis +penises +penitence +penitences +penitent +penitente +penitentes +penitential +penitentially +penitentials +penitentiaries +penitentiary +penitently +penitents +penknife +penknives +penlight +penlights +penlite +penlites +penman +penmanship +penmen +penn +penna +pennaceous +pennae +penname +pennames +pennant +pennants +pennate +pennated +penne +penned +penner +penners +penni +pennia +pennies +penniless +pennilessly +pennilessness +pennine +pennines +penning +pennis +pennon +pennoncel +pennoncelle +pennoncelles +pennoncels +pennoned +pennons +pennsylvania +pennsylvanian +pennsylvanians +penny +pennycress +pennycresses +pennyroyal +pennyroyals +pennyweight +pennyweights +pennywhistle +pennywhistles +pennywise +pennywort +pennyworth +pennyworths +pennyworts +penobscot +penobscots +penoche +penological +penologically +penologist +penologists +penology +penoncel +penoncels +pens +pensil +pensile +pensils +pension +pensionable +pensionaries +pensionary +pensione +pensioned +pensioner +pensioners +pensiones +pensioning +pensionless +pensions +pensive +pensively +pensiveness +penstemon +penstemons +penstock +penstocks +pensée +pensées +pent +pentachlorophenol +pentachlorophenols +pentacle +pentacles +pentad +pentadactyl +pentadactylate +pentadactylism +pentads +pentagon +pentagonal +pentagonally +pentagonese +pentagons +pentagram +pentagrams +pentagynous +pentahedra +pentahedral +pentahedron +pentahedrons +pentamerism +pentamerous +pentameter +pentameters +pentamidine +pentandrous +pentane +pentanes +pentangle +pentangles +pentangular +pentapeptide +pentapeptides +pentaploid +pentaploids +pentaploidy +pentaquin +pentaquine +pentaquines +pentaquins +pentarchical +pentarchies +pentarchy +pentastich +pentastiches +pentastome +pentastomes +pentateuch +pentateuchal +pentathlete +pentathletes +pentathlon +pentathlons +pentatonic +pentavalent +pentazocine +pentazocines +pentecost +pentecostal +pentecostalism +pentecostalist +pentecostalists +pentecostals +penthouse +penthouses +pentimenti +pentimento +pentlandite +pentlandites +pentobarbital +pentobarbitone +pentobarbitones +pentosan +pentosans +pentose +pentoses +pentothal +pentoxide +pentoxides +pentstemon +pentstemons +pentyl +pentylenetetrazol +pentylenetetrazols +pentyls +penuche +penuches +penuchi +penuchis +penuchle +penuckle +penult +penultima +penultimas +penultimate +penultimately +penultimates +penults +penumbra +penumbrae +penumbral +penumbras +penumbrous +penurious +penuriously +penuriousness +penury +penutian +peon +peonage +peones +peonies +peons +peony +people +peopled +peoplehood +peopleless +peopler +peoplers +peoples +peopling +peoria +peorias +pep +peperomia +peperomias +pepier +pepiest +pepino +pepinos +peplos +peploses +peplum +peplumed +peplums +peplus +pepluses +pepo +pepos +pepped +pepper +pepperbox +pepperboxes +pepperbush +pepperbushes +peppercorn +peppercorns +peppercress +peppercresses +peppered +pepperer +pepperers +peppergrass +peppergrasses +pepperidge +pepperidges +pepperiness +peppering +peppermint +peppermints +pepperminty +pepperoni +pepperonis +peppers +peppershaker +peppershakers +peppertree +peppertrees +pepperwood +pepperwoods +pepperwort +pepperworts +peppery +peppier +peppiest +peppily +peppiness +pepping +peppy +peps +pepsi +pepsin +pepsine +pepsines +pepsinogen +pepsinogens +pepsins +peptic +peptics +peptidase +peptidases +peptide +peptides +peptidic +peptidically +peptidoglycan +peptidoglycans +peptization +peptizations +peptize +peptized +peptizer +peptizers +peptizes +peptizing +peptone +peptones +peptonic +peptonization +peptonizations +peptonize +peptonized +peptonizes +peptonizing +pepys +pequot +pequots +per +peracid +peracids +peradventure +peradventures +perambulate +perambulated +perambulates +perambulating +perambulation +perambulations +perambulator +perambulators +perambulatory +perborate +perborates +percale +percales +percaline +percalines +perceivable +perceivably +perceive +perceived +perceiver +perceivers +perceives +perceiving +percent +percentage +percentages +percenter +percenters +percentile +percentiles +percentism +percents +percept +perceptibility +perceptible +perceptibly +perception +perceptional +perceptions +perceptive +perceptively +perceptiveness +perceptivity +percepts +perceptual +perceptually +perch +perchance +perched +percher +percheron +percherons +perchers +perches +perching +perchlorate +perchlorates +perchloric +perchlorid +perchloride +perchlorides +perchlorids +perchloroethylene +perchloroethylenes +perciatelli +percipience +percipiency +percipient +percipiently +percipients +percodan +percoid +percoidean +percoids +percolate +percolated +percolates +percolating +percolation +percolations +percolator +percolators +percurrent +percuss +percussed +percusses +percussing +percussion +percussionist +percussionists +percussions +percussive +percussively +percussiveness +percutaneous +percutaneously +percy +perdie +perdita +perdition +perdu +perdue +perdues +perdurability +perdurable +perdurably +perdure +perdured +perdures +perduring +perdus +peregrinate +peregrinated +peregrinates +peregrinating +peregrination +peregrinations +peregrinator +peregrinators +peregrine +peregrines +pereion +pereiopod +pereiopods +peremptorily +peremptoriness +peremptory +perennate +perennated +perennates +perennating +perennation +perennations +perennial +perennially +perennials +perentie +perenties +pereon +pereopod +pereopods +perestroika +perfect +perfecta +perfectas +perfected +perfecter +perfecters +perfectibility +perfectible +perfecting +perfection +perfectionism +perfectionist +perfectionistic +perfectionists +perfections +perfective +perfectively +perfectiveness +perfectives +perfectivity +perfectly +perfectness +perfecto +perfectos +perfects +perfervid +perfervidly +perfervidness +perfidies +perfidious +perfidiously +perfidiousness +perfidy +perfoliate +perfoliation +perforable +perforate +perforated +perforates +perforating +perforation +perforations +perforative +perforator +perforators +perforce +perform +performability +performable +performance +performances +performative +performatory +performed +performer +performers +performing +performs +perfume +perfumed +perfumer +perfumeries +perfumers +perfumery +perfumes +perfuming +perfunctorily +perfunctoriness +perfunctory +perfusate +perfusates +perfuse +perfused +perfuses +perfusing +perfusion +perfusionist +perfusionists +perfusions +perfusive +pergamum +pergola +pergolas +perhaps +perianth +perianths +periapt +periapts +periaqueductal +pericardia +pericardiac +pericardial +pericarditis +pericardium +pericarp +pericarpial +pericarps +perichondral +perichondria +perichondrial +perichondrium +periclase +periclases +periclean +pericles +pericline +periclines +pericope +pericopes +pericrania +pericranial +pericranium +pericycle +pericycles +pericyclic +periderm +peridermal +peridermic +periderms +peridia +peridial +peridium +peridot +peridotic +peridotite +peridotites +peridotitic +peridots +perigeal +perigean +perigee +perigees +perigynous +perigyny +perihelia +perihelial +perihelion +perikarya +perikaryal +perikaryon +peril +periled +periling +perilla +perillas +perilled +perilling +perilous +perilously +perilousness +perils +perilune +perilunes +perilymph +perilymphatic +perilymphs +perimeter +perimeters +perimetric +perimetrical +perimetrically +perimorph +perimorphic +perimorphism +perimorphous +perimorphs +perimysia +perimysium +perinatal +perinatally +perinatology +perinea +perineal +perinephral +perinephria +perinephrial +perinephric +perinephrium +perineum +perineuria +perineurial +perineurium +period +periodic +periodical +periodically +periodicals +periodicities +periodicity +periodization +periodizations +periodontal +periodontally +periodontia +periodontias +periodontic +periodontical +periodontics +periodontist +periodontists +periodontology +periods +perionychia +perionychium +periostea +periosteal +periosteous +periosteum +periostitic +periostitis +periostitises +periostraca +periostracum +periotic +peripatetic +peripatetically +peripateticism +peripatetics +peripatus +peripatuses +peripeteia +peripeteias +peripetia +peripetias +peripeties +peripety +peripheral +peripherally +peripherals +peripheries +periphery +periphrases +periphrasis +periphrastic +periphrastically +periphytic +periphytics +periphyton +periphytons +periplasm +periplasmic +periplasms +periplast +periplasts +periproct +periprocts +peripteral +perique +periques +perisarc +perisarcal +perisarcous +perisarcs +periscope +periscopes +periscopic +periscopical +perish +perishability +perishable +perishableness +perishables +perishably +perished +perishes +perishing +perisperm +perisperms +perissodactyl +perissodactyla +perissodactylous +perissodactyls +peristalses +peristalsis +peristaltic +peristaltically +peristomal +peristome +peristomes +peristomial +peristylar +peristyle +peristyles +perithecia +perithecial +perithecium +peritonaea +peritonaeum +peritonea +peritoneal +peritoneally +peritoneum +peritoneums +peritonitis +peritrich +peritricha +peritrichous +peritrichously +peritrichs +perivisceral +periwig +periwigged +periwigs +periwinkle +periwinkles +perjure +perjured +perjurer +perjurers +perjures +perjuries +perjuring +perjurious +perjuriously +perjury +perk +perked +perkier +perkiest +perkily +perkiness +perking +perks +perky +perlite +perlites +perlitic +perm +permaculture +permacultures +permafrost +permalloy +permanence +permanencies +permanency +permanent +permanently +permanentness +permanents +permanganate +permanganates +permanganic +permeabilities +permeability +permeable +permeably +permeance +permeances +permeant +permease +permeases +permeate +permeated +permeates +permeating +permeation +permeations +permeative +permed +permethrin +permian +permillage +perming +permissibility +permissible +permissibleness +permissibly +permission +permissions +permissive +permissively +permissiveness +permit +permits +permitted +permittee +permittees +permitter +permitters +permitting +permittivities +permittivity +perms +permutability +permutable +permutably +permutation +permutational +permutations +permute +permuted +permutes +permuting +pernambuco +pernicious +perniciously +perniciousness +pernickety +pernod +peroneal +peroral +perorally +perorate +perorated +perorates +perorating +peroration +perorational +perorations +perovskite +perovskites +peroxidase +peroxidases +peroxide +peroxided +peroxides +peroxidic +peroxiding +peroxisomal +peroxisome +peroxisomes +peroxyacetyl +perp +perpend +perpended +perpendicular +perpendicularity +perpendicularly +perpendiculars +perpending +perpends +perpetrate +perpetrated +perpetrates +perpetrating +perpetration +perpetrations +perpetrator +perpetrators +perpetual +perpetually +perpetuance +perpetuances +perpetuate +perpetuated +perpetuates +perpetuating +perpetuation +perpetuations +perpetuator +perpetuators +perpetuities +perpetuity +perphenazine +perphenazines +perpignan +perplex +perplexed +perplexedly +perplexes +perplexing +perplexingly +perplexities +perplexity +perps +perquisite +perquisites +perrault +perries +perron +perrons +perry +perse +persecute +persecuted +persecutee +persecutees +persecutes +persecuting +persecution +persecutional +persecutions +persecutive +persecutor +persecutors +persecutory +perseid +perseides +perseids +persephone +persepolis +perseus +perseverance +perseverant +perseverate +perseverated +perseverates +perseverating +perseveration +perseverations +perseverative +persevere +persevered +perseveres +persevering +perseveringly +persia +persian +persians +persiflage +persimmon +persimmons +persist +persisted +persistence +persistency +persistent +persistently +persister +persisters +persisting +persists +persnicketiness +persnickety +person +persona +personable +personableness +personably +personae +personage +personages +personal +personalia +personalism +personalisms +personalist +personalistic +personalists +personalities +personality +personalization +personalizations +personalize +personalized +personalizes +personalizing +personally +personals +personalties +personalty +personas +personate +personated +personates +personating +personation +personations +personative +personator +personators +personhood +personification +personifications +personified +personifier +personifiers +personifies +personify +personifying +personnel +persons +perspectival +perspective +perspectively +perspectives +perspex +perspicacious +perspicaciously +perspicaciousness +perspicacity +perspicuity +perspicuous +perspicuously +perspicuousness +perspiration +perspiratory +perspire +perspired +perspires +perspiring +persuadable +persuadably +persuade +persuaded +persuader +persuaders +persuades +persuading +persuasibility +persuasible +persuasibleness +persuasion +persuasions +persuasive +persuasively +persuasiveness +pert +pertain +pertained +pertaining +pertains +perter +pertest +perth +pertinacious +pertinaciously +pertinaciousness +pertinacity +pertinence +pertinency +pertinent +pertinently +pertly +pertness +perturb +perturbable +perturbation +perturbational +perturbations +perturbed +perturbing +perturbs +pertussal +pertussis +peru +perugia +peruke +peruked +perukes +perusable +perusal +perusals +peruse +perused +peruser +perusers +peruses +perusing +peruvian +peruvians +pervade +pervaded +pervader +pervaders +pervades +pervading +pervasion +pervasions +pervasive +pervasively +pervasiveness +perverse +perversely +perverseness +perversion +perversions +perversities +perversity +perversive +pervert +perverted +pervertedly +pervertedness +perverter +perverters +pervertible +perverting +perverts +pervious +perviously +perviousness +pes +pesach +pesade +pesades +pescadores +peseta +pesetas +pesewa +pesewas +peshawar +peskier +peskiest +peskily +peskiness +pesky +peso +pesos +pessaries +pessary +pessimism +pessimist +pessimistic +pessimistically +pessimists +pest +pester +pestered +pesterer +pesterers +pestering +pesters +pesthole +pestholes +pesthouse +pesthouses +pesticidal +pesticide +pesticides +pestiferous +pestiferously +pestiferousness +pestilence +pestilences +pestilent +pestilential +pestilentially +pestilently +pestle +pestled +pestles +pestling +pesto +pestos +pests +pesty +pet +petaampere +petaamperes +petabecquerel +petabecquerels +petabit +petabits +petabyte +petabytes +petacandela +petacandelas +petacoulomb +petacoulombs +petafarad +petafarads +petagram +petagrams +petahenries +petahenry +petahenrys +petahertz +petajoule +petajoules +petakelvin +petakelvins +petal +petaled +petaliferous +petaline +petalled +petallike +petaloid +petalous +petals +petalumen +petalumens +petalux +petameter +petameters +petamole +petamoles +petanewton +petanewtons +petaohm +petaohms +petapascal +petapascals +petaradian +petaradians +petard +petards +petasecond +petaseconds +petasiemens +petasievert +petasieverts +petasos +petasoses +petasteradian +petasteradians +petasus +petasuses +petatesla +petateslas +petavolt +petavolts +petawatt +petawatts +petaweber +petawebers +petcock +petcocks +petechia +petechiae +petechial +petechiate +peter +peter's +petered +petering +peters +petersburg +petiolar +petiolate +petiole +petioled +petioles +petiolule +petiolules +petit +petite +petiteness +petites +petition +petitionary +petitioned +petitioner +petitioners +petitioning +petitions +petits +petnapper +petnappers +petnapping +petnappings +petrale +petrarch +petrarchan +petrel +petrels +petri +petrifaction +petrifactions +petrification +petrifications +petrified +petrifies +petrify +petrifying +petrine +petrochemical +petrochemicals +petrochemistries +petrochemistry +petrodollar +petrodollars +petrogenesis +petrogenetic +petroglyph +petroglyphic +petroglyphs +petrograd +petrographer +petrographers +petrographic +petrographical +petrographically +petrography +petrol +petrolatum +petroleum +petrolic +petroliferous +petrologic +petrological +petrologically +petrologist +petrologists +petrology +petronel +petronels +petronius +petropolitics +petrosal +petrous +pets +petted +petter +petters +petti +petticoat +petticoated +petticoats +pettier +pettiest +pettifog +pettifogged +pettifogger +pettifoggers +pettifoggery +pettifogging +pettifogs +pettily +pettiness +pettinesses +petting +pettis +pettish +pettishly +pettishness +pettiskirt +pettiskirts +pettislip +pettislips +pettitoes +petty +petulance +petulancy +petulant +petulantly +petunia +petunias +petuntse +petuntses +petuntze +petuntzes +peugeot +pew +pewee +pewees +pewholder +pewholders +pewit +pewits +pews +pewter +pewterer +pewterers +peyote +peyotl +peyotls +pfennig +pfennige +pfennigs +pfft +ph +phacoemulsification +phacoemulsifications +phaedra +phaedrus +phaeton +phaetons +phage +phages +phagocyte +phagocytes +phagocytic +phagocytize +phagocytized +phagocytizes +phagocytizing +phagocytose +phagocytosed +phagocytoses +phagocytosing +phagocytosis +phagocytotic +phagosome +phagosomes +phalangal +phalange +phalangeal +phalangean +phalanger +phalangers +phalanges +phalangist +phalangists +phalansterian +phalansterianism +phalansterians +phalansteries +phalanstery +phalanx +phalanxes +phalarope +phalaropes +phalli +phallic +phallically +phallicism +phallocentric +phallus +phalluses +phanerogam +phanerogamic +phanerogamous +phanerogams +phanerophyte +phanerophytes +phanerozoic +phantasies +phantasm +phantasma +phantasmagoria +phantasmagorias +phantasmagoric +phantasmagorical +phantasmagorically +phantasmagories +phantasmagory +phantasmal +phantasmata +phantasmic +phantasms +phantasy +phantom +phantomlike +phantoms +pharaoh +pharaohs +pharaonic +pharisaic +pharisaical +pharisaically +pharisaicalness +pharisaism +pharisaisms +pharisee +phariseeism +phariseeisms +pharisees +pharmaceutic +pharmaceutical +pharmaceutically +pharmaceuticals +pharmaceutics +pharmacies +pharmacist +pharmacists +pharmacodynamic +pharmacodynamically +pharmacodynamics +pharmacogenetic +pharmacogenetics +pharmacogenomic +pharmacogenomics +pharmacognosist +pharmacognosists +pharmacognostic +pharmacognostical +pharmacognosy +pharmacokinetic +pharmacokinetics +pharmacologic +pharmacological +pharmacologically +pharmacologist +pharmacologists +pharmacology +pharmacopeia +pharmacopeial +pharmacopeias +pharmacopoeia +pharmacopoeial +pharmacopoeias +pharmacopoeist +pharmacopoeists +pharmacotherapies +pharmacotherapy +pharmacy +pharos +pharoses +pharyngal +pharyngals +pharyngeal +pharyngeals +pharyngectomies +pharyngectomy +pharynges +pharyngitis +pharyngitises +pharyngocele +pharyngoceles +pharyngology +pharyngoscope +pharyngoscopes +pharyngoscopy +pharynx +pharynxes +phase +phased +phasedown +phasedowns +phaseout +phaseouts +phases +phasic +phasing +phasmid +phasmids +phatic +phatically +phaëthon +pheasant +pheasants +phellem +phellems +phelloderm +phellodermal +phelloderms +phellogen +phellogenic +phellogens +phenacaine +phenacaines +phenacetin +phenacetins +phenacite +phenacites +phenakite +phenakites +phenanthrene +phenanthrenes +phenarsazine +phenazin +phenazine +phenazines +phenazins +phencyclidine +phencyclidines +phenelzine +phenelzines +phenetic +phenetically +pheneticist +pheneticists +phenetics +phenix +phenixes +phenmetrazine +phenmetrazines +phenobarbital +phenobarbitone +phenobarbitones +phenocopies +phenocopy +phenocryst +phenocrystic +phenocrysts +phenol +phenolate +phenolates +phenolic +phenolics +phenological +phenologically +phenologist +phenologists +phenology +phenolphthalein +phenolphthaleins +phenols +phenom +phenomena +phenomenal +phenomenalism +phenomenalisms +phenomenalist +phenomenalistic +phenomenalistically +phenomenalists +phenomenally +phenomenological +phenomenologically +phenomenologist +phenomenologists +phenomenology +phenomenon +phenomenons +phenoms +phenothiazine +phenothiazines +phenotype +phenotypes +phenotypic +phenotypical +phenotypically +phenoxide +phenoxides +phenoxybenzamine +phenoxybenzamines +phentolamine +phentolamines +phenyl +phenylalanine +phenylalanines +phenylbutazone +phenylbutazones +phenylene +phenylenes +phenylenevinylene +phenylephrine +phenylephrines +phenylethylamine +phenylethylamines +phenylic +phenylketonuria +phenylketonurias +phenylketonuric +phenylketonurics +phenylpropanolamine +phenylpropanolamines +phenyls +phenylthiocarbamide +phenylthiocarbamides +phenylthiourea +phenylthioureas +phenytoin +phenytoins +pheochromocytoma +pheochromocytomas +pheochromocytomata +pheresis +pheromonal +pheromone +pheromones +phew +phi +phial +phials +phidias +philadelphia +philadelphian +philadelphians +philadelphus +philander +philandered +philanderer +philanderers +philandering +philanders +philanthropic +philanthropical +philanthropically +philanthropies +philanthropist +philanthropists +philanthropoid +philanthropoids +philanthropy +philatelic +philatelical +philatelically +philatelist +philatelists +philately +philemon +philharmonic +philharmonics +philhellene +philhellenes +philhellenic +philhellenism +philhellenist +philhellenists +philip +philippi +philippians +philippic +philippics +philippine +philippines +philistia +philistine +philistines +philistinism +philistinisms +phillips +phillumenist +phillumenists +philoctetes +philodendra +philodendron +philodendrons +philologer +philologers +philologic +philological +philologically +philologist +philologists +philology +philomel +philomela +philomels +philoprogenitive +philoprogenitively +philoprogenitiveness +philosophe +philosopher +philosophers +philosophes +philosophic +philosophical +philosophically +philosophies +philosophize +philosophized +philosophizer +philosophizers +philosophizes +philosophizing +philosophy +philter +philtered +philtering +philters +philtre +philtred +philtres +philtring +phimoses +phimosis +phiz +phizes +phlebitic +phlebitides +phlebitis +phlebogram +phlebograms +phlebographic +phlebography +phlebology +phlebosclerosis +phlebotomic +phlebotomical +phlebotomies +phlebotomist +phlebotomists +phlebotomize +phlebotomized +phlebotomizes +phlebotomizing +phlebotomus +phlebotomy +phlegethon +phlegm +phlegmatic +phlegmatical +phlegmatically +phlegmy +phloem +phlogistic +phlogiston +phlogistons +phlogopite +phlogopites +phlox +phloxes +phlyctaena +phlyctaenae +phlyctena +phlyctenae +phlyctenar +phnom +phobia +phobias +phobic +phobics +phobos +phocine +phocomelia +phocomelias +phoebe +phoebes +phoebus +phoenicia +phoenician +phoenicians +phoenix +phoenixes +phoenixlike +phon +phonate +phonated +phonates +phonating +phonation +phonations +phone +phoned +phonematic +phoneme +phonemes +phonemic +phonemically +phonemicist +phonemicists +phonemics +phones +phonetic +phonetical +phonetically +phonetician +phoneticians +phoneticist +phoneticists +phonetics +phoney +phoneyed +phoneying +phoneys +phonic +phonically +phonics +phonied +phonier +phonies +phoniest +phonily +phoniness +phoning +phono +phonocardiogram +phonocardiograms +phonocardiograph +phonocardiographic +phonocardiographs +phonocardiography +phonogram +phonogramic +phonogramically +phonogrammic +phonogrammically +phonograms +phonograph +phonographer +phonographers +phonographic +phonographically +phonographist +phonographists +phonographs +phonography +phonolite +phonolites +phonolitic +phonologic +phonological +phonologically +phonologies +phonologist +phonologists +phonology +phonometric +phonon +phonons +phonoreception +phonoreceptions +phonoreceptor +phonoreceptors +phonos +phonoscope +phonoscopes +phonotactic +phonotactics +phonotype +phonotypes +phonotypic +phonotypical +phonotypically +phonotypist +phonotypists +phonotypy +phons +phony +phonying +phooey +phorate +phorates +phoresies +phoresy +phoronid +phoronids +phosgene +phosphamidon +phosphamidons +phosphatase +phosphatases +phosphate +phosphates +phosphatic +phosphatide +phosphatides +phosphatidic +phosphatization +phosphatizations +phosphatize +phosphatized +phosphatizes +phosphatizing +phosphaturia +phosphaturias +phosphaturic +phosphene +phosphenes +phosphid +phosphide +phosphides +phosphids +phosphin +phosphine +phosphines +phosphins +phosphite +phosphites +phosphocreatin +phosphocreatine +phosphocreatines +phosphocreatins +phosphofructokinase +phosphofructokinases +phosphoinositide +phospholipid +phospholipids +phosphonium +phosphoniums +phosphoprotein +phosphoproteins +phosphor +phosphorate +phosphorated +phosphorates +phosphorating +phosphore +phosphores +phosphoresce +phosphoresced +phosphorescence +phosphorescent +phosphorescently +phosphoresces +phosphorescing +phosphoric +phosphorism +phosphorisms +phosphorite +phosphorites +phosphoritic +phosphorolysis +phosphorolytic +phosphorous +phosphors +phosphorus +phosphoryl +phosphorylase +phosphorylases +phosphorylate +phosphorylated +phosphorylates +phosphorylating +phosphorylation +phosphorylations +phosphorylative +phosphoryls +phot +photic +photically +photo +photoactive +photoactivity +photoautotroph +photoautotrophic +photoautotrophically +photoautotrophs +photobiologic +photobiological +photobiologist +photobiologists +photobiology +photobiotic +photocathode +photocathodes +photocell +photocells +photochemical +photochemically +photochemist +photochemistry +photochemists +photochromic +photochromism +photocoagulate +photocoagulated +photocoagulates +photocoagulating +photocoagulation +photocoagulations +photocompose +photocomposed +photocomposer +photocomposers +photocomposes +photocomposing +photocomposition +photoconduction +photoconductive +photoconductivities +photoconductivity +photocopied +photocopier +photocopiers +photocopies +photocopy +photocopying +photocurrent +photocurrents +photodecomposition +photodecompositions +photodegradable +photodetector +photodetectors +photodiode +photodiodes +photodisintegrate +photodisintegrated +photodisintegrates +photodisintegrating +photodisintegration +photodisintegrations +photodissociate +photodissociated +photodissociates +photodissociating +photodissociation +photodissociations +photodrama +photodramas +photoduplicate +photoduplicated +photoduplicates +photoduplicating +photoduplication +photoduplications +photodynamic +photodynamically +photodynamics +photoed +photoelectric +photoelectrical +photoelectrically +photoelectron +photoelectronic +photoelectrons +photoemission +photoemissions +photoemissive +photoengrave +photoengraved +photoengraver +photoengravers +photoengraves +photoengraving +photoengravings +photoexcitation +photoexcitations +photoexcited +photofinisher +photofinishers +photofinishing +photofinishings +photoflash +photoflashes +photoflood +photofloods +photofluorogram +photofluorograms +photofluorographic +photofluorography +photog +photogelatin +photogene +photogenes +photogenic +photogenically +photogeologic +photogeological +photogeologist +photogeologists +photogeology +photogram +photogrammetric +photogrammetrist +photogrammetrists +photogrammetry +photograms +photograph +photographable +photographed +photographer +photographers +photographic +photographical +photographically +photographing +photographs +photography +photogravure +photogravures +photogs +photoheliograph +photoheliographs +photoinduced +photoinduction +photoinductions +photoinductive +photoing +photointerpretation +photointerpreter +photointerpreters +photoionization +photoionizations +photoionize +photoionized +photoionizes +photoionizing +photojournalism +photojournalist +photojournalistic +photojournalists +photokinesis +photokinetic +photolithograph +photolithographed +photolithographer +photolithographers +photolithographic +photolithographically +photolithographing +photolithographs +photolithography +photoluminescence +photolysis +photolytic +photolytically +photolyzable +photolyze +photolyzed +photolyzes +photolyzing +photomap +photomapped +photomapping +photomaps +photomask +photomasks +photomechanical +photomechanically +photometer +photometers +photometric +photometrical +photometrically +photometrist +photometrists +photometry +photomicrograph +photomicrographed +photomicrographer +photomicrographers +photomicrographic +photomicrographing +photomicrographs +photomicrography +photomicroscope +photomicroscopes +photomicroscopic +photomontage +photomontages +photomorphogenesis +photomorphogenic +photomosaic +photomosaics +photomultiplier +photomural +photomuralist +photomuralists +photomurals +photon +photonegative +photonic +photonics +photons +photonuclear +photooxidation +photooxidations +photooxidative +photooxidize +photooxidized +photooxidizes +photooxidizing +photoperiod +photoperiodic +photoperiodical +photoperiodically +photoperiodicities +photoperiodicity +photoperiodism +photoperiodisms +photoperiods +photophase +photophases +photophilic +photophilous +photophobia +photophobias +photophobic +photophore +photophores +photophosphorylation +photophosphorylations +photopia +photopias +photopic +photoplay +photoplays +photopolarimeter +photopolarimeters +photopolymer +photopolymers +photopositive +photoproduct +photoproduction +photoproductions +photoproducts +photoreaction +photoreactions +photoreactivating +photoreactivation +photoreactivations +photoreception +photoreceptive +photoreceptor +photoreceptors +photoreconnaissance +photoreduce +photoreduced +photoreduces +photoreducing +photoreduction +photoreductions +photoreproduction +photoreproductions +photoresist +photoresists +photorespiration +photorespirations +photos +photosensitive +photosensitivities +photosensitivity +photosensitization +photosensitizations +photosensitize +photosensitized +photosensitizer +photosensitizers +photosensitizes +photosensitizing +photoset +photosets +photosetter +photosetters +photosetting +photosphere +photospheres +photospheric +photostat +photostatic +photostats +photostatted +photostatting +photosynthate +photosynthates +photosynthesis +photosynthesize +photosynthesized +photosynthesizes +photosynthesizing +photosynthetic +photosynthetically +photosystem +photosystems +phototactic +phototactically +phototaxis +phototaxises +phototelegraphy +phototherapeutic +phototherapies +phototherapy +phototonic +phototonus +phototonuses +phototoxic +phototoxicity +phototransistor +phototransistors +phototroph +phototrophic +phototrophically +phototrophs +phototropic +phototropically +phototropism +phototube +phototubes +phototypeset +phototypesets +phototypesetter +phototypesetters +phototypesetting +phototypographic +phototypographical +phototypographically +phototypography +photovoltaic +photovoltaics +phots +phragmites +phragmoplast +phragmoplasts +phrasal +phrasally +phrase +phrased +phrasemaker +phrasemakers +phrasemaking +phrasemonger +phrasemongering +phrasemongers +phraseogram +phraseograms +phraseograph +phraseographic +phraseographs +phraseological +phraseologies +phraseologist +phraseologists +phraseology +phrases +phrasing +phrasings +phratric +phratries +phratry +phreatic +phreatophyte +phreatophytes +phreatophytic +phrenetic +phrenetical +phrenic +phrenitic +phrenitis +phrenologic +phrenological +phrenologist +phrenologists +phrenology +phrensy +phrenzied +phrenzies +phrenzy +phrenzying +phrygia +phrygian +phrygians +phthalate +phthalates +phthalein +phthaleine +phthaleines +phthaleins +phthalic +phthalin +phthalins +phthalocyanine +phthalocyanines +phthiriasis +phthises +phthisic +phthisical +phthisics +phthisis +phycobilin +phycobilins +phycocyanin +phycocyanins +phycoerythrin +phycoerythrins +phycological +phycologist +phycologists +phycology +phycomycete +phycomycetes +phycomycetous +phyla +phylacteries +phylactery +phylae +phyle +phyletic +phyletically +phylic +phyllaries +phyllary +phyllite +phyllites +phyllitic +phyllo +phylloclad +phylloclade +phylloclades +phylloclads +phyllode +phyllodes +phyllodia +phyllodial +phyllodium +phylloid +phyllome +phyllomes +phyllomic +phyllophagous +phyllopod +phyllopodan +phyllopodans +phyllopodous +phyllopods +phyllotactic +phyllotactical +phyllotaxes +phyllotaxies +phyllotaxis +phyllotaxy +phylloxera +phylloxerae +phylloxeran +phylloxerans +phylogenesis +phylogenetic +phylogenetically +phylogenetics +phylogenic +phylogenies +phylogeny +phylum +physiatrics +physiatrist +physiatrists +physiatry +physic +physical +physicalism +physicalist +physicalistic +physicalists +physicality +physicalization +physicalizations +physicalize +physicalized +physicalizes +physicalizing +physically +physicalness +physicals +physician +physicians +physicist +physicists +physicked +physicking +physicochemical +physicochemically +physics +physiochemical +physiocrat +physiocratic +physiocrats +physiognomic +physiognomical +physiognomically +physiognomies +physiognomist +physiognomists +physiognomy +physiographer +physiographers +physiographic +physiographical +physiographically +physiography +physiologic +physiological +physiologically +physiologist +physiologists +physiology +physiopathologic +physiopathological +physiopathologist +physiopathologists +physiopathology +physiotherapeutic +physiotherapist +physiotherapists +physiotherapy +physique +physiqued +physiques +physostigmin +physostigmine +physostigmines +physostigmins +physostomous +phytane +phytanes +phytoalexin +phytoalexins +phytochemical +phytochemically +phytochemist +phytochemistry +phytochemists +phytochrome +phytochromes +phytoflagellate +phytoflagellates +phytogenesis +phytogenetic +phytogenetical +phytogenetically +phytogenic +phytogenous +phytogeny +phytogeographer +phytogeographers +phytogeographic +phytogeographical +phytogeographically +phytogeography +phytography +phytohemagglutinin +phytohemagglutinins +phytohormone +phytohormones +phytol +phytologic +phytological +phytology +phytols +phyton +phytonic +phytons +phytopathogen +phytopathogenic +phytopathogens +phytopathologic +phytopathological +phytopathologist +phytopathologists +phytopathology +phytophagous +phytoplankter +phytoplankters +phytoplankton +phytoplanktonic +phytoplanktons +phytosociological +phytosociologically +phytosociologist +phytosociologists +phytosociology +phytosterol +phytosterols +phytotoxic +phytotoxicity +pi +pia +piacenza +piacular +piaffe +piaffed +piaffer +piaffers +piaffes +piaffing +piaget +pial +pianism +pianissimo +pianissimos +pianist +pianistic +pianistically +pianistics +pianists +piano +pianoforte +pianofortes +pianos +pias +piassaba +piassabas +piassava +piassavas +piaster +piasters +piastre +piastres +piazza +piazzas +piazze +pibroch +pibrochs +pic +pica +picador +picadores +picadors +picaninnies +picaninny +picante +picara +picaras +picardy +picaresque +picaro +picaroon +picarooned +picarooning +picaroons +picaros +picas +picasso +picayune +picayunes +picayunish +piccadilly +piccalilli +piccalillis +piccata +piccolo +piccoloist +piccoloists +piccolos +pice +piceous +pichiciego +pichiciegos +pick +pickaninnies +pickaninny +pickax +pickaxe +pickaxed +pickaxes +pickaxing +picked +picker +pickerel +pickerels +pickerelweed +pickerelweeds +pickers +picket +picketboat +picketboats +picketed +picketer +picketers +picketing +pickets +pickier +pickiest +picking +pickings +pickle +pickled +pickles +pickleworm +pickleworms +pickling +picklock +picklocks +pickoff +pickoffs +pickpocket +pickpockets +pickproof +picks +pickthank +pickthanks +pickup +pickups +pickwick +pickwickian +picky +picloram +piclorams +picnic +picnicked +picnicker +picnickers +picnicking +picnicky +picnics +picoampere +picoamperes +picobecquerel +picobecquerels +picocandela +picocandelas +picocoulomb +picocoulombs +picofarad +picofarads +picogram +picograms +picohenries +picohenry +picohenrys +picohertz +picojoule +picojoules +picokelvin +picokelvins +picoline +picolines +picolumen +picolumens +picolux +picometer +picometers +picomole +picomoles +piconewton +piconewtons +picoohm +picoohms +picopascal +picopascals +picoradian +picoradians +picornavirus +picornaviruses +picosecond +picoseconds +picosiemens +picosievert +picosieverts +picosteradian +picosteradians +picot +picoted +picotee +picotees +picotesla +picoteslas +picoting +picots +picovolt +picovolts +picowatt +picowatts +picowave +picowaved +picowaves +picowaving +picoweber +picowebers +picquet +picquets +picrate +picrates +picric +picrotoxic +picrotoxin +picrotoxins +pics +pict +pictish +pictogram +pictograms +pictograph +pictographic +pictographically +pictographs +pictography +pictor +pictorial +pictorialism +pictorialist +pictorialists +pictoriality +pictorialization +pictorializations +pictorialize +pictorialized +pictorializes +pictorializing +pictorially +pictorialness +pictorials +picts +picture +pictured +picturephone +picturephones +pictures +picturesque +picturesquely +picturesqueness +picturing +picturization +picturizations +picturize +picturized +picturizes +picturizing +picul +piculs +piddle +piddled +piddles +piddling +piddock +piddocks +pidgin +pidginization +pidginizations +pidginize +pidginized +pidginizes +pidginizing +pidgins +pie +piebald +piebalds +piece +pieced +piecemeal +piecer +piecers +pieces +piecewise +piecework +pieceworker +pieceworkers +piecing +piecrust +piecrusts +pied +piedmont +piedmontese +piedmonts +piegan +piegans +pieing +pieplant +pieplants +pier +pierce +pierced +piercer +piercers +pierces +piercing +piercingly +pierian +pierogi +pierogies +pierre +pierrot +piers +pies +pieta +pietas +pietermaritzburg +pieties +pietism +pietist +pietistic +pietistical +pietistically +pietists +piety +pietà +piezoelectric +piezoelectrical +piezoelectrically +piezoelectricity +piezometer +piezometers +piezometric +piezometrical +piezometry +piffle +piffled +piffles +piffling +pig +pigboat +pigboats +pigeon +pigeonhole +pigeonholed +pigeonholer +pigeonholers +pigeonholes +pigeonholing +pigeonite +pigeonites +pigeons +pigeonwing +pigeonwings +pigfish +pigfishes +pigged +piggeries +piggery +piggier +piggies +piggiest +piggin +pigging +piggins +piggish +piggishly +piggishness +piggledy +piggy +piggyback +piggybacked +piggybacking +piggybacks +pigheaded +pigheadedly +pigheadedness +piglet +piglets +piglike +pigment +pigmentary +pigmentation +pigmentations +pigmented +pigmenting +pigmentosa +pigments +pigmies +pigmy +pignoli +pignolia +pignut +pignuts +pigpen +pigpens +pigs +pigskin +pigskins +pigsney +pigsneys +pigstick +pigsticked +pigsticker +pigstickers +pigsticking +pigsticks +pigsties +pigsty +pigtail +pigtailed +pigtails +pigweed +pigweeds +piing +pika +pikake +pikakes +pikas +pike +piked +pikeman +pikemen +pikeperch +pikeperches +piker +pikers +pikes +pikestaff +pikestaffs +piki +piking +pilaf +pilaff +pilaffs +pilafs +pilar +pilaster +pilasters +pilate +pilatus +pilau +pilaw +pilchard +pilchards +pile +pilea +pileate +pileated +piled +pilei +pileless +piles +pileum +pileup +pileups +pileus +pilewort +pileworts +pilfer +pilferable +pilferage +pilfered +pilferer +pilferers +pilfering +pilferproof +pilfers +pilgarlic +pilgarlics +pilgrim +pilgrimage +pilgrimaged +pilgrimages +pilgrimaging +pilgrims +pili +piliferous +piliform +piling +pilings +pilipino +pill +pillage +pillaged +pillager +pillagers +pillages +pillaging +pillar +pillared +pillaring +pillarless +pillars +pillbox +pillboxes +pilled +pilling +pillion +pillions +pilloried +pillories +pillory +pillorying +pillow +pillowcase +pillowcases +pillowed +pillowing +pillows +pillowslip +pillowslips +pillowy +pills +pilocarpine +pilocarpines +pilose +pilosity +pilot +pilotage +piloted +pilothouse +pilothouses +piloting +pilotings +pilotless +pilots +pilous +pilsener +pilseners +pilsner +pilsners +piltdown +pilular +pilule +pilules +pilus +pima +piman +pimas +pimento +pimentos +pimiento +pimientos +piminy +pimp +pimped +pimpernel +pimpernels +pimping +pimple +pimpled +pimples +pimply +pimpmobile +pimpmobiles +pimps +pin +pinafore +pinafored +pinafores +pinaster +pinasters +pinball +pinballs +pinbone +pinbones +pince +pincer +pincerlike +pincers +pinch +pinchbeck +pinchbecks +pinchcock +pinchcocks +pinched +pincher +pinchers +pinches +pinching +pinchpennies +pinchpenny +pincushion +pincushions +pindar +pindaric +pindling +pine +pineal +pinealectomize +pinealectomized +pinealectomizes +pinealectomizing +pinealectomy +pineapple +pineapples +pinecone +pinecones +pined +pinedrops +pineland +pinelands +pinene +pinenes +pineries +pinery +pines +pinesap +pinesaps +pineta +pinetum +pinewood +pinewoods +piney +pinfeather +pinfeathers +pinfish +pinfishes +pinfold +pinfolded +pinfolding +pinfolds +ping +pinged +pinger +pingers +pinging +pingo +pingoes +pingos +pings +pinguid +pinhead +pinheaded +pinheadedness +pinheads +pinhole +pinholes +pinier +piniest +pining +pinion +pinioned +pinioning +pinions +pinite +pinites +pink +pinked +pinker +pinkest +pinkeye +pinkie +pinkies +pinking +pinkish +pinkishness +pinkly +pinkness +pinko +pinkoes +pinkos +pinkroot +pinkroots +pinks +pinkster +pinksters +pinky +pinna +pinnace +pinnaces +pinnacle +pinnacled +pinnacles +pinnacling +pinnae +pinnal +pinnas +pinnate +pinnated +pinnately +pinnatifid +pinnatifidly +pinnatiped +pinnatisect +pinned +pinner +pinners +pinnigrade +pinning +pinniped +pinnipeds +pinnula +pinnulae +pinnular +pinnule +pinnules +pinocchio +pinochle +pinocle +pinocytic +pinocytosis +pinocytotic +pinocytotically +pinole +pinoles +pinot +pinots +pinpoint +pinpointed +pinpointing +pinpoints +pinprick +pinpricked +pinpricking +pinpricks +pins +pinscher +pinschers +pinsetter +pinsetters +pinspotter +pinspotters +pinstripe +pinstriped +pinstripes +pint +pinta +pintail +pintails +pintano +pintanos +pintas +pintle +pintles +pinto +pintoes +pintos +pints +pintsize +pintsized +pinup +pinups +pinwale +pinweed +pinweeds +pinwheel +pinwheels +pinwork +pinworm +pinworms +pinwrench +pinwrenches +pinxter +pinxters +piny +pinyin +pinyon +pinyons +piolet +piolets +pion +pioneer +pioneered +pioneering +pioneers +pionic +pions +piosities +piosity +pious +piously +piousness +pip +pipal +pipals +pipe +piped +pipefish +pipefishes +pipefitting +pipefittings +pipeful +pipefuls +pipeless +pipelike +pipeline +pipelined +pipelines +pipelining +piper +piperazine +piperazines +piperidine +piperidines +piperine +piperines +piperonal +piperonals +piperonyl +pipers +pipes +pipestone +pipestones +pipet +pipets +pipette +pipetted +pipettes +pipetting +piping +pipings +pipistrel +pipistrelle +pipistrelles +pipistrels +pipit +pipits +pipkin +pipkins +pipped +pippin +pipping +pippins +pips +pipsissewa +pipsissewas +pipsqueak +pipsqueaks +piquance +piquancy +piquant +piquantly +piquantness +pique +piqued +piques +piquet +piquets +piquing +piqué +piracies +piracy +piraeus +piragua +piraguas +piranesi +piranha +piranhas +pirarucu +pirarucus +pirate +pirated +pirates +piratic +piratical +piratically +pirating +piraña +pirañas +pirog +piroghi +pirogi +pirogue +pirogues +piroplasm +piroplasma +piroplasmata +piroplasmoses +piroplasmosis +piroplasms +piroshki +pirouette +pirouetted +pirouettes +pirouetting +pirozhki +pis +pisa +pisan +pisans +piscaries +piscary +piscatorial +piscatorially +piscatory +piscean +pisceans +pisces +piscicultural +pisciculture +pisciculturist +pisciculturists +pisciform +piscina +piscinae +piscinal +piscine +piscis +piscivorous +pish +pishoge +pishoges +pishogue +pishogues +pisiform +pisiforms +pismire +pismires +pismo +piso +pisolite +pisolites +pisolith +pisoliths +pisolitic +pisos +piss +pissant +pissants +pissarro +pissed +pisser +pissers +pisses +pissing +pissoir +pissoirs +pistachio +pistachios +pistareen +pistareens +piste +pistes +pistil +pistillate +pistils +pistol +pistole +pistoled +pistoleer +pistoleers +pistoles +pistoling +pistols +piston +pistons +pistou +pistous +pit +pita +pitapat +pitapats +pitapatted +pitapatting +pitas +pitcairn +pitch +pitchblende +pitched +pitcher +pitcherful +pitcherfuls +pitchers +pitches +pitchfork +pitchforked +pitchforking +pitchforks +pitchier +pitchiest +pitchiness +pitching +pitchman +pitchmen +pitchout +pitchouts +pitchpole +pitchpoled +pitchpoles +pitchpoling +pitchstone +pitchstones +pitchwoman +pitchwomen +pitchy +piteous +piteously +piteousness +pitfall +pitfalls +pith +pithead +pitheads +pithecanthropi +pithecanthropic +pithecanthropine +pithecanthropus +pithecoid +pithed +pithier +pithiest +pithily +pithiness +pithing +piths +pithy +pitiable +pitiableness +pitiably +pitied +pitier +pitiers +pities +pitiful +pitifully +pitifulness +pitiless +pitilessly +pitilessness +pitman +pitmans +pitmen +piton +pitons +pitot +pits +pitsaw +pitsaws +pitta +pittance +pittances +pittas +pitted +pitter +pitting +pittosporum +pittosporums +pittsburgh +pituicyte +pituicytes +pituitaries +pituitary +pity +pitying +pityingly +pityriases +pityriasis +piute +piutes +pivot +pivotable +pivotal +pivotally +pivoted +pivoting +pivotman +pivotmen +pivots +pix +pixel +pixelate +pixelated +pixelates +pixelating +pixelation +pixels +pixes +pixie +pixieish +pixies +pixilated +pixilation +pixilations +pixillated +pixiness +pixy +pixyish +pizarro +pizazz +pizazzy +pizza +pizzalike +pizzas +pizzaz +pizzazes +pizzazz +pizzazzes +pizzazzy +pizzeria +pizzerias +pizzicati +pizzicato +pizzicatos +pizzle +pizzles +pièce +pièces +piña +piñata +piñon +piñones +piñons +più +pkwy +placability +placable +placably +placard +placarded +placarder +placarders +placarding +placards +placate +placated +placater +placaters +placates +placating +placatingly +placation +placations +placative +placatory +place +placeable +placebo +placeboes +placebos +placed +placeholder +placeholders +placekick +placekicked +placekicker +placekickers +placekicking +placekicks +placeless +placelessly +placeman +placemen +placement +placements +placenta +placentae +placental +placentas +placentation +placentations +placer +placers +places +placid +placidity +placidly +placidness +placing +placket +plackets +placoid +plafond +plafonds +plagal +plage +plages +plagiaries +plagiarism +plagiarisms +plagiarist +plagiaristic +plagiarists +plagiarize +plagiarized +plagiarizer +plagiarizers +plagiarizes +plagiarizing +plagiary +plagioclase +plagioclases +plagiotropic +plagiotropically +plagiotropism +plagiotropisms +plague +plagued +plaguer +plaguers +plagues +plaguey +plaguily +plaguing +plaguy +plaice +plaices +plaid +plaided +plaids +plain +plainchant +plainchants +plainclothes +plainclothesman +plainclothesmen +plainer +plainest +plainly +plainness +plains +plainsman +plainsmen +plainsong +plainsongs +plainspoken +plainspokenness +plainswoman +plainswomen +plaint +plaintext +plaintexts +plaintful +plaintiff +plaintiffs +plaintive +plaintively +plaintiveness +plaints +plait +plaited +plaiter +plaiters +plaiting +plaits +plan +planar +planaria +planarian +planarians +planarity +planate +planation +planations +planchet +planchets +planchette +planchettes +planck +plane +planed +planeload +planeloads +planeness +planer +planers +planes +planeside +planesides +planet +planetaria +planetarium +planetariums +planetary +planetesimal +planetesimals +planetlike +planetoid +planetoidal +planetoids +planetological +planetologist +planetologists +planetology +planets +planetwide +planform +planforms +plangency +plangent +plangently +planimeter +planimeters +planimetric +planimetrical +planimetrically +planimetry +planing +planish +planished +planisher +planishers +planishes +planishing +planisphere +planispheres +planispheric +planispherical +plank +planked +planking +plankings +planks +plankter +plankters +plankton +planktonic +planless +planlessly +planlessness +planned +planner +planners +planning +plano +planoblast +planoblasts +planoconcave +planoconvex +planogamete +planogametes +planographic +planographically +planography +planometer +planometers +planometry +planosol +planosols +plans +plant +plantable +plantagenet +plantagenets +plantain +plantains +plantar +plantation +plantations +planted +planter +planters +plantigrade +plantigrades +planting +plantings +plantlet +plantlets +plantlike +plantocracy +plants +plantsman +plantsmen +planula +planulae +planular +planulate +plaque +plaques +plash +plashed +plashes +plashing +plasm +plasma +plasmablast +plasmablasts +plasmacyte +plasmacytes +plasmagel +plasmagels +plasmagene +plasmagenes +plasmagenic +plasmalemma +plasmalemmas +plasmapheresis +plasmas +plasmasol +plasmasols +plasmatic +plasmic +plasmid +plasmids +plasmin +plasminogen +plasminogens +plasmins +plasmodesm +plasmodesma +plasmodesmas +plasmodesmata +plasmodesms +plasmodia +plasmodial +plasmodium +plasmogamies +plasmogamy +plasmolyses +plasmolysis +plasmolytic +plasmolytically +plasmolyze +plasmolyzed +plasmolyzes +plasmolyzing +plasmon +plasmons +plasms +plassey +plaster +plasterboard +plasterboards +plastered +plasterer +plasterers +plastering +plasterings +plasters +plasterwork +plasterworks +plastery +plastic +plastically +plasticene +plasticenes +plasticine +plasticines +plasticity +plasticization +plasticizations +plasticize +plasticized +plasticizer +plasticizers +plasticizes +plasticizing +plasticky +plastics +plastid +plastidial +plastids +plastique +plastisol +plastisols +plastocyanin +plastocyanins +plastoquinone +plastoquinones +plastral +plastron +plastrons +plat +platan +platans +plate +plateau +plateaued +plateauing +plateaus +plateaux +plated +plateful +platefuls +plateglass +platelet +platelets +platelike +platemaker +platemakers +platemaking +platen +platens +plater +plateresque +platers +plates +platform +platforms +platier +platies +platiest +platina +platinas +plating +platings +platinic +platinize +platinized +platinizes +platinizing +platinocyanide +platinocyanides +platinoid +platinoids +platinotype +platinotypes +platinous +platinum +platitude +platitudes +platitudinal +platitudinarian +platitudinarians +platitudinize +platitudinized +platitudinizes +platitudinizing +platitudinous +platitudinously +plato +platonic +platonical +platonically +platonism +platonist +platonistic +platonists +platonize +platonized +platonizes +platonizing +platoon +platooned +platooning +platoons +plats +plattdeutsch +platted +platter +platterful +platterfuls +platters +platting +platy +platyfish +platyfishes +platyhelminth +platyhelminthic +platyhelminths +platypi +platypus +platypuses +platyrrhine +platyrrhinian +platyrrhiny +platys +plaudit +plaudits +plausibility +plausible +plausibleness +plausibly +plausive +plautus +play +playa +playability +playable +playact +playacted +playacting +playacts +playas +playback +playbacks +playbill +playbills +playbook +playbooks +playboy +playboys +played +player +players +playfellow +playfellows +playfield +playfields +playful +playfully +playfulness +playgirl +playgirls +playgoer +playgoers +playgoing +playground +playgrounds +playhouse +playhouses +playing +playland +playlands +playlet +playlets +playlist +playlists +playmaker +playmakers +playmaking +playmate +playmates +playoff +playoffs +playpen +playpens +playroom +playrooms +plays +playsuit +playsuits +plaything +playthings +playtime +playtimes +playwear +playwright +playwrighting +playwrights +playwriting +plaza +plazas +plaît +plea +pleach +pleached +pleaches +pleaching +plead +pleadable +pleaded +pleader +pleaders +pleading +pleadingly +pleadings +pleads +pleas +pleasance +pleasances +pleasant +pleasanter +pleasantest +pleasantly +pleasantness +pleasantries +pleasantry +please +pleased +pleaser +pleasers +pleases +pleasing +pleasingly +pleasingness +pleasurability +pleasurable +pleasurableness +pleasurably +pleasure +pleasured +pleasureless +pleasures +pleasuring +pleat +pleated +pleater +pleaters +pleating +pleatless +pleats +pleb +plebe +plebeian +plebeianism +plebeianly +plebeians +plebes +plebianly +plebiscitary +plebiscite +plebiscites +plebs +plecopteran +plecopterans +plectognath +plectognaths +plectra +plectrum +plectrums +pled +pledge +pledged +pledgee +pledgees +pledgeor +pledgeors +pledger +pledgers +pledges +pledget +pledgets +pledging +pledgor +pledgors +pleiad +pleiades +plein +pleinairism +pleinairist +pleinairists +pleiotaxies +pleiotaxy +pleiotropic +pleiotropically +pleiotropies +pleiotropism +pleiotropisms +pleiotropy +pleistocene +plena +plenarily +plenariness +plenary +plenipotent +plenipotentiaries +plenipotentiary +plenish +plenished +plenishes +plenishing +plenitude +plenitudinous +plenteous +plenteously +plenteousness +plentiful +plentifully +plentifulness +plentitude +plenty +plenum +plenums +pleochroic +pleochroism +pleochroisms +pleomorphic +pleomorphism +pleomorphisms +pleonasm +pleonasms +pleonastic +pleonastically +pleopod +pleopods +plerocercoid +plerocercoids +plesiosaur +plesiosauri +plesiosaurs +plesiosaurus +plessimeter +plessimeters +plessor +plessors +plethora +plethoric +plethorically +plethysmogram +plethysmograms +plethysmograph +plethysmographic +plethysmographically +plethysmographs +plethysmography +pleura +pleurae +pleural +pleuras +pleurisy +pleuritic +pleurodont +pleurodonts +pleurodynia +pleurodynias +pleuron +pleuropneumonia +pleurotomies +pleurotomy +pleuston +pleustonic +pleustons +plexiform +plexiglas +pleximeter +pleximeters +pleximetric +pleximetry +plexor +plexors +plexus +plexuses +pliability +pliable +pliableness +pliably +pliancy +pliant +pliantly +pliantness +plica +plicae +plical +plicate +plicated +plicately +plicateness +plication +plications +plicature +plicatures +plied +plier +pliers +plies +plight +plighted +plighter +plighters +plighting +plights +plimsol +plimsole +plimsoles +plimsoll +plimsolls +plimsols +plink +plinked +plinker +plinkers +plinking +plinks +plinth +plinths +pliny +pliocene +pliofilm +pliskie +pliskies +plisky +plisse +plisses +plissé +plissés +plié +plod +plodded +plodder +plodders +plodding +ploddingly +plods +ploidies +ploidy +plonk +plonked +plonking +plonks +plop +plopped +plopping +plops +plosion +plosions +plosive +plosives +plot +plotinism +plotinist +plotinists +plotinus +plotless +plotlessness +plotline +plotlines +plots +plottage +plottages +plotted +plotter +plotters +plottier +plottiest +plotting +plotty +plough +ploughed +ploughing +ploughman +ploughs +plover +plovers +plow +plowable +plowback +plowbacks +plowboy +plowboys +plowed +plower +plowers +plowing +plowman +plowmen +plows +plowshare +plowshares +ploy +ploys +pluck +plucked +plucker +pluckers +pluckier +pluckiest +pluckily +pluckiness +plucking +plucks +plucky +plug +plugged +plugger +pluggers +plugging +plugola +plugs +plum +plumage +plumaged +plumate +plumb +plumbable +plumbago +plumbagos +plumbean +plumbed +plumber +plumberies +plumbers +plumbery +plumbic +plumbiferous +plumbing +plumbism +plumbisms +plumbs +plume +plumed +plumelet +plumelets +plumeria +plumes +plumier +plumiest +pluming +plumlike +plummet +plummeted +plummeting +plummets +plummier +plummiest +plummy +plumose +plumosely +plumosity +plump +plumped +plumpen +plumpened +plumpening +plumpens +plumper +plumpest +plumping +plumpish +plumply +plumpness +plumps +plums +plumule +plumules +plumulose +plumy +plunder +plunderable +plundered +plunderer +plunderers +plundering +plunderous +plunders +plunge +plunged +plunger +plungers +plunges +plunging +plunk +plunked +plunker +plunkers +plunking +plunks +plunky +pluperfect +pluperfects +plural +pluralism +pluralist +pluralistic +pluralistically +pluralists +pluralities +plurality +pluralization +pluralizations +pluralize +pluralized +pluralizes +pluralizing +plurally +plurals +pluribus +pluripotent +plus +pluses +plush +plusher +plushest +plushier +plushiest +plushily +plushiness +plushly +plushness +plushy +plussage +plusses +plutarch +plutarchan +plutarchian +pluto +plutocracies +plutocracy +plutocrat +plutocratic +plutocratical +plutocratically +plutocrats +plutographic +plutography +pluton +plutonian +plutonic +plutonium +plutons +pluvial +pluviograph +pluviographs +pluviometer +pluviometers +pluviometric +pluviometrical +pluviometrically +pluviometry +pluviose +pluviosity +pluvious +ply +plyer +plyers +plying +plymouth +plymouths +plywood +pneuma +pneumas +pneumatic +pneumatical +pneumatically +pneumaticity +pneumatics +pneumatograph +pneumatographs +pneumatologic +pneumatological +pneumatologist +pneumatologists +pneumatology +pneumatolysis +pneumatolytic +pneumatometer +pneumatometers +pneumatometry +pneumatophore +pneumatophores +pneumatophoric +pneumectomy +pneumobacilli +pneumobacillus +pneumococcal +pneumococci +pneumococcus +pneumoconiosis +pneumoconiotic +pneumoconiotics +pneumocystis +pneumocystises +pneumogastric +pneumograph +pneumographic +pneumographs +pneumonectomies +pneumonectomy +pneumonia +pneumonic +pneumonitis +pneumostome +pneumostomes +pneumotachogram +pneumotachograms +pneumotachograph +pneumotachographic +pneumotachographs +pneumotachography +pneumothorax +pneumothoraxes +po +poach +poachable +poached +poacher +poachers +poaches +poaching +poblano +pocahontas +pochard +pochards +pock +pocked +pocket +pocketable +pocketbook +pocketbooks +pocketed +pocketful +pocketfuls +pocketing +pocketknife +pocketknives +pocketless +pockets +pocketsful +pocketsize +pocking +pockmark +pockmarked +pockmarking +pockmarks +pocks +pocky +poco +pococurante +pococurantes +pococurantism +pocono +poconos +pocosin +pocosins +pocus +pocused +pocuses +pocusing +pocussed +pocusses +pocussing +pod +podagra +podagral +podagras +podagric +podded +podding +podesta +podestas +podetia +podetium +podgier +podgiest +podgy +podia +podiatric +podiatrist +podiatrists +podiatry +podite +podites +poditic +podium +podiums +podophylli +podophyllin +podophyllins +podophyllum +podophyllums +podrida +podridas +pods +podsol +podsolization +podsolizations +podsols +podunk +podzol +podzolic +podzolization +podzolizations +podzolize +podzolized +podzolizes +podzolizing +podzols +poem +poems +poenology +poesies +poesy +poet +poetaster +poetasters +poetess +poetesses +poetic +poetical +poeticality +poetically +poeticalness +poeticism +poeticisms +poeticize +poeticized +poeticizes +poeticizing +poetics +poetize +poetized +poetizer +poetizers +poetizes +poetizing +poetry +poets +pogies +pogo +pogonia +pogonias +pogonip +pogonips +pogonomyrmex +pogonophoran +pogonophorans +pogonophore +pogonophores +pogonophorous +pogrom +pogromed +pogroming +pogromist +pogromists +pogroms +pogy +poi +poignance +poignancy +poignant +poignantly +poikilotherm +poikilothermal +poikilothermia +poikilothermic +poikilothermism +poikilothermous +poikilotherms +poilu +poilus +poincaré +poinciana +poinsettia +poinsettias +point +pointblank +pointe +pointed +pointedly +pointedness +pointelle +pointer +pointers +pointes +pointier +pointiest +pointillism +pointillist +pointillistic +pointillists +pointing +pointless +pointlessly +pointlessness +points +pointtillist +pointy +pois +poise +poised +poises +poisha +poising +poison +poisoned +poisoner +poisoners +poisoning +poisonings +poisonous +poisonously +poisonousness +poisons +poisonwood +poisonwoods +poisson +poitiers +poitou +poivre +poke +pokeberries +pokeberry +poked +poker +pokerfaced +pokeroot +pokeroots +pokers +pokery +pokes +pokeweed +pokeweeds +pokey +pokeys +pokier +pokies +pokiest +pokily +pokiness +poking +poky +pol +polab +polabian +polabians +polabs +polack +polacks +poland +polar +polarimeter +polarimeters +polarimetric +polarimetry +polaris +polariscope +polariscopes +polariscopic +polarities +polarity +polarizability +polarizable +polarization +polarizations +polarize +polarized +polarizer +polarizers +polarizes +polarizing +polarographic +polarographically +polarography +polaroid +polaron +polarons +polder +polders +pole +poleax +poleaxe +poleaxed +poleaxes +poleaxing +polecat +polecats +poled +poleis +poleless +polemic +polemical +polemically +polemicist +polemicists +polemicize +polemicized +polemicizes +polemicizing +polemics +polemist +polemists +polemize +polemized +polemizes +polemizing +polemonium +polenta +polentas +poler +polers +poles +polestar +polestars +poleward +police +policeable +policed +policeman +policemen +policer +policers +polices +policewoman +policewomen +policies +policing +policlinic +policlinics +policy +policyholder +policyholders +policymaker +policymakers +policymaking +poling +polio +poliomyelitic +poliomyelitis +poliovirus +polioviruses +polis +polish +polished +polisher +polishers +polishes +polishing +polishings +politburo +politburos +polite +politely +politeness +politenesses +politer +politesse +politest +politic +political +politicalization +politicalizations +politicalize +politicalized +politicalizes +politicalizing +politically +politician +politicians +politicization +politicizations +politicize +politicized +politicizes +politicizing +politick +politicked +politicker +politickers +politicking +politicks +politicly +politico +politicos +politics +polities +polity +polka +polkaed +polkaing +polkas +poll +pollack +pollacks +pollard +pollarded +pollarding +pollards +polled +pollen +pollenate +pollenated +pollenates +pollenating +polleniferous +pollenosis +pollens +poller +pollers +pollex +pollices +pollinate +pollinated +pollinates +pollinating +pollination +pollinations +pollinator +pollinators +polling +pollinia +polliniferous +pollinium +pollinization +pollinizations +pollinize +pollinized +pollinizer +pollinizers +pollinizes +pollinizing +pollinosis +polliwog +polliwogs +pollo +pollock +pollocks +polloi +polls +pollster +pollsters +polltaker +polltakers +pollutant +pollutants +pollute +polluted +polluter +polluters +pollutes +polluting +pollution +pollutive +pollux +pollyanna +pollyannaish +pollyannaism +pollyannas +pollyannish +pollywog +pollywogs +polo +poloist +poloists +polonaise +polonaises +polonia +polonium +polonius +pols +poltergeist +poltergeists +poltroon +poltrooneries +poltroonery +poltroons +poly +polyacetylene +polyacrylamide +polyacrylamides +polyacrylonitrile +polyadenylic +polyalcohol +polyalcohols +polyamide +polyamides +polyamine +polyamines +polyandric +polyandrous +polyandry +polyantha +polyanthas +polyanthus +polyanthuses +polyatomic +polybasic +polybasite +polybasites +polybius +polybrominated +polybutadiene +polybutadienes +polycarbonate +polycarbonates +polycarpellary +polycarpic +polycarpous +polycarpy +polycentric +polycentrics +polycentrism +polychaete +polychaetes +polychete +polychetes +polychetous +polychlorinated +polychotomous +polychotomy +polychromatic +polychromatophile +polychromatophilia +polychromatophilic +polychrome +polychromes +polychromic +polychromies +polychromophilia +polychromous +polychromy +polycistronic +polyclinic +polyclinics +polyclonal +polyclonally +polyclone +polyclones +polycondensation +polycondensations +polyconic +polycot +polycots +polycotyledon +polycotyledonous +polycotyledons +polycrystal +polycrystalline +polycrystals +polycyclic +polycystic +polycythemia +polycythemias +polycythemic +polycytidylic +polydactyl +polydactylism +polydactylous +polydactyly +polydemic +polydiacetylene +polydipsia +polydipsic +polydisperse +polydispersity +polydorus +polyelectrolyte +polyelectrolytes +polyembryonic +polyembryonies +polyembryony +polyene +polyenes +polyenic +polyester +polyesterification +polyesterifications +polyesters +polyestrous +polyether +polyethers +polyethylene +polygala +polygalas +polygamic +polygamist +polygamists +polygamize +polygamized +polygamizes +polygamizing +polygamous +polygamously +polygamy +polygene +polygenes +polygenesis +polygenesist +polygenesists +polygenetic +polygenic +polygenically +polyglot +polyglotism +polyglots +polyglottism +polygon +polygonal +polygonally +polygons +polygonum +polygonums +polygraph +polygraphed +polygrapher +polygraphers +polygraphic +polygraphing +polygraphist +polygraphists +polygraphs +polygynous +polygyny +polyhedra +polyhedral +polyhedron +polyhedrons +polyhedroses +polyhedrosis +polyhistor +polyhistoric +polyhistors +polyhydric +polyhydroxy +polyhydroxybutyrate +polyhymnia +polyimide +polyimides +polyinosinic +polylysine +polylysines +polymath +polymathic +polymaths +polymathy +polymer +polymerase +polymerases +polymeric +polymerically +polymerism +polymerization +polymerizations +polymerize +polymerized +polymerizes +polymerizing +polymerous +polymers +polymethyl +polymnia +polymorph +polymorphic +polymorphically +polymorphism +polymorphisms +polymorphonuclear +polymorphonuclears +polymorphous +polymorphously +polymorphs +polymyxin +polymyxins +polynesia +polynesian +polynesians +polyneuritic +polyneuritis +polyneuritises +polynices +polynomial +polynomials +polynuclear +polynucleotide +polynucleotides +polynya +polynyas +polynyi +polyolefin +polyolefins +polyoma +polyomas +polyonymous +polyp +polyparia +polyparies +polyparium +polypary +polypeptide +polypeptides +polypeptidic +polypetalous +polyphagia +polyphagian +polyphagous +polyphagy +polyphase +polyphasic +polyphemus +polyphenol +polyphenolic +polyphenols +polyphiloprogenitive +polyphone +polyphones +polyphonic +polyphonically +polyphonies +polyphonous +polyphonously +polyphony +polyphosphate +polyphosphates +polyphyletic +polyphyletically +polypide +polypides +polyploid +polyploids +polyploidy +polypnea +polypneas +polypneic +polypod +polypodies +polypodous +polypody +polypoid +polypore +polypores +polyposes +polyposis +polypropylene +polypropylenes +polyprotic +polyps +polyptych +polyptyches +polyrhythm +polyrhythmic +polyrhythmically +polyrhythms +polyribonucleotide +polyribonucleotides +polyribosomal +polyribosome +polyribosomes +polys +polysaccharid +polysaccharide +polysaccharides +polysaccharids +polysaccharose +polysaccharoses +polysemous +polysemy +polysepalous +polysome +polysomes +polysomic +polysomics +polysorbate +polysorbates +polyspermic +polyspermies +polyspermy +polystichous +polystyrene +polystyrenes +polysulfide +polysulfides +polysyllabic +polysyllabically +polysyllable +polysyllables +polysynaptic +polysynaptically +polysyndeton +polysyndetons +polysynthetic +polytechnic +polytechnics +polytene +polytenic +polyteny +polytetrafluoroethylene +polytetrafluoroethylenes +polytheism +polytheist +polytheistic +polytheistical +polytheists +polythene +polythenes +polytocous +polytonal +polytonality +polytonally +polytrophic +polytypic +polytypical +polyunsaturate +polyunsaturated +polyunsaturates +polyurethane +polyurethanes +polyuria +polyurias +polyuric +polyvalence +polyvalency +polyvalent +polyvinyl +polywater +polyzoan +polyzoans +polyzoaria +polyzoaries +polyzoarium +polyzoary +polyzoic +pom +pomace +pomaceous +pomaces +pomade +pomaded +pomades +pomading +pomander +pomanders +pomatum +pomatums +pome +pomegranate +pomegranates +pomelo +pomelos +pomerania +pomeranian +pomeranians +pomes +pomiculture +pomicultures +pomiferous +pommee +pommel +pommeled +pommeling +pommelled +pommelling +pommels +pommie +pommies +pommy +pomo +pomological +pomologically +pomologist +pomologists +pomology +pomona +pomos +pomp +pompadour +pompadoured +pompadours +pompano +pompanos +pompei +pompeian +pompeians +pompeii +pompeiian +pompeiians +pompelmous +pompelmouses +pompey +pompidou +pompom +pompoms +pompon +pompons +pomposity +pompous +pompously +pompousness +poms +ponca +poncas +ponce +ponces +poncho +ponchos +pond +ponder +ponderability +ponderable +pondered +ponderer +ponderers +pondering +ponderosa +ponderosas +ponderosity +ponderous +ponderously +ponderousness +ponders +pondicherry +ponds +pondweed +pondweeds +pone +pones +pong +pongee +pongees +pongid +pongids +poniard +poniarded +poniarding +poniards +ponied +ponies +pons +pontes +ponthieu +pontiac +pontic +pontifex +pontiff +pontiffs +pontifical +pontifically +pontificals +pontificate +pontificated +pontificates +pontificating +pontification +pontifications +pontificator +pontificators +pontifices +pontil +pontils +pontine +pontonier +pontoniers +pontoon +pontoons +pontus +pony +ponying +ponytail +ponytailed +ponytails +ponzi +pooch +pooches +pood +poodle +poodled +poodles +poodling +poods +poof +poofs +pooftah +poofter +poofters +pooh +poohed +poohing +poohs +pool +pooled +pooler +poolers +pooling +poolroom +poolrooms +pools +poolside +poolsides +poon +poona +poons +poop +pooped +pooper +pooping +poops +poor +poorer +poorest +poorhouse +poorhouses +poori +pooris +poorish +poorly +poormouth +poormouthed +poormouthing +poormouths +poorness +poove +pooves +pop +popcorn +pope +popedom +popedoms +popery +popes +popeyed +popgun +popguns +popinjay +popinjays +popish +popishly +popishness +poplar +poplars +poplin +poplins +popliteal +popocatépetl +popover +popovers +poppa +poppas +popped +popper +poppers +poppet +poppets +poppied +poppies +popping +popple +poppled +popples +poppling +poppy +poppycock +poppyhead +poppyheads +pops +popsicle +popsicles +populace +populaces +popular +popularity +popularization +popularizations +popularize +popularized +popularizer +popularizers +popularizes +popularizing +popularly +populate +populated +populates +populating +population +populational +populations +populi +populism +populist +populistic +populists +populous +populously +populousness +popup +porbeagle +porbeagles +porcelain +porcelainize +porcelainized +porcelainizes +porcelainizing +porcelainlike +porcelains +porcelaneous +porcellaneous +porch +porches +porcine +porcini +porcino +porcupine +porcupines +pore +pored +pores +porgies +porgy +poriferal +poriferan +poriferans +poriferous +poring +pork +porker +porkers +porkier +porkies +porkiest +porkpie +porkpies +porky +porn +pornier +porniest +porno +pornographer +pornographers +pornographic +pornographically +pornography +porny +poromeric +poromerics +porosities +porosity +porous +porously +porousness +porphyria +porphyrias +porphyric +porphyries +porphyrin +porphyrins +porphyritic +porphyritical +porphyroid +porphyroids +porphyropsin +porphyropsins +porphyry +porpoise +porpoises +porrect +porridge +porridges +porridgy +porringer +porringers +port +portability +portable +portableness +portables +portably +portage +portaged +portages +portaging +portal +portals +portamenti +portamento +portamentos +portapack +portapacks +portapak +portapaks +portative +portcullis +portcullises +porte +ported +portend +portended +portending +portends +portent +portentous +portentously +portentousness +portents +porter +porterage +porterages +porteress +porteresses +porterhouse +porterhouses +porters +portfolio +portfolios +porthole +portholes +portia +portico +porticoed +porticoes +porticos +portiere +portieres +porting +portion +portionable +portioned +portioner +portioners +portioning +portionless +portions +portière +portières +portland +portlander +portlanders +portlier +portliest +portliness +portly +portmanteau +portmanteaus +portmanteaux +portofino +portrait +portraitist +portraitists +portraits +portraiture +portraitures +portray +portrayable +portrayal +portrayals +portrayed +portrayer +portrayers +portraying +portrays +portress +portresses +ports +portside +portugal +portuguese +portulaca +portulacas +posable +posada +posadas +pose +posed +poseidon +poser +posers +poses +poseur +poseurs +posh +poshly +poshness +posies +posigrade +posing +posit +positano +posited +positing +position +positional +positionally +positioned +positioner +positioners +positioning +positions +positive +positively +positiveness +positives +positivism +positivist +positivistic +positivistically +positivists +positivity +positron +positronium +positrons +posits +posology +posse +posses +possess +possessed +possessedly +possessedness +possesses +possessing +possession +possessional +possessionless +possessions +possessive +possessively +possessiveness +possessives +possessor +possessors +possessory +posset +possets +possibilities +possibility +possible +possibly +possum +possums +post +postabortion +postaccident +postadolescent +postage +postages +postal +postally +postamputation +postapocalyptic +postarrest +postatomic +postattack +postaxial +postaxially +postbaccalaureate +postbag +postbags +postbase +postbellum +postbiblical +postbourgeois +postbox +postboxes +postboy +postboys +postburn +postcapitalist +postcard +postcardlike +postcards +postcava +postcaval +postcavas +postclassic +postclassical +postcode +postcodes +postcoital +postcollege +postcollegiate +postcolonial +postconception +postconcert +postcondition +postconditions +postconquest +postconsonantal +postconvention +postcopulatory +postcoronary +postcoup +postcranial +postcranially +postcrash +postcrisis +postdate +postdated +postdates +postdating +postdeadline +postdebate +postdebutante +postdelivery +postdepositional +postdepression +postdevaluation +postdiluvial +postdiluvian +postdive +postdivestiture +postdivorce +postdoc +postdocs +postdoctoral +postdoctorate +postdrug +poste +posted +postediting +postelection +postembryonal +postembryonic +postemergence +postemergency +postencephalitic +postepileptic +poster +posterior +posteriori +posteriority +posteriorly +posteriors +posterity +postern +posterns +posterolateral +posters +posteruptive +postexercise +postexilian +postexilic +postexperience +postexperimental +postexposure +postface +postfaces +postfault +postfeminist +postfire +postfix +postfixal +postfixed +postfixes +postfixial +postfixing +postflight +postfracture +postfreeze +postfrontal +postgame +postganglionic +postglacial +postgraduate +postgraduates +postgraduation +postharvest +posthaste +posthemorrhagic +posthole +postholes +postholiday +postholocaust +posthospital +posthumous +posthumously +posthumousness +posthypnotic +postiche +postiches +postilion +postilions +postillion +postillions +postimpact +postimperial +postimpressionism +postimpressionist +postimpressionistic +postimpressionists +postinaugural +postindependence +postindustrial +postinfection +posting +postings +postinjection +postinoculation +postirradiation +postischemic +postisolation +postlanding +postlapsarian +postlaunch +postliberation +postliterate +postlude +postludes +postman +postmarital +postmark +postmarked +postmarking +postmarks +postmastectomy +postmaster +postmasters +postmastership +postmasterships +postmating +postmedieval +postmen +postmenopausal +postmenstrual +postmeridian +postmidnight +postmillenarian +postmillenarianism +postmillenarians +postmillennial +postmillennialism +postmillennialist +postmillennialists +postmillennian +postmistress +postmistresses +postmodern +postmodernism +postmodernist +postmodernists +postmortem +postmortems +postnasal +postnatal +postnatally +postneonatal +postnuptial +postnuptially +postoperative +postoperatively +postorbital +postorgasmic +postovulatory +postpaid +postpartum +postpollination +postponable +postpone +postponed +postponement +postponements +postponer +postponers +postpones +postponing +postpose +postposed +postposes +postposing +postposition +postpositional +postpositionally +postpositions +postpositive +postpositively +postpositives +postprandial +postprandially +postpresidential +postprimary +postprison +postprocessor +postprocessors +postproduction +postproductions +postpsychoanalytic +postpuberty +postpubescent +postrace +postrecession +postresurrection +postretirement +postrevolutionary +postriot +postromantic +posts +postscript +postscripts +postseason +postsecondary +postshow +poststimulation +poststimulatory +poststimulus +poststrike +postsurgical +postsynaptic +postsynaptically +posttax +postteen +posttension +posttensioned +posttensioning +posttensions +posttest +posttests +posttranscriptional +posttransfusion +posttranslational +posttraumatic +posttreatment +posttrial +postulancy +postulant +postulants +postulantship +postulate +postulated +postulates +postulating +postulation +postulational +postulations +postulator +postulators +postural +posture +postured +posturer +posturers +postures +posturing +posturist +posturists +postvaccinal +postvaccination +postvagotomy +postvasectomy +postvertebral +postvocalic +postwar +postweaning +postworkshop +posy +pot +potability +potable +potableness +potables +potage +potages +potamoplankton +potamoplanktons +potash +potashes +potassic +potassium +potation +potations +potato +potatoes +potatory +potawatomi +potawatomis +potbellied +potbellies +potbelly +potboil +potboiled +potboiler +potboilers +potboiling +potboils +potbound +potboy +potboys +poteen +poteens +potemkin +potence +potences +potencies +potency +potent +potentate +potentates +potential +potentialities +potentiality +potentialize +potentialized +potentializes +potentializing +potentially +potentials +potentiate +potentiated +potentiates +potentiating +potentiation +potentiations +potentiator +potentiators +potentilla +potentillas +potentiometer +potentiometers +potentiometric +potently +potentness +potful +potfuls +pothead +potheads +potheen +potheens +pother +potherb +potherbs +pothered +pothering +pothers +potholder +potholders +pothole +potholed +potholes +pothook +pothooks +pothouse +pothouses +pothunter +pothunters +pothunting +potiche +potiches +potion +potions +potiphar +potlatch +potlatches +potline +potlines +potluck +potlucks +potomac +potometer +potometers +potpie +potpies +potpourri +potpourris +pots +potsdam +potshard +potshards +potsherd +potsherds +potshot +potshots +potshotting +potstone +potstones +pottage +potted +potter +pottered +potterer +potterers +potteries +pottering +potteringly +potters +pottery +pottier +potties +pottiest +potting +pottle +pottles +potto +pottos +potty +potzer +potzers +pouch +pouched +pouches +pouchier +pouchiest +pouching +pouchy +pouf +poufed +pouffe +pouffed +pouffes +pouffy +poufs +pouilly +poulard +poularde +poulardes +poulards +poult +poulter +poulterer +poulterers +poultice +poulticed +poultices +poulticing +poultry +poultryman +poultrymen +poults +pounce +pounced +pouncer +pouncers +pounces +pouncet +pouncets +pouncing +pound +poundage +poundal +poundals +pounded +pounder +pounders +pounding +pounds +pour +pourable +pourboire +pourboires +poured +pourer +pourers +pouring +pouringly +pourparler +pourparlers +pourpoint +pourpoints +pours +pousse +poussette +poussetted +poussettes +poussetting +poussin +pout +pouted +pouter +pouters +pouting +pouts +pouty +poverty +pow +powder +powdered +powderer +powderers +powdering +powderless +powderlike +powders +powdery +powell +power +powerboat +powerboats +powered +powerful +powerfully +powerfulness +powerhouse +powerhouses +powering +powerless +powerlessly +powerlessness +powerlifting +powerliftings +powers +powerwalking +powhatan +powhatans +pows +powwow +powwowed +powwowing +powwows +powys +pox +poxes +poxvirus +poxviruses +pozzolan +pozzolana +pozzolanas +pozzolanic +pozzolans +pozzuolana +pozzuolanas +pozzuolanic +pozzuoli +ppm +pq +praam +praams +practicability +practicable +practicableness +practicably +practical +practicalities +practicality +practically +practicalness +practice +practiced +practicer +practicers +practices +practicing +practicum +practicums +practise +practised +practises +practising +practitioner +practitioners +pradesh +prado +praecipe +praecipes +praecox +praedial +praemunire +praemunires +praenomen +praenomens +praenomina +praenominal +praesidium +praesidiums +praetor +praetorial +praetorian +praetorians +praetors +praetorship +praetorships +pragmatic +pragmatical +pragmatically +pragmaticism +pragmaticist +pragmaticists +pragmatics +pragmatism +pragmatist +pragmatistic +pragmatists +prague +prahu +prahus +prairie +prairies +praise +praised +praiseful +praiser +praisers +praises +praiseworthier +praiseworthiest +praiseworthily +praiseworthiness +praiseworthy +praising +prakrit +prakritic +prakrits +praline +pralines +pralltriller +pralltrillers +pram +prams +prance +pranced +prancer +prancers +prances +prancing +prancingly +prandial +prandially +prang +pranged +pranging +prangs +prank +pranked +pranking +prankish +prankishly +prankishness +pranks +prankster +pranksters +prase +praseodymium +prases +prat +prate +prated +prater +praters +prates +pratfall +pratfalls +pratincole +pratincoles +prating +pratingly +pratique +pratiques +prato +prats +prattle +prattled +prattler +prattlers +prattles +prattling +prattlingly +prau +praus +prawn +prawned +prawner +prawners +prawning +prawns +praxeological +praxeology +praxes +praxiology +praxis +praxiteles +pray +prayed +prayer +prayerful +prayerfully +prayerfulness +prayerlessness +prayers +praying +prays +prazosin +prazosins +pre +preach +preached +preacher +preachers +preaches +preachier +preachiest +preachification +preachifications +preachified +preachifies +preachify +preachifying +preachily +preachiness +preaching +preachingly +preachment +preachments +preachy +preadaptation +preadaptations +preadapted +preadaptive +preadmission +preadmissions +preadolescence +preadolescent +preadolescents +preadult +preagricultural +preamble +preambles +preambulary +preamp +preamplified +preamplifier +preamplifiers +preamps +preanesthetic +preannounce +preannounced +preannounces +preannouncing +preapprehension +preapprove +preapproved +preapproves +preapproving +prearrange +prearranged +prearrangement +prearrangements +prearranges +prearranging +preassembled +preassign +preassigned +preassigning +preassigns +preatomic +preaxial +preaxially +prebake +prebaked +prebakes +prebaking +prebattle +prebattled +prebattles +prebattling +prebend +prebendal +prebendaries +prebendary +prebends +prebiblical +prebiologic +prebiological +prebiologist +prebiologists +prebiology +prebiotic +prebook +prebooked +prebooking +prebooks +prebreakfast +prebreakfasts +prebuilt +precalculus +precambrian +precancel +precanceled +precanceling +precancellation +precancellations +precancelled +precancelling +precancels +precancer +precancerous +precancers +precapitalist +precarious +precariously +precariousness +precast +precasting +precasts +precative +precatory +precaution +precautional +precautionary +precautions +precava +precavae +precaval +precede +preceded +precedence +precedency +precedent +precedential +precedents +precedes +preceding +precensor +precensored +precensoring +precensors +precentor +precentorial +precentors +precentorship +precentorships +precept +preceptive +preceptively +preceptor +preceptorial +preceptorially +preceptories +preceptors +preceptorship +preceptorships +preceptory +precepts +precess +precessed +precesses +precessing +precession +precessional +precessions +prechill +prechilled +prechilling +prechills +prechristmas +precieuse +precieux +precinct +precincts +preciosities +preciosity +precious +preciously +preciousness +precipe +precipes +precipice +precipices +precipitable +precipitance +precipitancy +precipitant +precipitantly +precipitantness +precipitants +precipitate +precipitated +precipitately +precipitateness +precipitates +precipitating +precipitation +precipitations +precipitative +precipitator +precipitators +precipitin +precipitinogen +precipitinogens +precipitins +precipitous +precipitously +precipitousness +precise +precisely +preciseness +precisian +precisianism +precisians +precision +precisionism +precisionist +precisionists +precisions +preclear +preclearance +precleared +preclearing +preclears +preclinical +preclude +precluded +precludes +precluding +preclusion +preclusive +preclusively +precocial +precocious +precociously +precociousness +precocity +precode +precoded +precodes +precoding +precognition +precognitions +precognitive +precognizant +precoital +precollege +precollegiate +precolonial +precombustion +precommitment +precommitments +precompute +precomputed +precomputer +precomputes +precomputing +preconceive +preconceived +preconceives +preconceiving +preconception +preconceptions +preconcert +preconcerted +preconcerting +preconcerts +precondition +preconditioned +preconditioning +preconditions +preconquest +preconscious +preconsciously +preconsonantal +preconstructed +precontact +precontract +precontracted +precontracting +precontracts +precontrived +preconvention +preconviction +preconvictions +precook +precooked +precooking +precooks +precool +precooled +precooling +precools +precopulatory +precrash +precrease +precreased +precreases +precreasing +precrisis +precritical +precursive +precursor +precursors +precursory +precut +precuts +precutting +predaceous +predaceousness +predacious +predaciousness +predacity +predate +predated +predates +predating +predation +predations +predator +predatorily +predatoriness +predators +predatory +predawn +predawns +predecease +predeceased +predeceases +predeceasing +predecessor +predecessors +predefine +predefined +predefines +predefining +predefinition +predefinitions +predelivery +predeparture +predesignate +predesignated +predesignates +predesignating +predesignation +predesignations +predestinarian +predestinarianism +predestinarians +predestinate +predestinated +predestinates +predestinating +predestination +predestinator +predestinators +predestine +predestined +predestines +predestining +predeterminate +predetermination +predeterminations +predetermine +predetermined +predeterminer +predeterminers +predetermines +predetermining +predevaluation +predevelopment +prediabetes +prediabetic +prediabetics +predial +predicability +predicable +predicableness +predicables +predicament +predicamental +predicamentally +predicaments +predicate +predicated +predicates +predicating +predication +predicational +predications +predicative +predicatively +predicator +predicators +predicatory +predict +predictability +predictable +predictably +predicted +predicting +prediction +predictions +predictive +predictively +predictiveness +predictor +predictors +predicts +predigest +predigested +predigesting +predigestion +predigestions +predigests +predilection +predilections +predinner +predischarge +prediscoveries +prediscovery +predispose +predisposed +predisposes +predisposing +predisposition +predispositions +predive +prednisolone +prednisolones +prednisone +prednisones +predoctoral +predominance +predominancy +predominant +predominantly +predominate +predominated +predominately +predominates +predominating +predominatingly +predomination +predominations +predominator +predominators +predrill +predrilled +predrilling +predrills +predynastic +preeclampsia +preeclamptic +preelection +preelectric +preembargo +preemergence +preemergent +preemie +preemies +preeminence +preeminent +preeminently +preemployment +preemployments +preempt +preempted +preempting +preemption +preemptions +preemptive +preemptively +preemptor +preemptors +preemptory +preempts +preen +preened +preener +preeners +preengineered +preening +preenrollment +preens +preerect +preerected +preerecting +preerects +preestablish +preestablished +preestablishes +preestablishing +preethical +preexilian +preexilic +preexist +preexisted +preexistence +preexistent +preexisting +preexists +preexperiment +prefab +prefabed +prefabing +prefabricate +prefabricated +prefabricates +prefabricating +prefabrication +prefabrications +prefabricator +prefabricators +prefabs +preface +prefaced +prefacer +prefacers +prefaces +prefacing +prefade +prefaded +prefades +prefading +prefascist +prefatorily +prefatory +prefect +prefects +prefectural +prefecture +prefectures +prefer +preferability +preferable +preferableness +preferably +preference +preferences +preferential +preferentialism +preferentialist +preferentialists +preferentially +preferment +preferments +preferred +preferrer +preferrers +preferring +prefers +prefeudal +prefight +prefiguration +prefigurations +prefigurative +prefiguratively +prefigurativeness +prefigure +prefigured +prefigurement +prefigurements +prefigures +prefiguring +prefile +prefiled +prefiles +prefiling +prefilled +prefinance +prefinanced +prefinances +prefinancing +prefinished +prefire +prefix +prefixal +prefixally +prefixed +prefixes +prefixing +preflame +preflight +preflighted +preflighting +preflights +prefocus +prefocused +prefocuses +prefocusing +preform +preformat +preformation +preformationist +preformationists +preformations +preformats +preformatted +preformatting +preformed +preforming +preforms +preformulate +preformulated +preformulates +preformulating +prefreshman +prefreshmen +prefrontal +prefrozen +pregame +preganglionic +pregenital +pregnability +pregnable +pregnancies +pregnancy +pregnant +pregnantly +pregnenolone +pregnenolones +preharvest +preheadache +preheat +preheated +preheater +preheaters +preheating +preheats +prehensile +prehensility +prehension +prehensions +prehiring +prehistorian +prehistorians +prehistoric +prehistorical +prehistorically +prehistories +prehistory +preholiday +prehominid +prehominids +prehuman +preignition +preignitions +preimplantation +preinaugural +preincorporation +preinduction +preindustrial +preinstall +preinstalled +preinstalling +preinstalls +preinterview +preinvasion +prejudge +prejudged +prejudgement +prejudgements +prejudger +prejudgers +prejudges +prejudging +prejudgment +prejudgments +prejudice +prejudiced +prejudices +prejudicial +prejudicially +prejudicialness +prejudicing +prejudicious +prejudiciously +prekindergarten +prelacies +prelacy +prelapsarian +prelate +prelates +prelateship +prelateships +prelatic +prelature +prelatures +prelaunch +prelaw +prelect +prelected +prelecting +prelection +prelections +prelector +prelectors +prelects +prelibation +prelibations +prelife +prelim +preliminaries +preliminarily +preliminary +prelims +preliterary +preliterate +preliterates +preloaded +prelogical +prelude +preluded +preluder +preluders +preludes +preludial +preluding +prelunch +preluncheon +prelusion +prelusions +prelusive +prelusively +premade +premalignant +preman +premanufacture +premarital +premaritally +premarket +premarketed +premarketing +premarkets +premarriage +premature +prematurely +prematureness +prematurity +premaxilla +premaxillae +premaxillary +premeal +premeasure +premeasured +premeasures +premeasuring +premed +premedical +premedieval +premeditate +premeditated +premeditatedly +premeditates +premeditating +premeditation +premeditative +premeditator +premeditators +premeds +premeet +premeiotic +premenopausal +premenstrual +premenstrually +premerger +premie +premier +premiere +premiered +premieres +premiering +premiers +premiership +premierships +premies +premigration +premillenarian +premillenarianism +premillenarians +premillennial +premillennialism +premillennialist +premillennialists +premillennially +premise +premised +premises +premising +premiss +premisses +premium +premiums +premix +premixed +premixes +premixing +première +premièred +premières +premièring +premodern +premodification +premodified +premodifies +premodify +premodifying +premoisten +premoistened +premoistening +premoistens +premolar +premolars +premold +premolded +premolding +premolds +premolt +premonish +premonished +premonishes +premonishing +premonition +premonitions +premonitorily +premonitory +premonstratensian +premonstratensians +premoral +premorse +premune +premunition +premunitions +premycotic +prename +prenames +prenatal +prenatally +prenominate +prenominated +prenominates +prenominating +prenomination +prenominations +prenoon +prenotification +prenotifications +prenotified +prenotifies +prenotify +prenotifying +prenotion +prenotions +prentice +prenticed +prentices +prenticing +prenumber +prenumbered +prenumbering +prenumbers +prenuptial +preoccupancy +preoccupation +preoccupations +preoccupied +preoccupies +preoccupy +preoccupying +preopening +preoperational +preoperative +preoperatively +preoral +preorbital +preordain +preordained +preordaining +preordainment +preordainments +preordains +preorder +preordered +preordering +preorders +preordination +preordinations +preovulatory +preowned +prep +prepack +prepackage +prepackaged +prepackages +prepackaging +prepacked +prepacking +prepacks +prepaid +preparation +preparations +preparative +preparatively +preparatives +preparator +preparatorily +preparators +preparatory +prepare +prepared +preparedly +preparedness +preparer +preparers +prepares +preparing +prepaste +prepasted +prepastes +prepasting +prepay +prepaying +prepayment +prepayments +prepays +prepense +prepensely +preperformance +prepill +preplan +preplanned +preplanning +preplans +preplant +preplanting +preponderance +preponderancy +preponderant +preponderantly +preponderate +preponderated +preponderately +preponderates +preponderating +preponderation +preponderations +preportion +preportioned +preportioning +preportions +preposition +prepositional +prepositionally +prepositioned +prepositioning +prepositions +prepositive +prepositively +prepositives +prepossess +prepossessed +prepossesses +prepossessing +prepossessingly +prepossessingness +prepossession +prepossessions +preposterous +preposterously +preposterousness +prepotencies +prepotency +prepotent +prepotently +prepped +preppie +preppies +preppily +preppiness +prepping +preppy +preprandial +prepreg +preprepared +prepresidential +preprice +prepriced +preprices +prepricing +preprimaries +preprimary +preprint +preprinted +preprinting +preprints +preprocess +preprocessed +preprocesses +preprocessing +preprocessor +preprocessors +preproduction +preproductions +preprofessional +preprogram +preprogramed +preprograming +preprogrammed +preprogramming +preprograms +preps +prepsychedelic +prepuberal +prepubertal +prepuberty +prepubescence +prepubescent +prepubescents +prepublication +prepuce +prepuces +prepunch +prepunched +prepunches +prepunching +prepupa +prepupae +prepupal +prepupas +prepurchase +prepurchased +prepurchases +prepurchasing +preputial +prequalification +prequalified +prequalifies +prequalify +prequalifying +prequel +prequels +prerace +prerecession +prerecord +prerecorded +prerecording +prerecords +preregister +preregistered +preregistering +preregisters +preregistration +preregistrations +prerehearsal +prerelease +prereleases +prerequire +prerequired +prerequires +prerequiring +prerequisite +prerequisites +preretirement +preretirements +prereturn +prereview +prerevisionist +prerevolution +prerevolutionary +prerinse +prerinsed +prerinses +prerinsing +preriot +prerock +prerogative +prerogatived +prerogatives +preromantic +presage +presaged +presageful +presager +presagers +presages +presaging +presale +presales +presanctified +presbyope +presbyopes +presbyopia +presbyopic +presbyter +presbyterate +presbyterates +presbyterial +presbyterially +presbyterian +presbyterianism +presbyterians +presbyteries +presbyters +presbytery +preschedule +prescheduled +preschedules +prescheduling +preschool +preschooler +preschoolers +preschooling +preschools +prescience +prescient +prescientific +presciently +prescind +prescinded +prescinding +prescinds +prescore +prescored +prescores +prescoring +prescreen +prescreened +prescreening +prescreens +prescribe +prescribed +prescriber +prescribers +prescribes +prescribing +prescript +prescriptibility +prescriptible +prescription +prescriptions +prescriptive +prescriptively +prescriptiveness +prescriptivist +prescriptivists +prescripts +preseason +preseasons +preselect +preselected +preselecting +preselection +preselections +preselects +presell +preselling +presells +presence +present +presentability +presentable +presentableness +presentably +presentation +presentational +presentations +presentative +presentativeness +presented +presentee +presentees +presentence +presentencing +presenter +presenters +presentient +presentiment +presentimental +presentiments +presenting +presentism +presentist +presentists +presently +presentment +presentments +presentness +presents +preservability +preservable +preservation +preservationism +preservationist +preservationists +preservations +preservative +preservatives +preserve +preserved +preserver +preservers +preserves +preservice +preserving +preset +presets +presettable +presetting +presettlement +preshow +preshrank +preshrink +preshrinks +preshrunk +preside +presided +presidencies +presidency +president +presidential +presidentially +presidents +presidentship +presidentships +presider +presiders +presides +presidia +presidial +presidiary +presiding +presidio +presidios +presidium +presidiums +presignified +presignifies +presignify +presignifying +preslaughter +presleep +preslice +presliced +preslices +preslicing +presoak +presoaked +presoaking +presoaks +presold +presong +presort +presorted +presorting +presorts +prespecified +prespecifies +prespecify +prespecifying +presplit +press +pressboard +pressboards +pressed +presser +pressers +presses +pressing +pressingly +pressings +pressman +pressmark +pressmarks +pressmen +pressor +pressroom +pressrooms +pressrun +pressruns +pressure +pressured +pressureless +pressures +pressuring +pressurization +pressurizations +pressurize +pressurized +pressurizer +pressurizers +pressurizes +pressurizing +presswork +prest +prestamp +prestamped +prestamping +prestamps +prestellar +prester +presterilize +presterilized +presterilizes +presterilizing +presternum +presternums +prestidigitation +prestidigitations +prestidigitator +prestidigitators +prestige +prestigeful +prestigious +prestigiously +prestigiousness +prestissimo +prestissimos +presto +prestorage +prestos +prestress +prestressed +prestresses +prestressing +prestrike +prestructure +prestructured +prestructures +prestructuring +presumable +presumably +presume +presumed +presumedly +presumer +presumers +presumes +presuming +presumingly +presummit +presumption +presumptions +presumptive +presumptively +presumptuous +presumptuously +presumptuousness +presuppose +presupposed +presupposes +presupposing +presupposition +presuppositional +presuppositions +presurgery +presweeten +presweetened +presweetening +presweetens +presymptomatic +presynaptic +presynaptically +pretape +pretaped +pretapes +pretaping +pretax +pretechnological +preteen +preteenager +preteenagers +preteens +pretelevision +pretence +pretences +pretend +pretended +pretendedly +pretender +pretenders +pretending +pretends +pretense +pretenses +pretension +pretensionless +pretensions +pretentious +pretentiously +pretentiousness +preterit +preterite +preterition +preteritions +preterits +preterm +preterminal +pretermination +pretermission +pretermissions +pretermit +pretermits +pretermitted +pretermitter +pretermitters +pretermitting +preterms +preternatural +preternaturalism +preternaturally +preternaturalness +pretest +pretested +pretesting +pretests +pretext +pretexted +pretexting +pretexts +pretheater +preticket +preticketed +preticketing +pretickets +pretor +pretoria +pretorian +pretorians +pretors +pretournament +pretrain +pretravel +pretreat +pretreated +pretreating +pretreatment +pretreatments +pretreats +pretrial +pretrials +pretrimmed +prettied +prettier +pretties +prettiest +prettification +prettifications +prettified +prettifier +prettifiers +prettifies +prettify +prettifying +prettily +prettiness +pretty +prettying +prettyish +pretype +pretyped +pretypes +pretyping +pretzel +pretzels +preunification +preuniversity +prevail +prevailed +prevailer +prevailers +prevailing +prevailingly +prevailingness +prevails +prevalence +prevalent +prevalently +prevaricate +prevaricated +prevaricates +prevaricating +prevarication +prevarications +prevaricator +prevaricators +prevenience +preveniences +prevenient +preveniently +prevent +preventability +preventable +preventative +preventatively +preventatives +prevented +preventer +preventers +preventibility +preventible +preventing +prevention +preventions +preventive +preventively +preventiveness +preventives +prevents +preverb +preverbal +preverbs +previable +preview +previewed +previewer +previewers +previewing +previews +previous +previously +previousness +previse +prevised +previses +prevising +prevision +previsional +previsionary +previsioned +previsioning +previsions +previsor +previsors +prevocalic +prevocational +prevue +prevued +prevues +prevuing +prewar +prewarn +prewarned +prewarning +prewarns +prewash +prewashed +prewashes +prewashing +preweaning +prework +prewrap +prewrapped +prewrapping +prewraps +prewriting +prex +prexes +prexies +prexy +prey +preyed +preyer +preyers +preying +preys +prez +prezes +priam +priapean +priapic +priapism +priapus +priapuses +pribilof +price +priceable +priced +priceless +pricelessly +pricer +pricers +prices +pricey +priceyness +pricier +priciest +pricily +pricing +prick +pricked +pricker +prickers +pricket +prickets +prickier +prickiest +pricking +prickle +prickled +prickles +pricklier +prickliest +prickliness +prickling +prickly +pricks +pricky +pricy +pride +prided +prideful +pridefully +pridefulness +prides +priding +pried +prier +priers +pries +priest +priested +priestess +priestesses +priesthood +priesting +priestley +priestlier +priestliest +priestliness +priestly +priests +prig +prigged +priggery +prigging +priggish +priggishly +priggishness +priggism +prigs +prill +prilled +prilling +prills +prim +prima +primacies +primacy +primal +primality +primaries +primarily +primary +primate +primates +primateship +primatial +primatological +primatologist +primatologists +primatology +primavera +primaveras +prime +primed +primely +primeness +primer +primero +primers +primes +primeval +primevally +primi +priming +primings +primipara +primiparae +primiparas +primiparity +primiparous +primitive +primitively +primitiveness +primitives +primitivism +primitivist +primitivistic +primitivists +primitivity +primly +primmed +primmer +primmest +primming +primness +primo +primogenital +primogenitary +primogenitor +primogenitors +primogeniture +primogenitures +primordia +primordial +primordially +primordials +primordium +primos +primp +primped +primping +primps +primrose +primroses +prims +primula +primus +primuses +prince +princedom +princedoms +princelet +princelets +princelier +princeliest +princeliness +princeling +princelings +princely +princes +princeship +princeships +princess +princesse +princesses +princeton +principal +principalities +principality +principally +principals +principalship +principalships +principe +principia +principium +principle +principled +principles +princox +prink +prinked +prinker +prinkers +prinking +prinks +print +printability +printable +printed +printer +printer's +printeries +printers +printery +printhead +printheads +printing +printings +printless +printmaker +printmakers +printmaking +printout +printouts +prints +prion +prions +prior +priorate +priorates +prioress +prioresses +priori +priories +priorities +prioritization +prioritizations +prioritize +prioritized +prioritizes +prioritizing +priority +priorly +priors +priorship +priorships +priory +pris +prise +prised +prises +prising +prism +prismatic +prismatical +prismatically +prismatoid +prismatoidal +prismatoids +prismoid +prismoidal +prismoids +prisms +prison +prisoned +prisoner +prisoners +prisoning +prisons +prissier +prissiest +prissily +prissiness +prissy +pristane +pristanes +pristine +pristinely +prithee +privacy +privatdocent +privatdocents +private +privateer +privateered +privateering +privateers +privately +privateness +privates +privation +privations +privatism +privatist +privatistic +privatists +privative +privatively +privatives +privatization +privatizations +privatize +privatized +privatizes +privatizing +privet +privets +privies +privilege +privileged +privileges +privileging +privily +privities +privity +privy +prix +prize +prized +prizefight +prizefighter +prizefighters +prizefighting +prizefights +prizer +prizers +prizes +prizewinner +prizewinners +prizewinning +prizing +pro +proa +proabortion +proaction +proactions +proactive +proactively +proas +probabilism +probabilist +probabilistic +probabilistically +probabilists +probabilities +probability +probable +probably +proband +probands +probang +probangs +probate +probated +probates +probating +probation +probational +probationally +probationary +probationer +probationers +probations +probative +probatory +probe +probed +probenecid +probenecids +prober +probers +probes +probing +probingly +probit +probits +probity +problem +problematic +problematical +problematically +problematization +problematize +problematized +problematizes +problematizing +problems +proboscidean +proboscideans +proboscides +proboscidian +proboscidians +proboscis +proboscises +procaine +procaines +procambial +procambium +procambiums +procarbazine +procarbazines +procaryote +procaryotes +procathedral +procathedrals +procedural +procedurally +procedurals +procedure +procedures +proceed +proceeded +proceeder +proceeders +proceeding +proceedings +proceeds +procephalic +procercoid +procercoids +process +processability +processable +processed +processes +processibility +processible +processing +procession +processional +processionally +processionals +processioned +processioning +processions +processor +processors +proclaim +proclaimed +proclaimer +proclaimers +proclaiming +proclaims +proclamation +proclamations +proclamatory +proclitic +proclitics +proclivities +proclivity +procoagulant +procoagulants +procommunist +procommunists +proconsul +proconsular +proconsulate +proconsulates +proconsuls +proconsulship +proconsulships +procrastinate +procrastinated +procrastinates +procrastinating +procrastination +procrastinations +procrastinative +procrastinator +procrastinators +procrastinatory +procreant +procreate +procreated +procreates +procreating +procreation +procreations +procreative +procreativity +procreator +procreators +procrustean +procryptic +proctitis +proctodaea +proctodaeum +proctodaeums +proctodea +proctodeum +proctodeums +proctologic +proctological +proctologically +proctologist +proctologists +proctology +proctor +proctored +proctorial +proctoring +proctors +proctorship +proctorships +proctoscope +proctoscopes +proctoscopic +proctoscopy +procumbent +procurable +procurance +procuration +procurations +procurator +procuratorial +procurators +procure +procured +procurement +procurements +procurer +procurers +procures +procuress +procuresses +procuring +procyon +procès +prod +prodded +prodder +prodders +prodding +prodigal +prodigalities +prodigality +prodigally +prodigals +prodigies +prodigious +prodigiously +prodigiousness +prodigy +prodromal +prodromata +prodrome +prodromes +prodromic +prodrug +prodrugs +prods +produce +produceable +produced +producer +producers +produces +producible +producing +product +production +productional +productions +productive +productively +productiveness +productivity +products +proem +proemial +proems +proenzyme +proenzymes +proestrus +proestruses +prof +profanation +profanations +profanatory +profane +profaned +profanely +profaneness +profaner +profaners +profanes +profaning +profanities +profanity +profess +professed +professedly +professes +professing +profession +professional +professionalism +professionalization +professionalizations +professionalize +professionalized +professionalizes +professionalizing +professionally +professionals +professions +professor +professorate +professorates +professorial +professorially +professoriat +professoriate +professoriates +professoriats +professors +professorship +professorships +proffer +proffered +profferer +profferers +proffering +proffers +proficiencies +proficiency +proficient +proficiently +proficients +profile +profiled +profiler +profilers +profiles +profiling +profit +profitability +profitable +profitableness +profitably +profited +profiteer +profiteered +profiteering +profiteers +profiterole +profiteroles +profiting +profitless +profits +profitwise +profligacy +profligate +profligately +profligates +profluent +profound +profounder +profoundest +profoundly +profoundness +profs +profundis +profundities +profundity +profundo +profundos +profuse +profusely +profuseness +profusion +progenies +progenitor +progenitors +progeny +progeria +progestational +progesterone +progestin +progestins +progestogen +progestogenic +progestogens +proglottic +proglottid +proglottidean +proglottides +proglottids +proglottis +prognathic +prognathism +prognathous +prognoses +prognosis +prognostic +prognosticate +prognosticated +prognosticates +prognosticating +prognostication +prognostications +prognosticative +prognosticator +prognosticators +prognosticatory +prognostics +prograde +program +programed +programer +programers +programing +programmability +programmable +programmatic +programmatically +programmed +programmer +programmers +programming +programs +progress +progressed +progresses +progressing +progression +progressional +progressions +progressive +progressively +progressiveness +progressives +progressivism +progressivist +progressivistic +progressivists +progressivities +progressivity +prohibit +prohibited +prohibiting +prohibition +prohibitionism +prohibitionist +prohibitionists +prohibitions +prohibitive +prohibitively +prohibitiveness +prohibitory +prohibits +proinsulin +proinsulins +project +projectable +projected +projectile +projectiles +projecting +projection +projectional +projectionist +projectionists +projections +projective +projectively +projector +projectors +projects +projet +projets +prokaryote +prokaryotes +prokaryotic +prokofiev +prolactin +prolactins +prolamin +prolamine +prolamines +prolamins +prolan +prolans +prolapse +prolapsed +prolapses +prolapsing +prolapsus +prolate +prolately +prolateness +prole +proleg +prolegomena +prolegomenon +prolegomenous +prolegs +prolepses +prolepsis +proleptic +proleptical +proleptically +proles +proletarian +proletarianism +proletarianization +proletarianizations +proletarianize +proletarianized +proletarianizes +proletarianizing +proletarians +proletariat +proletariats +proliferate +proliferated +proliferates +proliferating +proliferation +proliferations +proliferative +proliferator +proliferators +proliferous +proliferously +prolific +prolificacy +prolifically +prolificity +prolificness +proline +prolines +prolix +prolixity +prolixly +prolocutor +prolocutors +prolog +prologize +prologized +prologizes +prologizing +prologs +prologue +prologues +prologuize +prologuized +prologuizes +prologuizing +prolong +prolongate +prolongated +prolongates +prolongating +prolongation +prolongations +prolonged +prolonger +prolongers +prolonging +prolongs +prolusion +prolusions +prolusory +prom +promenade +promenaded +promenader +promenaders +promenades +promenading +promethean +prometheans +prometheus +promethium +prominence +prominences +prominency +prominent +prominently +promiscuities +promiscuity +promiscuous +promiscuously +promiscuousness +promise +promised +promisee +promisees +promiser +promisers +promises +promising +promisingly +promisor +promisors +promissory +promo +promontories +promontory +promos +promotability +promotable +promote +promoted +promoter +promoters +promotes +promoting +promotion +promotional +promotionally +promotions +promotive +promotiveness +prompt +promptbook +promptbooks +prompted +prompter +prompters +promptest +prompting +promptitude +promptly +promptness +prompts +proms +promulgate +promulgated +promulgates +promulgating +promulgation +promulgations +promulgator +promulgators +pronatalism +pronatalist +pronatalistic +pronatalists +pronate +pronated +pronates +pronating +pronation +pronations +pronator +pronators +prone +pronely +proneness +pronephra +pronephric +pronephroi +pronephros +prong +pronged +pronghorn +pronghorns +pronging +prongs +pronograde +pronominal +pronominally +pronoun +pronounce +pronounceability +pronounceable +pronounced +pronouncedly +pronouncedness +pronouncement +pronouncements +pronouncer +pronouncers +pronounces +pronouncing +pronouns +pronto +prontosil +pronuclear +pronuclei +pronucleus +pronunciamento +pronunciamentoes +pronunciamentos +pronunciation +pronunciational +pronunciations +proof +proofed +proofer +proofers +proofing +proofread +proofreader +proofreaders +proofreading +proofreads +proofroom +proofrooms +proofs +prop +propaedeutic +propaedeutics +propagable +propaganda +propagandism +propagandist +propagandistic +propagandistically +propagandists +propagandize +propagandized +propagandizer +propagandizers +propagandizes +propagandizing +propagate +propagated +propagates +propagating +propagation +propagational +propagations +propagative +propagator +propagators +propagule +propagules +propane +propanoate +propanoic +propanol +propel +propellant +propellants +propelled +propellent +propellents +propeller +propellers +propelling +propellor +propellors +propels +propend +propended +propending +propends +propene +propenes +propense +propensities +propensity +proper +properdin +properdins +properly +properness +propertied +properties +propertius +property +propertyless +propertylessness +prophage +prophages +prophase +prophases +prophasic +prophecies +prophecy +prophesied +prophesier +prophesiers +prophesies +prophesy +prophesying +prophet +prophetess +prophetesses +prophethood +prophetic +prophetical +prophetically +propheticalness +prophets +prophylactic +prophylactically +prophylactics +prophylaxes +prophylaxis +propinquity +propionaldehyde +propionaldehydes +propionate +propionates +propionic +propitiable +propitiate +propitiated +propitiates +propitiating +propitiatingly +propitiation +propitiations +propitiative +propitiator +propitiatorily +propitiators +propitiatory +propitious +propitiously +propitiousness +propjet +propjets +proplastid +proplastids +propman +propmen +propolis +propolises +propone +proponed +proponent +proponents +propones +proponing +proportion +proportionable +proportionably +proportional +proportionality +proportionally +proportionals +proportionate +proportionated +proportionately +proportionateness +proportionates +proportionating +proportioned +proportioner +proportioners +proportioning +proportionment +proportionments +proportions +proposal +proposals +propose +proposed +proposer +proposers +proposes +proposing +propositi +proposition +propositional +propositionally +propositioned +propositioning +propositions +propositus +propound +propounded +propounder +propounders +propounding +propounds +propoxyphene +propoxyphenes +propped +propping +propraetor +propraetorial +propraetorian +propraetors +propranolol +propranolols +propre +propretor +propretors +propria +propriae +proprietaries +proprietarily +proprietary +proprieties +proprietor +proprietorial +proprietorially +proprietors +proprietorship +proprietorships +proprietress +proprietresses +propriety +proprioception +proprioceptions +proprioceptive +proprioceptor +proprioceptors +props +proptoses +proptosis +propulsion +propulsions +propulsive +propulsory +propyl +propyla +propylaea +propylaeum +propylene +propylic +propylon +propyls +proratable +prorate +prorated +prorates +prorating +proration +prorations +prorogate +prorogated +prorogates +prorogating +prorogation +prorogations +prorogue +prorogued +prorogues +proroguing +pros +prosaic +prosaically +prosaicness +prosaism +prosaisms +prosaist +prosaists +prosateur +prosateurs +prosauropod +prosauropods +proscenia +proscenium +prosceniums +prosciutti +prosciutto +prosciuttos +proscribe +proscribed +proscriber +proscribers +proscribes +proscribing +proscription +proscriptions +proscriptive +proscriptively +prose +prosector +prosectors +prosecutable +prosecute +prosecuted +prosecutes +prosecuting +prosecution +prosecutions +prosecutor +prosecutorial +prosecutors +prosed +proselyte +proselyted +proselyter +proselyters +proselytes +proselytical +proselyting +proselytism +proselytisms +proselytization +proselytizations +proselytize +proselytized +proselytizer +proselytizers +proselytizes +proselytizing +proseminar +proseminars +prosencephalic +prosencephalon +prosencephalons +prosenchyma +prosenchymas +prosenchymatous +prosequi +prosequitur +proser +proserpine +prosers +proses +prosier +prosiest +prosily +prosimian +prosimians +prosiness +prosing +prosit +proslavery +proso +prosobranch +prosobranchs +prosodic +prosodical +prosodically +prosodies +prosodist +prosodists +prosody +prosoma +prosomal +prosomas +prosopographical +prosopography +prosopopeia +prosopopeial +prosopopeias +prosopopoeia +prosopopoeias +prospect +prospected +prospecting +prospective +prospectively +prospector +prospectors +prospects +prospectus +prospectuses +prosper +prospered +prospering +prosperity +prosperous +prosperously +prosperousness +prospers +prost +prostacyclin +prostacyclins +prostaglandin +prostaglandins +prostate +prostatectomies +prostatectomy +prostates +prostatic +prostatism +prostatisms +prostatitis +prostheses +prosthesis +prosthetic +prosthetically +prosthetics +prosthetist +prosthetists +prosthodontia +prosthodontic +prosthodontics +prosthodontist +prosthodontists +prostitute +prostituted +prostitutes +prostituting +prostitution +prostitutions +prostitutor +prostitutors +prostomia +prostomial +prostomium +prostrate +prostrated +prostrates +prostrating +prostration +prostrations +prostrator +prostrators +prostyle +prosy +protactinium +protagonist +protagonists +protamin +protamine +protamines +protamins +protandrous +protandry +protanopia +protanopias +protanopic +protases +protasis +protatic +protea +protean +proteas +protease +proteases +protect +protectant +protectants +protected +protecter +protecters +protecting +protectingly +protection +protectional +protectionism +protectionist +protectionists +protections +protective +protectively +protectiveness +protectives +protector +protectoral +protectorate +protectorates +protectories +protectors +protectorship +protectorships +protectory +protectress +protectresses +protects +protei +proteid +proteids +protein +proteinaceous +proteinase +proteinases +proteinic +proteinoid +proteinoids +proteins +proteinuria +proteinurias +protend +protended +protending +protends +protensive +protensively +proteoclastic +proteoglycan +proteoglycans +proteolyses +proteolysis +proteolytic +proteolytically +proteose +proteoses +proteron +proterozoic +protest +protestant +protestantism +protestants +protestation +protestations +protested +protester +protesters +protesting +protestingly +protestor +protestors +protests +proteus +prothalamia +prothalamion +prothalamium +prothalli +prothallia +prothallial +prothallium +prothallus +protheses +prothesis +prothetic +prothetically +prothonotarial +prothonotaries +prothonotary +prothoraces +prothoracic +prothorax +prothoraxes +prothrombin +prothrombins +protist +protista +protistan +protistans +protistology +protists +protium +protiums +protocol +protocolar +protocolary +protocoled +protocoling +protocolled +protocolling +protocols +protocontinent +protocontinents +protoctist +protoctists +protoderm +protodermal +protoderms +protogalaxies +protogalaxy +protogynous +protogyny +protohistorian +protohistorians +protohistoric +protohistory +protohuman +protohumans +protolanguage +protolanguages +protolithic +protomartyr +protomartyrs +protomorph +protomorphic +protomorphs +proton +protonate +protonated +protonates +protonating +protonation +protonations +protonema +protonemal +protonemata +protonematal +protonic +protonotaries +protonotary +protons +protopathic +protopathy +protophloem +protophloems +protoplanet +protoplanetary +protoplanets +protoplasm +protoplasmal +protoplasmatic +protoplasmic +protoplast +protoplastic +protoplasts +protoporphyrin +protoporphyrins +protostar +protostars +protostele +protosteles +protostelic +protostome +protostomes +prototroph +prototrophic +prototrophs +prototrophy +prototypal +prototype +prototyped +prototypes +prototypic +prototypical +prototypically +prototyping +protoxylem +protoxylems +protozoa +protozoal +protozoan +protozoans +protozoic +protozoological +protozoologist +protozoologists +protozoology +protozoon +protract +protracted +protractedly +protractedness +protractible +protractile +protractility +protracting +protraction +protractions +protractive +protractor +protractors +protracts +protreptic +protreptics +protrude +protruded +protrudent +protrudes +protruding +protrusible +protrusile +protrusility +protrusion +protrusions +protrusive +protrusively +protrusiveness +protuberance +protuberances +protuberancies +protuberancy +protuberant +protuberantly +protuberate +protuberated +protuberates +protuberating +protuberation +protuberations +protégé +protégée +protégées +protégés +proud +prouder +proudest +proudful +proudhearted +proudly +proudness +proust +proustian +proustite +proustites +provability +provable +provableness +provably +provascular +prove +proved +proven +provenance +provenances +provence +provender +provenience +proveniences +provenly +proventricular +proventriculi +proventriculus +provençal +provençale +provençals +provençaux +prover +proverb +proverbial +proverbially +proverbs +provers +proves +provide +provided +providence +provident +providential +providentially +providently +provider +providers +provides +providing +province +provinces +provincial +provincialism +provincialist +provincialists +provinciality +provincialization +provincializations +provincialize +provincialized +provincializes +provincializing +provincially +provincials +proving +proviral +provirus +proviruses +provision +provisional +provisionally +provisionals +provisionary +provisioned +provisioner +provisioners +provisioning +provisions +proviso +provisoes +provisorily +provisory +provisos +provitamin +provitamins +provo +provocateur +provocateurs +provocation +provocations +provocative +provocatively +provocativeness +provocatives +provoke +provoked +provoker +provokers +provokes +provoking +provokingly +provolone +provos +provost +provosts +prow +prowess +prowl +prowled +prowler +prowlers +prowling +prowls +prows +proxemic +proxemics +proxies +proximal +proximally +proximate +proximately +proximateness +proximity +proximo +proxy +prude +prudence +prudent +prudential +prudentially +prudently +pruderies +prudery +prudes +prudish +prudishly +prudishness +pruinose +prune +pruned +prunella +prunellas +prunelle +prunelles +prunello +prunellos +pruner +pruners +prunes +pruning +prunus +prurience +pruriency +prurient +pruriently +pruriginous +prurigo +prurigos +pruritic +pruritus +prurituses +prussia +prussian +prussianism +prussianization +prussianizations +prussianize +prussianized +prussianizes +prussianizing +prussians +prussiate +prussiates +prussic +pruta +prutah +prutot +prutoth +pry +pryer +pryers +prying +pryingly +przewalski +précis +précised +précises +précising +príncipe +ps +psalm +psalmbook +psalmbooks +psalmed +psalming +psalmist +psalmists +psalmodies +psalmodist +psalmodists +psalmody +psalms +psalter +psalteria +psalterial +psalteries +psalterium +psalters +psaltery +psaltries +psaltry +psephological +psephologist +psephologists +psephology +pseudaxis +pseudaxises +pseudepigraph +pseudepigrapha +pseudepigraphal +pseudepigraphic +pseudepigraphical +pseudepigraphon +pseudepigraphous +pseudepigraphs +pseudepigraphy +pseudo +pseudoallele +pseudoalleles +pseudobulb +pseudobulbs +pseudocarp +pseudocarpous +pseudocarps +pseudocholinesterase +pseudocholinesterases +pseudoclassic +pseudoclassicism +pseudoclassics +pseudocoel +pseudocoelom +pseudocoelomate +pseudocoelomates +pseudocoeloms +pseudocoels +pseudocyesis +pseudogene +pseudogenes +pseudohermaphrodite +pseudohermaphrodites +pseudohermaphroditic +pseudohermaphroditism +pseudomonad +pseudomonades +pseudomonads +pseudomonas +pseudomorph +pseudomorphic +pseudomorphism +pseudomorphous +pseudomorphs +pseudonym +pseudonymity +pseudonymous +pseudonymously +pseudonymousness +pseudonyms +pseudoparenchyma +pseudoparenchymatous +pseudopod +pseudopodal +pseudopodia +pseudopodial +pseudopodium +pseudopods +pseudopregnancies +pseudopregnancy +pseudopregnant +pseudorandom +pseudoscience +pseudoscientific +pseudoscientist +pseudoscientists +pseudoscorpion +pseudoscorpions +pseudosophisticated +pseudosophistication +pseudotuberculosis +pshaw +psi +psilocin +psilocins +psilocybin +psilomelane +psilomelanes +psilophyte +psilophytes +psilophytic +psittacine +psittacoses +psittacosis +psittacotic +psoas +psoases +psocid +psocids +psoralen +psoralens +psoriases +psoriasis +psoriatic +psych +psychasthenia +psychasthenias +psychasthenic +psyche +psyched +psychedelia +psychedelias +psychedelic +psychedelically +psychedelics +psyches +psychiatric +psychiatrical +psychiatrically +psychiatrist +psychiatrists +psychiatry +psychic +psychical +psychically +psychics +psyching +psycho +psychoacoustic +psychoacoustical +psychoacoustics +psychoactive +psychoanalyses +psychoanalysis +psychoanalyst +psychoanalysts +psychoanalytic +psychoanalytical +psychoanalytically +psychoanalyze +psychoanalyzed +psychoanalyzes +psychoanalyzing +psychobabble +psychobabbler +psychobabblers +psychobabbles +psychobiographer +psychobiographers +psychobiographic +psychobiographical +psychobiographies +psychobiography +psychobiologic +psychobiological +psychobiologically +psychobiologist +psychobiologists +psychobiology +psychochemical +psychochemicals +psychodrama +psychodramas +psychodramatic +psychodynamic +psychodynamically +psychodynamics +psychogenesis +psychogenetic +psychogenetically +psychogenic +psychogenically +psychograph +psychographic +psychographics +psychographs +psychohistorian +psychohistorians +psychohistorical +psychohistories +psychohistory +psychokineses +psychokinesis +psychokinetic +psychokinetically +psycholinguist +psycholinguistic +psycholinguistics +psycholinguists +psychologic +psychological +psychologically +psychologies +psychologism +psychologist +psychologists +psychologize +psychologized +psychologizes +psychologizing +psychology +psychometric +psychometrical +psychometrically +psychometrician +psychometricians +psychometrics +psychometrist +psychometrists +psychometry +psychomotor +psychoneuroses +psychoneurosis +psychoneurotic +psychoneurotics +psychopath +psychopathic +psychopathically +psychopathologic +psychopathological +psychopathologically +psychopathologist +psychopathologists +psychopathology +psychopaths +psychopathy +psychopharmacologic +psychopharmacological +psychopharmacologist +psychopharmacologists +psychopharmacology +psychophysical +psychophysically +psychophysicist +psychophysicists +psychophysics +psychophysiologic +psychophysiological +psychophysiologically +psychophysiologist +psychophysiologists +psychophysiology +psychos +psychoses +psychosexual +psychosexuality +psychosexually +psychosis +psychosocial +psychosocially +psychosomatic +psychosomatically +psychosomatics +psychosurgeon +psychosurgeons +psychosurgeries +psychosurgery +psychosurgical +psychosynthesis +psychotechnical +psychotechnician +psychotechnicians +psychotechnics +psychotherapeutic +psychotherapeutically +psychotherapeutics +psychotherapies +psychotherapist +psychotherapists +psychotherapy +psychotic +psychotically +psychotics +psychotomimetic +psychotomimetically +psychotomimetics +psychotropic +psychotropics +psychrometer +psychrometers +psychrometric +psychrometry +psychrophile +psychrophiles +psychrophilic +psylla +psyllas +psyllid +psyllids +psyllium +psylliums +psywar +psywars +pt +pta +ptarmigan +ptarmigans +ptas +pteranodon +pteranodons +pteridine +pteridines +pteridological +pteridologist +pteridologists +pteridology +pteridophyte +pteridophytes +pteridophytic +pteridophytous +pteridosperm +pteridosperms +pterin +pterins +pterodactyl +pterodactyloid +pterodactylous +pterodactyls +pteropod +pteropodan +pteropodans +pteropods +pterosaur +pterosaurs +pteroylglutamic +pterygia +pterygial +pterygium +pterygiums +pterygoid +pterygoids +pteryla +pterylae +ptisan +ptisans +ptolemaic +ptolemaist +ptolemaists +ptolemies +ptolemy +ptomaine +ptoses +ptosis +ptotic +ptyalin +ptyalism +ptyalisms +pub +puberal +pubertal +puberty +puberulent +puberulous +pubes +pubescence +pubescent +pubic +pubis +public +publica +publically +publican +publicans +publication +publications +publicist +publicists +publicity +publicize +publicized +publicizes +publicizing +publicly +publicness +publico +publics +publish +publishable +published +publisher +publishers +publishes +publishing +pubs +puccini +puccoon +puccoons +puce +puck +pucka +pucker +puckered +puckering +puckers +puckery +puckish +puckishly +puckishness +pucks +pudding +puddings +puddingstone +puddingstones +puddle +puddled +puddler +puddlers +puddles +puddling +puddlings +puddly +pudency +pudenda +pudendal +pudendum +pudgier +pudgiest +pudginess +pudgy +pudibund +pueblo +pueblos +puerile +puerilely +puerileness +puerilism +puerilisms +puerilities +puerility +puerperal +puerperia +puerperium +puerto +puff +puffball +puffballs +puffed +puffer +puffers +puffery +puffier +puffiest +puffily +puffin +puffiness +puffing +puffins +puffs +puffy +pug +pugaree +pugarees +puget +puggaree +puggarees +pugged +pugging +puggree +puggrees +pugil +pugilism +pugilist +pugilistic +pugilists +pugmark +pugmarks +pugnacious +pugnaciously +pugnaciousness +pugnacity +pugs +puisne +puisnes +puissance +puissant +puissantly +puke +puked +pukes +puking +pukka +pul +pula +pulas +pulaski +pulchritude +pulchritudinous +pule +puled +puler +pulers +pules +puli +pulik +puling +pulis +pulitzer +pull +pullback +pullbacks +pulled +puller +pullers +pullet +pullets +pulley +pulleys +pulling +pullman +pullmans +pullorum +pullout +pullouts +pullover +pullovers +pulls +pullulate +pullulated +pullulates +pullulating +pullulation +pullulations +pullulative +pulmonale +pulmonalia +pulmonary +pulmonate +pulmonates +pulmonic +pulmotor +pulmotors +pulp +pulpal +pulpally +pulped +pulper +pulpers +pulpier +pulpiest +pulpiness +pulping +pulpit +pulpits +pulpous +pulps +pulpwood +pulpy +pulque +pulques +puls +pulsant +pulsar +pulsars +pulsate +pulsated +pulsates +pulsatile +pulsating +pulsation +pulsations +pulsator +pulsators +pulsatory +pulse +pulsed +pulsejet +pulsejets +pulser +pulsers +pulses +pulsing +pulsometer +pulsometers +pulverable +pulverizable +pulverization +pulverizations +pulverizator +pulverizators +pulverize +pulverized +pulverizer +pulverizers +pulverizes +pulverizing +pulverous +pulverulent +pulvilli +pulvillus +pulvinate +pulvinated +pulvini +pulvinus +puma +pumas +pumelo +pumelos +pumice +pumiced +pumiceous +pumicer +pumicers +pumices +pumicing +pumicite +pumicites +pummel +pummeled +pummeling +pummelled +pummelling +pummelo +pummelos +pummels +pump +pumped +pumper +pumpernickel +pumpernickels +pumpers +pumping +pumpkin +pumpkins +pumpkinseed +pumpkinseeds +pumps +pun +puna +punch +punchball +punchboard +punchboards +punchbowl +punchbowls +punched +puncheon +puncheons +puncher +punchers +punches +punchier +punchiest +punchily +punchinello +punchinelloes +punchinellos +punchiness +punching +punchless +punchy +punctate +punctated +punctation +punctations +punctilio +punctilios +punctilious +punctiliously +punctiliousness +punctual +punctuality +punctually +punctualness +punctuate +punctuated +punctuates +punctuating +punctuation +punctuations +punctuative +punctuator +punctuators +puncturable +puncture +punctured +punctures +puncturing +pundit +punditry +pundits +pung +pungency +pungent +pungently +pungle +pungled +pungles +pungling +pungs +punic +punier +puniest +punily +puniness +punish +punishability +punishable +punishably +punished +punisher +punishers +punishes +punishing +punishment +punishments +punition +punitions +punitive +punitively +punitiveness +punitory +punjab +punjabi +punjabis +punji +punk +punka +punkah +punkahs +punkas +punker +punkers +punkie +punkier +punkies +punkiest +punkin +punkiness +punkins +punkish +punks +punky +punned +punnet +punnets +punnier +punniest +punning +punningly +punny +puns +punster +punsters +punt +punted +punter +punters +punties +punting +punts +punty +punxsutawney +puny +pup +pupa +pupae +pupal +puparia +puparium +pupas +pupate +pupated +pupates +pupating +pupation +pupations +pupfish +pupfishes +pupil +pupilage +pupilages +pupilar +pupillage +pupillages +pupillary +pupils +pupiparous +pupped +puppet +puppeteer +puppeteers +puppetlike +puppetries +puppetry +puppets +puppies +pupping +puppis +puppy +puppyhood +puppyish +puppylike +pups +purana +puranas +puranic +purblind +purblindly +purblindness +purcell +purchasability +purchasable +purchase +purchased +purchaser +purchasers +purchases +purchasing +purdah +purdahs +pure +pureblood +pureblooded +purebloods +purebred +purebreds +puree +pureed +pureeing +purees +purely +pureness +purer +purest +purfle +purfled +purfles +purfling +purgation +purgations +purgative +purgatives +purgatorial +purgatories +purgatory +purge +purgeable +purged +purger +purgers +purges +purging +puri +purification +purifications +purificator +purificators +purificatory +purified +purifier +purifiers +purifies +purify +purifying +purim +purine +purines +puris +purism +purisms +purist +puristic +puristically +purists +puritan +puritanical +puritanically +puritanicalness +puritanism +puritans +purity +purkinje +purl +purled +purlieu +purlieus +purlin +purline +purlines +purling +purlins +purloin +purloined +purloiner +purloiners +purloining +purloins +purls +puromycin +puromycins +purple +purpled +purpleheart +purplehearts +purpler +purples +purplest +purpling +purplish +purply +purport +purported +purportedly +purporting +purports +purpose +purposed +purposeful +purposefully +purposefulness +purposeless +purposelessly +purposelessness +purposely +purposes +purposing +purposive +purposively +purposiveness +purpura +purpuras +purpure +purpures +purpuric +purpurin +purpurins +purr +purred +purring +purringly +purrs +purse +pursed +purselike +purser +pursers +purses +pursestrings +pursier +pursiest +pursiness +pursing +purslane +pursuable +pursuance +pursuant +pursue +pursued +pursuer +pursuers +pursues +pursuing +pursuit +pursuits +pursuivant +pursuivants +pursy +purtenance +purtenances +purty +purulence +purulent +purulently +purvey +purveyance +purveyed +purveying +purveyor +purveyors +purveys +purview +purviews +purée +puréed +puréeing +purées +puréing +pus +pusey +puseyism +puseyite +puseyites +push +pushback +pushbacks +pushball +pushballs +pushbutton +pushbuttons +pushcart +pushcarts +pushchair +pushchairs +pushdown +pushdowns +pushed +pusher +pushers +pushes +pushful +pushfulness +pushier +pushiest +pushily +pushiness +pushing +pushingly +pushkin +pushover +pushovers +pushpin +pushpins +pushrod +pushrods +pushtu +pushtun +pushtuns +pushup +pushups +pushy +pusillanimity +pusillanimous +pusillanimously +puss +pusses +pussier +pussies +pussiest +pussley +pussy +pussycat +pussycats +pussyfoot +pussyfooted +pussyfooter +pussyfooters +pussyfooting +pussyfoots +pussytoes +pustulant +pustulants +pustular +pustulate +pustulated +pustulates +pustulating +pustulation +pustulations +pustule +pustules +put +putamen +putamina +putaminous +putative +putatively +putdown +putdownable +putdowns +putlog +putlogs +putnam +putoff +putoffs +putonghua +putout +putouts +putrefacient +putrefaction +putrefactive +putrefied +putrefies +putrefy +putrefying +putrescence +putrescent +putrescible +putrescine +putrescines +putrid +putridity +putridly +putridness +puts +putsch +putsches +putschist +putschists +putt +putted +puttee +puttees +putter +puttered +putterer +putterers +puttering +putters +putti +puttied +putties +putting +puttingly +putto +puttrefied +puttrefies +puttrefying +putts +putty +puttying +puttyless +puttylike +puttyroot +puttyroots +putz +putzed +putzes +putzing +puzzle +puzzled +puzzleheaded +puzzleheadedness +puzzlement +puzzler +puzzlers +puzzles +puzzling +puzzlingly +pvc +pycnidia +pycnidial +pycnidium +pycnogonid +pycnogonids +pycnometer +pycnometers +pyelitic +pyelitis +pyelitises +pyelogram +pyelograms +pyelographic +pyelography +pyelonephritic +pyelonephritis +pyelonephritises +pyemia +pyemic +pygidia +pygidial +pygidium +pygmaean +pygmalion +pygmean +pygmies +pygmoid +pygmy +pyknic +pyknics +pylon +pylons +pylori +pyloric +pylorus +pylos +pyoderma +pyodermas +pyodermic +pyogenesis +pyogenic +pyoid +pyongyang +pyorrhea +pyorrheal +pyorrheas +pyorrhoea +pyorrhoeas +pyosis +pyracantha +pyracanthas +pyralid +pyralidid +pyralidids +pyralids +pyramid +pyramidal +pyramidally +pyramided +pyramidic +pyramidical +pyramiding +pyramids +pyramus +pyran +pyrans +pyrargyrite +pyrargyrites +pyre +pyrene +pyrenean +pyrenees +pyrenes +pyrenoid +pyrenoids +pyres +pyrethrin +pyrethrins +pyrethroid +pyrethroids +pyrethrum +pyrethrums +pyretic +pyrex +pyrexia +pyrexial +pyrexias +pyrexic +pyrheliometer +pyrheliometers +pyrheliometric +pyric +pyridic +pyridine +pyridines +pyridoxal +pyridoxals +pyridoxamine +pyridoxamines +pyridoxin +pyridoxine +pyridoxines +pyridoxins +pyriform +pyrimethamine +pyrimethamines +pyrimidine +pyrimidines +pyrite +pyrites +pyritic +pyritical +pyrocellulose +pyrocelluloses +pyrochemical +pyrochemically +pyroclastic +pyroelectric +pyroelectricity +pyroelectrics +pyrogallic +pyrogallol +pyrogallols +pyrogen +pyrogenic +pyrogenicity +pyrogenous +pyrogens +pyrograph +pyrographer +pyrographers +pyrographic +pyrographies +pyrographs +pyrography +pyroligneous +pyrolusite +pyrolusites +pyrolysis +pyrolytic +pyrolytically +pyrolyze +pyrolyzed +pyrolyzes +pyrolyzing +pyromancy +pyromania +pyromaniac +pyromaniacal +pyromaniacs +pyromantic +pyrometallurgical +pyrometallurgies +pyrometallurgy +pyrometer +pyrometers +pyrometric +pyrometrical +pyrometrically +pyrometry +pyromorphite +pyromorphites +pyronine +pyronines +pyrope +pyropes +pyrophoric +pyrophosphate +pyrophosphates +pyrophosphatic +pyrophosphoric +pyrophyllite +pyrophyllites +pyrosis +pyrostat +pyrostats +pyrosulfate +pyrosulfates +pyrosulfuric +pyrotechnic +pyrotechnical +pyrotechnically +pyrotechnics +pyrotechnist +pyrotechnists +pyrotechny +pyroxene +pyroxenes +pyroxenic +pyroxenite +pyroxenites +pyroxenitic +pyroxenoid +pyroxenoids +pyroxylin +pyroxyline +pyroxylines +pyroxylins +pyrrhic +pyrrhics +pyrrhonism +pyrrhonist +pyrrhonists +pyrrhotine +pyrrhotines +pyrrhotite +pyrrhotites +pyrrhuloxia +pyrrhuloxias +pyrrhus +pyrrole +pyrroles +pyrrolic +pyruvate +pyruvates +pyruvic +pythagoras +pythagorean +pythagoreanism +pythagoreans +pythiad +pythiads +pythian +pythias +pythic +python +pythoness +pythonesses +pythonic +pythons +pyuria +pyurias +pyx +pyxes +pyxides +pyxidia +pyxidium +pyxie +pyxies +pyxis +páros +pátmos +pâte +pâté +pâtés +pépin +périgord +pétanque +père +q +qantas +qatar +qatari +qataris +qattara +qed +qilian +qindarka +qindarkas +qindars +qinghai +qintar +qintars +qiviut +qiviuts +qoph +qophs +qt +qty +qua +quaalude +quaaludes +quack +quacked +quackery +quacking +quackish +quackishly +quacks +quacksalver +quacksalvers +quacky +quad +quadded +quadding +quadragenarian +quadragesima +quadragesimal +quadrangle +quadrangles +quadrangular +quadrangularly +quadrangularness +quadrant +quadrantal +quadrantid +quadrants +quadraphonic +quadraphonically +quadraphonics +quadraphony +quadrasonic +quadrat +quadrate +quadrated +quadrates +quadratic +quadratically +quadratics +quadrating +quadrats +quadrature +quadratures +quadrennia +quadrennial +quadrennially +quadrennials +quadrennium +quadrenniums +quadric +quadricentennial +quadricentennials +quadriceps +quadricipital +quadrics +quadrifid +quadriga +quadrigae +quadrilateral +quadrilaterals +quadrille +quadrilles +quadrillion +quadrillions +quadrillionth +quadrillionths +quadrinomial +quadripartite +quadriphonic +quadriphonics +quadriphony +quadriplegia +quadriplegic +quadriplegics +quadrisect +quadrivalence +quadrivalency +quadrivalent +quadrivia +quadrivial +quadrivium +quadroon +quadroons +quadrophonic +quadrumanal +quadrumanous +quadrumvir +quadrumvirate +quadrumvirates +quadrumvirs +quadruped +quadrupedal +quadrupeds +quadruple +quadrupled +quadruples +quadruplet +quadruplets +quadruplicate +quadruplicated +quadruplicately +quadruplicates +quadruplicating +quadruplication +quadruplications +quadruplicity +quadrupling +quadruply +quadrupole +quadrupoles +quads +quaere +quaeres +quaestor +quaestorial +quaestors +quaestorship +quaestorships +quaff +quaffed +quaffer +quaffers +quaffing +quaffs +quag +quagga +quaggas +quaggier +quaggiest +quaggy +quagmire +quagmires +quags +quahaug +quahaugs +quahog +quahogs +quai +quaich +quaiches +quaigh +quaighs +quail +quailed +quailing +quails +quaint +quainter +quaintest +quaintly +quaintness +quake +quaked +quakeproof +quakeproofed +quakeproofing +quakeproofs +quaker +quakerish +quakerism +quakerly +quakers +quakes +quaking +quaky +quale +qualia +qualifiable +qualification +qualifications +qualificatory +qualified +qualifiedly +qualifier +qualifiers +qualifies +qualify +qualifying +qualitative +qualitatively +qualities +quality +qualm +qualmish +qualmishly +qualmishness +qualms +qualmy +quamash +quamashes +quandang +quandangs +quandaries +quandary +quandong +quandongs +quango +quangos +quant +quanta +quantal +quantally +quantasome +quantasomes +quanted +quantic +quantics +quantifiability +quantifiable +quantifiably +quantification +quantificational +quantificationally +quantifications +quantified +quantifier +quantifiers +quantifies +quantify +quantifying +quanting +quantitate +quantitated +quantitates +quantitating +quantitation +quantitations +quantitative +quantitatively +quantitativeness +quantities +quantity +quantization +quantizations +quantize +quantized +quantizer +quantizers +quantizes +quantizing +quants +quantum +quapaw +quapaws +quarantinable +quarantine +quarantined +quarantines +quarantining +quark +quarks +quarrel +quarreled +quarreler +quarrelers +quarreling +quarrelled +quarreller +quarrellers +quarrelling +quarrels +quarrelsome +quarrelsomely +quarrelsomeness +quarried +quarrier +quarriers +quarries +quarry +quarrying +quarryman +quarrymen +quart +quartan +quartans +quarter +quarterage +quarterages +quarterback +quarterbacked +quarterbacking +quarterbacks +quarterdeck +quarterdecks +quartered +quarterfinal +quarterfinalist +quarterfinalists +quarterfinals +quartering +quarterlies +quarterly +quartermaster +quartermasters +quartern +quarterns +quarters +quartersaw +quartersawed +quartersawing +quartersawn +quartersaws +quarterstaff +quarterstaves +quartertone +quartertones +quartet +quartets +quartette +quartettes +quartic +quartics +quartile +quartiles +quarto +quartos +quarts +quartz +quartzes +quartziferous +quartzite +quartzitic +quartzose +quasar +quasars +quash +quashed +quashes +quashing +quasi +quasiliquid +quasimodo +quasiparticle +quasiparticles +quasiperiodic +quasiperiodicity +quassia +quassias +quatercentenaries +quatercentenary +quaternaries +quaternary +quaternion +quaternions +quaternities +quaternity +quatorze +quatrain +quatrains +quatre +quatrefoil +quatrefoils +quattrocento +quattrocentos +quattuordecillion +quattuordecillions +quaver +quavered +quavering +quaveringly +quavers +quavery +quay +quayage +quayages +quays +quayside +quaysides +quean +queans +queasier +queasiest +queasily +queasiness +queasy +queazier +queaziest +queazy +quebec +quebecer +quebecers +quebecker +quebeckers +quebecois +quebracho +quebrachos +quechan +quechua +quechuan +quechuas +quechumaran +quechumarans +queen +queen's +queened +queening +queenlier +queenliest +queenliness +queenly +queens +queensberry +queenship +queenships +queenside +queensides +queensland +queer +queered +queerer +queerest +queering +queerish +queerly +queerness +queers +queleas +quell +quelled +queller +quellers +quelling +quells +quem +quench +quenchable +quenched +quencher +quenchers +quenches +quenching +quenchless +quenelle +quenelles +quercetin +quercetins +quercitron +quercitrons +queried +querier +queriers +queries +querist +querists +quern +querns +querulous +querulously +querulousness +query +querying +quesadilla +quesadillas +quest +quested +quester +questers +questing +question +questionability +questionable +questionableness +questionably +questionaries +questionary +questioned +questioner +questioners +questioning +questioningly +questionings +questionless +questionnaire +questionnaires +questions +questor +questors +quests +quetzal +quetzalcoatl +quetzales +quetzals +queue +queued +queueing +queuer +queuers +queues +queuing +quibble +quibbled +quibbler +quibblers +quibbles +quibbling +quiberon +quiche +quiches +quiché +quichés +quick +quicken +quickened +quickener +quickeners +quickening +quickens +quicker +quickest +quickie +quickies +quicklime +quickly +quickness +quicks +quicksand +quicksands +quickset +quicksets +quicksilver +quickstep +quickstepped +quickstepping +quicksteps +quid +quiddities +quiddity +quidnunc +quidnuncs +quids +quiescence +quiescent +quiescently +quiet +quieted +quieten +quietened +quietening +quietens +quieter +quietest +quieting +quietism +quietisms +quietist +quietistic +quietists +quietly +quietness +quiets +quietude +quietus +quietuses +quiff +quiffs +quill +quillback +quillbacks +quilled +quiller +quilling +quills +quillwork +quillworks +quillwort +quillworts +quilt +quilted +quilter +quilters +quilting +quilts +quinacrine +quinalizarin +quinalizarins +quinary +quinate +quince +quincentenary +quincentennial +quinces +quincey +quincuncial +quincuncially +quincunx +quincunxes +quincunxial +quincy +quindecennial +quindecennials +quindecillion +quindecillions +quinella +quinellas +quinidine +quinidines +quiniela +quinielas +quinine +quinines +quinnat +quinoa +quinoas +quinoid +quinoidine +quinoidines +quinoids +quinoline +quinolines +quinone +quinones +quinonoid +quinquagenarian +quinquagenarians +quinquagesima +quinquagesimas +quinquennia +quinquennial +quinquennially +quinquennials +quinquennium +quinquenniums +quinquevalence +quinquevalent +quinsy +quint +quinta +quintain +quintains +quintal +quintals +quintan +quintas +quintessence +quintessential +quintessentially +quintet +quintets +quintette +quintettes +quintic +quintics +quintile +quintiles +quintilian +quintillion +quintillions +quintillionth +quintillionths +quints +quintuple +quintupled +quintuples +quintuplet +quintuplets +quintuplicate +quintuplicated +quintuplicates +quintuplicating +quintupling +quintuply +quinze +quip +quipped +quipper +quippers +quipping +quippy +quips +quipster +quipsters +quipu +quipus +quire +quires +quirinal +quirinus +quirk +quirked +quirkier +quirkiest +quirkily +quirkiness +quirking +quirkish +quirks +quirky +quirt +quirts +quisling +quislingism +quislings +quit +quitch +quitclaim +quitclaimed +quitclaiming +quitclaims +quite +quito +quitrent +quitrents +quits +quittance +quittances +quitted +quitter +quitters +quitting +quittor +quittors +quiver +quivered +quivering +quiveringly +quivers +quivery +quixote +quixotes +quixotic +quixotical +quixotically +quixotism +quixotry +quiz +quizmaster +quizmasters +quizzed +quizzer +quizzers +quizzes +quizzical +quizzicality +quizzically +quizzing +quo +quod +quodlibet +quodlibets +quoi +quoin +quoined +quoining +quoins +quoit +quoits +quokka +quokkas +quondam +quonset +quorum +quorums +quos +quota +quotability +quotable +quotably +quotas +quotation +quotational +quotationally +quotations +quote +quoted +quoter +quoters +quotes +quoth +quotha +quotidian +quotient +quotients +quoting +quran +qurush +qurushes +québec +québecois +qwerty +r +ra +rabat +rabato +rabatos +rabats +rabbet +rabbeted +rabbeting +rabbets +rabbi +rabbin +rabbinate +rabbinates +rabbinic +rabbinical +rabbinically +rabbinism +rabbinist +rabbinistic +rabbinists +rabbinitic +rabbins +rabbis +rabbit +rabbitbrush +rabbited +rabbiter +rabbiters +rabbiting +rabbitries +rabbitry +rabbits +rabbity +rabble +rabbled +rabblement +rabblements +rabbler +rabblers +rabbles +rabbling +rabe +rabelais +rabelaisian +rabi +rabia +rabic +rabid +rabidity +rabidly +rabidness +rabies +rabietic +raccoon +raccoons +race +racecar +racecars +racecourse +racecourses +raced +racehorse +racehorses +racemate +racemates +raceme +racemes +racemic +racemiform +racemism +racemization +racemizations +racemize +racemized +racemizes +racemizing +racemose +racemosely +racer +racers +racerunner +racerunners +races +racetrack +racetracker +racetrackers +racetracks +racewalker +racewalkers +racewalking +raceway +raceways +rachel +rachial +rachides +rachilla +rachillae +rachis +rachises +rachitic +rachitis +rachmaninoff +rachmanism +racial +racialism +racialist +racialistic +racialists +racially +racier +raciest +racily +racine +raciness +racing +racism +racist +racists +rack +racked +racker +rackers +racket +racketed +racketeer +racketeered +racketeering +racketeers +racketing +rackets +rackety +rackful +rackfuls +racking +rackingly +racks +raclette +raclettes +raclopride +racon +racons +raconteur +raconteurs +racoon +racoons +racquet +racquetball +racquets +racy +rad +radar +radars +radarscope +radarscopes +raddle +raddled +raddles +raddling +radial +radially +radials +radian +radiance +radiancy +radians +radiant +radiantly +radiants +radiate +radiated +radiately +radiates +radiating +radiation +radiational +radiationless +radiations +radiative +radiator +radiators +radical +radicalism +radicalization +radicalizations +radicalize +radicalized +radicalizes +radicalizing +radically +radicalness +radicals +radicand +radicands +radicchio +radicchios +radices +radicle +radicles +radicular +radii +radio +radioactive +radioactively +radioactivity +radioallergosorbent +radioastronomy +radioautograph +radioautographic +radioautographs +radioautography +radiobiologic +radiobiological +radiobiologically +radiobiologist +radiobiologists +radiobiology +radiobroadcast +radiobroadcasted +radiobroadcaster +radiobroadcasters +radiobroadcasting +radiobroadcasts +radiocarbon +radiocast +radiocasts +radiochemical +radiochemically +radiochemist +radiochemistry +radiochemists +radiochromatogram +radiochromatograms +radioecological +radioecologist +radioecologists +radioecology +radioed +radioelement +radioelements +radiogenic +radiogram +radiograms +radiograph +radiographed +radiographer +radiographers +radiographic +radiographically +radiographing +radiographs +radiography +radioimmunoassay +radioimmunoassayable +radioimmunological +radioimmunology +radioing +radioiodine +radioiodines +radioisotope +radioisotopes +radioisotopic +radioisotopically +radiolabel +radiolabeled +radiolabeling +radiolabelled +radiolabelling +radiolabels +radiolarian +radiolarians +radiolocation +radiologic +radiological +radiologically +radiologist +radiologists +radiology +radiolucency +radiolucent +radiolyses +radiolysis +radiolytic +radioman +radiomen +radiometer +radiometers +radiometric +radiometrically +radiometry +radiomimetic +radionuclide +radionuclides +radiopacity +radiopaque +radiopharmaceutical +radiopharmaceuticals +radiophone +radiophones +radiophonic +radiophoto +radiophotograph +radiophotographs +radiophotography +radiophotos +radioprotection +radioprotections +radioprotective +radios +radioscopic +radioscopical +radioscopy +radiosensitive +radiosensitivity +radiosonde +radiosondes +radiostrontium +radiotelegraph +radiotelegraphic +radiotelegraphs +radiotelegraphy +radiotelemetric +radiotelemetry +radiotelephone +radiotelephones +radiotelephonic +radiotelephony +radiotherapies +radiotherapist +radiotherapists +radiotherapy +radiothorium +radiotoxic +radiotoxicity +radiotracer +radiotracers +radish +radishes +radium +radius +radiuses +radix +radixes +radome +radomes +radon +rads +radula +radulae +radular +radwaste +raeburn +raff +raffia +raffias +raffinate +raffinates +raffinose +raffinoses +raffish +raffishly +raffishness +raffle +raffled +raffler +rafflers +raffles +rafflesia +rafflesias +raffling +raft +rafted +rafter +raftered +rafters +rafting +rafts +raftsman +raftsmen +rag +raga +ragamuffin +ragamuffins +ragas +ragbag +ragbags +rage +raged +rages +ragged +raggedier +raggediest +raggedly +raggedness +raggedy +ragging +raggle +ragi +raging +ragis +raglan +raglans +ragman +ragmen +ragnarok +ragout +ragouts +ragpicker +ragpickers +rags +ragtag +ragtime +ragtop +ragtops +ragusa +ragweed +ragwort +ragworts +rah +raiatea +raid +raided +raider +raiders +raiding +raids +rail +railbird +railbirds +railbus +railcar +railcars +railed +railer +railers +railhead +railheads +railing +railings +railleries +raillery +railroad +railroaded +railroader +railroaders +railroading +railroadings +railroads +rails +railway +railways +raiment +rain +rainbird +rainbirds +rainbow +rainbowlike +rainbows +raincoat +raincoats +raindrop +raindrops +rained +rainfall +rainfalls +rainforest +rainforests +rainier +rainiest +raininess +raining +rainless +rainmaker +rainmakers +rainmaking +rainout +rainouts +rainproof +rains +rainspout +rainspouts +rainsquall +rainsqualls +rainstorm +rainstorms +rainwash +rainwater +rainwear +rainy +raise +raised +raiser +raisers +raises +raisin +raising +raisingly +raisings +raisins +raison +raisonné +raisonnés +raisons +raj +raja +rajab +rajabs +rajah +rajahs +rajas +rajasthan +rajasthani +rajpoot +rajpoots +rajput +rajputana +rajputs +rajs +rake +raked +rakee +rakees +rakehell +rakehells +rakehelly +raker +rakers +rakes +raki +raking +rakis +rakish +rakishly +rakishness +rale +raleigh +rales +ralik +rallentando +rallentandos +rallied +rallies +ralliform +rally +rallye +rallyes +rallying +ralph +ralphed +ralphing +ralphs +ram +rama +ramada +ramadan +ramadas +ramadhan +ramakrishna +raman +ramate +ramayana +ramble +rambled +rambler +ramblers +rambles +rambling +ramblingly +ramblings +rambo +rambos +rambouillet +rambouillets +rambunctious +rambunctiously +rambunctiousness +rambutan +rambutans +ramekin +ramekins +ramequin +ramequins +rameses +ramet +ramets +rami +ramie +ramification +ramifications +ramified +ramifies +ramiform +ramify +ramifying +ramillies +ramism +ramist +ramists +ramjet +ramjets +rammed +rammer +rammers +ramming +ramona +ramonas +ramose +ramous +ramp +rampage +rampaged +rampageous +rampageously +rampageousness +rampager +rampagers +rampages +rampaging +rampancy +rampant +rampantly +rampart +ramparted +ramparting +ramparts +ramped +rampike +rampikes +ramping +rampion +rampions +ramps +ramrod +ramrodded +ramrodding +ramrods +rams +ramses +ramshackle +ramshorn +ramshorns +ramson +ramsons +ramtil +ramtilla +ramtillas +ramtils +ramulose +ramus +ran +ranch +ranched +rancher +rancheria +rancherias +ranchero +rancheros +ranchers +ranches +ranching +ranchman +ranchmen +rancho +ranchos +rancid +rancidity +rancidness +rancor +rancorous +rancorously +rancorousness +rancors +rand +randan +randans +randier +randiest +random +randomization +randomizations +randomize +randomized +randomizer +randomizers +randomizes +randomizing +randomly +randomness +rands +randy +ranee +ranees +rang +range +ranged +rangefinder +rangefinders +rangeland +rangelands +ranger +rangers +ranges +rangier +rangiest +ranginess +ranging +rangoon +rangy +rani +ranid +ranids +ranis +rank +ranked +ranker +rankers +rankest +rankine +ranking +rankings +rankle +rankled +rankles +rankling +rankly +rankness +ranks +ransack +ransacked +ransacker +ransackers +ransacking +ransacks +ransom +ransomed +ransomer +ransomers +ransoming +ransoms +rant +ranted +ranter +ranters +ranting +rantingly +rantings +rants +ranula +ranulas +ranunculi +ranunculus +ranunculuses +rap +rapacious +rapaciously +rapaciousness +rapacity +rapallo +rape +raped +raper +rapers +rapes +rapeseed +rapeseeds +raphae +raphael +raphaelesque +raphaelite +raphaelites +raphaelitism +raphe +raphia +raphias +raphide +raphides +raphis +rapid +rapider +rapidest +rapidity +rapidly +rapidness +rapids +rapier +rapierlike +rapiers +rapine +rapines +raping +rapini +rapist +rapists +rapparee +rapparees +rapped +rappee +rappees +rappel +rappelled +rappelling +rappels +rappen +rapper +rappers +rapping +rappini +rapport +rapporteur +rapporteurs +rapprochement +rapprochements +raps +rapscallion +rapscallions +rapt +raptly +raptness +raptor +raptorial +raptors +rapture +raptured +raptures +rapturing +rapturous +rapturously +rapturousness +rara +rarae +rare +rarebit +rarebits +raree +rarefaction +rarefactional +rarefactions +rarefactive +rarefiable +rarefication +rarefied +rarefies +rarefy +rarefying +rarely +rareness +rarer +rareripe +rareripes +rarest +rarified +rarifies +rarify +rarifying +raring +rarities +rarity +rarotonga +rasa +rasae +rasbora +rasboras +rascal +rascalities +rascality +rascally +rascals +rase +rased +rases +rash +rasher +rashers +rashes +rashest +rashly +rashness +rasing +rasorial +rasp +raspberries +raspberry +rasped +rasper +raspers +raspier +raspiest +rasping +raspingly +rasps +rasputin +raspy +rasselas +rasta +rastafarian +rastafarianism +rastafarians +rastas +raster +rasters +rat +rata +ratability +ratable +ratableness +ratables +ratably +ratafee +ratafees +ratafia +ratafias +ratak +rataplan +rataplans +ratatouille +ratatouilles +ratbag +ratbags +ratchet +ratcheted +ratcheting +ratchets +rate +rateable +rated +ratel +ratels +ratemaking +ratemakings +ratemeter +ratemeters +ratepayer +ratepayers +rater +raters +rates +ratfink +ratfinks +ratfish +ratfishes +rathe +rather +rathskeller +rathskellers +raticide +raticides +ratifiable +ratification +ratifications +ratified +ratifier +ratifiers +ratifies +ratify +ratifying +ratine +ratines +rating +ratings +ratiné +ratio +ratiocinate +ratiocinated +ratiocinates +ratiocinating +ratiocination +ratiocinations +ratiocinative +ratiocinator +ratiocinators +ration +rational +rationale +rationales +rationalism +rationalist +rationalistic +rationalistically +rationalists +rationalities +rationality +rationalizable +rationalization +rationalizations +rationalize +rationalized +rationalizer +rationalizers +rationalizes +rationalizing +rationally +rationalness +rationed +rationing +rations +ratios +ratite +ratites +ratlike +ratlin +ratline +ratlines +ratlins +ratoon +ratooned +ratooning +ratoons +rats +ratsbane +ratsbanes +rattail +rattails +rattan +rattans +ratted +ratteen +ratteens +ratter +ratters +rattier +rattiest +ratting +rattle +rattlebox +rattleboxes +rattlebrain +rattlebrained +rattlebrains +rattled +rattler +rattlers +rattles +rattlesnake +rattlesnakes +rattletrap +rattletraps +rattling +rattlingly +rattly +rattoon +rattooned +rattooning +rattoons +rattrap +rattraps +ratty +raucity +raucous +raucously +raucousness +raunch +raunchier +raunchiest +raunchily +raunchiness +raunchy +rauwolfia +rauwolfias +ravage +ravaged +ravagement +ravagements +ravager +ravagers +ravages +ravaging +rave +raved +ravel +raveled +raveler +ravelers +raveling +ravelings +ravelled +ravelling +ravellings +ravello +ravelment +ravelments +ravels +raven +ravened +ravener +raveners +ravening +raveningly +ravenings +ravenna +ravenous +ravenously +ravenousness +ravens +raver +ravers +raves +ravigote +ravigotes +ravigotte +ravigottes +ravin +ravine +ravined +ravines +raving +ravingly +ravings +ravins +ravioli +raviolis +ravish +ravished +ravisher +ravishers +ravishes +ravishing +ravishingly +ravishment +ravishments +raw +rawalpindi +rawboned +rawer +rawest +rawhide +rawhided +rawhides +rawhiding +rawinsonde +rawinsondes +rawly +rawness +ray +rayed +raying +rayleigh +rayless +raylessness +raynaud +rayon +rayonism +rayonist +rayonistic +rayonists +rays +raze +razed +razee +razees +razer +razers +razes +razing +razor +razorback +razorbacks +razorbill +razorbills +razorblade +razorblades +razors +razz +razzed +razzes +razzing +razzle +razzmatazz +rca +rd +re +rea +reabsorb +reabsorbed +reabsorbing +reabsorbs +reabsorption +reabsorptions +reaccelerate +reaccelerated +reaccelerates +reaccelerating +reaccept +reaccepted +reaccepting +reaccepts +reaccession +reaccessioned +reaccessioning +reaccessions +reacclimatize +reacclimatized +reacclimatizes +reacclimatizing +reaccredit +reaccreditation +reaccreditations +reaccredited +reaccrediting +reaccredits +reach +reachable +reached +reacher +reachers +reaches +reaching +reacquaint +reacquainted +reacquainting +reacquaints +reacquire +reacquired +reacquires +reacquiring +reacquisition +reacquisitions +react +reactance +reactant +reactants +reacted +reacting +reaction +reactionaries +reactionary +reactionaryism +reactions +reactivate +reactivated +reactivates +reactivating +reactivation +reactivations +reactive +reactively +reactiveness +reactivity +reactor +reactors +reacts +read +readability +readable +readableness +readably +readapt +readapted +readapting +readapts +readdress +readdressed +readdresses +readdressing +reader +readerly +readers +readership +readerships +readied +readier +readies +readiest +readily +readiness +reading +readings +readjust +readjusted +readjuster +readjusters +readjusting +readjustment +readjustments +readjusts +readmission +readmissions +readmit +readmits +readmitted +readmitting +readopt +readopted +readopting +readopts +readout +readouts +reads +ready +readying +readymade +reaffirm +reaffirmation +reaffirmations +reaffirmed +reaffirming +reaffirms +reaffix +reaffixed +reaffixes +reaffixing +reagent +reagents +reaggregate +reaggregated +reaggregates +reaggregating +reaggregation +reaggregations +reagin +reaginic +reaginically +reagins +real +realer +reales +realest +realgar +realgars +realia +realign +realigned +realigning +realignment +realignments +realigns +realism +realist +realistic +realistically +realists +realities +reality +realizability +realizable +realizably +realization +realizationism +realizationist +realizationists +realizations +realize +realized +realizer +realizers +realizes +realizing +reallocate +reallocated +reallocates +reallocating +reallocation +reallocations +really +realm +realms +realness +realpolitik +realpolitiker +realpolitikers +realpolitiks +reals +realties +realtor +realtors +realty +ream +reamed +reamer +reamers +reaming +reams +reanalyses +reanalysis +reanalyze +reanalyzed +reanalyzes +reanalyzing +reanimate +reanimated +reanimates +reanimating +reanimation +reanimations +reannex +reannexation +reannexations +reannexed +reannexes +reannexing +reap +reaped +reaper +reapers +reaphook +reaphooks +reaping +reappear +reappearance +reappearances +reappeared +reappearing +reappears +reapplication +reapplications +reapplied +reapplies +reapply +reapplying +reappoint +reappointed +reappointing +reappointment +reappointments +reappoints +reapportion +reapportioned +reapportioning +reapportionment +reapportionments +reapportions +reappraisal +reappraisals +reappraise +reappraised +reappraises +reappraising +reappropriate +reappropriated +reappropriates +reappropriating +reapprove +reapproved +reapproves +reapproving +reaps +rear +reared +rearer +rearers +rearguard +rearguards +reargue +reargued +reargues +rearguing +reargument +rearguments +rearing +rearm +rearmament +rearmaments +rearmed +rearming +rearmost +rearms +rearousal +rearousals +rearouse +rearoused +rearouses +rearousing +rearrange +rearranged +rearrangement +rearrangements +rearranges +rearranging +rearrest +rearrested +rearresting +rearrests +rears +rearticulate +rearticulated +rearticulates +rearticulating +rearview +rearward +rearwards +reascend +reascended +reascending +reascends +reascent +reascents +reason +reasonability +reasonable +reasonableness +reasonably +reasoned +reasoner +reasoners +reasoning +reasonings +reasonless +reasonlessly +reasons +reassemblage +reassemblages +reassemble +reassembled +reassembles +reassemblies +reassembling +reassembly +reassert +reasserted +reasserting +reassertion +reassertions +reasserts +reassess +reassessed +reassesses +reassessing +reassessment +reassessments +reassign +reassigned +reassigning +reassignment +reassignments +reassigns +reassume +reassumed +reassumes +reassuming +reassurance +reassurances +reassure +reassured +reassures +reassuring +reassuringly +reata +reatas +reattach +reattached +reattaches +reattaching +reattachment +reattachments +reattain +reattained +reattaining +reattains +reattempt +reattempted +reattempting +reattempts +reattribute +reattributed +reattributes +reattributing +reattribution +reattributions +reaumur +reauthorization +reauthorizations +reauthorize +reauthorized +reauthorizes +reauthorizing +reave +reaved +reaver +reavers +reaves +reaving +reawake +reawaked +reawaken +reawakened +reawakening +reawakens +reawakes +reawaking +reb +rebait +rebaited +rebaiting +rebaits +rebalance +rebalanced +rebalances +rebalancing +rebaptism +rebaptisms +rebaptize +rebaptized +rebaptizes +rebaptizing +rebar +rebarbative +rebarbatively +rebars +rebate +rebated +rebater +rebaters +rebates +rebating +rebato +rebatos +rebbe +rebbes +rebec +rebecca +rebeck +rebecks +rebecs +rebegan +rebegin +rebeginning +rebegins +rebegun +rebel +rebelled +rebelling +rebellion +rebellions +rebellious +rebelliously +rebelliousness +rebels +rebid +rebidden +rebidding +rebids +rebilling +rebind +rebinding +rebinds +rebirth +rebirths +reblend +reblended +reblending +reblends +reblochon +rebloom +rebloomed +reblooming +reblooms +reboant +reboard +reboarded +reboarding +reboards +reboil +reboiled +reboiling +reboils +rebook +rebooked +rebooking +rebooks +reboot +rebooted +rebooting +reboots +rebore +rebored +rebores +reboring +reborn +rebottle +rebottled +rebottles +rebottling +rebought +rebound +rebounded +rebounder +rebounders +rebounding +rebounds +rebozo +rebozos +rebranch +rebranched +rebranches +rebranching +rebred +rebreed +rebreeding +rebreeds +rebroadcast +rebroadcasted +rebroadcasting +rebroadcasts +rebs +rebuff +rebuffed +rebuffing +rebuffs +rebuild +rebuilding +rebuilds +rebuilt +rebuke +rebuked +rebuker +rebukers +rebukes +rebuking +reburial +reburials +reburied +reburies +rebury +reburying +rebus +rebuses +rebut +rebuts +rebuttable +rebuttal +rebuttals +rebutted +rebutter +rebutters +rebutting +rebuy +rebuying +rebuys +rec +recalcitrance +recalcitrancy +recalcitrant +recalcitrants +recalculate +recalculated +recalculates +recalculating +recalculation +recalculations +recalescence +recalescences +recalescent +recalibrate +recalibrated +recalibrates +recalibrating +recalibration +recalibrations +recall +recallability +recallable +recalled +recaller +recallers +recalling +recalls +recamier +recamiers +recanalization +recanalizations +recanalize +recanalized +recanalizes +recanalizing +recant +recantation +recantations +recanted +recanter +recanters +recanting +recants +recap +recapitalization +recapitalizations +recapitalize +recapitalized +recapitalizes +recapitalizing +recapitulate +recapitulated +recapitulates +recapitulating +recapitulation +recapitulations +recapitulative +recapitulatory +recappable +recapped +recapping +recaps +recapture +recaptured +recaptures +recapturing +recast +recasting +recasts +recce +recces +recd +recede +receded +recedes +receding +receipt +receipted +receipting +receipts +receivable +receivables +receive +received +receiver +receivers +receivership +receiverships +receives +receiving +recency +recension +recensions +recent +recently +recentness +recentralization +recentrifuge +recentrifuged +recentrifuges +recentrifuging +receptacle +receptacles +reception +receptionist +receptionists +receptions +receptive +receptively +receptiveness +receptivity +receptor +receptors +recertification +recertifications +recertified +recertifies +recertify +recertifying +recess +recessed +recesses +recessing +recession +recessional +recessionals +recessionary +recessions +recessive +recessively +recessiveness +recessives +rechallenge +rechallenged +rechallenges +rechallenging +rechannel +rechanneled +rechanneling +rechannels +recharge +rechargeable +recharged +recharger +rechargers +recharges +recharging +recharter +rechartered +rechartering +recharters +recheat +recheats +recheck +rechecked +rechecking +rechecks +recherché +rechoreograph +rechoreographed +rechoreographing +rechoreographs +rechristen +rechristened +rechristening +rechristens +rechromatograph +rechromatography +recidivate +recidivism +recidivist +recidivistic +recidivists +recidivous +recipe +recipes +recipience +recipiency +recipient +recipients +reciprocal +reciprocality +reciprocally +reciprocalness +reciprocals +reciprocate +reciprocated +reciprocates +reciprocating +reciprocation +reciprocations +reciprocative +reciprocator +reciprocators +reciprocities +reciprocity +recirculate +recirculated +recirculates +recirculating +recirculation +recirculations +recision +recisions +recital +recitalist +recitalists +recitals +recitation +recitations +recitative +recitatives +recitativi +recitativo +recitativos +recite +recited +reciter +reciters +recites +reciting +reck +recked +recking +reckless +recklessly +recklessness +reckon +reckoned +reckoner +reckoners +reckoning +reckonings +reckons +recks +reclad +recladding +reclads +reclaim +reclaimable +reclaimant +reclaimants +reclaimed +reclaimer +reclaimers +reclaiming +reclaims +reclamation +reclamations +reclassification +reclassifications +reclassified +reclassifies +reclassify +reclassifying +reclinate +reclination +reclinations +recline +reclined +recliner +recliners +reclines +reclining +reclosable +reclothe +reclothed +reclothes +reclothing +recluse +recluses +reclusion +reclusions +reclusive +reclusively +reclusiveness +recock +recocked +recocking +recocks +recodification +recodifications +recodified +recodifies +recodify +recodifying +recognition +recognitions +recognitive +recognitory +recognizability +recognizable +recognizably +recognizance +recognizances +recognizant +recognize +recognized +recognizer +recognizers +recognizes +recognizing +recoil +recoiled +recoiler +recoilers +recoiling +recoilless +recoils +recoin +recoinage +recoined +recoining +recoins +recollect +recollected +recollecting +recollection +recollections +recollective +recollectively +recollects +recolonization +recolonize +recolonized +recolonizes +recolonizing +recolor +recolored +recoloring +recolors +recombinant +recombinants +recombinase +recombinases +recombination +recombinational +recombinations +recombine +recombined +recombines +recombining +recommence +recommenced +recommencement +recommencements +recommences +recommencing +recommend +recommendable +recommendation +recommendations +recommendatory +recommended +recommender +recommenders +recommending +recommends +recommission +recommissioned +recommissioning +recommissions +recommit +recommitment +recommitments +recommits +recommittal +recommittals +recommitted +recommitting +recompense +recompensed +recompenses +recompensing +recompilation +recompilations +recompile +recompiled +recompiles +recompiling +recompose +recomposed +recomposes +recomposing +recomposition +recompositions +recompress +recompressed +recompresses +recompressing +recompression +recompressions +recomputation +recomputations +recompute +recomputed +recomputes +recomputing +recon +reconceive +reconceived +reconceives +reconceiving +reconcentrate +reconcentrated +reconcentrates +reconcentrating +reconcentration +reconcentrations +reconception +reconceptions +reconceptualization +reconceptualizations +reconceptualize +reconceptualized +reconceptualizes +reconceptualizing +reconcilability +reconcilable +reconcilableness +reconcilably +reconcile +reconciled +reconcilement +reconcilements +reconciler +reconcilers +reconciles +reconciliation +reconciliations +reconciliatory +reconciling +recondense +recondensed +recondenses +recondensing +recondite +reconditely +reconditeness +recondition +reconditioned +reconditioning +reconditions +reconfiguration +reconfigurations +reconfigure +reconfigured +reconfigures +reconfiguring +reconfirm +reconfirmation +reconfirmations +reconfirmed +reconfirming +reconfirms +reconnaissance +reconnaissances +reconnect +reconnected +reconnecting +reconnection +reconnections +reconnects +reconnoissance +reconnoissances +reconnoiter +reconnoitered +reconnoiterer +reconnoiterers +reconnoitering +reconnoiters +reconnoitre +reconnoitred +reconnoitres +reconnoitring +reconquer +reconquered +reconquering +reconquers +reconquest +reconquests +recons +reconsecrate +reconsecrated +reconsecrates +reconsecrating +reconsecration +reconsecrations +reconsider +reconsideration +reconsiderations +reconsidered +reconsidering +reconsiders +reconsolidate +reconsolidated +reconsolidates +reconsolidating +reconsolidation +reconsolidations +reconstitute +reconstituted +reconstitutes +reconstituting +reconstitution +reconstitutions +reconstruct +reconstructed +reconstructible +reconstructing +reconstruction +reconstructionism +reconstructionist +reconstructionists +reconstructions +reconstructive +reconstructor +reconstructors +reconstructs +recontact +recontacted +recontacting +recontacts +recontaminate +recontaminated +recontaminates +recontaminating +recontamination +recontextualize +recontextualized +recontextualizes +recontextualizing +recontour +recontoured +recontouring +recontours +reconvene +reconvened +reconvenes +reconvening +reconvention +reconversion +reconversions +reconvert +reconverted +reconverting +reconverts +reconvey +reconveyance +reconveyances +reconveyed +reconveying +reconveys +reconvict +reconvicted +reconvicting +reconviction +reconvictions +reconvicts +reconvince +reconvinced +reconvinces +reconvincing +recopied +recopies +recopy +recopying +record +recordable +recordation +recordations +recorded +recorder +recorders +recording +recordings +recordist +recordists +records +recork +recorked +recorking +recorks +recount +recountal +recountals +recounted +recounter +recounters +recounting +recounts +recoup +recoupable +recouped +recouping +recoupment +recoupments +recoups +recourse +recourses +recover +recoverability +recoverable +recoverably +recovered +recoverer +recoverers +recoveries +recovering +recovers +recovery +recreance +recreancy +recreant +recreantly +recreants +recreate +recreated +recreates +recreating +recreation +recreational +recreationally +recreationist +recreationists +recreations +recreative +recrement +recremental +recrements +recriminate +recriminated +recriminates +recriminating +recrimination +recriminations +recriminative +recriminator +recriminators +recriminatory +recross +recrossed +recrosses +recrossing +recrudesce +recrudesced +recrudescence +recrudescent +recrudesces +recrudescing +recruit +recruited +recruiter +recruiters +recruiting +recruitment +recruitments +recruits +recrystallization +recrystallizations +recrystallize +recrystallized +recrystallizes +recrystallizing +recta +rectal +rectally +rectangle +rectangles +rectangular +rectangularity +rectangularly +recti +rectifiability +rectifiable +rectification +rectifications +rectified +rectifier +rectifiers +rectifies +rectify +rectifying +rectilinear +rectilinearly +rectitude +rectitudinous +recto +rector +rectorate +rectorates +rectorial +rectories +rectors +rectorship +rectorships +rectory +rectos +rectrices +rectrix +rectum +rectums +rectus +recultivate +recultivated +recultivates +recultivating +recumbence +recumbency +recumbent +recumbently +recuperate +recuperated +recuperates +recuperating +recuperation +recuperations +recuperative +recuperatory +recur +recurred +recurrence +recurrences +recurrent +recurrently +recurring +recurs +recursion +recursions +recursive +recursively +recursiveness +recurvate +recurvation +recurvations +recurve +recurved +recurves +recurving +recusal +recusancies +recusancy +recusant +recusants +recuse +recused +recuses +recusing +recut +recuts +recutting +recyclable +recyclables +recycle +recycled +recycler +recyclers +recycles +recycling +red +redact +redacted +redacting +redaction +redactional +redactor +redactors +redacts +redargue +redargued +redargues +redarguing +redate +redated +redates +redating +redbait +redbaited +redbaiter +redbaiters +redbaiting +redbaitings +redbaits +redbelly +redbird +redbirds +redbone +redbones +redbreast +redbreasts +redbrick +redbud +redbuds +redbug +redbugs +redcap +redcaps +redcoat +redcoats +redden +reddened +reddener +reddeners +reddening +reddens +redder +reddest +reddish +reddishness +reddle +reddled +reddles +reddling +rede +redear +redecorate +redecorated +redecorates +redecorating +redecoration +redecorations +redecorator +redecorators +reded +rededicate +rededicated +rededicates +rededicating +rededication +rededications +redeem +redeemable +redeemably +redeemed +redeemer +redeemers +redeeming +redeems +redefect +redefine +redefined +redefines +redefining +redefinition +redefinitions +redeliver +redelivered +redeliveries +redelivering +redelivers +redelivery +redemption +redemptional +redemptioner +redemptioners +redemptions +redemptive +redemptorist +redemptorists +redemptory +redeploy +redeployed +redeploying +redeployment +redeployments +redeploys +redeposit +redeposited +redepositing +redeposits +redes +redescribe +redescribed +redescribes +redescribing +redescription +redescriptions +redesign +redesigned +redesigning +redesigns +redetect +redetected +redetects +redetermination +redeterminations +redetermine +redetermined +redetermines +redetermining +redevelop +redeveloped +redeveloper +redevelopers +redeveloping +redevelopment +redevelopments +redevelops +redeye +redeyes +redfish +redfishes +redhead +redheaded +redheads +redhorse +redhorses +redia +rediae +redial +redialed +redialing +redialled +redialling +redials +redias +redid +redifferentiation +redifferentiations +redigestion +reding +redingote +redingotes +redintegrate +redintegrated +redintegrates +redintegrating +redintegration +redintegrations +redintegrative +redintegrator +redintegrators +redirect +redirected +redirecting +redirection +redirections +redirector +redirectors +redirects +rediscount +rediscountable +rediscounted +rediscounting +rediscounts +rediscover +rediscovered +rediscoveries +rediscovering +rediscovers +rediscovery +rediscuss +rediscussed +rediscusses +rediscussing +redisplay +redisplayed +redisplaying +redisplays +redispose +redisposed +redisposes +redisposing +redisposition +redispositions +redissolve +redissolved +redissolves +redissolving +redistill +redistillation +redistillations +redistilled +redistilling +redistills +redistribute +redistributed +redistributes +redistributing +redistribution +redistributional +redistributionist +redistributionists +redistributions +redistributive +redistrict +redistricted +redistricting +redistricts +redivide +redivided +redivides +redividing +redivision +redivisions +redivivus +redleg +redlegs +redline +redlined +redlines +redlining +redly +redneck +rednecked +rednecks +redness +redo +redoes +redoing +redolence +redolency +redolent +redolently +redon +redone +redonned +redonning +redons +redouble +redoubled +redoubles +redoubling +redoubt +redoubtable +redoubtably +redoubts +redound +redounded +redounding +redounds +redout +redouts +redox +redoxes +redpoll +redpolls +redraft +redrafted +redrafting +redrafts +redraw +redrawing +redrawn +redraws +redream +redreamed +redreaming +redreams +redreamt +redress +redressed +redresser +redressers +redresses +redressing +redressor +redressors +redrew +redrill +redrilled +redrilling +redrills +redroot +redroots +reds +redshank +redshanks +redshift +redshifted +redshifts +redshirt +redshirted +redshirting +redshirts +redshouldered +redskin +redskins +redstart +redstarts +redtop +redtops +redub +redubbed +redubbing +redubs +reduce +reduced +reducer +reducers +reduces +reducibility +reducible +reducibly +reducing +reductant +reductants +reductase +reductases +reductio +reduction +reductional +reductiones +reductionism +reductionist +reductionistic +reductionists +reductions +reductive +reductively +reductiveness +reductivism +reductivist +reductivists +redundancies +redundancy +redundant +redundantly +reduplicate +reduplicated +reduplicates +reduplicating +reduplication +reduplications +reduplicative +reduplicatively +reduviid +reduviids +redux +redware +redwing +redwings +redwood +redwoods +reecho +reechoed +reechoes +reechoing +reed +reedbird +reedbirds +reedbuck +reedbucks +reeded +reedier +reediest +reedified +reedifies +reedify +reedifying +reediness +reeding +reedings +reedit +reedited +reediting +reedition +reeditions +reedits +reedlike +reedling +reedlings +reedman +reedmen +reeds +reeducate +reeducated +reeducates +reeducating +reeducation +reeducations +reeducative +reedy +reef +reefable +reefed +reefer +reefers +reefing +reefs +reefy +reek +reeked +reeker +reekers +reeking +reeks +reeky +reel +reelable +reelect +reelected +reelecting +reelection +reelections +reelects +reeled +reeler +reelers +reeligibility +reeligible +reeling +reels +reembroider +reembroidered +reembroidering +reembroiders +reemerge +reemerged +reemergence +reemergences +reemerges +reemerging +reemission +reemissions +reemit +reemits +reemitted +reemitting +reemphases +reemphasis +reemphasize +reemphasized +reemphasizes +reemphasizing +reemploy +reemployed +reemploying +reemployment +reemployments +reemploys +reenact +reenacted +reenacting +reenactment +reenactments +reenacts +reencounter +reencountered +reencountering +reencounters +reendow +reendowed +reendowing +reendows +reenergize +reenergized +reenergizes +reenergizing +reenforce +reenforced +reenforces +reenforcing +reengage +reengaged +reengagement +reengagements +reengages +reengaging +reengineer +reengineered +reengineering +reengineers +reengrave +reengraved +reengraves +reengraving +reenlist +reenlisted +reenlisting +reenlistment +reenlistments +reenlists +reenroll +reenrolled +reenrolling +reenrolls +reenter +reentered +reentering +reenters +reenthrone +reenthroned +reenthrones +reenthroning +reentrance +reentrances +reentrant +reentrants +reentries +reentry +reequip +reequipment +reequipped +reequipping +reequips +reerect +reerected +reerecting +reerects +reescalate +reescalated +reescalates +reescalating +reescalation +reescalations +reestablish +reestablished +reestablishes +reestablishing +reestablishment +reestimate +reestimated +reestimates +reestimating +reevaluate +reevaluated +reevaluates +reevaluating +reevaluation +reevaluations +reeve +reeved +reeves +reeving +reexamination +reexaminations +reexamine +reexamined +reexamines +reexamining +reexperience +reexperienced +reexperiences +reexperiencing +reexplore +reexplored +reexplores +reexploring +reexport +reexportation +reexportations +reexported +reexporting +reexports +reexpose +reexposed +reexposes +reexposing +reexposure +reexposures +reexpress +reexpressed +reexpresses +reexpressing +ref +reface +refaced +refaces +refacing +refashion +refashioned +refashioning +refashions +refasten +refastened +refastening +refastens +refect +refected +refecting +refection +refections +refectories +refectory +refects +refed +refeed +refeeding +refeeds +refeel +refeeling +refeels +refelt +refence +refenced +refences +refencing +refer +referable +referee +refereed +refereeing +referees +reference +referenced +referencer +referencers +references +referencing +referenda +referendum +referendums +referent +referential +referentiality +referentially +referents +referral +referrals +referred +referrer +referrers +referring +refers +refight +refighting +refights +refigure +refigured +refigures +refiguring +refile +refiled +refiles +refiling +refill +refillable +refilled +refilling +refills +refinance +refinanced +refinancer +refinancers +refinances +refinancier +refinanciers +refinancing +refind +refinding +refinds +refine +refined +refinement +refinements +refiner +refineries +refiners +refinery +refines +refining +refinish +refinished +refinisher +refinishers +refinishes +refinishing +refire +refired +refires +refiring +refit +refits +refitted +refitting +refix +refixed +refixes +refixing +reflag +reflagged +reflagging +reflags +reflate +reflated +reflates +reflating +reflation +reflationary +reflect +reflectance +reflected +reflecting +reflection +reflectional +reflections +reflective +reflectively +reflectiveness +reflectivities +reflectivity +reflectometer +reflectometers +reflectometry +reflector +reflectorize +reflectorized +reflectorizes +reflectorizing +reflectors +reflects +reflex +reflexed +reflexes +reflexing +reflexive +reflexively +reflexiveness +reflexives +reflexivity +reflexly +reflexologist +reflexologists +reflexology +refloat +refloated +refloating +refloats +reflow +reflowed +reflowing +reflows +refluence +refluent +reflux +refluxed +refluxes +refluxing +refocus +refocused +refocuses +refocusing +refocussed +refocussing +refold +refolded +refolding +refolds +reforecast +reforecasting +reforecasts +reforest +reforestation +reforestations +reforested +reforesting +reforests +reforge +reforged +reforges +reforging +reform +reformability +reformable +reformat +reformate +reformates +reformation +reformational +reformations +reformative +reformatories +reformatory +reformats +reformatted +reformatting +reformed +reformer +reformers +reforming +reformism +reformist +reformists +reforms +reformulate +reformulated +reformulates +reformulating +reformulation +reformulations +refortification +refortified +refortifies +refortify +refortifying +refought +refound +refoundation +refoundations +refounded +refounding +refounds +refract +refracted +refractile +refracting +refraction +refractional +refractive +refractively +refractiveness +refractivity +refractometer +refractometers +refractometric +refractometry +refractor +refractories +refractorily +refractoriness +refractors +refractory +refracts +refrain +refrained +refrainer +refrainers +refraining +refrainment +refrainments +refrains +reframe +reframed +reframes +reframing +refrangibility +refrangible +refrangibleness +refreeze +refreezes +refreezing +refresh +refreshed +refreshen +refreshened +refreshening +refreshens +refresher +refreshers +refreshes +refreshing +refreshingly +refreshment +refreshments +refried +refries +refrigerant +refrigerants +refrigerate +refrigerated +refrigerates +refrigerating +refrigeration +refrigerations +refrigerative +refrigerator +refrigerators +refrigeratory +refringence +refringences +refringent +refroze +refrozen +refry +refrying +refs +reft +refuel +refueled +refueling +refuelled +refuelling +refuels +refuge +refuged +refugee +refugeeism +refugees +refuges +refugia +refuging +refugium +refulgence +refulgency +refulgent +refulgently +refund +refundability +refundable +refunded +refunder +refunders +refunding +refundment +refundments +refunds +refurbish +refurbished +refurbisher +refurbishers +refurbishes +refurbishing +refurbishment +refurbishments +refurnish +refurnished +refurnishes +refurnishing +refusal +refusals +refuse +refused +refusednik +refusedniks +refusenik +refuseniks +refuser +refusers +refuses +refusing +refusnik +refusniks +refutability +refutable +refutably +refutal +refutals +refutation +refutations +refute +refuted +refuter +refuters +refutes +refuting +regain +regained +regainer +regainers +regaining +regains +regal +regale +regaled +regalement +regalements +regales +regalia +regaling +regalities +regality +regally +regard +regardant +regarded +regardful +regardfully +regardfulness +regarding +regardless +regardlessly +regardlessness +regards +regather +regathered +regathering +regathers +regatta +regattas +regave +regear +regeared +regearing +regears +regelate +regelated +regelates +regelating +regelation +regelations +regencies +regency +regenerable +regeneracy +regenerate +regenerated +regenerately +regenerateness +regenerates +regenerating +regeneration +regenerations +regenerative +regeneratively +regenerator +regenerators +regensburg +regent +regental +regents +regerminate +regerminated +regerminates +regerminating +regermination +reggae +reggaes +reggio +regicidal +regicide +regicides +regild +regilded +regilding +regilds +regime +regimen +regimens +regiment +regimental +regimentally +regimentals +regimentation +regimentations +regimented +regimenting +regiments +regimes +regina +region +regional +regionalism +regionalisms +regionalist +regionalistic +regionalists +regionalization +regionalizations +regionalize +regionalized +regionalizes +regionalizing +regionally +regionals +regions +regisseurs +register +registerable +registered +registerer +registerers +registering +registers +registrable +registrant +registrants +registrar +registrars +registration +registrations +registries +registry +regius +regive +regiven +regives +regiving +reglaze +reglazed +reglazes +reglazing +reglet +reglets +regna +regnal +regnant +regnum +regolith +regoliths +regorge +regorged +regorges +regorging +regosol +regosols +regrade +regraded +regrades +regrading +regraft +regrafted +regrafting +regrafts +regrant +regranted +regranting +regrants +regreen +regreened +regreening +regreens +regress +regressed +regresses +regressing +regression +regressions +regressive +regressively +regressiveness +regressivity +regressor +regressors +regret +regretful +regretfully +regretfulness +regretless +regrets +regrettable +regrettably +regretted +regretter +regretters +regretting +regrew +regrind +regrinding +regrinds +regroom +regroomed +regrooming +regrooms +regroove +regrooved +regrooves +regrooving +reground +regroup +regrouped +regrouping +regroups +regrow +regrowing +regrown +regrows +regrowth +regrowths +regular +regularities +regularity +regularization +regularizations +regularize +regularized +regularizer +regularizers +regularizes +regularizing +regularly +regulars +regulate +regulated +regulates +regulating +regulation +regulations +regulative +regulator +regulators +regulatory +reguli +reguline +regulus +reguluses +regurgitant +regurgitate +regurgitated +regurgitates +regurgitating +regurgitation +regurgitations +regurgitative +rehab +rehabbed +rehabber +rehabbers +rehabbing +rehabilitant +rehabilitants +rehabilitatable +rehabilitate +rehabilitated +rehabilitates +rehabilitating +rehabilitation +rehabilitations +rehabilitative +rehabilitator +rehabilitators +rehabs +rehandle +rehandled +rehandles +rehandling +rehang +rehanged +rehanging +rehangs +rehash +rehashed +rehashes +rehashing +rehear +reheard +rehearing +rehearings +rehears +rehearsal +rehearsals +rehearse +rehearsed +rehearser +rehearsers +rehearses +rehearsing +reheat +reheated +reheating +reheats +rehinge +rehinged +rehinges +rehinging +rehire +rehired +rehires +rehiring +rehospitalization +rehospitalizations +rehospitalize +rehospitalized +rehospitalizes +rehospitalizing +rehouse +rehoused +rehouses +rehousing +rehumanize +rehumanized +rehumanizes +rehumanizing +rehung +rehydratable +rehydrate +rehydrated +rehydrates +rehydrating +rehydration +rehydrations +rehypnotize +rehypnotized +rehypnotizes +rehypnotizing +reich +reichsmark +reichsmarks +reichstag +reidentified +reidentifies +reidentify +reidentifying +reification +reifications +reificatory +reified +reifier +reifiers +reifies +reify +reifying +reign +reigned +reigning +reignite +reignited +reignites +reigniting +reignition +reigns +reimage +reimagine +reimagined +reimagines +reimagining +reimbursable +reimburse +reimbursed +reimbursement +reimbursements +reimburses +reimbursing +reimmerse +reimmersed +reimmerses +reimmersing +reimplant +reimplantation +reimplanted +reimplanting +reimplants +reimport +reimportation +reimportations +reimported +reimporting +reimports +reimpose +reimposed +reimposes +reimposing +reimposition +reimpositions +reimpression +reimpressions +rein +reincarnate +reincarnated +reincarnates +reincarnating +reincarnation +reincarnations +reincorporate +reincorporated +reincorporates +reincorporating +reincorporation +reincorporations +reindeer +reindeers +reindict +reindicted +reindicting +reindictment +reindictments +reindicts +reindustrialization +reindustrialize +reindustrialized +reindustrializes +reindustrializing +reined +reinfection +reinfections +reinfestation +reinfestations +reinflate +reinflated +reinflates +reinflating +reinflation +reinforce +reinforceable +reinforced +reinforcement +reinforcements +reinforcer +reinforcers +reinforces +reinforcing +reinhabit +reinhabited +reinhabiting +reinhabits +reining +reinitialization +reinitializations +reinitialize +reinitialized +reinitializer +reinitializers +reinitializes +reinitializing +reinitiate +reinitiated +reinitiates +reinitiating +reinject +reinjected +reinjecting +reinjection +reinjections +reinjects +reinjure +reinjured +reinjures +reinjuries +reinjuring +reinjury +reink +reinked +reinking +reinks +reinnervate +reinnervated +reinnervates +reinnervating +reinnervation +reinoculate +reinoculated +reinoculates +reinoculating +reinoculation +reinoculations +reins +reinsert +reinserted +reinserting +reinsertion +reinsertions +reinserts +reinsman +reinsmen +reinspect +reinspected +reinspecting +reinspection +reinspections +reinspects +reinspire +reinspired +reinspires +reinspiring +reinstall +reinstallation +reinstalled +reinstalling +reinstalls +reinstate +reinstated +reinstatement +reinstatements +reinstates +reinstating +reinstitute +reinstituted +reinstitutes +reinstituting +reinstitution +reinstitutionalization +reinsurance +reinsurances +reinsure +reinsured +reinsurer +reinsurers +reinsures +reinsuring +reintegrate +reintegrated +reintegrates +reintegrating +reintegration +reintegrations +reintegrative +reinter +reinterpret +reinterpretation +reinterpretations +reinterpreted +reinterpreting +reinterprets +reinterred +reinterring +reinterrogate +reinterrogated +reinterrogates +reinterrogating +reinterrogation +reinterrogations +reinters +reinterview +reinterviewed +reinterviewing +reinterviews +reintroduce +reintroduced +reintroduces +reintroducing +reintroduction +reintroductions +reinvade +reinvaded +reinvades +reinvading +reinvasion +reinvasions +reinvent +reinvented +reinventing +reinvention +reinvents +reinvest +reinvested +reinvestigate +reinvestigated +reinvestigates +reinvestigating +reinvestigation +reinvestigations +reinvesting +reinvestment +reinvestments +reinvests +reinvigorate +reinvigorated +reinvigorates +reinvigorating +reinvigoration +reinvigorations +reinvigorator +reinvigorators +reis +reissue +reissued +reissues +reissuing +reiter +reiterate +reiterated +reiterates +reiterating +reiteration +reiterations +reiterative +reiteratively +reiterator +reiterators +reith +rejacket +rejacketed +rejacketing +rejackets +reject +rejected +rejectee +rejectees +rejecter +rejecters +rejecting +rejectingly +rejection +rejections +rejective +rejectivist +rejector +rejectors +rejects +rejig +rejigged +rejigger +rejiggered +rejiggering +rejiggers +rejigging +rejigs +rejoice +rejoiced +rejoicer +rejoicers +rejoices +rejoicing +rejoicingly +rejoicings +rejoin +rejoinder +rejoinders +rejoined +rejoining +rejoins +rejudge +rejudged +rejudges +rejudging +rejuggle +rejuggled +rejuggles +rejuggling +rejuvenate +rejuvenated +rejuvenates +rejuvenating +rejuvenation +rejuvenations +rejuvenator +rejuvenators +rejuvenescence +rejuvenescences +rejuvenescent +rekey +rekeyboard +rekeyed +rekeying +rekeys +rekindle +rekindled +rekindles +rekindling +reknit +reknits +reknitted +reknitting +relabel +relabeled +relabeling +relabels +relacquer +relacquered +relacquering +relacquers +relaid +relandscape +relandscaped +relandscapes +relandscaping +relapse +relapsed +relapser +relapsers +relapses +relapsing +relatable +relate +related +relatedly +relatedness +relater +relaters +relates +relating +relation +relational +relationally +relations +relationship +relationships +relative +relatively +relativeness +relatives +relativism +relativist +relativistic +relativistically +relativists +relativity +relativize +relativized +relativizes +relativizing +relator +relators +relaunch +relaunched +relaunches +relaunching +relax +relaxable +relaxant +relaxants +relaxation +relaxations +relaxed +relaxedly +relaxedness +relaxer +relaxers +relaxes +relaxin +relaxing +relay +relayed +relaying +relays +relearn +relearned +relearning +relearns +relearnt +releasability +releasable +releasably +release +released +releaser +releasers +releases +releasing +relegate +relegated +relegates +relegating +relegation +relegations +relend +relending +relends +relent +relented +relenting +relentless +relentlessly +relentlessness +relents +relevance +relevancy +relevant +relevantly +reliability +reliable +reliableness +reliably +reliance +reliant +reliantly +relic +relicense +relicensed +relicenses +relicensing +relicensure +relics +relict +reliction +relictions +relicts +relied +relief +reliefs +relier +reliers +relies +relievable +relieve +relieved +relievedly +reliever +relievers +relieves +relieving +relievo +relievos +relight +relighted +relighting +relights +religion +religionism +religionist +religionists +religionless +religions +religiose +religiosity +religious +religiously +religiousness +reline +relined +relines +relining +relink +relinked +relinking +relinks +relinquish +relinquished +relinquisher +relinquishers +relinquishes +relinquishing +relinquishment +relinquishments +reliquaries +reliquary +reliquefied +reliquefies +reliquefy +reliquefying +reliquiae +relish +relishable +relished +relishes +relishing +relit +relive +relived +relives +reliving +reload +reloaded +reloading +reloads +relocatable +relocate +relocated +relocatee +relocatees +relocates +relocating +relocation +relocations +relock +relocked +relocking +relocks +relook +relooked +relooking +relooks +relubricate +relubricated +relubricates +relubricating +relubrication +relubrications +relucent +reluct +reluctance +reluctancy +reluctant +reluctantly +reluctate +reluctated +reluctates +reluctating +reluctation +reluctations +relucted +relucting +reluctivity +relucts +relume +relumed +relumes +reluming +rely +relying +rem +remade +remain +remainder +remaindered +remaindering +remainders +remained +remaining +remains +remake +remaker +remakers +remakes +remaking +reman +remand +remanded +remanding +remandment +remandments +remands +remanence +remanent +remanned +remanning +remans +remanufacture +remanufactured +remanufacturer +remanufacturers +remanufactures +remanufacturing +remap +remapped +remapping +remaps +remark +remarkable +remarkableness +remarkably +remarked +remarker +remarkers +remarket +remarketed +remarketing +remarkets +remarking +remarks +remarque +remarques +remarriage +remarriages +remarried +remarries +remarry +remarrying +remaster +remastered +remastering +remasters +rematch +rematches +remate +remated +rematerialize +rematerialized +rematerializes +rematerializing +remates +remating +rembrandt +remeasure +remeasured +remeasurement +remeasurements +remeasures +remeasuring +remediability +remediable +remediableness +remediably +remedial +remedially +remediate +remediated +remediates +remediating +remediation +remediations +remedied +remedies +remediless +remedy +remedying +remeet +remeeting +remeets +remelt +remelted +remelting +remelts +remember +rememberability +rememberable +remembered +rememberer +rememberers +remembering +remembers +remembrance +remembrancer +remembrancers +remembrances +remerge +remerged +remerges +remerging +remet +remex +remiges +remigial +remigration +remigrations +remilitarization +remilitarizations +remilitarize +remilitarized +remilitarizes +remilitarizing +remind +reminded +reminder +reminders +remindful +reminding +reminds +remington +reminisce +reminisced +reminiscence +reminiscences +reminiscent +reminiscential +reminiscently +reminiscer +reminiscers +reminisces +reminiscing +remint +reminted +reminting +remints +remise +remised +remises +remising +remiss +remissibility +remissible +remissibly +remission +remissions +remissly +remissness +remit +remitment +remitments +remits +remittable +remittal +remittals +remittance +remittances +remitted +remittence +remittency +remittent +remittently +remitter +remitters +remitting +remix +remixed +remixes +remixing +remnant +remnants +remo +remobilization +remobilizations +remobilize +remobilized +remobilizes +remobilizing +remodel +remodeled +remodeler +remodelers +remodeling +remodelled +remodelling +remodels +remodification +remodifications +remodified +remodifies +remodify +remodifying +remoisten +remoistened +remoistening +remoistens +remold +remolded +remolding +remolds +remonetization +remonetizations +remonetize +remonetized +remonetizes +remonetizing +remonstrance +remonstrances +remonstrant +remonstrantly +remonstrants +remonstrate +remonstrated +remonstrates +remonstrating +remonstration +remonstrations +remonstrative +remonstratively +remonstrator +remonstrators +remora +remoras +remorse +remorseful +remorsefully +remorsefulness +remorseless +remorselessly +remorselessness +remote +remotely +remoteness +remoter +remotes +remotest +remotion +remotions +remotivate +remotivated +remotivates +remotivating +remotivation +remotivations +remoulins +remount +remounted +remounting +remounts +removability +removable +removableness +removably +removal +removals +remove +removed +removedly +removedness +remover +removers +removes +removing +rems +remuda +remudas +remunerability +remunerable +remunerably +remunerate +remunerated +remunerates +remunerating +remuneration +remunerations +remunerative +remuneratively +remunerativeness +remunerator +remunerators +remuneratory +remus +remy +remythologize +remythologized +remythologizes +remythologizing +renail +renailed +renailing +renails +renaissance +renal +rename +renamed +renames +renaming +renascence +renascences +renascent +renationalization +renationalizations +renationalize +renationalized +renationalizes +renationalizing +renaturation +renaturations +renature +renatured +renatures +renaturing +rencontre +rencontres +rencounter +rencountered +rencountering +rencounters +rend +rended +render +renderable +rendered +renderer +renderers +rendering +renderings +renders +rendezvous +rendezvoused +rendezvousing +rending +rendition +renditions +rends +rendzina +rendzinas +renegade +renegaded +renegades +renegading +renege +reneged +reneger +renegers +reneges +reneging +renegotiable +renegotiate +renegotiated +renegotiates +renegotiating +renegotiation +renegotiations +renest +renested +renesting +renests +renew +renewability +renewable +renewably +renewal +renewals +renewed +renewedly +renewer +renewers +renewing +renews +reniform +renin +renins +renitence +renitency +renitent +renminbi +rennet +rennin +renninogen +renninogens +reno +renogram +renograms +renographic +renography +renoir +renominate +renominated +renominates +renominating +renomination +renominations +renormalization +renormalizations +renormalize +renormalized +renormalizes +renormalizing +renounce +renounced +renouncement +renouncements +renouncer +renouncers +renounces +renouncing +renovascular +renovate +renovated +renovates +renovating +renovation +renovations +renovative +renovator +renovators +renown +renowned +rent +rentability +rentable +rental +rentals +rented +renter +renters +rentier +rentiers +renting +rents +renumber +renumbered +renumbering +renumbers +renunciation +renunciations +renunciative +renunciatory +reobserve +reobserved +reobserves +reobserving +reoccupation +reoccupied +reoccupies +reoccupy +reoccupying +reoccur +reoccurred +reoccurrence +reoccurrences +reoccurring +reoccurs +reoffer +reoffered +reoffering +reoffers +reoil +reoiled +reoiling +reoils +reopen +reopened +reopening +reopens +reoperate +reoperated +reoperates +reoperating +reoperation +reoperations +reorchestrate +reorchestrated +reorchestrates +reorchestrating +reorchestration +reorchestrations +reorder +reordered +reordering +reorders +reorganization +reorganizational +reorganizations +reorganize +reorganized +reorganizer +reorganizers +reorganizes +reorganizing +reorient +reorientate +reorientated +reorientates +reorientating +reorientation +reorientations +reoriented +reorienting +reorients +reoutfit +reoutfits +reoutfitted +reoutfitting +reovirus +reoviruses +reoxidation +reoxidations +reoxidize +reoxidized +reoxidizes +reoxidizing +rep +repack +repackage +repackaged +repackager +repackagers +repackages +repackaging +repacked +repacking +repacks +repaginate +repaginated +repaginates +repaginating +repagination +repaid +repaint +repainted +repainting +repaints +repair +repairability +repairable +repairably +repaired +repairer +repairers +repairing +repairman +repairmen +repairperson +repairpersons +repairs +repairwoman +repairwomen +repand +reparability +reparable +reparably +reparation +reparations +reparative +reparatory +repark +reparked +reparking +reparks +repartee +repartees +repartition +repartitioned +repartitioning +repartitions +repass +repassage +repassages +repassed +repasses +repassing +repast +repasted +repasting +repasts +repatch +repatched +repatches +repatching +repatriate +repatriated +repatriates +repatriating +repatriation +repatriations +repattern +repatterned +repatterning +repatterns +repave +repaved +repaves +repaving +repay +repayable +repaying +repayment +repayments +repays +repeal +repealable +repealed +repealer +repealers +repealing +repeals +repeat +repeatability +repeatable +repeated +repeatedly +repeater +repeaters +repeating +repeats +repechage +repechages +repeg +repegged +repegging +repegs +repel +repellant +repelled +repellence +repellency +repellent +repellently +repellents +repeller +repellers +repelling +repels +repent +repentance +repentant +repentantly +repented +repenter +repenters +repenting +repents +repeople +repeopled +repeoples +repeopling +repercussion +repercussions +repercussive +repertoire +repertoires +repertorial +repertories +repertory +repetend +repetends +repetition +repetitional +repetitions +repetitious +repetitiously +repetitiousness +repetitive +repetitively +repetitiveness +rephotograph +rephotographed +rephotographing +rephotographs +rephrase +rephrased +rephrases +rephrasing +repine +repined +repiner +repiners +repines +repining +replace +replaceable +replaced +replacement +replacements +replacer +replacers +replaces +replacing +replan +replanned +replanning +replans +replant +replantation +replantations +replanted +replanting +replants +replaster +replastered +replastering +replasters +replate +replated +replates +replating +replay +replayed +replaying +replays +repleader +repleaders +repledge +repledged +repledges +repledging +replenish +replenishable +replenished +replenisher +replenishers +replenishes +replenishing +replenishment +replenishments +replete +repleteness +repletion +repleviable +replevied +replevies +replevin +replevined +replevines +replevining +replevins +replevy +replevying +replica +replicability +replicable +replicas +replicase +replicases +replicate +replicated +replicates +replicating +replication +replications +replicative +replicon +replicons +replied +replier +repliers +replies +replot +replots +replotted +replotting +replumb +replumbed +replumbing +replumbs +reply +replying +repo +repolarization +repolarizations +repolarize +repolarized +repolarizes +repolarizing +repolish +repolished +repolishes +repolishing +repoll +repolled +repolling +repolls +repopularize +repopularized +repopularizes +repopularizing +repopulate +repopulated +repopulates +repopulating +repopulation +report +reportable +reportage +reported +reportedly +reporter +reporters +reporting +reportorial +reportorially +reports +repos +reposal +reposals +repose +reposed +reposeful +reposefully +reposefulness +reposer +reposers +reposes +reposing +reposit +reposited +repositing +reposition +repositioned +repositioning +repositions +repositories +repository +reposits +repossess +repossessed +repossesses +repossessing +repossession +repossessions +repossessor +repossessors +repot +repots +repotted +repotting +repoussé +repower +repowered +repowering +repowers +repp +repps +reprehend +reprehended +reprehending +reprehends +reprehensibility +reprehensible +reprehensibleness +reprehensibly +reprehension +reprehensions +reprehensive +represent +representability +representable +representation +representational +representationalism +representationalist +representationalists +representationally +representations +representative +representatively +representativeness +representatives +representativity +represented +representer +representers +representing +represents +repress +repressed +represser +repressers +represses +repressibility +repressible +repressing +repression +repressionist +repressionists +repressions +repressive +repressively +repressiveness +repressor +repressors +repressurize +repressurized +repressurizes +repressurizing +reprice +repriced +reprices +repricing +reprievable +reprieval +reprievals +reprieve +reprieved +reprieves +reprieving +reprimand +reprimanded +reprimanding +reprimands +reprint +reprinted +reprinter +reprinters +reprinting +reprints +reprisal +reprisals +reprise +reprised +reprises +reprising +repristinate +repristinated +repristinates +repristinating +repristination +repristinations +reprivatization +reprivatizations +reprivatize +reprivatized +reprivatizes +reprivatizing +repro +reproach +reproachable +reproachableness +reproachably +reproached +reproacher +reproachers +reproaches +reproachful +reproachfully +reproachfulness +reproaching +reproachingly +reprobance +reprobances +reprobate +reprobated +reprobates +reprobating +reprobation +reprobations +reprobative +reprobatory +reprocess +reprocessed +reprocesses +reprocessing +reproduce +reproduced +reproducer +reproducers +reproduces +reproducibility +reproducible +reproducibly +reproducing +reproduction +reproductions +reproductive +reproductively +reproductiveness +reproductives +reprogram +reprogramed +reprograming +reprogrammability +reprogrammable +reprogrammed +reprogramming +reprograms +reprographer +reprographers +reprographic +reprographics +reprography +reproof +reproofing +reproofs +repros +reprovable +reprove +reproved +reprover +reprovers +reproves +reproving +reprovingly +reprovision +reprovisioned +reprovisioning +reprovisions +reps +reptant +reptile +reptilelike +reptiles +reptilia +reptilian +reptilians +reptilium +republic +republican +republicanism +republicanization +republicanizations +republicanize +republicanized +republicanizes +republicanizing +republicans +republication +republications +republics +republish +republished +republisher +republishers +republishes +republishing +repudiate +repudiated +repudiates +repudiating +repudiation +repudiationist +repudiationists +repudiations +repudiative +repudiator +repudiators +repugn +repugnance +repugnancies +repugnancy +repugnant +repugnantly +repugned +repugning +repugns +repulse +repulsed +repulser +repulsers +repulses +repulsing +repulsion +repulsions +repulsive +repulsively +repulsiveness +repump +repumped +repumping +repumps +repunctuation +repurchase +repurchased +repurchases +repurchasing +repurified +repurifies +repurify +repurifying +reputability +reputable +reputably +reputation +reputational +reputations +repute +reputed +reputedly +reputes +reputing +request +requested +requester +requesters +requesting +requestor +requestors +requests +requiem +requiems +requiescat +requiescats +requirable +require +required +requirement +requirements +requirer +requirers +requires +requiring +requisite +requisitely +requisiteness +requisites +requisition +requisitioned +requisitioning +requisitions +requitable +requital +requitals +requite +requited +requiter +requiters +requites +requiting +rerack +reracked +reracking +reracks +reradiate +reradiated +reradiates +reradiating +reradiation +reradiations +reraise +reraised +reraises +reraising +reran +reread +rereading +rereadings +rereads +rerecord +rerecorded +rerecording +rerecords +reredos +reredoses +reregister +reregistered +reregistering +reregisters +reregistration +reregistrations +reregulate +reregulated +reregulates +reregulating +reregulation +rerelease +rereleased +rereleases +rereleasing +reremind +rereminded +rereminding +rereminds +rerepeat +rerepeated +rerepeating +rerepeats +rereview +rereviewed +rereviewing +rereviews +rereward +rerewards +rerig +rerigged +rerigging +rerigs +reroof +reroofed +reroofing +reroofs +reroute +rerouted +reroutes +rerouting +rerun +rerunning +reruns +res +resail +resailed +resailing +resails +resalable +resale +resales +resample +resampled +resamples +resampling +resat +resaw +resawed +resawing +resawn +resaws +rescale +rescaled +rescales +rescaling +rescan +rescanned +rescanning +rescans +reschedule +rescheduled +reschedules +rescheduling +reschool +reschooled +reschooling +reschools +rescind +rescindable +rescinded +rescinder +rescinders +rescinding +rescindment +rescindments +rescinds +rescission +rescissions +rescissory +rescore +rescored +rescores +rescoring +rescreen +rescreened +rescreening +rescreens +rescript +rescripts +rescuable +rescue +rescued +rescuer +rescuers +rescues +rescuing +resculpt +resculpted +resculpting +resculpts +reseal +resealable +resealed +resealing +reseals +research +researchable +researched +researcher +researchers +researches +researching +researchist +researchists +reseason +reseasoned +reseasoning +reseasons +reseat +reseated +reseating +reseats +reseau +resect +resectability +resectable +resected +resecting +resection +resections +resectoscope +resectoscopes +resects +resecure +resecured +resecures +resecuring +reseda +resedas +resee +reseed +reseeded +reseeding +reseeds +reseeing +reseen +resees +resegregate +resegregated +resegregates +resegregating +resegregation +resegregations +reselect +reselected +reselecting +reselection +reselections +reselects +resell +reseller +resellers +reselling +resells +resemblance +resemblances +resemblant +resemble +resembled +resembler +resemblers +resembles +resembling +resend +resending +resends +resensitize +resensitized +resensitizes +resensitizing +resent +resented +resentence +resentenced +resentences +resentencing +resentful +resentfully +resentfulness +resenting +resentment +resentments +resents +reserpine +reserpines +reservable +reservation +reservationist +reservationists +reservations +reserve +reserved +reservedly +reservedness +reserver +reservers +reserves +reservice +reserviced +reservices +reservicing +reserving +reservist +reservists +reservoir +reservoirs +reset +resets +resettable +resetter +resetters +resetting +resettle +resettled +resettlement +resettlements +resettles +resettling +resew +resewed +resewing +resewn +resews +resh +reshape +reshaped +reshaper +reshapers +reshapes +reshaping +reshes +reshingle +reshingled +reshingles +reshingling +reship +reshipment +reshipments +reshipped +reshipping +reships +reshod +reshoe +reshoed +reshoeing +reshoes +reshoot +reshooting +reshoots +reshot +reshow +reshowed +reshowing +reshown +reshows +reshuffle +reshuffled +reshuffles +reshuffling +resid +reside +resided +residence +residences +residencies +residency +resident +residential +residentially +residentiaries +residentiary +residents +resider +residers +resides +residing +resids +residua +residual +residually +residuals +residuary +residue +residues +residuum +resift +resifted +resifting +resifts +resight +resighted +resighting +resights +resign +resignation +resignations +resigned +resignedly +resignedness +resigner +resigners +resigning +resigns +resile +resiled +resiles +resilience +resiliency +resilient +resiliently +resilin +resiling +resilins +resilver +resilvered +resilvering +resilvers +resin +resinate +resinated +resinates +resinating +resined +resines +resiniferous +resining +resinoid +resinoids +resinous +resins +resist +resistance +resistances +resistant +resisted +resister +resisters +resistibility +resistible +resistibly +resisting +resistive +resistively +resistiveness +resistivities +resistivity +resistless +resistlessly +resistlessness +resistor +resistors +resists +resit +resite +resited +resites +resiting +resits +resitting +resittings +resituate +resituated +resituates +resituating +resize +resized +resizes +resizing +reslate +reslated +reslates +reslating +resoak +resoaked +resoaking +resoaks +resocialization +resocialize +resocialized +resocializes +resocializing +resod +resodded +resodding +resods +resold +resolder +resoldered +resoldering +resolders +resole +resoled +resoles +resolidification +resolidified +resolidifies +resolidify +resolidifying +resoling +resolubility +resoluble +resolubleness +resolute +resolutely +resoluteness +resolution +resolutions +resolvability +resolvable +resolvableness +resolve +resolved +resolvedly +resolvent +resolvents +resolver +resolvers +resolves +resolving +resonance +resonances +resonant +resonantly +resonate +resonated +resonates +resonating +resonation +resonations +resonator +resonators +resorb +resorbed +resorbing +resorbs +resorcin +resorcinol +resorcinols +resorcins +resorption +resorptions +resorptive +resort +resorted +resorter +resorters +resorting +resorts +resound +resounded +resounding +resoundingly +resounds +resource +resourceful +resourcefully +resourcefulness +resources +resow +resowed +resowing +resown +resows +respect +respectability +respectable +respectableness +respectably +respected +respecter +respecters +respectful +respectfully +respectfulness +respecting +respective +respectively +respectiveness +respects +respell +respelled +respelling +respells +respelt +respirability +respirable +respiration +respirational +respirations +respirator +respirators +respiratory +respire +respired +respires +respiring +respiritualize +respiritualized +respiritualizes +respiritualizing +respirometer +respirometers +respirometric +respirometry +respite +respited +respites +respiting +resplendence +resplendency +resplendent +resplendently +respond +responded +respondence +respondency +respondent +respondents +responder +responders +responding +responds +responsa +response +responses +responsibilities +responsibility +responsible +responsibleness +responsibly +responsions +responsive +responsively +responsiveness +responsorial +responsories +responsory +responsum +respot +respots +respotted +respotting +respray +resprayed +respraying +resprays +respring +respringing +resprings +resprout +resprouted +resprouting +resprouts +resprung +ressentiment +ressentiments +rest +restabilize +restabilized +restabilizes +restabilizing +restack +restacked +restacking +restacks +restage +restaged +restages +restaging +restamp +restamped +restamping +restamps +restante +restart +restartable +restarted +restarting +restarts +restate +restated +restatement +restatements +restates +restating +restaurant +restauranteur +restauranteurs +restaurants +restaurateur +restaurateurs +rested +rester +resters +restful +restfully +restfulness +restharrow +restharrows +restick +resticking +resticks +restiform +restimulate +restimulated +restimulates +restimulating +restimulation +resting +restitute +restituted +restitutes +restituting +restitution +restitutions +restive +restively +restiveness +restless +restlessly +restlessness +restock +restocked +restocking +restocks +restoke +restoked +restokes +restoking +restorability +restorable +restoral +restorals +restoration +restorations +restorative +restoratively +restorativeness +restoratives +restore +restored +restorer +restorers +restores +restoring +restrain +restrainable +restrained +restrainedly +restrainer +restrainers +restraining +restrains +restraint +restraints +restrengthen +restrengthened +restrengthening +restrengthens +restress +restressed +restresses +restressing +restrict +restricted +restrictedly +restricter +restricters +restricting +restriction +restrictionism +restrictionist +restrictionists +restrictions +restrictive +restrictively +restrictiveness +restrictor +restrictors +restricts +restrike +restrikes +restriking +restring +restringing +restrings +restroom +restrooms +restruck +restructure +restructured +restructures +restructuring +restrung +rests +restuck +restudied +restudies +restudy +restudying +restuff +restuffed +restuffing +restuffs +restyle +restyled +restyles +restyling +resublime +resublimed +resublimes +resubliming +resubmission +resubmissions +resubmit +resubmits +resubmitted +resubmitting +result +resultant +resultantly +resultants +resulted +resultful +resultfulness +resulting +resultless +results +resumable +resume +resumed +resumer +resumers +resumes +resuming +resummon +resummoned +resummoning +resummons +resumption +resumptions +resumé +resumés +resupinate +resupination +resupinations +resupine +resupplied +resupplies +resupply +resupplying +resurface +resurfaced +resurfacer +resurfacers +resurfaces +resurfacing +resurge +resurged +resurgence +resurgent +resurgently +resurges +resurging +resurrect +resurrected +resurrecting +resurrection +resurrectional +resurrectionist +resurrectionists +resurrections +resurrector +resurrectors +resurrects +resurvey +resurveyed +resurveying +resurveys +resuscitable +resuscitate +resuscitated +resuscitates +resuscitating +resuscitation +resuscitations +resuscitative +resuscitator +resuscitators +resveratrol +resynchronization +resynchronize +resyntheses +resynthesis +resynthesize +resynthesized +resynthesizes +resynthesizing +resystematize +resystematized +resystematizes +resystematizing +ret +retable +retables +retackle +retackled +retackles +retackling +retag +retagged +retagging +retags +retail +retailed +retailer +retailers +retailing +retails +retain +retainability +retainable +retained +retainer +retainers +retaining +retainment +retainments +retains +retake +retaken +retakes +retaking +retaliate +retaliated +retaliates +retaliating +retaliation +retaliations +retaliative +retaliator +retaliators +retaliatory +retard +retardant +retardants +retardate +retardates +retardation +retardations +retarded +retarder +retarders +retarding +retards +retarget +retargeted +retargeting +retargets +retaste +retasted +retastes +retasting +retaught +retch +retched +retches +retching +rete +reteach +reteaches +reteaching +reteam +reteamed +reteaming +reteams +retell +retelling +retellings +retells +retene +retenes +retention +retentions +retentive +retentively +retentiveness +retentivity +retest +retested +retesting +retests +retexture +retextured +retextures +retexturing +rethink +rethinker +rethinkers +rethinking +rethinks +rethought +rethread +rethreaded +rethreading +rethreads +retia +retiary +reticence +reticencies +reticency +reticent +reticently +reticle +reticles +reticula +reticular +reticulate +reticulated +reticulately +reticulates +reticulating +reticulation +reticulations +reticule +reticules +reticulocyte +reticulocytes +reticulocytic +reticuloendothelial +reticulum +retie +retied +reties +retiform +retighten +retightened +retightening +retightens +retile +retiled +retiles +retiling +retime +retimed +retimes +retiming +retina +retinacula +retinacular +retinaculum +retinae +retinal +retinas +retinene +retinenes +retinitis +retinoblastoma +retinoblastomas +retinoblastomata +retinoic +retinoid +retinoids +retinol +retinols +retinopathic +retinopathies +retinopathy +retinoscope +retinoscopes +retinoscopic +retinoscopies +retinoscopy +retinotectal +retinue +retinues +retinula +retinulae +retinular +retirant +retirants +retire +retired +retiredly +retiredness +retiree +retirees +retirement +retirements +retires +retiring +retiringly +retiringness +retold +retook +retool +retooled +retooling +retools +retorsion +retorsions +retort +retorted +retorter +retorters +retorting +retortion +retortions +retorts +retouch +retouched +retoucher +retouchers +retouches +retouching +retrace +retraceable +retraced +retracement +retracements +retracer +retracers +retraces +retracing +retract +retractability +retractable +retractation +retractations +retracted +retractibility +retractible +retractile +retractility +retracting +retraction +retractions +retractive +retractively +retractiveness +retractor +retractors +retracts +retrain +retrainable +retrained +retrainee +retrainees +retraining +retrains +retral +retrally +retransfer +retransferred +retransferring +retransfers +retransform +retransformation +retransformations +retransformed +retransforming +retransforms +retranslate +retranslated +retranslates +retranslating +retranslation +retranslations +retransmission +retransmissions +retransmit +retransmits +retransmitted +retransmitting +retread +retreaded +retreading +retreads +retreat +retreatant +retreatants +retreated +retreater +retreaters +retreating +retreats +retrench +retrenched +retrencher +retrenchers +retrenches +retrenching +retrenchment +retrenchments +retrial +retrials +retribution +retributions +retributive +retributively +retributory +retried +retries +retrievability +retrievable +retrievably +retrieval +retrievals +retrieve +retrieved +retriever +retrievers +retrieves +retrieving +retro +retroact +retroacted +retroacting +retroaction +retroactions +retroactive +retroactively +retroactivity +retroacts +retrocede +retroceded +retrocedes +retroceding +retrocession +retrocessions +retrodict +retrodicted +retrodicting +retrodiction +retrodictions +retrodictive +retrodicts +retrofire +retrofired +retrofires +retrofiring +retrofit +retrofits +retrofittable +retrofitted +retrofitter +retrofitters +retrofitting +retroflection +retroflections +retroflex +retroflexed +retroflexes +retroflexion +retroflexions +retrogradation +retrogradations +retrograde +retrograded +retrogradely +retrogrades +retrograding +retrogress +retrogressed +retrogresses +retrogressing +retrogression +retrogressions +retrogressive +retrogressively +retrolental +retroocular +retropack +retropacks +retroperitoneal +retroperitoneally +retropharyngeal +retroreflection +retroreflections +retroreflective +retroreflector +retroreflectors +retrorocket +retrorockets +retrorse +retrorsely +retros +retrospect +retrospected +retrospecting +retrospection +retrospections +retrospective +retrospectively +retrospectives +retrospects +retroussé +retroversion +retroversions +retroviral +retrovirus +retroviruses +retry +retrying +rets +retsina +retted +retting +retune +retuned +retunes +retuning +return +returnable +returnables +returned +returnee +returnees +returner +returners +returning +returns +retuse +retying +retype +retyped +retypes +retyping +reuben +reunification +reunifications +reunified +reunifies +reunify +reunifying +reunion +reunionism +reunionist +reunionistic +reunionists +reunions +reunite +reunited +reunites +reuniting +reupholster +reupholstered +reupholstering +reupholsters +reusability +reusable +reuse +reused +reuses +reusing +reuter +reutilization +reutilize +reutilized +reutilizes +reutilizing +rev +revaccinate +revaccinated +revaccinates +revaccinating +revaccination +revaccinations +revalidate +revalidated +revalidates +revalidating +revalidation +revalidations +revalorization +revalorizations +revalorize +revalorized +revalorizes +revalorizing +revaluate +revaluated +revaluates +revaluating +revaluation +revaluations +revalue +revalued +revalues +revaluing +revamp +revamped +revamping +revampment +revampments +revamps +revanche +revanches +revanchism +revanchist +revanchistic +revanchists +revascularization +revascularizations +reveal +revealable +revealed +revealer +revealers +revealing +revealingly +revealment +revealments +reveals +revegetate +revegetated +revegetates +revegetating +revegetation +revegetations +reveille +reveilles +revel +revelation +revelations +revelator +revelators +revelatory +reveled +reveler +revelers +reveling +revelled +reveller +revellers +revelling +revelries +revelrous +revelry +revels +revenant +revenants +revenge +revenged +revengeful +revengefully +revengefulness +revenger +revengers +revenges +revenging +revenue +revenuer +revenuers +revenues +reverb +reverbed +reverberant +reverberantly +reverberate +reverberated +reverberates +reverberating +reverberation +reverberations +reverberative +reverberatively +reverberator +reverberatories +reverberators +reverberatory +reverbing +reverbs +revere +revered +reverence +reverenced +reverencer +reverencers +reverences +reverencing +reverend +reverends +reverent +reverential +reverentially +reverently +reveres +reverie +reveries +reverification +revering +revers +reversal +reversals +reverse +reversed +reversely +reverser +reversers +reverses +reversibility +reversible +reversibleness +reversibles +reversibly +reversing +reversion +reversional +reversionary +reversioner +reversioners +reversions +revert +revertant +revertants +reverted +reverter +reverters +revertible +reverting +revertive +reverts +revery +revest +revested +revesting +revests +revet +revetment +revetments +revets +revetted +revetting +revictual +revictualed +revictualing +revictuals +review +reviewable +reviewed +reviewer +reviewers +reviewing +reviews +revile +reviled +revilement +revilements +reviler +revilers +reviles +reviling +revilingly +revillagigedo +revisable +revisal +revisals +revise +revised +reviser +revisers +revises +revising +revision +revisionary +revisionism +revisionist +revisionists +revisions +revisit +revisitation +revisitations +revisited +revisiting +revisits +revisor +revisors +revisory +revisualization +revisualizations +revitalization +revitalizations +revitalize +revitalized +revitalizes +revitalizing +revivable +revival +revivalism +revivalist +revivalistic +revivalists +revivals +revive +revived +reviver +revivers +revives +revivification +revivifications +revivified +revivifies +revivify +revivifying +reviving +reviviscence +reviviscent +revocability +revocable +revocation +revocations +revocatory +revoir +revoirs +revokable +revoke +revoked +revoker +revokers +revokes +revoking +revolt +revolted +revolter +revolters +revolting +revoltingly +revolts +revolute +revolution +revolutionaries +revolutionarily +revolutionariness +revolutionary +revolutionist +revolutionists +revolutionize +revolutionized +revolutionizer +revolutionizers +revolutionizes +revolutionizing +revolutions +revolvable +revolve +revolved +revolver +revolvers +revolves +revolving +revote +revoted +revotes +revoting +revs +revue +revues +revulsed +revulsion +revulsive +revved +revving +rewake +rewaked +rewaken +rewakened +rewakening +rewakens +rewakes +rewaking +reward +rewardable +rewarded +rewarder +rewarders +rewarding +rewardingly +rewards +rewarm +rewarmed +rewarming +rewarms +rewash +rewashed +rewashes +rewashing +reweave +reweaves +reweaving +reweigh +reweighed +reweighing +reweighs +rewet +rewets +rewetted +rewetting +rewind +rewinder +rewinders +rewinding +rewinds +rewire +rewired +rewires +rewiring +rewoke +rewoken +reword +reworded +rewording +rewordings +rewords +rework +reworked +reworking +reworks +rewound +rewove +rewoven +rewrap +rewrapped +rewrapping +rewraps +rewrite +rewriter +rewriters +rewrites +rewriting +rewritten +rewrote +rex +rexes +reye +reykjavik +reykjavík +reynard +reynards +reynolds +rezone +rezoned +rezones +rezoning +rhabdocoele +rhabdocoeles +rhabdom +rhabdomancer +rhabdomancers +rhabdomancy +rhabdome +rhabdomere +rhabdomeres +rhabdomes +rhabdoms +rhabdomyoma +rhabdomyomas +rhabdomyomata +rhabdomyosarcoma +rhabdomyosarcomas +rhabdomyosarcomata +rhabdovirus +rhabdoviruses +rhadamanthine +rhadamanthus +rhadamanthys +rhaetia +rhaetian +rhaetians +rhamnose +rhamnoses +rhaphe +rhapsode +rhapsodes +rhapsodic +rhapsodical +rhapsodically +rhapsodies +rhapsodist +rhapsodists +rhapsodize +rhapsodized +rhapsodizes +rhapsodizing +rhapsody +rhatanies +rhatany +rhea +rheas +rhebok +rheboks +rhenish +rhenishes +rhenium +rheological +rheologically +rheologist +rheologists +rheology +rheometer +rheometers +rheostat +rheostatic +rheostats +rheotactic +rheotaxis +rheotaxises +rhesus +rhesuses +rhetor +rhetoric +rhetorical +rhetorically +rhetorician +rhetoricians +rhetors +rheum +rheumatic +rheumatically +rheumatics +rheumatism +rheumatoid +rheumatoidal +rheumatoidally +rheumatologist +rheumatologists +rheumatology +rheumy +rhinal +rhine +rhineland +rhinencephala +rhinencephalic +rhinencephalon +rhinestone +rhinestoned +rhinestones +rhinitis +rhino +rhinoceros +rhinoceroses +rhinologist +rhinologists +rhinology +rhinopharyngitis +rhinoplastic +rhinoplasties +rhinoplasty +rhinos +rhinoscopies +rhinoscopy +rhinovirus +rhinoviruses +rhizanthous +rhizobia +rhizobial +rhizobium +rhizocephalan +rhizocephalans +rhizocephalous +rhizoctonia +rhizoctonias +rhizogenetic +rhizogenic +rhizoid +rhizoidal +rhizoids +rhizomatous +rhizome +rhizomes +rhizomic +rhizophagous +rhizoplane +rhizoplanes +rhizopod +rhizopodan +rhizopodans +rhizopodous +rhizopods +rhizopus +rhizopuses +rhizosphere +rhizospheres +rhizotomies +rhizotomy +rho +rhodamine +rhodamines +rhode +rhodes +rhodesia +rhodesian +rhodesians +rhodium +rhodochrosite +rhodochrosites +rhododendron +rhododendrons +rhodolite +rhodolites +rhodomontade +rhodomontaded +rhodomontades +rhodomontading +rhodonite +rhodonites +rhodope +rhodopsin +rhodopsins +rhodora +rhodoras +rhomb +rhombencephalic +rhombencephalon +rhombencephalons +rhombi +rhombic +rhombohedra +rhombohedral +rhombohedron +rhombohedrons +rhomboid +rhomboidal +rhomboidei +rhomboideus +rhomboids +rhombs +rhombus +rhombuses +rhonchal +rhonchi +rhonchial +rhonchus +rhone +rhos +rhubarb +rhubarbs +rhumb +rhumba +rhumbaed +rhumbaing +rhumbas +rhumbs +rhus +rhuses +rhyme +rhymed +rhymeless +rhymer +rhymers +rhymes +rhymester +rhymesters +rhyming +rhynchocephalian +rhynchocephalians +rhyolite +rhyolites +rhyolitic +rhythm +rhythmic +rhythmical +rhythmically +rhythmicity +rhythmics +rhythmist +rhythmists +rhythmization +rhythmizations +rhythmize +rhythmized +rhythmizes +rhythmizing +rhythms +rhytidectomies +rhytidectomy +rhytidome +rhytidomes +rhyton +rhytons +rhône +rial +rials +rialto +rialtos +riant +riantly +riata +riatas +rib +ribald +ribaldries +ribaldry +ribalds +riband +ribands +ribavirin +ribavirins +ribband +ribbands +ribbed +ribbentrop +ribber +ribbers +ribbing +ribbings +ribbon +ribboned +ribbonfish +ribbonfishes +ribboning +ribbonlike +ribbons +ribbony +ribby +ribcage +ribcages +ribes +ribgrass +ribgrasses +riblet +riblets +riboflavin +ribonuclease +ribonucleases +ribonucleic +ribonucleoprotein +ribonucleoproteins +ribonucleoside +ribonucleosides +ribonucleotide +ribonucleotides +ribose +ribosomal +ribosome +ribosomes +ribozymes +ribs +ribwort +ribworts +rica +rican +ricans +riccio +riccocheted +riccocheting +riccochets +rice +ricebird +ricebirds +riced +ricer +ricercar +ricercare +ricercari +ricercars +ricers +rices +rich +richard +riche +richelieu +richen +richened +richening +richens +richer +riches +richest +richfield +richly +richmond +richness +richter +richweed +richweeds +ricin +ricing +ricinoleic +ricins +rick +ricked +ricketier +ricketiest +ricketiness +rickets +rickettsia +rickettsiae +rickettsial +rickettsioses +rickettsiosis +rickety +rickey +rickeys +ricking +rickrack +ricks +ricksha +rickshas +rickshaw +rickshaws +rico +ricochet +ricocheted +ricocheting +ricochets +ricotta +ricottas +ricrac +rictal +rictus +rictuses +rid +ridable +riddance +ridded +ridden +ridder +ridders +ridding +riddle +riddled +riddler +riddlers +riddles +riddling +ride +rideable +rider +riderless +riders +ridership +riderships +rides +ridesharing +ridesharings +ridge +ridgeback +ridgebacks +ridged +ridgeline +ridgelines +ridgeling +ridgelings +ridgepole +ridgepoles +ridges +ridgier +ridgiest +ridging +ridgling +ridglings +ridgy +ridicule +ridiculed +ridiculer +ridiculers +ridicules +ridiculing +ridiculous +ridiculously +ridiculousness +riding +ridings +ridley +ridleys +ridotto +ridottos +rids +riel +riels +riemann +riemannian +riesling +rieslings +rifampicin +rifampicins +rifampin +rifampins +rifamycin +rifamycins +rife +rifely +rifer +rifest +riff +riffed +riffian +riffians +riffing +riffle +riffled +riffler +rifflers +riffles +riffling +riffraff +riffs +rifle +riflebird +riflebirds +rifled +rifleman +riflemen +rifler +riflers +riflery +rifles +riflescope +riflescopes +rifling +rift +rifted +rifting +rifts +rig +rigadoon +rigadoons +rigamarole +rigamaroles +rigatoni +rigaudon +rigaudons +rigel +rigged +rigger +riggers +rigging +riggings +right +righted +righteous +righteously +righteousness +righter +righters +rightest +rightful +rightfully +rightfulness +righties +righting +rightish +rightism +rightist +rightists +rightly +rightmost +rightness +righto +rights +rightward +rightwards +righty +rigid +rigidification +rigidifications +rigidified +rigidifies +rigidify +rigidifying +rigidities +rigidity +rigidly +rigidness +rigmarole +rigmaroles +rigor +rigorism +rigorist +rigoristic +rigorists +rigorous +rigorously +rigorousness +rigors +rigs +rigueur +rijstafel +rijstafels +rijstaffel +rijstaffels +rijsttafel +rijsttaffel +rijsttaffels +riksmaal +riksmal +rile +riled +riles +riley +riling +rill +rille +rilles +rillet +rillets +rillettes +rills +rim +rima +rimbaud +rime +rimed +rimer +rimers +rimes +rimester +rimesters +rimfire +rimier +rimiest +riming +rimini +rimland +rimlands +rimless +rimmed +rimming +rimose +rimosely +rimosity +rimple +rimpled +rimples +rimpling +rimrock +rims +rimsky +rimy +rind +rinded +rinderpest +rinderpests +rinds +rinforzando +ring +ringbark +ringbarked +ringbarking +ringbarks +ringbolt +ringbolts +ringbone +ringbones +ringdove +ringdoves +ringed +ringent +ringer +ringers +ringgit +ringgits +ringhals +ringhalses +ringing +ringingly +ringleader +ringleaders +ringlet +ringleted +ringlets +ringlike +ringmaster +ringmasters +ringneck +ringnecks +rings +ringside +ringsider +ringsiders +ringsides +ringstraked +ringtail +ringtails +ringtaw +ringtoss +ringworm +ringworms +rink +rinks +rinky +rinsable +rinse +rinsed +rinser +rinsers +rinses +rinsible +rinsing +rio +rioja +riot +rioted +rioter +rioters +rioting +riotous +riotously +riotousness +riots +rip +riparian +ripcord +ripcords +ripe +ripely +ripen +ripened +ripener +ripeners +ripeness +ripening +ripens +riper +ripest +ripieni +ripieno +ripienos +riposte +riposted +ripostes +riposting +ripped +ripper +rippers +ripping +ripple +rippled +ripplegrass +ripplegrasses +rippler +ripplers +ripples +ripplet +ripplets +ripplier +rippliest +rippling +ripplingly +ripply +riprap +riprapped +riprapping +ripraps +rips +ripsaw +ripsaws +ripsnorter +ripsnorters +ripsnorting +ripstop +riptide +riptides +ripuarian +ripuarians +rise +risen +riser +risers +rises +risibilities +risibility +risible +risibles +risibly +rising +risings +risk +risked +risker +riskers +riskier +riskiest +riskiness +risking +riskless +risks +risky +risorgimento +risotto +risottos +risqué +rissole +rissoles +rissolé +ritalin +ritard +ritardando +ritards +rite +rites +ritornelli +ritornello +ritornellos +ritter +ritual +ritualism +ritualist +ritualistic +ritualistically +ritualists +rituality +ritualization +ritualizations +ritualize +ritualized +ritualizes +ritualizing +ritually +rituals +ritz +ritzier +ritziest +ritziness +ritzy +rivage +rivages +rival +rivaled +rivaling +rivalled +rivalling +rivalries +rivalrous +rivalry +rivals +rive +rived +riven +river +riverbank +riverbanks +riverbed +riverbeds +riverboat +riverboats +riverfront +riverfronts +riverhead +riverheads +riverine +riverines +rivers +riverside +riversides +riverward +riverwards +riverweed +riverweeds +rives +rivet +riveted +riveter +riveters +riveting +rivetingly +rivets +riviera +riving +rivière +rivulet +rivulets +riyadh +riyal +rizzio +rna +rns +roach +roached +roaches +roaching +road +roadability +roadbed +roadbeds +roadblock +roadblocks +roadholding +roadhouse +roadhouses +roadie +roadies +roadkill +roadkills +roadless +roadrunner +roadrunners +roads +roadside +roadsides +roadstead +roadsteads +roadster +roadsters +roadway +roadways +roadwork +roadworthier +roadworthiest +roadworthiness +roadworthy +roady +roam +roamed +roamer +roamers +roaming +roams +roan +roanoke +roans +roar +roared +roarer +roarers +roaring +roaringly +roars +roast +roasted +roaster +roasters +roasting +roasts +rob +robalo +robalos +roband +robands +robbed +robber +robberies +robbers +robbery +robbing +robe +robed +robert +robertson +robes +robespierre +robin +robing +robins +robinson +roble +robles +roborant +roborants +robot +robotic +robotically +roboticize +roboticized +roboticizes +roboticizing +robotics +robotism +robotistic +robotization +robotizations +robotize +robotized +robotizes +robotizing +robots +robs +robust +robusta +robustious +robustiously +robustiousness +robustly +robustness +roc +rocaille +rocambole +rocamboles +roche +rochefoucauld +rochelle +roches +rochester +rochet +rochets +rock +rock'n'roll +rockabilly +rockaby +rockabye +rockaway +rockaways +rockbound +rocked +rockefeller +rocker +rockeries +rockers +rockery +rocket +rocketed +rocketeer +rocketeers +rocketing +rocketry +rockets +rocketsonde +rocketsondes +rockfall +rockfalls +rockfish +rockfishes +rockhopper +rockhoppers +rockhounding +rockier +rockies +rockiest +rockiness +rocking +rockingly +rocklike +rockling +rocklings +rockoon +rockoons +rockrose +rockroses +rocks +rockshaft +rockshafts +rockslide +rockslides +rockweed +rockweeds +rockwork +rocky +rococo +rocs +rod +rodded +rodding +rode +rodent +rodenticide +rodenticides +rodents +rodeo +rodeos +rodes +rodin +rodless +rodlike +rodman +rodmen +rodomontade +rodomontaded +rodomontades +rodomontading +rods +roe +roebuck +roebucks +roentgen +roentgenize +roentgenized +roentgenizes +roentgenizing +roentgenogram +roentgenograms +roentgenograph +roentgenographic +roentgenographically +roentgenographs +roentgenography +roentgenologic +roentgenological +roentgenologically +roentgenologist +roentgenologists +roentgenology +roentgenoscope +roentgenoscopes +roentgenoscopic +roentgenoscopy +roentgenotherapies +roentgenotherapy +roentgens +roes +rogation +rogations +rogatory +roger +roget +rogue +rogued +rogueing +rogueries +roguery +rogues +roguing +roguish +roguishly +roguishness +roil +roiled +roilier +roiliest +roiling +roils +roily +roister +roistered +roisterer +roisterers +roistering +roisterous +roisterously +roisters +rolamite +rolamites +roland +role +roles +rolf +rolfed +rolfer +rolfers +rolfing +rolfs +roll +rollaway +rollback +rollbacks +rolle +rolled +roller +rollers +rollick +rollicked +rollicking +rollickingly +rollicks +rollicksome +rollicky +rolling +rollmops +rollout +rollouts +rollover +rollovers +rolls +rolltop +rollway +rollways +rolodex +roly +roma +romagna +romaic +romaine +roman +romance +romanced +romancer +romancers +romances +romancing +romanesque +romania +romanian +romanians +romanic +romanics +romanies +romanism +romanist +romanistic +romanists +romanization +romanizations +romanize +romanized +romanizes +romanizing +romano +romanoff +romanoffs +romanov +romanovs +romans +romansch +romansh +romantic +romantically +romanticism +romanticist +romanticists +romanticization +romanticizations +romanticize +romanticized +romanticizes +romanticizing +romantics +romany +romaunt +romaunts +romblon +rome +romeldale +romeldales +romeo +romeos +romish +romishly +romishness +rommel +romney +romp +romped +romper +rompers +romping +romps +roms +romulus +roncevaux +rondeau +rondeaux +rondel +rondelet +rondelets +rondelle +rondelles +rondels +rondo +rondos +rondure +rondures +ronnel +ronnels +ronyon +ronyons +rood +roods +roof +roofed +roofer +roofers +roofing +roofless +rooflike +roofline +rooflines +roofs +rooftop +rooftops +rooftree +rooftrees +rook +rooked +rookeries +rookery +rookie +rookies +rooking +rooks +rooky +room +roomed +roomer +roomers +roomette +roomettes +roomful +roomfuls +roomier +roomiest +roomily +roominess +rooming +roommate +roommates +rooms +roomy +roorback +roorbacks +roosevelt +roost +roosted +rooster +roosterfish +roosterfishes +roosters +roosting +roosts +root +rootage +rootages +rooted +rootedness +rooter +rooters +roothold +rootholds +rootier +rootiest +rootiness +rooting +rootless +rootlessness +rootlet +rootlets +rootlike +roots +rootstalk +rootstalks +rootstock +rootstocks +rootworm +rootworms +rooty +rope +roped +ropedancer +ropedancers +ropedancing +ropelike +roper +ropers +ropery +ropes +ropewalk +ropewalker +ropewalkers +ropewalks +ropeway +ropeways +ropey +ropier +ropiest +ropily +ropiness +roping +ropy +roque +roquefort +roquelaure +roquelaures +roquet +roqueted +roqueting +roquets +roquette +rorqual +rorquals +rorschach +rosa +rosacea +rosaceous +rosalind +rosanilin +rosaniline +rosanilines +rosanilins +rosarian +rosarians +rosaries +rosary +roscius +roscoe +roscoes +rose +roseate +roseately +rosebay +rosebays +rosebud +rosebuds +rosebush +rosebushes +rosefish +rosefishes +roselle +roselles +rosemaries +rosemary +rosencrantz +roseola +roseolar +roseolas +roseroot +roseroots +roses +rosetta +rosette +rosettes +rosewater +rosewood +rosewoods +rosh +rosicrucian +rosicrucianism +rosicrucians +rosier +rosiest +rosily +rosin +rosined +rosiness +rosining +rosins +rosinweed +rosinweeds +rosiny +rossetti +rossini +rostella +rostellar +rostellate +rostellum +roster +rosters +rostock +rostra +rostral +rostrally +rostrate +rostrum +rostrums +rosy +rosé +rosés +rot +rota +rotameter +rotameters +rotarian +rotarians +rotaries +rotary +rotas +rotatable +rotate +rotated +rotates +rotating +rotation +rotational +rotationally +rotations +rotative +rotatively +rotator +rotatores +rotators +rotatory +rotavirus +rotaviruses +rote +rotenone +rotes +rotgut +rothschild +rothschilds +roti +rotifer +rotiferal +rotiferous +rotifers +rotiform +rotisserie +rotisseries +rotl +rotls +roto +rotogravure +rotogravures +rotor +rotorcraft +rotorcrafts +rotors +rotos +rototill +rototilled +rototiller +rototillers +rototilling +rototills +rots +rotted +rotten +rottener +rottenest +rottenly +rottenness +rottenstone +rottenstones +rotter +rotterdam +rotters +rotting +rottweiler +rottweilers +rotund +rotunda +rotundas +rotundity +rotundly +rotundness +roturier +roturiers +rouble +roubles +rouen +rouge +rouged +rouges +rough +roughage +roughback +roughbacks +roughcast +roughcaster +roughcasters +roughcasting +roughcasts +roughdried +roughdries +roughdry +roughdrying +roughed +roughen +roughened +roughening +roughens +rougher +roughers +roughest +roughhew +roughhewed +roughhewing +roughhewn +roughhews +roughhouse +roughhoused +roughhouses +roughhousing +roughies +roughing +roughish +roughleg +roughlegs +roughly +roughneck +roughnecks +roughness +roughrider +roughriders +roughs +roughshod +roughy +rouging +rouille +roulade +roulades +rouleau +rouleaus +rouleaux +roulette +rouletted +roulettes +rouletting +roumanian +round +roundabout +roundaboutness +roundabouts +rounded +roundedness +roundel +roundelay +roundelays +roundels +rounder +rounders +roundest +roundhead +roundheaded +roundheadedness +roundheads +roundhouse +roundhouses +rounding +roundish +roundishness +roundlet +roundlets +roundly +roundness +roundoff +rounds +roundsman +roundsmen +roundtable +roundtables +roundtrip +roundtrips +roundup +roundups +roundwood +roundworm +roundworms +roup +roups +rouse +rouseabout +rouseabouts +roused +rousement +rousements +rouser +rousers +rouses +rousing +rousingly +rousseau +rousseauism +rousseauist +rousseauistic +rousseauists +roussillon +roust +roustabout +roustabouts +rousted +rouster +rousters +rousting +rousts +rout +route +routed +routeman +routemen +router +routers +routes +routeway +routeways +routine +routinely +routines +routing +routings +routinism +routinist +routinists +routinization +routinizations +routinize +routinized +routinizes +routinizing +routs +roux +roué +roués +rove +roved +rover +rovers +roves +roving +row +rowan +rowanberries +rowanberry +rowans +rowboat +rowboats +rowdier +rowdies +rowdiest +rowdily +rowdiness +rowdy +rowdyish +rowdyism +rowed +rowel +roweled +roweling +rowels +rowen +rowens +rower +rowers +rowing +rowlandson +rowlock +rowlocks +rows +royal +royalism +royalist +royalists +royally +royalmast +royalmasts +royals +royalties +royalty +rpm +rsvp +ruana +ruanas +rub +rubaiyat +rubasse +rubasses +rubato +rubatos +rubbed +rubber +rubberier +rubberiest +rubberize +rubberized +rubberizes +rubberizing +rubberlike +rubberneck +rubbernecked +rubbernecker +rubberneckers +rubbernecking +rubbernecks +rubbers +rubberstamp +rubberstamps +rubbery +rubbing +rubbings +rubbish +rubbishing +rubbishy +rubble +rubbled +rubbles +rubblework +rubbling +rubbly +rubdown +rubdowns +rube +rubefacient +rubefacients +rubefaction +rubefactions +rubella +rubellite +rubellites +rubenesque +rubens +rubeola +rubeolar +rubes +rubescence +rubescent +rubicon +rubicund +rubicundity +rubidium +rubies +rubiginose +rubiginous +rubik +rubious +ruble +rubles +ruboff +ruboffs +rubout +rubouts +rubredoxin +rubredoxins +rubric +rubrical +rubrically +rubricate +rubricated +rubricates +rubricating +rubrication +rubrications +rubricator +rubricators +rubrician +rubricians +rubrics +rubs +rubus +ruby +rubythroat +rubythroats +rubáiyát +ruche +ruched +ruches +ruching +ruck +rucked +rucking +rucks +rucksack +rucksacks +ruckus +ruckuses +ruction +ructions +rudbeckia +rudd +rudder +rudderfish +rudderfishes +rudderless +rudderpost +rudderposts +rudders +rudderstock +rudderstocks +ruddier +ruddiest +ruddily +ruddiness +ruddle +ruddled +ruddles +ruddling +ruddock +ruddocks +rudds +ruddy +rude +rudely +rudeness +rudenesses +ruder +ruderal +ruderals +rudest +rudiment +rudimental +rudimentarily +rudimentariness +rudimentary +rudiments +rudolf +rue +rued +rueful +ruefully +ruefulness +ruer +ruers +rues +rufescence +rufescent +ruff +ruffe +ruffed +ruffes +ruffian +ruffianism +ruffianly +ruffians +ruffing +ruffle +ruffled +ruffler +rufflers +ruffles +ruffling +ruffly +ruffs +rufiyaa +rufiyaas +rufous +rufus +rug +ruga +rugae +rugate +rugby +rugged +ruggedization +ruggedizations +ruggedize +ruggedized +ruggedizes +ruggedizing +ruggedly +ruggedness +rugola +rugosa +rugose +rugosely +rugosity +rugous +rugs +rugulose +ruin +ruinable +ruinate +ruination +ruinations +ruined +ruiner +ruiners +ruing +ruining +ruinous +ruinously +ruinousness +ruins +rulable +rule +ruled +ruleless +ruler +rulers +rulership +rulerships +rules +rulier +ruliest +ruling +rulings +ruly +rum +rumaki +rumakis +rumania +rumanian +rumanians +rumba +rumbaed +rumbaing +rumbas +rumble +rumbled +rumbler +rumblers +rumbles +rumbling +rumblingly +rumblings +rumbly +rumbustious +rumbustiously +rumbustiousness +rumen +rumens +rumina +ruminal +ruminant +ruminantly +ruminants +ruminate +ruminated +ruminates +ruminating +rumination +ruminations +ruminative +ruminatively +ruminator +ruminators +rummage +rummaged +rummager +rummagers +rummages +rummaging +rummer +rummers +rummest +rummier +rummies +rummiest +rummy +rumor +rumored +rumoring +rumormonger +rumormongered +rumormongering +rumormongers +rumors +rump +rumpelstiltskin +rumple +rumpled +rumples +rumplier +rumpliest +rumpling +rumply +rumps +rumpus +rumpuses +rumrunner +rumrunners +rums +run +runabout +runabouts +runagate +runagates +runaround +runarounds +runaway +runaways +runback +runbacks +runcible +runcinate +rundle +rundles +rundlet +rundlets +rundown +rundowns +rune +runes +rung +rungs +runic +runless +runlet +runlets +runnable +runnel +runnels +runner +runners +runnier +runniest +running +runnings +runny +runnymede +runoff +runoffs +runout +runouts +runover +runovers +runs +runt +runtime +runtiness +runtish +runts +runty +runway +runways +runza +runzas +rupee +rupees +rupiah +rupiahs +rupicolous +rupturable +rupture +ruptured +ruptures +rupturing +rural +ruralism +ruralist +ruralists +ruralities +rurality +ruralization +ruralizations +ruralize +ruralized +ruralizes +ruralizing +rurally +rurban +ruritan +ruritania +ruritanian +ruritans +ruse +ruses +rush +rushed +rushee +rushees +rusher +rushers +rushes +rushier +rushiest +rushing +rushlight +rushlights +rushmore +rushy +rusine +rusk +ruskin +ruskinian +rusks +russell +russet +russeting +russets +russetting +russia +russian +russianization +russianizations +russianize +russianized +russianizes +russianizing +russianness +russians +russification +russifications +russified +russifies +russify +russifying +russki +russkie +russkies +russkis +russky +russo +russophile +russophiles +russophilia +russophobe +russophobes +russophobia +rust +rustable +rusted +rustic +rustical +rustically +rusticate +rusticated +rusticates +rusticating +rustication +rustications +rusticator +rusticators +rusticities +rusticity +rustics +rustier +rustiest +rustily +rustiness +rusting +rustle +rustled +rustler +rustlers +rustles +rustless +rustling +rustlingly +rustproof +rustproofed +rustproofing +rustproofs +rusts +rusty +rut +rutabaga +rutabagas +ruth +ruthenia +ruthenian +ruthenians +ruthenic +ruthenious +ruthenium +rutherford +rutherfordium +rutherfords +ruthful +ruthfully +ruthfulness +ruthless +ruthlessly +ruthlessness +rutilant +rutile +rutiles +ruts +rutted +ruttier +ruttiest +ruttiness +rutting +ruttish +ruttishly +ruttishness +rutty +ruwenzori +rwanda +rwandan +rwandans +rya +ryas +rye +ryegrass +ryegrasses +ryes +ryukyu +râle +râles +réaumur +réchauffé +réclame +régime +régimes +régisseur +régisseurs +rémoulade +répondez +réseau +réseaus +réseaux +résistance +résumé +résumés +réunion +rôle +rôles +röntgen +röntgens +rügen +s +s'le +s'n +s'ns +saanen +saaremaa +saarland +saarlander +saarlanders +sabadilla +sabadillas +sabal +sabals +sabaoth +sabayon +sabayons +sabbat +sabbatarian +sabbatarianism +sabbatarians +sabbath +sabbaths +sabbatic +sabbatical +sabbaticals +sabbats +sabellian +sabellians +saber +sabered +sabering +sabermetrician +sabermetricians +sabermetrics +sabers +sabian +sabians +sabin +sabine +sabines +sabins +sable +sablefish +sablefishes +sables +sabot +sabotage +sabotaged +sabotages +sabotaging +saboteur +saboteurs +sabots +sabra +sabras +sabre +sabred +sabres +sabring +sabulose +sabulosity +sabulous +sac +sacahuista +sacahuiste +sacajawea +sacaton +sacatons +saccade +saccades +saccadic +saccate +saccharase +saccharases +saccharate +saccharates +saccharic +saccharide +saccharides +saccharification +saccharifications +saccharified +saccharifies +saccharify +saccharifying +saccharimeter +saccharimeters +saccharimetry +saccharin +saccharine +saccharinely +saccharinity +saccharoid +saccharoidal +saccharometer +saccharometers +saccharomyces +saccharomycete +saccharomycetes +saccharomycetic +saccharomycetous +saccharose +saccharoses +saccular +sacculate +sacculated +sacculation +sacculations +saccule +saccules +sacculi +sacculus +sacerdotal +sacerdotalism +sacerdotalist +sacerdotalists +sacerdotally +sachem +sachemic +sachems +sacher +sachet +sacheted +sachets +sack +sackbut +sackbuts +sackcloth +sacked +sacker +sackers +sackful +sackfuls +sacking +sackings +sacks +saclike +sacque +sacques +sacra +sacral +sacrament +sacramental +sacramentalism +sacramentalist +sacramentalists +sacramentally +sacramentals +sacramentarian +sacramentarianism +sacramentarians +sacramento +sacraments +sacraria +sacrarium +sacred +sacredly +sacredness +sacrifice +sacrificed +sacrificer +sacrificers +sacrifices +sacrificial +sacrificially +sacrificing +sacrificingly +sacrilege +sacrileges +sacrilegious +sacrilegiously +sacrilegiousness +sacrilegist +sacrilegists +sacristan +sacristans +sacristies +sacristy +sacrococcygeal +sacroiliac +sacroiliacs +sacrolumbar +sacrosanct +sacrosanctity +sacrosciatic +sacrum +sacs +sad +sadden +saddened +saddening +saddens +sadder +saddest +saddhu +saddhus +saddle +saddleback +saddlebacks +saddlebag +saddlebags +saddlebow +saddlebows +saddlebred +saddlebreds +saddlecloth +saddlecloths +saddled +saddleless +saddler +saddleries +saddlers +saddlery +saddles +saddletree +saddletrees +saddling +sadducean +sadducee +sadduceeism +sadducees +sadhe +sadhes +sadhu +sadhus +sadiron +sadirons +sadism +sadist +sadistic +sadistically +sadists +sadly +sadness +sadnesses +sadomasochism +sadomasochist +sadomasochistic +sadomasochists +safar +safari +safaris +safe +safecracker +safecrackers +safecracking +safeguard +safeguarded +safeguarding +safeguards +safekeeping +safelight +safelights +safely +safeness +safer +safes +safest +safetied +safeties +safety +safetying +safetyman +safetymen +safflower +safflowers +saffron +safranin +safranine +safranines +safranins +safrole +safroles +sag +saga +sagacious +sagaciously +sagaciousness +sagacity +sagamore +sagamores +sagas +sage +sagebrush +sagebrushes +sagely +sageness +sager +sages +sagest +saggar +saggars +sagged +sagger +saggers +sagging +saggy +sagitta +sagittal +sagittally +sagittarian +sagittarians +sagittarius +sagittate +sago +sagos +sagrada +sags +saguaro +saguaros +sahaptian +sahara +saharan +sahel +sahelian +sahib +sahibs +sahuaro +sahuaros +said +saiga +saigas +saigon +sail +sailable +sailboard +sailboarded +sailboarder +sailboarders +sailboarding +sailboards +sailboat +sailboater +sailboaters +sailboating +sailboats +sailcloth +sailed +sailer +sailers +sailfish +sailfishes +sailing +sailor +sailorman +sailormen +sailors +sailplane +sailplaned +sailplaner +sailplaners +sailplanes +sailplaning +sails +saimin +saimins +sainfoin +sainfoins +saint +saintdom +sainted +sainthood +sainting +saintlier +saintliest +saintlike +saintliness +saintly +saints +saintship +saipan +saipanese +sais +saith +saithe +saiva +saivas +saivism +sake +saker +sakers +sakes +saki +sakishima +sakti +saktism +sal +salaam +salaamed +salaaming +salaams +salability +salable +salableness +salably +salacious +salaciously +salaciousness +salacity +salad +saladin +salads +salal +salals +salamanca +salamander +salamanders +salamandrine +salami +salamis +salariat +salaried +salaries +salary +salaryman +salarymen +salbutamol +salbutamols +salchow +salchows +sale +saleable +salem +salep +saleps +saleratus +salerno +saleroom +salerooms +sales +salesclerk +salesclerks +salesgirl +salesgirls +salesian +salesians +salesladies +saleslady +salesman +salesmanship +salesmen +salespeople +salesperson +salespersons +salesroom +salesrooms +saleswoman +saleswomen +salian +salians +salic +salicin +salicins +salicylate +salicylates +salicylic +salicylism +salience +saliences +saliencies +saliency +salient +salientian +salientians +saliently +salientness +salients +saliferous +salimeter +salimeters +salimetric +salimetry +salina +salinas +saline +salinity +salinization +salinizations +salinize +salinized +salinizes +salinizing +salinometer +salinometers +salinometric +salinometry +salique +salisbury +salish +salishan +saliva +salivary +salivate +salivated +salivates +salivating +salivation +salivator +salivators +salk +sallet +sallets +sallied +sallies +sallow +sallowed +sallower +sallowest +sallowing +sallowish +sallowly +sallowness +sallows +sally +sallying +salmacis +salmagundi +salmagundis +salmi +salmis +salmon +salmonberries +salmonberry +salmonella +salmonellae +salmonellas +salmonelloses +salmonellosis +salmonid +salmonids +salmonoid +salmonoids +salmons +salol +salols +salome +salometer +salometers +salon +salonika +salons +saloon +saloonkeeper +saloonkeepers +saloons +saloop +saloops +salopian +salopians +salp +salpa +salpas +salpiform +salpiglossis +salpingectomies +salpingectomy +salpinges +salpingian +salpingitis +salpinx +salps +sals +salsa +salsas +salsifies +salsify +salt +saltarelli +saltarello +saltarellos +saltation +saltations +saltatorial +saltatory +saltbox +saltboxes +saltbush +saltbushes +saltcellar +saltcellars +salted +salter +saltern +salterns +salters +saltgrass +saltier +saltiest +saltily +saltimbocca +saltimboccas +saltine +saltines +saltiness +salting +saltire +saltires +saltish +saltless +saltlike +saltness +saltpeter +salts +saltshaker +saltshakers +saltwater +saltworks +saltwort +salty +salubrious +salubriously +salubriousness +salubrity +saluki +salukis +saluretic +saluretics +salutarily +salutariness +salutary +salutation +salutational +salutations +salutatorian +salutatorians +salutatories +salutatory +salute +saluted +saluter +saluters +salutes +salutiferous +saluting +salvable +salvador +salvadoran +salvadorans +salvadorean +salvadoreans +salvadorian +salvage +salvageability +salvageable +salvaged +salvager +salvagers +salvages +salvaging +salvarsan +salvation +salvational +salvationism +salvationist +salvationists +salve +salved +salver +salverform +salvers +salves +salvia +salvias +salvific +salvifically +salving +salvo +salvoes +salvor +salvors +salvos +salzburg +samara +samaras +samaria +samaritan +samaritans +samarium +samarkand +samarskite +samarskites +samba +sambaed +sambaing +sambal +sambar +sambars +sambas +sambo +sambuca +sambucas +sambur +samburs +same +samekh +sameness +samian +samians +samiel +samiels +samisen +samisens +samite +samites +samizdat +samlet +samlets +sammarinese +sammarinesi +samnite +samnites +samnium +samoa +samoan +samoans +samos +samosa +samosas +samothrace +samothráki +samovar +samovars +samoyed +samoyede +samoyedes +samoyedic +samoyeds +samp +sampan +sampans +samphire +samphires +sample +sampled +sampler +samplers +samples +sampling +samplings +samsara +samson +samsonian +samsons +samuel +samurai +samurais +san +san'a +sana +sanaa +sanataria +sanatarium +sanatariums +sanative +sanatoria +sanatorium +sanatoriums +sanbenito +sanbenitos +sancerre +sancta +sanctification +sanctifications +sanctified +sanctifier +sanctifiers +sanctifies +sanctify +sanctifying +sanctimonious +sanctimoniously +sanctimoniousness +sanctimony +sanction +sanctionable +sanctioned +sanctioning +sanctions +sanctities +sanctity +sanctuaries +sanctuary +sanctum +sanctums +sanctus +sanctuses +sand +sandal +sandaled +sandals +sandalwood +sandalwoods +sandarac +sandaracs +sandbag +sandbagged +sandbagger +sandbaggers +sandbagging +sandbags +sandbank +sandbanks +sandbar +sandbars +sandblast +sandblasted +sandblaster +sandblasters +sandblasting +sandblasts +sandblindness +sandbox +sandboxes +sandbur +sandburs +sanded +sander +sanderling +sanderlings +sanders +sandfish +sandfishes +sandfly +sandglass +sandglasses +sandgrouse +sandhi +sandhill +sandhis +sandhog +sandhogs +sandier +sandiest +sandiness +sanding +sandinista +sandinistas +sandlot +sandlots +sandlotter +sandlotters +sandman +sandmen +sandpainting +sandpaper +sandpapered +sandpapering +sandpapers +sandpapery +sandpile +sandpiles +sandpiper +sandpipers +sandpit +sandpits +sands +sandshoe +sandshoes +sandsoap +sandspur +sandspurs +sandstone +sandstorm +sandstorms +sandwich +sandwiched +sandwiches +sandwiching +sandworm +sandworms +sandwort +sandworts +sandy +sane +sanely +saneness +saner +sanest +sanforized +sang +sangaree +sangarees +sangfroid +sangreal +sangria +sangrias +sanguicolous +sanguinaria +sanguinarias +sanguinarily +sanguinary +sanguine +sanguinely +sanguineness +sanguineous +sanguinity +sanguinolent +sanhedrim +sanhedrin +sanicle +sanicles +sanidine +sanidines +sanies +sanified +sanifies +sanify +sanifying +sanious +sanitaire +sanitaria +sanitarian +sanitarians +sanitarily +sanitarium +sanitariums +sanitary +sanitate +sanitated +sanitates +sanitating +sanitation +sanitization +sanitizations +sanitize +sanitized +sanitizer +sanitizers +sanitizes +sanitizing +sanitoria +sanitorium +sanitoriums +sanity +sank +sankhya +sannup +sannups +sannyasi +sannyasin +sannyasins +sannyasis +sanpaku +sanpakus +sans +sansculotte +sansculottes +sansculottic +sansculottish +sansculottism +sansei +sanseis +sanserif +sanserifs +sansevieria +sansevierias +sanskrit +sanskritic +sanskritist +sanskritists +santa +santalol +santalols +santander +santas +santee +santees +santeria +santiago +santir +santirs +santo +santolina +santolinas +santonica +santonicas +santonin +santonins +santorini +santos +santour +santours +sao +sap +sapajou +sapajous +saphar +saphead +sapheaded +sapheads +saphena +saphenae +saphenous +sapid +sapidity +sapience +sapiens +sapient +sapiently +sapless +saplessness +sapling +saplings +sapodilla +sapogenin +sapogenins +saponaceous +saponaceousness +saponated +saponifiable +saponification +saponified +saponifier +saponifiers +saponifies +saponify +saponifying +saponin +saponins +saponite +saponites +sapor +saporific +saporous +sapota +sapotas +sapote +sapotes +sappanwood +sappanwoods +sapped +sapper +sappers +sapphic +sapphics +sapphire +sapphires +sapphirine +sapphirines +sapphism +sappho +sappier +sappiest +sappily +sappiness +sapping +sappy +sapraemia +sapremia +sapremic +saprobe +saprobes +saprobial +saprobic +saprobically +saprobiological +saprobiologist +saprobiologists +saprobiology +saprogenic +saprogenicity +saprogenous +saprolite +saprolites +sapropel +sapropelic +sapropels +saprophagous +saprophyte +saprophytes +saprophytic +saprophytically +saprozoic +saps +sapsago +sapsagos +sapsucker +sapsuckers +sapwood +saraband +sarabande +sarabandes +sarabands +saracen +saracenic +saracens +saragossa +sarah +sarajevo +saran +sarape +sarapes +sarasvati +saratoga +sarawak +sarcasm +sarcasms +sarcastic +sarcastically +sarcenet +sarcenets +sarcodinian +sarcodinians +sarcoid +sarcoidoses +sarcoidosis +sarcoids +sarcolactic +sarcolemma +sarcolemmal +sarcolemmas +sarcoma +sarcomas +sarcomata +sarcomatoid +sarcomatosis +sarcomatous +sarcomere +sarcomeres +sarcophagi +sarcophagic +sarcophagous +sarcophagus +sarcophaguses +sarcoplasm +sarcoplasmatic +sarcoplasmic +sarcoptic +sarcosomal +sarcosome +sarcosomes +sarcostyle +sarcostyles +sarcous +sard +sardanapalus +sardar +sardars +sardine +sardined +sardines +sardinia +sardinian +sardinians +sardining +sardius +sardiuses +sardonic +sardonically +sardonicism +sardonyx +sardonyxes +sards +saree +sarema +sargasso +sargassos +sargassum +sargassums +sarge +sarges +sargon +sargonid +sari +sarin +saris +sark +sarkese +sarmatia +sarmatian +sarmatians +sarmentose +sarod +sarode +sarodes +sarodist +sarodists +sarods +sarong +sarongs +sarpedon +sarracenia +sarsaparilla +sarsaparillas +sarsenet +sarsenets +sartorial +sartorially +sartorii +sartorius +sartre +sartrean +sarum +sarus +sasanian +sasanid +sasanids +sash +sashay +sashayed +sashaying +sashays +sashed +sashes +sashimi +sashimis +sashing +saskatchewan +saskatoon +saskatoons +sasquatch +sass +sassabies +sassaby +sassafras +sassanian +sassanid +sassanide +sassed +sasses +sassier +sassies +sassiest +sassily +sassiness +sassing +sassoon +sasswood +sasswoods +sassy +sastruga +sastrugas +sat +satan +satang +satangs +satanic +satanical +satanically +satanism +satanist +satanists +satay +satchel +satcheled +satchelful +satchelfuls +satchels +sate +sated +sateen +satellite +satellites +satem +sates +sati +satiability +satiable +satiably +satiate +satiated +satiates +satiating +satiation +satiations +satiety +satin +satinet +satinets +sating +satinized +satins +satinwood +satinwoods +satiny +satire +satires +satiric +satirical +satirically +satirist +satirists +satirizable +satirization +satirize +satirized +satirizes +satirizing +satis +satisfaction +satisfactions +satisfactorily +satisfactoriness +satisfactory +satisfiability +satisfiable +satisfied +satisfiedly +satisfier +satisfiers +satisfies +satisfy +satisfying +satisfyingly +satori +satrap +satrapies +satraps +satrapy +satsuma +satsumas +saturable +saturant +saturants +saturate +saturated +saturates +saturating +saturation +saturations +saturator +saturators +saturday +saturdays +saturn +saturnalia +saturnalian +saturnalianly +saturnalias +saturnian +saturniid +saturniids +saturnine +saturninely +saturnism +satyagraha +satyr +satyriasis +satyric +satyrical +satyrid +satyrids +satyrs +saté +sauce +sauceboat +sauceboats +saucebox +sauceboxes +sauced +saucepan +saucepans +saucepot +saucepots +saucer +saucerlike +saucers +sauces +saucier +sauciest +saucily +sauciness +saucing +saucy +saudi +saudis +sauerbraten +sauerkraut +sauger +saugers +sauk +sauks +saul +sault +saults +saumur +sauna +saunas +saunter +sauntered +saunterer +saunterers +sauntering +saunters +saurel +saurels +saurian +saurians +sauries +saurischian +saurischians +sauropod +sauropodous +sauropods +saury +sausage +sausages +sauterne +sauternes +sauté +sautéed +sautéing +sautés +sauvignon +savable +savage +savaged +savagely +savageness +savageries +savagery +savages +savaging +savagism +savagisms +savai'i +savaii +savanna +savannah +savannahs +savannas +savant +savants +savarin +savarins +savate +save +saveable +saved +saveloy +saveloys +saver +savers +saves +savin +savine +savines +saving +savings +savins +savior +saviors +saviour +saviours +savoir +savonarola +savor +savored +savorer +savorers +savories +savorily +savoriness +savoring +savorless +savorous +savors +savory +savour +savoured +savouries +savouring +savours +savoury +savoy +savoyard +savoyards +savvied +savvier +savvies +savviest +savvily +savvy +savvying +saw +sawbones +sawboneses +sawbuck +sawbucks +sawdust +sawdusty +sawed +sawer +sawers +sawfish +sawfishes +sawflies +sawfly +sawhorse +sawhorses +sawing +sawlike +sawlog +sawlogs +sawmill +sawmills +sawn +sawney +sawneys +saws +sawtimber +sawtimbers +sawtooth +sawyer +sawyers +sax +saxatile +saxe +saxes +saxhorn +saxhorns +saxicoline +saxicolous +saxifrage +saxifrages +saxitoxin +saxitoxins +saxon +saxondom +saxonies +saxonism +saxons +saxony +saxophone +saxophones +saxophonic +saxophonist +saxophonists +saxtuba +saxtubas +say +sayable +sayer +sayers +sayest +saying +sayings +sayonara +says +sayyid +sazerac +saëns +saône +scab +scabbard +scabbarded +scabbarding +scabbards +scabbed +scabbier +scabbiest +scabbily +scabbiness +scabbing +scabble +scabbled +scabbles +scabbling +scabby +scabies +scabietic +scabiosa +scabiosas +scabious +scabiouses +scabland +scablands +scabrous +scabrously +scabrousness +scabs +scad +scads +scaffold +scaffolded +scaffolding +scaffoldings +scaffolds +scag +scagliola +scagliolas +scalability +scalable +scalade +scalades +scalado +scalados +scalage +scalages +scalar +scalare +scalares +scalariform +scalariformly +scalars +scalawag +scalawags +scald +scalded +scalding +scaldingly +scalds +scale +scaled +scaleless +scalelike +scalene +scaleni +scalenus +scaler +scalers +scales +scalier +scaliest +scaliness +scaling +scall +scallion +scallions +scallop +scalloped +scalloper +scallopers +scalloping +scallopini +scallops +scalls +scallywag +scallywags +scalogram +scalograms +scaloppine +scaloppini +scalp +scalped +scalpel +scalpels +scalper +scalpers +scalping +scalps +scaly +scam +scammed +scammer +scammers +scamming +scammonies +scammony +scamp +scamped +scamper +scampered +scampering +scampers +scampi +scamping +scampish +scamps +scams +scan +scandal +scandale +scandalization +scandalizations +scandalize +scandalized +scandalizer +scandalizers +scandalizes +scandalizing +scandalmonger +scandalmongering +scandalmongers +scandalous +scandalously +scandalousness +scandals +scandent +scandia +scandian +scandians +scandic +scandinavia +scandinavian +scandinavians +scandium +scannable +scanned +scanner +scanners +scanning +scans +scansion +scansions +scansorial +scant +scanted +scanter +scantest +scantier +scanties +scantiest +scantily +scantiness +scanting +scantling +scantlings +scantly +scantness +scants +scanty +scape +scaped +scapegoat +scapegoated +scapegoating +scapegoatism +scapegoats +scapegrace +scapegraces +scapes +scaphocephalic +scaphocephaly +scaphoid +scaphoids +scaphopod +scaphopods +scaping +scapolite +scapolites +scapose +scapula +scapulae +scapular +scapulars +scapulary +scapulas +scapuloclavicular +scar +scarab +scarabaei +scarabaeid +scarabaeids +scarabaeus +scarabaeuses +scaraboid +scarabs +scaramouch +scaramouche +scaramouches +scarce +scarcely +scarceness +scarcer +scarcest +scarcities +scarcity +scare +scarecrow +scarecrows +scared +scaredy +scarehead +scareheads +scaremonger +scaremongering +scaremongers +scarer +scarers +scares +scarf +scarfed +scarfing +scarfpin +scarfpins +scarfs +scarfskin +scarfskins +scarier +scariest +scarification +scarifications +scarificator +scarificators +scarified +scarifier +scarifiers +scarifies +scarify +scarifying +scarifyingly +scarily +scariness +scaring +scariose +scarious +scarlatina +scarlatinal +scarlatinoid +scarlatti +scarless +scarlet +scarlets +scarp +scarped +scarping +scarps +scarred +scarring +scarry +scars +scarum +scarves +scary +scat +scatback +scatbacks +scathe +scathed +scatheless +scathes +scathing +scathingly +scatologic +scatological +scatologies +scatologist +scatologists +scatology +scats +scatted +scatter +scatteration +scatterations +scatterbrain +scatterbrained +scatterbrains +scattered +scatterer +scatterers +scattergood +scattergoods +scattergram +scattergrams +scattergun +scatterguns +scattering +scatteringly +scatterings +scatters +scattershot +scattier +scattiest +scatting +scatty +scaup +scaups +scavenge +scavenged +scavenger +scavengers +scavenges +scavenging +scena +scenario +scenarios +scenarist +scenarists +scenas +scend +scended +scending +scends +scene +sceneries +scenery +scenes +sceneshifter +sceneshifters +scenic +scenical +scenically +scenics +scenographer +scenographers +scenographic +scenography +scent +scented +scenting +scentless +scents +scepter +sceptered +sceptering +scepters +sceptic +sceptical +scepticism +sceptics +schadenfreude +schadenfreudes +scharnhorst +schav +schavs +schedular +schedule +scheduled +scheduler +schedulers +schedules +scheduling +scheelite +scheelites +schefflera +scheffleras +scheherazade +schelde +scheldt +schema +schemas +schemata +schematic +schematically +schematics +schematism +schematization +schematizations +schematize +schematized +schematizes +schematizing +scheme +schemed +schemer +schemers +schemes +scheming +scherzando +scherzandos +scherzi +scherzo +scherzos +scheveningen +schick +schiff +schiller +schillers +schilling +schillings +schindler +schiphol +schipperke +schipperkes +schism +schismatic +schismatical +schismatically +schismatics +schismatize +schismatized +schismatizes +schismatizing +schisms +schist +schistocyte +schistocytes +schistocytoses +schistocytosis +schistorrhachis +schistorrhachises +schistose +schistosity +schistosomal +schistosome +schistosomes +schistosomiases +schistosomiasis +schistosomula +schistosomulum +schistous +schists +schizier +schiziest +schizo +schizoaffective +schizocarp +schizocarpic +schizocarpous +schizocarps +schizogamy +schizogenesis +schizogenous +schizogonic +schizogonous +schizogony +schizoid +schizoids +schizont +schizonts +schizophrene +schizophrenes +schizophrenia +schizophrenic +schizophrenically +schizophrenics +schizophreniform +schizophrenogenic +schizopod +schizopodous +schizopods +schizos +schizothyme +schizothymes +schizothymia +schizothymic +schizothymics +schizy +schizzy +schlemiel +schlemiels +schlep +schlepp +schlepped +schlepper +schleppers +schlepping +schlepps +schleps +schleswig +schliemann +schlieren +schlieric +schlimazel +schlimazels +schlock +schlockmeister +schlockmeisters +schlocky +schmaltz +schmaltzier +schmaltziest +schmaltziness +schmaltzy +schmalz +schmalzy +schmear +schmeer +schmidt +schmo +schmoe +schmoes +schmoose +schmoosed +schmooses +schmoosing +schmooze +schmoozed +schmoozes +schmoozing +schmos +schmuck +schmucks +schnapper +schnappers +schnapps +schnauzer +schnauzers +schnitzel +schnitzels +schnook +schnooks +schnorrer +schnorrers +schnoz +schnozes +schnozzle +schnozzles +schoenberg +schoenbergian +scholar +scholarliness +scholarly +scholars +scholarship +scholarships +scholastic +scholastically +scholasticate +scholasticates +scholasticism +scholastics +scholia +scholiast +scholiastic +scholiasts +scholium +scholiums +school +schoolbag +schoolbags +schoolbook +schoolbooks +schoolboy +schoolboyish +schoolboys +schoolchild +schoolchildren +schooldays +schooled +schooler +schoolers +schoolfellow +schoolfellows +schoolgirl +schoolgirls +schoolhouse +schoolhouses +schooling +schoolings +schoolkid +schoolkids +schoolma'am +schoolma'ams +schoolman +schoolmarm +schoolmarmish +schoolmarms +schoolmaster +schoolmasterish +schoolmasterly +schoolmasters +schoolmate +schoolmates +schoolmen +schoolmistress +schoolmistresses +schoolroom +schoolrooms +schools +schoolteacher +schoolteachers +schooltime +schooltimes +schoolwork +schoolyard +schoolyards +schooner +schooners +schopenhauer +schopenhauerian +schorl +schorls +schottische +schottisches +schouten +schrod +schrodinger +schtick +schticks +schubert +schumann +schuss +schussboomer +schussboomers +schussed +schusses +schussing +schuylkill +schwa +schwann +schwarmerei +schwarzhorn +schwarzschild +schwarzwald +schwas +sciaenid +sciaenoid +sciaenoids +sciatic +sciatica +science +sciences +scienter +sciential +scientific +scientifically +scientism +scientist +scientistic +scientists +scientize +scientized +scientizes +scientizing +scientology +scilicet +scilla +scilly +scimitar +scimitars +scincoid +scincoids +scintigram +scintigrams +scintigraph +scintigraphic +scintigraphically +scintigraphs +scintigraphy +scintilla +scintillant +scintillantly +scintillate +scintillated +scintillates +scintillating +scintillatingly +scintillation +scintillations +scintillator +scintillators +scintillometer +scintillometers +scintiscan +scintiscanner +scintiscanners +scintiscans +sciolism +sciolist +sciolistic +sciolists +scion +scions +scipio +scirocco +sciroccos +scirrhi +scirrhoid +scirrhous +scirrhus +scirrhuses +scissile +scission +scissions +scissor +scissored +scissoring +scissors +scissortail +scissortails +scissure +scissures +sciurid +sciurids +sciuroid +sclaff +sclaffed +sclaffer +sclaffers +sclaffing +sclaffs +sclera +scleral +sclereid +sclereids +sclerenchyma +sclerenchymas +sclerenchymatous +sclerite +sclerites +scleritic +scleritis +scleroderma +sclerodermatous +scleroid +scleroma +scleromas +scleromata +sclerometer +sclerometers +scleroprotein +scleroproteins +sclerosed +scleroses +sclerosing +sclerosis +sclerotia +sclerotial +sclerotic +sclerotics +sclerotin +sclerotins +sclerotium +sclerotization +sclerotizations +sclerotized +sclerotomies +sclerotomy +sclerous +scoff +scoffed +scoffer +scoffers +scoffing +scoffingly +scofflaw +scofflaws +scoffs +scold +scolded +scolder +scolders +scolding +scoldingly +scoldings +scolds +scoleces +scolecite +scolecites +scolex +scolices +scoliosis +scoliotic +scollop +scolloped +scolloping +scollops +scolopendra +scolopendrid +scolopendrids +scolopendrine +scombroid +scombroids +sconce +sconces +scone +scones +scoop +scooped +scooper +scoopers +scoopful +scoopfuls +scooping +scoops +scoot +scooted +scooter +scooters +scooting +scoots +scop +scope +scoped +scopes +scoping +scopolamine +scops +scopula +scopulae +scopulate +scorbutic +scorbutical +scorbutically +scorch +scorched +scorcher +scorchers +scorches +scorching +scorchingly +score +scoreboard +scoreboards +scorecard +scorecards +scored +scorekeeper +scorekeepers +scorekeeping +scoreless +scorer +scorers +scores +scoresby +scoria +scoriaceous +scoriae +scorification +scorifications +scorified +scorifier +scorifiers +scorifies +scorify +scorifying +scoring +scorings +scorn +scorned +scorner +scorners +scornful +scornfully +scornfulness +scorning +scorns +scorpaenid +scorpaenids +scorpaenoid +scorpaenoids +scorpio +scorpioid +scorpion +scorpions +scorpios +scorpius +scot +scotch +scotched +scotches +scotching +scotchman +scotchmen +scotchwoman +scotchwomen +scoter +scoters +scotia +scotic +scotism +scotist +scotists +scotland +scotoma +scotomas +scotomata +scotomatous +scotophil +scotophilic +scotophily +scotophobic +scotophobin +scotophobins +scotopia +scotopias +scotopic +scots +scotsman +scotsmen +scotswoman +scotswomen +scott +scotticism +scotticisms +scottie +scotties +scottish +scottishness +scotty +scotus +scoundrel +scoundrelly +scoundrels +scour +scoured +scourer +scourers +scourge +scourged +scourger +scourgers +scourges +scourging +scouring +scourings +scours +scouse +scouser +scousers +scouses +scout +scoutcraft +scoutcrafts +scouted +scouter +scouters +scouting +scoutings +scoutmaster +scoutmasters +scouts +scow +scowl +scowled +scowler +scowlers +scowling +scowlingly +scowls +scows +scrabble +scrabbled +scrabbler +scrabblers +scrabbles +scrabbling +scrabbly +scrag +scragged +scraggier +scraggiest +scraggily +scragginess +scragging +scragglier +scraggliest +scraggly +scraggy +scrags +scram +scramble +scrambled +scrambler +scramblers +scrambles +scrambling +scramjet +scramjets +scrammed +scramming +scrams +scrannel +scrap +scrapbook +scrapbooks +scrape +scraped +scraper +scraperboard +scraperboards +scrapers +scrapes +scrapheap +scrapheaps +scrapie +scraping +scrapings +scrappage +scrapped +scrapper +scrappers +scrappier +scrappiest +scrappily +scrappiness +scrapping +scrapple +scrappy +scraps +scratch +scratchboard +scratchboards +scratched +scratcher +scratchers +scratches +scratchier +scratchiest +scratchily +scratchiness +scratching +scratchpad +scratchpads +scratchproof +scratchy +scrawl +scrawled +scrawler +scrawlers +scrawling +scrawls +scrawly +scrawnier +scrawniest +scrawniness +scrawny +screak +screaked +screaking +screaks +screaky +scream +screamed +screamer +screamers +screaming +screamingly +screams +scree +screech +screeched +screecher +screechers +screeches +screeching +screechy +screed +screeds +screen +screenable +screened +screener +screeners +screening +screenings +screenland +screenplay +screenplays +screens +screenwriter +screenwriters +screenwriting +screes +screw +screwable +screwball +screwballs +screwbean +screwbeans +screwdriver +screwdrivers +screwed +screwer +screwers +screwier +screwiest +screwiness +screwing +screwlike +screws +screwup +screwups +screwworm +screwworms +screwy +scribal +scribble +scribbled +scribbler +scribblers +scribbles +scribbling +scribbly +scribe +scribed +scriber +scribers +scribes +scribing +scried +scries +scrim +scrimmage +scrimmaged +scrimmager +scrimmagers +scrimmages +scrimmaging +scrimp +scrimped +scrimper +scrimpers +scrimpiness +scrimping +scrimps +scrimption +scrimpy +scrims +scrimshander +scrimshanders +scrimshaw +scrimshawed +scrimshawing +scrimshaws +scrip +scrips +script +scripted +scripter +scripters +scripting +scriptoria +scriptorium +scriptoriums +scripts +scriptural +scripturally +scripture +scriptures +scriptwriter +scriptwriters +scriptwriting +scrivener +scriveners +scrobiculate +scrod +scrods +scrofula +scrofulous +scrofulously +scrofulousness +scroll +scrollbar +scrollbars +scrolled +scrolling +scrolls +scrollwork +scrooch +scrooched +scrooches +scrooching +scrooge +scrooges +scroogie +scroogies +scrootch +scrootched +scrootches +scrootching +scrota +scrotal +scrotum +scrotums +scrouge +scrouged +scrouges +scrouging +scrounge +scrounged +scrounger +scroungers +scrounges +scroungier +scroungiest +scrounging +scroungy +scrub +scrubbable +scrubbed +scrubber +scrubbers +scrubbier +scrubbiest +scrubbily +scrubbiness +scrubbing +scrubby +scrubland +scrublands +scrubs +scrubwoman +scrubwomen +scruff +scruffier +scruffiest +scruffily +scruffiness +scruffs +scruffy +scrum +scrummage +scrummaged +scrummager +scrummagers +scrummages +scrummaging +scrummed +scrumming +scrumptious +scrumptiously +scrumptiousness +scrums +scrunch +scrunchable +scrunched +scrunches +scrunching +scruple +scrupled +scruples +scrupling +scrupulosity +scrupulous +scrupulously +scrupulousness +scrutable +scrutineer +scrutineers +scrutinies +scrutinize +scrutinized +scrutinizer +scrutinizers +scrutinizes +scrutinizing +scrutinizingly +scrutiny +scry +scrying +scuba +scubas +scud +scudded +scudding +scudi +scudo +scuds +scuff +scuffed +scuffer +scuffers +scuffing +scuffle +scuffled +scuffler +scufflers +scuffles +scuffling +scuffs +scull +sculled +sculler +sculleries +scullers +scullery +sculling +scullion +scullions +sculls +sculpin +sculpins +sculpt +sculpted +sculpting +sculptor +sculptors +sculptress +sculptresses +sculpts +sculptural +sculpturally +sculpture +sculptured +sculptures +sculpturesque +sculpturesquely +sculpturing +scum +scumbag +scumbags +scumble +scumbled +scumbles +scumbling +scummed +scummer +scummers +scummier +scummiest +scummily +scumminess +scumming +scummy +scums +scungilli +scunner +scunners +scup +scupper +scuppered +scuppering +scuppernong +scuppernongs +scuppers +scups +scurf +scurfiness +scurfy +scurried +scurries +scurril +scurrile +scurrilities +scurrility +scurrilous +scurrilously +scurrilousness +scurry +scurrying +scurvier +scurviest +scurvily +scurviness +scurvy +scut +scuta +scutage +scutages +scutate +scutch +scutched +scutcheon +scutcheons +scutcher +scutchers +scutches +scutching +scute +scutella +scutellar +scutellate +scutellated +scutellation +scutellations +scutellum +scutes +scutiform +scuts +scutter +scuttered +scuttering +scutters +scuttle +scuttlebutt +scuttled +scuttles +scuttling +scutum +scutwork +scuzzier +scuzziest +scuzzy +scylla +scyphistoma +scyphistomae +scyphistomas +scyphozoan +scyphozoans +scyros +scythe +scythed +scythes +scythia +scythian +scythians +scything +scène +scènes +se +sea +seabag +seabags +seabed +seabeds +seabee +seabees +seabird +seabirds +seaboard +seaboards +seaboot +seaboots +seaborgium +seaborne +seacoast +seacoasts +seacock +seacocks +seacraft +seadog +seadogs +seafarer +seafarers +seafaring +seafloor +seafloors +seafood +seafowl +seafront +seafronts +seagirt +seagoing +seagull +seagulls +seahorse +seahorses +seajack +seajacked +seajacker +seajackers +seajacking +seajackings +seajacks +seal +sealable +sealant +sealants +sealed +sealer +sealers +sealift +sealifted +sealifting +sealifts +sealing +seals +sealskin +sealskins +sealyham +seam +seaman +seamanlike +seamanly +seamanship +seamark +seamarks +seamed +seamen +seamer +seamers +seamier +seamiest +seaminess +seaming +seamless +seamlessly +seamlessness +seamlike +seamount +seamounts +seams +seamster +seamsters +seamstress +seamstresses +seamy +seance +seances +seapiece +seapieces +seaplane +seaplanes +seaport +seaports +seaquake +seaquakes +sear +search +searchable +searched +searcher +searchers +searches +searching +searchingly +searchless +searchlight +searchlights +seared +searing +searingly +sears +seas +seascape +seascapes +seashell +seashells +seashore +seashores +seasick +seasickness +seaside +season +seasonable +seasonableness +seasonably +seasonal +seasonality +seasonally +seasoned +seasoner +seasoners +seasoning +seasonings +seasonless +seasons +seastrand +seastrands +seat +seatback +seatbacks +seated +seater +seaters +seating +seatmate +seatmates +seatrain +seatrains +seats +seattle +seatwork +seawall +seawalls +seaward +seawards +seaware +seawater +seaway +seaways +seaweed +seaweeds +seaworthier +seaworthiest +seaworthiness +seaworthy +sebaceous +sebacic +sebastian +sebastopol +sebiferous +sebiparous +seborrhea +seborrheic +seborrhoea +sebum +sec +secant +secants +secco +seccos +secede +seceded +seceder +seceders +secedes +seceding +secern +secerned +secerning +secernment +secernments +secerns +secession +secessional +secessionism +secessionist +secessionists +secessions +sechuana +seckel +seclude +secluded +secludedly +secludedness +secludes +secluding +seclusion +seclusive +seclusively +seclusiveness +secobarbital +secobarbitals +seconal +second +secondaries +secondarily +secondariness +secondary +seconded +seconder +seconders +secondhand +secondi +seconding +secondly +secondo +seconds +secondstory +secrecies +secrecy +secret +secreta +secretagogue +secretagogues +secretarial +secretariat +secretariats +secretaries +secretary +secretaryship +secrete +secreted +secreter +secreters +secretes +secretin +secreting +secretins +secretion +secretionary +secretions +secretive +secretively +secretiveness +secretly +secretor +secretors +secretory +secrets +sect +sectarian +sectarianism +sectarianize +sectarianized +sectarianizes +sectarianizing +sectarians +sectaries +sectary +sectile +sectility +section +sectional +sectionalism +sectionalist +sectionalists +sectionalization +sectionalizations +sectionalize +sectionalized +sectionalizes +sectionalizing +sectionally +sectionals +sectioned +sectioning +sections +sector +sectored +sectorial +sectoring +sectors +sects +secular +secularism +secularist +secularistic +secularists +secularities +secularity +secularization +secularizations +secularize +secularized +secularizer +secularizers +secularizes +secularizing +secularly +seculars +secund +secundines +securable +secure +secured +securely +securement +securements +secureness +securer +securers +secures +securest +securing +securities +securitization +securitize +securitized +securitizes +securitizing +security +sedan +sedans +sedarim +sedate +sedated +sedately +sedateness +sedates +sedating +sedation +sedations +sedative +sedatives +sedentarily +sedentariness +sedentary +seder +seders +sederunt +sederunts +sedge +sedges +sedgwick +sedile +sedilia +sediment +sedimental +sedimentary +sedimentation +sedimentologic +sedimentological +sedimentologist +sedimentologists +sedimentology +sediments +sedition +seditionist +seditionists +seditious +seditiously +seditiousness +seduce +seduceable +seduced +seducement +seducements +seducer +seducers +seduces +seducible +seducing +seduction +seductions +seductive +seductively +seductiveness +seductress +seductresses +sedulity +sedulous +sedulously +sedulousness +sedum +see +seeable +seecatch +seecatchie +seed +seedbed +seedbeds +seedcake +seedcakes +seedcase +seedcases +seedeater +seedeaters +seeded +seeder +seeders +seedier +seediest +seedily +seediness +seeding +seedless +seedlike +seedling +seedlings +seedpod +seedpods +seeds +seedsman +seedsmen +seedtime +seedtimes +seedy +seeing +seek +seeker +seekers +seeking +seeks +seel +seeled +seeling +seels +seem +seemed +seeming +seemingly +seemingness +seemlier +seemliest +seemliness +seemly +seems +seen +seep +seepage +seeped +seeping +seeps +seepy +seer +seeress +seeresses +seers +seersucker +sees +seesaw +seesawed +seesawing +seesaws +seethe +seethed +seethes +seething +segment +segmental +segmentally +segmentary +segmentation +segmentations +segmented +segmenting +segments +segno +segnos +sego +segos +segovia +segregable +segregant +segregants +segregate +segregated +segregates +segregating +segregation +segregationist +segregationists +segregations +segregative +segregator +segregators +segue +segued +segueing +segues +seguidilla +seguidillas +seguing +sei +seicento +seicentos +seiche +seiches +seidel +seidels +seidlitz +seigneur +seigneurial +seigneuries +seigneurs +seigneury +seignior +seigniorage +seigniorial +seigniories +seigniors +seigniory +seignorage +seignorial +seignory +seine +seined +seiner +seiners +seines +seining +seis +seise +seised +seises +seisin +seising +seisins +seism +seismic +seismically +seismicity +seismism +seismogram +seismograms +seismograph +seismographer +seismographers +seismographic +seismographical +seismographs +seismography +seismologic +seismological +seismologically +seismologist +seismologists +seismology +seismometer +seismometers +seismometric +seismometrical +seismometry +seismoscope +seismoscopes +seismoscopic +seisms +seisor +seisors +seizable +seize +seized +seizer +seizers +seizes +seizin +seizing +seizings +seizins +seizor +seizors +seizure +seizures +sejant +selachian +selachians +seladang +seladangs +selaginella +selaginellas +selah +selassie +selcouth +seldom +seldomness +select +selectable +selected +selectee +selectees +selecting +selection +selectional +selectionism +selectionist +selectionists +selections +selective +selectively +selectiveness +selectivities +selectivity +selectman +selectmen +selectness +selector +selectors +selects +selectwoman +selectwomen +selenate +selenates +selene +selenic +selenide +selenides +seleniferous +selenite +selenites +selenium +selenocentric +selenographer +selenographers +selenographic +selenographical +selenographically +selenographist +selenographists +selenography +selenological +selenologist +selenologists +selenology +selenosis +seleucid +seleucids +self +selfdom +selfhood +selfish +selfishly +selfishness +selfless +selflessly +selflessness +selfmate +selfness +selfridge +selfsame +selfsameness +seljuk +seljukian +sell +sellable +sellback +sellbacks +seller +sellers +selling +selloff +sellout +sellouts +sells +selsyn +selsyns +seltzer +seltzers +selva +selvage +selvaged +selvages +selvas +selvedge +selvedged +selvedges +selves +semanteme +semantemes +semantic +semantical +semantically +semanticist +semanticists +semantics +semaphore +semaphored +semaphores +semaphoric +semaphorically +semaphoring +semasiological +semasiologist +semasiologists +semasiology +sematic +semblable +semblables +semblably +semblance +seme +semeiology +semeiotic +semeiotical +semeiotics +sememe +sememes +sememic +semen +semes +semester +semesters +semestral +semestrial +semi +semiabstract +semiabstraction +semiabstractions +semiannual +semiannually +semiaquatic +semiarboreal +semiarid +semiaridity +semiattached +semiautobiographical +semiautomated +semiautomatic +semiautomatically +semiautomatics +semiautonomous +semiautonomously +semiautonomy +semibreve +semibreves +semicentennial +semicentennials +semicircle +semicircles +semicircular +semicivilized +semiclassic +semiclassical +semiclassics +semicolon +semicolonial +semicolonialism +semicolonies +semicolons +semicolony +semicoma +semicomas +semicomatose +semicommercial +semiconducting +semiconductor +semiconductors +semiconscious +semiconsciously +semiconsciousness +semiconservative +semiconservatively +semicrystalline +semidarkness +semidarknesses +semideified +semideifies +semideify +semideifying +semidesert +semideserts +semidetached +semidiameter +semidiameters +semidiurnal +semidivine +semidocumentaries +semidocumentary +semidome +semidomed +semidomes +semidomesticated +semidomestication +semidominant +semidried +semidry +semidrying +semidwarf +semidwarfs +semielliptical +semiempirical +semierect +semievergreen +semifeudal +semifinal +semifinalist +semifinalists +semifinals +semifinished +semifitted +semiflexible +semiflexion +semiflexions +semifluid +semifluidity +semifluids +semiformal +semigloss +semiglosses +semiglossy +semigovernmental +semigroup +semigroups +semihard +semilegendary +semilethal +semiliquid +semiliquidity +semiliquids +semiliteracy +semiliterate +semillon +semillons +semilog +semilogarithmic +semilunar +semilunate +semilustrous +semimajor +semimat +semimatt +semimatte +semimembranous +semimetal +semimetallic +semimetals +semimicro +semiminor +semimoist +semimonastic +semimonthlies +semimonthly +semimystical +seminal +seminally +seminar +seminarian +seminarians +seminaries +seminarist +seminarists +seminars +seminary +seminatural +seminiferous +seminivorous +seminole +seminoles +seminoma +seminomad +seminomadic +seminomads +seminomas +seminomata +seminude +seminudity +semiofficial +semiofficially +semiological +semiologically +semiologist +semiologists +semiology +semiopaque +semiosis +semiotic +semiotical +semiotician +semioticians +semioticist +semioticists +semiotics +semioviparous +semipalmate +semipalmated +semiparasite +semiparasites +semiparasitic +semiparasitism +semipermanent +semipermeability +semipermeable +semipolitical +semipopular +semiporcelain +semiporcelains +semipornographic +semipornography +semipostal +semipostals +semiprecious +semiprivate +semipro +semiprofessional +semiprofessionally +semiprofessionals +semipros +semipublic +semipublicly +semiquantitative +semiquantitatively +semiquaver +semiquavers +semireligious +semiretired +semiretirement +semiretirements +semirigid +semiround +semirounds +semirural +semis +semisacred +semisecret +semisedentary +semiserious +semiseriously +semishrubby +semiskilled +semisoft +semisolid +semisolids +semispherical +semistaged +semisterile +semisubmersible +semisubmersibles +semisweet +semisynthetic +semite +semiterrestrial +semites +semitic +semiticist +semiticists +semitics +semitism +semitist +semitists +semitization +semitize +semitized +semitizes +semitizing +semitonal +semitonally +semitone +semitones +semitonic +semitonically +semitrailer +semitrailers +semitranslucent +semitransparent +semitropic +semitropical +semitropics +semivowel +semivowels +semiweeklies +semiweekly +semiworks +semiyearlies +semiyearly +semolina +sempervivum +sempervivums +sempiternal +sempiternally +sempiternity +semplice +sempre +sempstress +sempstresses +semtex +semé +sen +senarii +senarius +senary +senate +senates +senator +senatorial +senatorially +senatorian +senators +senatorship +senatorships +send +sendal +sendals +sender +senders +sending +sendoff +sendoffs +sends +sene +seneca +senecas +senecio +senecios +senectitude +senega +senegal +senegalese +senegambia +senegas +senesce +senesced +senescence +senescent +senesces +seneschal +seneschals +senescing +senhor +senhora +senhores +senhorita +senhors +senile +senilely +senility +senior +seniorities +seniority +seniors +seniti +senna +sennas +sennet +sennets +sennight +sennights +sennit +sennits +senopia +senopias +senryu +sensa +sensate +sensated +sensately +sensation +sensational +sensationalism +sensationalist +sensationalistic +sensationalists +sensationalization +sensationalizations +sensationalize +sensationalized +sensationalizes +sensationalizing +sensationally +sensations +sensatory +sense +sensed +senseful +sensei +senseis +senseless +senselessly +senselessness +senses +sensibilia +sensibilities +sensibility +sensible +sensibleness +sensibly +sensilla +sensillum +sensing +sensitive +sensitively +sensitiveness +sensitives +sensitivities +sensitivity +sensitization +sensitizations +sensitize +sensitized +sensitizer +sensitizers +sensitizes +sensitizing +sensitometer +sensitometers +sensitometric +sensitometry +sensor +sensoria +sensorial +sensorially +sensorimotor +sensorineural +sensorium +sensoriums +sensors +sensory +sensual +sensualism +sensualist +sensualistic +sensualists +sensuality +sensualization +sensualizations +sensualize +sensualized +sensualizes +sensualizing +sensually +sensualness +sensum +sensuosity +sensuous +sensuously +sensuousness +sensurround +sent +sentence +sentenced +sentencer +sentencers +sentences +sentencing +sentencings +sententia +sententiae +sentential +sententially +sententious +sententiously +sententiousness +sentience +sentient +sentiently +sentiment +sentimental +sentimentalism +sentimentalist +sentimentalists +sentimentalities +sentimentality +sentimentalization +sentimentalizations +sentimentalize +sentimentalized +sentimentalizes +sentimentalizing +sentimentally +sentiments +sentimo +sentimos +sentinel +sentineled +sentineling +sentinelled +sentinelling +sentinels +sentries +sentry +seoul +sepal +sepaled +sepaline +sepaloid +sepalous +sepals +separability +separable +separableness +separably +separate +separated +separately +separateness +separates +separating +separation +separationist +separationists +separations +separatism +separatist +separatistic +separatists +separative +separator +separators +sephardi +sephardic +sephardim +sepia +sepias +sepiolite +sepiolites +sepoy +sepoys +seppuku +seppukus +sepses +sepsis +sept +septa +septage +septages +septal +septaria +septarian +septarium +septate +septavalent +septcentenary +septectomies +septectomy +september +septembers +septembrist +septembrists +septenarii +septenarius +septenary +septenate +septendecillion +septendecillions +septennial +septennially +septennials +septentrion +septentrional +septentrions +septet +septets +septette +septettes +septic +septicemia +septicemic +septicidal +septicidally +septicity +septifragal +septifragally +septilateral +septillion +septillions +septillionth +septillionths +septimal +septivalent +septs +septuagenarian +septuagenarians +septuagesima +septuagesimas +septuagint +septuagintal +septum +septuple +septupled +septuples +septuplet +septuplets +septupling +sepulcher +sepulchered +sepulchering +sepulchers +sepulchral +sepulchrally +sepulchre +sepulchred +sepulchres +sepulchring +sepulture +sepultures +seq +sequacious +sequaciously +sequacity +sequel +sequela +sequelae +sequels +sequenator +sequenators +sequence +sequenced +sequencer +sequencers +sequences +sequencing +sequency +sequent +sequential +sequentiality +sequentially +sequents +sequester +sequestered +sequestering +sequesters +sequestra +sequestrant +sequestrants +sequestrate +sequestrated +sequestrates +sequestrating +sequestration +sequestrations +sequestrator +sequestrators +sequestrum +sequin +sequined +sequining +sequinned +sequins +sequitur +sequiturs +sequoia +sequoias +sera +seraglio +seraglios +serai +seral +serape +serapes +seraph +seraphic +seraphical +seraphically +seraphim +seraphs +serapis +serb +serbia +serbian +serbians +serbo +serbs +sere +serenade +serenaded +serenader +serenaders +serenades +serenading +serenata +serenatas +serendipitous +serendipitously +serendipity +serene +serenely +sereneness +serener +serenest +serenissima +serenity +serer +serest +serf +serfage +serfdom +serfs +serge +sergeancy +sergeant +sergeanties +sergeants +sergeantship +sergeanty +serges +serging +serial +serialism +serialist +serialists +serialization +serializations +serialize +serialized +serializes +serializing +serially +serials +seriate +seriated +seriately +seriates +seriatim +seriating +seriation +sericeous +sericin +sericins +sericteria +sericterium +sericultural +sericulture +sericulturist +sericulturists +seriema +seriemas +series +serif +serifed +seriffed +serifs +serigraph +serigrapher +serigraphers +serigraphs +serigraphy +serin +serine +serines +serins +seriocomic +seriocomically +serious +seriously +seriousness +serjeant +serjeants +serjeanty +sermon +sermonette +sermonettes +sermonic +sermonical +sermonize +sermonized +sermonizer +sermonizers +sermonizes +sermonizing +sermons +seroconversion +seroconversions +serodiagnoses +serodiagnosis +serodiagnostic +serologic +serological +serologically +serologies +serologist +serologists +serology +seronegative +seronegativity +seropositive +seropositivity +seropurulent +serosa +serosae +serosal +serosas +serositis +serositises +serotherapies +serotherapist +serotherapists +serotherapy +serotinal +serotine +serotines +serotinous +serotonergic +serotonin +serotoninergic +serotonins +serotype +serotyped +serotypes +serotyping +serous +serow +serows +serpens +serpent +serpentaria +serpentarium +serpentariums +serpentine +serpentinely +serpentines +serpents +serpiginous +serpiginously +serpigo +serpigos +serranid +serranids +serrano +serranos +serrate +serrated +serrates +serrating +serration +serried +serriedly +serriedness +serries +serrulate +serrulated +serrulation +serry +serrying +sertoli +sertoman +sertularian +sertularians +serum +serums +serval +servant +servanthood +servantless +servants +serve +served +server +servers +serves +servibar +servibars +service +serviceability +serviceable +serviceableness +serviceably +serviceberries +serviceberry +serviced +serviceman +servicemen +servicepeople +serviceperson +servicepersons +servicer +servicers +services +servicewoman +servicewomen +servicing +serviette +serviettes +servile +servilely +servileness +servility +serving +servingly +servings +servite +servites +servitor +servitors +servitorship +servitorships +servitude +servo +servomechanism +servomechanisms +servomotor +servomotors +servos +sesame +sesames +sesamoid +sesamoids +sesotho +sesquicarbonate +sesquicarbonates +sesquicentenary +sesquicentennial +sesquicentennials +sesquipedal +sesquipedalian +sesquipedalians +sesquiterpene +sesquiterpenes +sessile +sessility +session +sessional +sessionally +sessions +sesterce +sesterces +sestertia +sestertium +sestet +sestets +sestina +sestinas +set +seta +setaceous +setaceously +setae +setal +setback +setbacks +seth +setiferous +setiform +setigerous +setline +setlines +setoff +setoffs +setose +setout +setouts +sets +setscrew +setscrews +setswana +settable +settee +settees +setter +setters +setting +settings +settle +settleable +settled +settlement +settlements +settler +settlers +settles +settling +settlings +settlor +settlors +setup +setups +seurat +sevastopol +seven +sevenfold +sevens +seventeen +seventeenfold +seventeens +seventeenth +seventeenths +seventh +seventhly +sevenths +seventies +seventieth +seventieths +seventy +seventyfold +sever +severability +severable +several +severalfold +severally +severalties +severalty +severance +severances +severe +severed +severely +severeness +severer +severest +severing +severities +severity +severs +severus +seviche +seviches +seville +sevres +sevruga +sevrugas +sew +sewability +sewable +sewage +sewed +sewellel +sewellels +sewer +sewerage +sewers +sewing +sewn +sews +sex +sexagenarian +sexagenarians +sexagenaries +sexagenary +sexagesima +sexagesimal +sexagesimally +sexagesimas +sexcentenaries +sexcentenary +sexdecillion +sexdecillions +sexduction +sexductions +sexed +sexennial +sexennially +sexennials +sexes +sexier +sexiest +sexily +sexiness +sexing +sexism +sexist +sexists +sexivalent +sexless +sexlessly +sexlessness +sexologic +sexological +sexologist +sexologists +sexology +sexpartite +sexploitation +sexpot +sexpots +sext +sextans +sextant +sextants +sextet +sextets +sextile +sextillion +sextillions +sextillionth +sextillionths +sexto +sextodecimo +sextodecimos +sexton +sextons +sextos +sexts +sextuple +sextupled +sextuples +sextuplet +sextuplets +sextuplicate +sextuplicated +sextuplicately +sextuplicates +sextuplicating +sextuplication +sextuplications +sextupling +sextuply +sexual +sexuality +sexualization +sexualizations +sexualize +sexualized +sexualizes +sexualizing +sexually +sexvalent +sexy +seychelles +seychellois +seyfert +seymour +seymours +señor +señora +señores +señorita +señors +sferics +sforza +sforzandi +sforzando +sforzandos +sforzas +sfumato +sfumatos +sgraffiti +sgraffito +sh +sha'ban +shaaban +shaanxi +shaba +shabbat +shabbier +shabbiest +shabbily +shabbiness +shabby +shabu +shabuoth +shack +shacked +shacking +shackle +shacklebone +shacklebones +shackled +shackler +shacklers +shackles +shackling +shacko +shacks +shad +shadberries +shadberry +shadblow +shadblows +shadbush +shadbushes +shaddock +shaddocks +shade +shaded +shadeless +shader +shaders +shades +shadflies +shadfly +shadier +shadiest +shadily +shadiness +shading +shadings +shadoof +shadoofs +shadow +shadowbox +shadowboxed +shadowboxes +shadowboxing +shadowed +shadower +shadowers +shadowgraph +shadowgraphs +shadowgraphy +shadowier +shadowiest +shadowily +shadowiness +shadowing +shadowless +shadowlike +shadows +shadowy +shads +shaduf +shadufs +shady +shaft +shafted +shafting +shaftings +shafts +shag +shagbark +shagbarks +shagged +shaggier +shaggiest +shaggily +shagginess +shagging +shaggy +shaggymane +shaggymanes +shagreen +shagreens +shags +shah +shahaptian +shahaptians +shahaptin +shahaptins +shahdom +shahdoms +shahs +shaitan +shaitans +shakable +shake +shakeable +shakedown +shakedowns +shaken +shakeout +shakeouts +shaker +shakerism +shakers +shakes +shakespeare +shakespearean +shakespeareana +shakespeareans +shakespearian +shakespeariana +shakespearians +shakeup +shakeups +shakier +shakiest +shakily +shakiness +shaking +shako +shakoes +shakos +shaksperean +shaksperian +shakta +shaktas +shakti +shaktism +shaktist +shaktists +shaky +shale +shaley +shalimar +shall +shallied +shallies +shalling +shalloon +shalloons +shallop +shallops +shallot +shallots +shallow +shallowed +shallower +shallowest +shallowing +shallowly +shallowness +shallows +shallu +shallus +shally +shallying +shallys +shalom +shalt +sham +shaman +shamanic +shamanism +shamanist +shamanistic +shamanists +shamans +shamash +shamble +shambled +shambles +shambling +shambolic +shambolically +shame +shamed +shamefaced +shamefacedly +shamefacedness +shamefast +shameful +shamefully +shamefulness +shameless +shamelessly +shamelessness +shames +shaming +shammed +shammer +shammers +shammes +shammies +shamming +shammosim +shammy +shampoo +shampooed +shampooer +shampooers +shampooing +shampoos +shamrock +shamrocks +shams +shamus +shamuses +shan +shan't +shandies +shandong +shandy +shandygaff +shandygaffs +shanghai +shanghaied +shanghaier +shanghaiers +shanghaiing +shanghais +shangri +shank +shanked +shanking +shankpiece +shankpieces +shanks +shans +shansi +shanter +shanters +shantey +shanteys +shanties +shantung +shanty +shantyman +shantymen +shantytown +shantytowns +shanxi +shapable +shape +shapeable +shaped +shapeless +shapelessly +shapelessness +shapelier +shapeliest +shapeliness +shapely +shapen +shaper +shapers +shapes +shapeup +shapeups +shaping +sharable +shard +shards +share +shareability +shareable +sharecrop +sharecropped +sharecropper +sharecroppers +sharecropping +sharecrops +shared +shareholder +shareholders +shareholding +shareowner +shareowners +sharer +sharers +shares +shareware +shari'a +shari'ah +sharia +sharif +sharifian +sharifs +sharing +shark +sharked +sharking +sharklike +sharks +sharkskin +sharon +sharp +sharped +sharpen +sharpened +sharpener +sharpeners +sharpening +sharpens +sharper +sharpers +sharpest +sharpie +sharpies +sharping +sharply +sharpness +sharps +sharpshooter +sharpshooters +sharpshooting +sharpshootings +sharpy +shashlick +shashlicks +shashlik +shashliks +shaslik +shasta +shastra +shastras +shat +shatter +shattered +shattering +shatteringly +shatterproof +shatters +shave +shaved +shaveling +shavelings +shaven +shaver +shavers +shaves +shavetail +shavetails +shavian +shavians +shaving +shavings +shavuot +shaw +shawl +shawled +shawling +shawls +shawm +shawms +shawnee +shawnees +shawwal +shay +shays +she +she'd +she'll +she's +shea +sheaf +sheafed +sheafing +sheaflike +sheafs +shear +sheared +shearer +shearers +shearing +shearling +shearlings +shears +shearwater +shearwaters +sheatfish +sheatfishes +sheath +sheathbill +sheathbills +sheathe +sheathed +sheather +sheathers +sheathes +sheathing +sheathings +sheaths +sheave +sheaved +sheaves +sheaving +shebang +shebat +shebats +shebeen +shebeens +shechinah +shed +shedder +shedders +shedding +shedlike +shedrow +shedrows +sheds +sheen +sheenies +sheeny +sheep +sheepberries +sheepberry +sheepcote +sheepcotes +sheepdog +sheepdogs +sheepfold +sheepfolds +sheepherder +sheepherders +sheepherding +sheepish +sheepishly +sheepishness +sheepshank +sheepshanks +sheepshead +sheepsheads +sheepshearer +sheepshearers +sheepshearing +sheepshearings +sheepskin +sheepskins +sheer +sheered +sheerer +sheerest +sheering +sheerlegs +sheerly +sheerness +sheers +sheet +sheeted +sheeter +sheeters +sheetfed +sheeting +sheetlike +sheetrock +sheets +shegetz +sheik +sheika +sheikas +sheikdom +sheikdoms +sheikh +sheikha +sheikhas +sheikhdom +sheikhdoms +sheikhs +sheiks +sheila +shekel +shekels +shekinah +shelby +sheldonian +sheldrake +sheldrakes +shelduck +shelducks +shelf +shelfful +shelffuls +shelflike +shelikof +shell +shellac +shellack +shellacked +shellacking +shellacks +shellacs +shellback +shellbacks +shellbark +shellbarks +shellcracker +shellcrackers +shelled +sheller +shellers +shelley +shelleys +shellfire +shellfish +shellfisheries +shellfishery +shellfishes +shellfishing +shellflower +shellflowers +shellier +shelliest +shelling +shellproof +shells +shellshocked +shellwork +shelly +shelta +shelter +shelterbelt +shelterbelts +sheltered +shelterer +shelterers +sheltering +shelterless +shelters +sheltie +shelties +shelty +shelve +shelved +shelver +shelvers +shelves +shelving +shema +shemini +shenandoah +shenanigan +shenanigans +shensi +sheol +shepherd +shepherded +shepherdess +shepherdesses +shepherding +shepherds +sheqalim +sheqel +sheraton +sherbert +sherberts +sherbet +sherbets +sherd +sherds +shergottite +shergottites +sheridan +sherif +sheriff +sheriffdom +sheriffs +sherifs +sherlock +sheroot +sheroots +sherpa +sherpas +sherries +sherry +shetland +shetlander +shetlanders +shetlands +shevat +shevats +shewbread +shewbreads +shi +shi'ism +shi'ite +shi'ites +shia +shias +shiatsu +shiatzu +shibah +shibboleth +shibboleths +shied +shield +shielded +shielder +shielders +shielding +shields +shieling +shielings +shier +shies +shiest +shift +shiftable +shifted +shifter +shifters +shiftier +shiftiest +shiftily +shiftiness +shifting +shiftless +shiftlessly +shiftlessness +shifts +shifty +shigella +shigellae +shigellas +shigelloses +shigellosis +shiism +shiitake +shiite +shiites +shiitic +shikar +shikari +shikaris +shikarred +shikarring +shikoku +shiksa +shiksas +shikse +shikses +shill +shillalah +shillalahs +shilled +shillelagh +shillelaghs +shilling +shillings +shills +shilluk +shilluks +shilly +shim +shimmed +shimmer +shimmered +shimmering +shimmeringly +shimmers +shimmery +shimmied +shimmies +shimming +shimmy +shimmying +shims +shin +shina +shinbone +shinbones +shindies +shindig +shindigs +shindy +shindys +shine +shined +shiner +shiners +shines +shingle +shingled +shingler +shinglers +shingles +shingling +shingly +shingon +shinier +shiniest +shininess +shining +shiningly +shinleaf +shinleafs +shinleaves +shinned +shinneries +shinnery +shinney +shinneys +shinnied +shinnies +shinning +shinny +shinnying +shinplaster +shinplasters +shins +shinsplints +shinto +shintoism +shintoist +shintoistic +shintoists +shiny +ship +shipboard +shipborne +shipbuilder +shipbuilders +shipbuilding +shipfitter +shipfitters +shiplap +shiplapped +shipload +shiploads +shipman +shipmaster +shipmasters +shipmate +shipmates +shipmen +shipment +shipments +shipowner +shipowners +shippable +shipped +shipper +shippers +shipping +ships +shipshape +shipside +shipsides +shipway +shipways +shipworm +shipworms +shipwreck +shipwrecked +shipwrecking +shipwrecks +shipwright +shipwrights +shipyard +shipyards +shire +shires +shirk +shirked +shirker +shirkers +shirking +shirks +shirr +shirred +shirring +shirrs +shirt +shirtdress +shirtdresses +shirted +shirtfront +shirtfronts +shirtier +shirtiest +shirting +shirtless +shirtmaker +shirtmakers +shirts +shirtsleeve +shirtsleeved +shirtsleeves +shirttail +shirttails +shirtwaist +shirtwaists +shirty +shish +shit +shitake +shitfaced +shithead +shitheads +shitless +shitlist +shitlists +shits +shittah +shittahs +shittier +shittiest +shittim +shittimwood +shittimwoods +shitting +shitty +shiv +shiva +shivah +shivaism +shivaist +shivaists +shivaree +shivarees +shiver +shivered +shivering +shivers +shivery +shivs +shkotzim +shlemiehl +shlemiehls +shlemiel +shlemiels +shlep +shlepp +shlepped +shlepper +shleppers +shlepping +shlepps +shleps +shlock +shmear +shmooze +shmoozed +shmoozes +shmoozing +shmuck +shmucks +shoal +shoaled +shoaling +shoals +shoat +shoats +shock +shockable +shocked +shocker +shockers +shocking +shockingly +shockproof +shocks +shod +shodden +shoddier +shoddies +shoddiest +shoddily +shoddiness +shoddy +shoe +shoebill +shoebills +shoeblack +shoeblacks +shoebox +shoeboxes +shoed +shoehorn +shoehorned +shoehorning +shoehorns +shoeing +shoelace +shoelaces +shoeless +shoemaker +shoemakers +shoemaking +shoepac +shoepack +shoepacks +shoepacs +shoes +shoeshine +shoeshines +shoestring +shoestrings +shoetree +shoetrees +shofar +shofars +shofroth +shogi +shogis +shogun +shogunal +shogunate +shogunates +shoguns +shoji +shojis +shona +shonas +shone +shoo +shooed +shooflies +shoofly +shooing +shook +shooks +shoos +shoot +shootdown +shootdowns +shooter +shooters +shooting +shootings +shootout +shootouts +shoots +shop +shopkeeper +shopkeepers +shoplift +shoplifted +shoplifter +shoplifters +shoplifting +shoplifts +shoppe +shopped +shopper +shoppers +shoppes +shopping +shops +shoptalk +shopwindow +shopwindows +shopworn +shoran +shorans +shore +shorebird +shorebirds +shored +shorefront +shorefronts +shoreline +shorelines +shores +shoreside +shoreward +shorewards +shoring +shorings +shorn +short +shortage +shortages +shortbread +shortcake +shortcakes +shortchange +shortchanged +shortchanger +shortchangers +shortchanges +shortchanging +shortcoming +shortcomings +shortcut +shortcuts +shortcutting +shorted +shorten +shortened +shortener +shorteners +shortening +shortenings +shortens +shorter +shortest +shortfall +shortfalls +shorthair +shorthaired +shorthairs +shorthand +shorthanded +shorthands +shorthorn +shorthorns +shortia +shortias +shortie +shorties +shorting +shortish +shortleaf +shortlist +shortlists +shortly +shortness +shorts +shortsighted +shortsightedly +shortsightedness +shortstop +shortstops +shortwave +shorty +shoshone +shoshonean +shoshones +shoshoni +shoshonis +shostakovich +shot +shote +shotes +shotgun +shotgunner +shotgunners +shotguns +shots +shott +shotted +shotten +shotting +shotts +should +should've +shoulder +shouldered +shouldering +shoulders +shouldest +shouldn +shouldn't +shouldst +shout +shouted +shouter +shouters +shouting +shouts +shove +shoved +shovel +shoveled +shoveler +shovelers +shovelful +shovelfuls +shovelhead +shovelheads +shoveling +shovelled +shoveller +shovellers +shovelling +shovelnose +shovelnoses +shovels +shovelsful +shover +shovers +shoves +shoving +show +showable +showbiz +showbizzy +showboat +showboated +showboating +showboats +showbread +showbreads +showcase +showcased +showcases +showcasing +showdown +showdowns +showed +shower +showered +showerer +showerers +showerhead +showerheads +showering +showerless +showers +showery +showgirl +showgirls +showier +showiest +showily +showiness +showing +showings +showman +showmanship +showmen +shown +showoff +showoffs +showpiece +showpieces +showplace +showplaces +showring +showrings +showroom +showrooms +shows +showstopper +showstoppers +showstopping +showtime +showtimes +showy +shoyu +shrank +shrapnel +shred +shredded +shredder +shredders +shredding +shreds +shrew +shrewd +shrewder +shrewdest +shrewdly +shrewdness +shrewish +shrewishly +shrewishness +shrewlike +shrewmice +shrewmouse +shrews +shriek +shrieked +shrieker +shriekers +shrieking +shrieks +shrieval +shrievalty +shrift +shrifts +shrike +shrikes +shrill +shrilled +shriller +shrillest +shrilling +shrillness +shrills +shrilly +shrimp +shrimped +shrimper +shrimpers +shrimpfish +shrimpfishes +shrimping +shrimplike +shrimps +shrimpy +shrine +shrined +shriner +shriners +shrines +shrining +shrink +shrinkable +shrinkage +shrinkages +shrinker +shrinkers +shrinking +shrinks +shrive +shrived +shrivel +shriveled +shriveling +shrivelled +shrivelling +shrivels +shriven +shriver +shrivers +shrives +shriving +shroff +shroffs +shropshire +shroud +shrouded +shrouding +shrouds +shrove +shrovetide +shrub +shrubberies +shrubbery +shrubbier +shrubbiest +shrubbiness +shrubby +shrubs +shrug +shrugged +shrugging +shrugs +shrunk +shrunken +shtetel +shtetels +shtetl +shtetlach +shtetls +shtick +shticks +shtik +shtiks +shuck +shucked +shucker +shuckers +shucking +shucks +shudder +shuddered +shuddering +shudderingly +shudders +shuddery +shuffle +shuffleboard +shuffled +shuffler +shufflers +shuffles +shuffling +shui +shul +shuls +shun +shunned +shunner +shunners +shunning +shunpike +shunpiked +shunpiker +shunpikers +shunpikes +shunpiking +shuns +shunt +shunted +shunter +shunters +shunting +shunts +shush +shushed +shushes +shushing +shut +shutdown +shutdowns +shute +shuteye +shutoff +shutoffs +shutout +shutouts +shuts +shutter +shutterbug +shutterbugs +shuttered +shuttering +shutterless +shutters +shutting +shuttle +shuttlecock +shuttlecocked +shuttlecocking +shuttlecocks +shuttlecraft +shuttlecrafts +shuttled +shuttleless +shuttler +shuttlers +shuttles +shuttling +shy +shyer +shyers +shyest +shying +shylock +shylocked +shylocking +shylocks +shyly +shyness +shyster +shysterism +shysters +si +siabon +siabons +sial +sialadenitis +sialadenitises +sialagogic +sialagogue +sialagogues +sialic +sialomucin +sialomucins +sialorrhea +sialorrheas +sialorrhoea +sialorrhoeas +sials +siam +siamang +siamangs +siamese +sib +sibari +sibelius +siberia +siberian +siberians +sibilance +sibilancy +sibilant +sibilantly +sibilants +sibilate +sibilated +sibilates +sibilating +sibilation +sibilations +sibling +siblings +sibs +sibuyan +sibyl +sibylic +sibyllic +sibylline +sibyls +sic +siccative +siccatives +sicced +siccing +sichuan +sicilian +sicilians +sicily +sick +sickbay +sickbays +sickbed +sickbeds +sicked +sicken +sickened +sickener +sickeners +sickening +sickeningly +sickens +sicker +sickert +sickest +sickie +sickies +sicking +sickish +sickishly +sickishness +sickle +sicklebill +sicklebills +sickled +sicklemia +sicklemias +sickles +sicklied +sicklier +sicklies +sickliest +sicklily +sickliness +sickling +sickly +sicklying +sickness +sicknesses +sicko +sickos +sickout +sickouts +sickroom +sickrooms +sicks +sics +siddons +siddur +siddurim +side +sidearm +sidearms +sideband +sidebands +sidebar +sidebars +sideboard +sideboards +sideburn +sideburned +sideburns +sidecar +sidecars +sided +sidedly +sidedness +sidedress +sidedresses +sidehill +sidehills +sidekick +sidekicks +sidelight +sidelights +sideline +sidelined +sideliner +sideliners +sidelines +sideling +sidelining +sidelong +sideman +sidemen +sidepiece +sidepieces +sider +sidereal +siderite +siderites +sideritic +siderochrome +siderochromes +siderocyte +siderocytes +siderolite +siderolites +siderosis +sides +sidesaddle +sidesaddles +sideshow +sideshows +sideslip +sideslipped +sideslipping +sideslips +sidespin +sidespins +sidesplitting +sidesplittingly +sidestep +sidestepped +sidestepper +sidesteppers +sidestepping +sidesteps +sidestream +sidestroke +sidestroked +sidestroker +sidestrokers +sidestrokes +sidestroking +sideswipe +sideswiped +sideswiper +sideswipers +sideswipes +sideswiping +sidetrack +sidetracked +sidetracking +sidetracks +sidewalk +sidewalks +sidewall +sidewalls +sideward +sidewards +sideway +sideways +sidewinder +sidewinders +sidewise +siding +sidings +sidle +sidled +sidles +sidling +sidlingly +sidney +sidon +siege +sieged +sieges +siegfried +sieging +siemens +siena +sienese +sienna +sierozem +sierozems +sierra +sierran +sierras +siesta +siestas +sieva +sieve +sieved +sievert +sieverts +sieves +sieving +sifaka +sifakas +sift +sifted +sifter +sifters +sifting +siftings +sifts +sigh +sighed +sigher +sighers +sighing +sighs +sight +sighted +sightedly +sightedness +sighting +sightings +sightless +sightlessly +sightlessness +sightlier +sightliest +sightline +sightlines +sightliness +sightly +sights +sightsaw +sightsee +sightseeing +sightseen +sightseer +sightseers +sightsees +sigil +sigils +sigismund +sigma +sigmas +sigmate +sigmoid +sigmoidal +sigmoidally +sigmoidoscope +sigmoidoscopes +sigmoidoscopic +sigmoidoscopy +sign +signage +signal +signaled +signaler +signalers +signaling +signalization +signalizations +signalize +signalized +signalizes +signalizing +signalled +signaller +signallers +signalling +signally +signalman +signalmen +signalment +signalments +signals +signatories +signatory +signature +signatures +signboard +signboards +signed +signee +signees +signer +signers +signet +signeted +signeting +signets +signifiable +significance +significances +significancy +significant +significantly +signification +significations +significative +significativeness +significs +signified +signifier +signifiers +signifies +signify +signifying +signing +signings +signior +signiories +signiors +signiory +signoff +signoffs +signor +signora +signoras +signore +signori +signories +signorina +signorinas +signorine +signors +signory +signpost +signposts +signs +sihasapa +sihasapas +sika +sikas +sikh +sikhism +sikhs +sikkim +sikkimese +silage +silane +silanes +silastic +sild +silds +silence +silenced +silencer +silencers +silences +silencing +sileni +silent +silently +silentness +silents +silenus +silesia +silesian +silesians +silesias +silex +silexes +silhouette +silhouetted +silhouettes +silhouetting +silhouettist +silhouettists +silica +silicate +silicates +siliceous +silicic +silicide +silicides +siliciferous +silicification +silicifications +silicified +silicifies +silicify +silicifying +silicious +silicle +silicles +silicon +silicone +silicones +siliconized +silicoses +silicosis +silicotic +silique +siliques +siliquose +siliquous +silk +silkaline +silked +silken +silkier +silkiest +silkily +silkiness +silking +silklike +silkoline +silks +silkscreen +silkscreened +silkscreening +silkscreens +silkweed +silkweeds +silkworm +silkworms +silky +sill +sillabub +sillabubs +sillier +sillies +silliest +sillily +sillimanite +silliness +sills +silly +silo +siloed +siloing +silos +siloxane +siloxanes +silt +siltation +siltations +silted +silting +silts +siltstone +siltstones +silty +silures +silurian +silurid +silurids +silva +silvae +silvan +silvanus +silvas +silver +silverback +silverbacked +silverbacks +silverbell +silverberries +silverberry +silvered +silverer +silverers +silvereye +silvereyes +silverfish +silverfishes +silveriness +silvering +silverly +silvern +silverpoint +silverpoints +silverrod +silverrods +silvers +silverside +silversides +silversmith +silversmithing +silversmiths +silvertip +silvertips +silverware +silverweed +silverweeds +silverwork +silvery +silvex +silvexes +silvichemical +silvichemicals +silvicolous +silvicultural +silviculturally +silviculture +silviculturist +silviculturists +sima +simas +simazine +simchas +simchat +simeon +simian +simians +similar +similarities +similarity +similarly +simile +similes +similitude +simla +simmental +simmentals +simmenthal +simmenthals +simmer +simmered +simmering +simmers +simnel +simnels +simoleon +simoleons +simon +simoniac +simoniacal +simoniacally +simoniacs +simonist +simonists +simonize +simonized +simonizes +simonizing +simony +simoom +simooms +simoon +simoons +simp +simpatico +simper +simpered +simperer +simperers +simpering +simperingly +simpers +simple +simpleminded +simplemindedly +simplemindedness +simpleness +simpler +simples +simplest +simpleton +simpletons +simplex +simplexes +simplices +simplicia +simplicial +simplicially +simplicities +simplicity +simplification +simplifications +simplified +simplifier +simplifiers +simplifies +simplify +simplifying +simplism +simplistic +simplistically +simplon +simply +simps +simpson +simulacra +simulacre +simulacres +simulacrum +simulacrums +simular +simulars +simulate +simulated +simulates +simulating +simulation +simulations +simulative +simulator +simulators +simulcast +simulcasted +simulcasting +simulcasts +simulium +simuliums +simultaneity +simultaneous +simultaneously +simultaneousness +sin +sinai +sinanthropus +sinanthropuses +sinapism +sinapisms +sinbad +since +sincere +sincerely +sincereness +sincerer +sincerest +sincerity +sincipita +sincipital +sinciput +sinciputs +sind +sindbad +sindhi +sindhis +sine +sinecure +sinecures +sinecurism +sinecurist +sinecurists +sines +sinew +sinewed +sinewing +sinews +sinewy +sinfonia +sinfonias +sinfonietta +sinfoniettas +sinful +sinfully +sinfulness +sing +singable +singapore +singaporean +singaporeans +singe +singed +singeing +singer +singers +singes +singh +singhalese +singing +singings +single +singled +singlehood +singleness +singles +singlestick +singlesticker +singlestickers +singlesticks +singlet +singleton +singletons +singletree +singletrees +singlets +singlewide +singlewides +singling +singly +sings +singsong +singsongs +singsongy +singspiel +singspiels +singular +singularities +singularity +singularize +singularized +singularizes +singularizing +singularly +singularness +singulars +sinhala +sinhalese +sinicism +sinicisms +sinicization +sinicizations +sinicize +sinicized +sinicizes +sinicizing +sinification +sinifications +sinified +sinifies +sinify +sinifying +sinister +sinisterly +sinisterness +sinistral +sinistrally +sinistrorse +sinistrorsely +sinistrous +sinistrously +sinitic +sink +sinkable +sinkage +sinkages +sinker +sinkerball +sinkerballs +sinkers +sinkhole +sinkholes +sinkiang +sinking +sinks +sinless +sinlessly +sinlessness +sinn +sinned +sinner +sinners +sinning +sino +sinoatrial +sinoauricular +sinolog +sinological +sinologist +sinologists +sinologs +sinologue +sinologues +sinology +sinope +sinophile +sinophiles +sinophilia +sinophobe +sinophobes +sinophobia +sinophobic +sinopia +sinopias +sinopie +sins +sinsemilla +sinsemillas +sinter +sinterability +sintered +sintering +sinters +sinuate +sinuated +sinuately +sinuates +sinuating +sinuation +sinuations +sinuosities +sinuosity +sinuous +sinuously +sinuousness +sinus +sinuses +sinusitis +sinusoid +sinusoidal +sinusoidally +sinusoids +siouan +siouans +sioux +sip +siphon +siphonal +siphoned +siphonic +siphoning +siphonophore +siphonophores +siphonostele +siphonosteles +siphonostelic +siphons +siphuncle +siphuncles +siphuncular +siphunculate +sipped +sipper +sippers +sippet +sippets +sipping +sips +sir +sirach +sirdar +sirdars +sire +sired +siree +siren +sirenian +sirenians +sirens +sires +siriases +siriasis +siring +sirius +sirloin +sirloins +sirocco +siroccos +sirrah +sirrahs +sirree +sirs +sirup +sirups +sirupy +sirvente +sirventes +sis +sisal +sisals +siscowet +siscowets +siskin +siskins +sisseton +sissetons +sissies +sissified +sissify +sissifying +sissiness +sissy +sissyish +sissyness +sister +sisterhood +sisterhoods +sisterliness +sisterly +sisters +sistine +sistra +sistrum +sistrums +sisyphean +sisyphian +sisyphus +sit +sita +sitar +sitarist +sitarists +sitars +sitatunga +sitatungas +sitcom +sitcoms +site +sited +sites +sith +siting +sitka +sitkas +sitology +sitomania +sitomanias +sitophobia +sitophobias +sitosterol +sitosterols +sits +sitter +sitters +sitting +sittings +situ +situate +situated +situates +situating +situation +situational +situationally +situations +situs +situtunga +situtungas +sitz +sitzkrieg +sitzkriegs +sitzmark +sitzmarks +siva +sivaism +sivaist +sivaists +sivan +siwalik +siwash +six +sixes +sixfold +sixmo +sixmos +sixpence +sixpences +sixpenny +sixteen +sixteenfold +sixteenmo +sixteenmos +sixteenpenny +sixteens +sixteenth +sixteenths +sixth +sixthly +sixths +sixties +sixtieth +sixtieths +sixtine +sixty +sixtyfold +sixtyish +sizable +sizableness +sizably +sizar +sizars +size +sizeable +sized +sizer +sizers +sizes +sizing +sizings +sizzle +sizzled +sizzler +sizzlers +sizzles +sizzling +sizzlingly +siècle +sjaelland +sjambok +sjamboked +sjamboking +sjamboks +sjögren +ska +skag +skagerak +skagerrak +skags +skald +skaldic +skalds +skamble +skanda +skaneateles +skat +skate +skateboard +skateboarded +skateboarder +skateboarders +skateboarding +skateboards +skated +skater +skaters +skates +skating +skatol +skatole +skatoles +skatols +skean +skeane +skeans +skedaddle +skedaddled +skedaddler +skedaddlers +skedaddles +skedaddling +skeet +skeeter +skeeters +skeg +skegs +skein +skeins +skeletal +skeletally +skeleton +skeletonic +skeletonize +skeletonized +skeletonizer +skeletonizers +skeletonizes +skeletonizing +skeletons +skell +skells +skelter +skeltered +skeltering +skelters +skeltonics +skene +skenes +skep +skeps +skepsis +skeptic +skeptical +skeptically +skepticism +skeptics +skerries +skerry +sketch +sketchbook +sketchbooks +sketched +sketcher +sketchers +sketches +sketchier +sketchiest +sketchily +sketchiness +sketching +sketchpad +sketchpads +sketchy +skew +skewback +skewbacks +skewbald +skewbalds +skewed +skewer +skewered +skewering +skewers +skewing +skewness +skews +ski +skiable +skiagram +skiagrams +skiagraph +skiagraphs +skiagraphy +skiascope +skiascopes +skiascopies +skiascopy +skibob +skibobber +skibobbers +skibobbing +skibobs +skid +skidded +skidder +skidders +skiddier +skiddiest +skidding +skiddoo +skiddy +skidoo +skidoos +skidproof +skids +skied +skier +skiers +skies +skiey +skiff +skiffle +skiffs +skiing +skijoring +skilful +skill +skilled +skilless +skillessness +skillet +skillets +skillful +skillfully +skillfulness +skilling +skillings +skills +skim +skimble +skimmed +skimmer +skimmers +skimming +skimobile +skimobiles +skimp +skimped +skimpier +skimpiest +skimpily +skimpiness +skimping +skimps +skimpy +skims +skin +skinflint +skinflints +skinful +skinfuls +skinhead +skinheads +skink +skinker +skinkers +skinks +skinless +skinned +skinner +skinnerian +skinnerians +skinnerism +skinners +skinnier +skinniest +skinniness +skinning +skinny +skins +skintight +skip +skipjack +skipjacks +skippable +skipped +skipper +skippered +skippering +skippers +skipping +skips +skirl +skirled +skirling +skirls +skirmish +skirmished +skirmisher +skirmishers +skirmishes +skirmishing +skirr +skirred +skirret +skirrets +skirring +skirrs +skirt +skirted +skirter +skirters +skirting +skirts +skis +skit +skits +skitter +skittered +skittering +skitters +skittery +skittish +skittishly +skittishness +skittle +skittles +skive +skived +skiver +skivers +skives +skiving +skivvies +skivvy +skiwear +skoal +skoda +skopje +skosh +skua +skuas +skulduggeries +skulduggery +skulk +skulked +skulker +skulkers +skulking +skulks +skull +skullcap +skullcaps +skullduggeries +skullduggery +skulled +skulls +skunk +skunked +skunking +skunks +skunkweed +skunkweeds +skunkworks +sky +skyborne +skybox +skyboxes +skycap +skycaps +skydive +skydived +skydiver +skydivers +skydives +skydiving +skye +skyey +skyhook +skyhooks +skying +skyjack +skyjacked +skyjacker +skyjackers +skyjacking +skyjacks +skylark +skylarked +skylarker +skylarkers +skylarking +skylarks +skylight +skylighted +skylights +skyline +skylines +skylit +skyrocket +skyrocketed +skyrocketing +skyrockets +skyros +skysail +skysails +skyscraper +skyscrapers +skyscraping +skywalk +skywalks +skyward +skywards +skyway +skyways +skywrite +skywriter +skywriters +skywrites +skywriting +skywritten +skywrote +skíros +slab +slabbed +slabber +slabbered +slabbering +slabbers +slabbing +slablike +slabs +slack +slacked +slacken +slackened +slackening +slackens +slacker +slackers +slackest +slacking +slackly +slackness +slacks +slag +slagged +slagging +slaggy +slags +slain +slake +slaked +slakes +slaking +slalom +slalomed +slalomer +slalomers +slaloming +slalomist +slalomists +slaloms +slam +slammed +slammer +slammers +slamming +slams +slander +slandered +slanderer +slanderers +slandering +slanderous +slanderously +slanderousness +slanders +slang +slanged +slangily +slanginess +slanging +slangs +slanguage +slangy +slant +slanted +slanting +slantingly +slants +slantways +slantwise +slanty +slap +slapdash +slaphappier +slaphappiest +slaphappy +slapjack +slapjacks +slapped +slapper +slappers +slapping +slaps +slapstick +slapsticks +slash +slashed +slasher +slashers +slashes +slashing +slashingly +slat +slate +slated +slatelike +slater +slaters +slates +slatey +slather +slathered +slathering +slathers +slatier +slatiest +slating +slats +slatted +slattern +slatternliness +slatternly +slatterns +slatting +slaty +slaughter +slaughtered +slaughterer +slaughterers +slaughterhouse +slaughterhouses +slaughtering +slaughterous +slaughterously +slaughters +slav +slave +slaved +slaveholder +slaveholders +slaveholding +slaveholdings +slaver +slavered +slaveries +slavering +slavers +slavery +slaves +slavey +slaveys +slavic +slavicist +slavicists +slaving +slavish +slavishly +slavishness +slavism +slavist +slavists +slavocracies +slavocracy +slavocrat +slavocratic +slavocrats +slavonia +slavonian +slavonians +slavonic +slavophil +slavophile +slavophiles +slavophilism +slavophils +slavs +slaw +slaws +slay +slayed +slayer +slayers +slaying +slays +sle +sleave +sleaves +sleaze +sleazebag +sleazebags +sleazeball +sleazeballs +sleazier +sleaziest +sleazily +sleaziness +sleazo +sleazy +sled +sledded +sledder +sledders +sledding +sledge +sledged +sledgehammer +sledgehammered +sledgehammering +sledgehammers +sledges +sledging +sleds +sleek +sleeked +sleeken +sleekened +sleekening +sleekens +sleeker +sleekest +sleeking +sleekly +sleekness +sleeks +sleep +sleeper +sleepers +sleepier +sleepiest +sleepily +sleepiness +sleeping +sleepless +sleeplessly +sleeplessness +sleeplike +sleepover +sleepovers +sleeps +sleepwalk +sleepwalked +sleepwalker +sleepwalkers +sleepwalking +sleepwalks +sleepwear +sleepy +sleepyhead +sleepyheads +sleet +sleeted +sleeting +sleets +sleety +sleeve +sleeved +sleeveless +sleevelet +sleevelets +sleeves +sleeving +sleigh +sleighed +sleigher +sleighers +sleighing +sleighs +sleight +sleights +slender +slenderer +slenderest +slenderize +slenderized +slenderizes +slenderizing +slenderly +slenderness +slept +sles +sleuth +sleuthed +sleuthhound +sleuthhounds +sleuthing +sleuths +slew +slewed +slewing +slews +slice +sliceable +sliced +slicer +slicers +slices +slicing +slick +slicked +slicken +slickened +slickener +slickeners +slickening +slickens +slickenside +slickensides +slicker +slickers +slickest +slicking +slickly +slickness +slickrock +slicks +slid +slidden +slide +slider +sliders +slides +slideway +slideways +sliding +slier +sliest +slight +slighted +slighter +slightest +slighting +slightingly +slightly +slightness +slights +slim +slime +slimeball +slimeballs +slimed +slimes +slimier +slimiest +slimily +sliminess +sliming +slimly +slimmed +slimmer +slimmers +slimmest +slimming +slimnastics +slimness +slimpsy +slims +slimsier +slimsiest +slimsy +slimy +sling +slinger +slingers +slinging +slings +slingshot +slingshots +slink +slinked +slinkier +slinkiest +slinkily +slinkiness +slinking +slinkingly +slinks +slinky +slip +slipcase +slipcased +slipcases +slipcover +slipcovered +slipcovering +slipcovers +slipform +slipformed +slipforming +slipforms +slipknot +slipknots +slipover +slipovers +slippage +slipped +slipper +slippered +slipperier +slipperiest +slipperiness +slippers +slipperwort +slipperworts +slippery +slippier +slippiest +slipping +slippy +slips +slipshod +slipshoddiness +slipshodness +slipslop +slipslops +slipsole +slipsoles +slipstitch +slipstitches +slipstream +slipstreamed +slipstreaming +slipstreams +slipup +slipups +slipware +slipway +slipways +slit +slither +slithered +slithering +slithers +slithery +slitless +slits +slitter +slitters +slitting +slitty +sliver +slivered +slivering +slivers +slivery +slivovitz +slob +slobber +slobbered +slobberer +slobberers +slobbering +slobbers +slobbery +slobbish +slobby +slobs +sloe +sloes +slog +slogan +sloganeer +sloganeered +sloganeering +sloganeers +sloganize +sloganized +sloganizer +sloganizers +sloganizes +sloganizing +slogans +slogged +slogger +sloggers +slogging +slogs +sloop +sloops +slop +slope +sloped +sloper +slopers +slopes +sloping +slopingly +slopped +sloppier +sloppiest +sloppily +sloppiness +slopping +sloppy +slops +slopwork +slosh +sloshed +sloshes +sloshing +sloshy +slot +slotback +slotbacks +sloth +slothful +slothfully +slothfulness +sloths +slots +slotted +slotting +slouch +slouched +sloucher +slouchers +slouches +slouchier +slouchiest +slouchily +slouchiness +slouching +slouchy +slough +sloughed +sloughing +sloughs +sloughy +slovak +slovakia +slovakian +slovakians +slovaks +sloven +slovene +slovenes +slovenia +slovenian +slovenians +slovenlier +slovenliest +slovenliness +slovenly +slovens +slow +slowdown +slowdowns +slowed +slower +slowest +slowing +slowish +slowly +slowness +slowpoke +slowpokes +slows +slowwitted +slowworm +slowworms +sloyd +sloyds +slub +slubbed +slubbing +slubs +sludge +sludged +sludges +sludgiest +sludging +sludgy +slue +slued +slues +slug +slugabed +slugabeds +slugfest +slugfests +sluggard +sluggardly +sluggardness +sluggards +slugged +slugger +sluggers +slugging +sluggish +sluggishly +sluggishness +slugs +sluice +sluiced +sluices +sluiceway +sluiceways +sluicing +sluicy +sluing +slum +slumber +slumbered +slumberer +slumberers +slumbering +slumberingly +slumberous +slumberously +slumberousness +slumbers +slumbery +slumbrous +slumgullion +slumgullions +slumlord +slumlords +slummed +slummer +slummier +slummiest +slumming +slummy +slump +slumped +slumpflation +slumping +slumps +slums +slung +slungshot +slungshots +slunk +slur +slurb +slurbs +slurp +slurped +slurping +slurps +slurred +slurried +slurries +slurring +slurry +slurrying +slurs +slush +slushed +slushes +slushier +slushiest +slushily +slushiness +slushing +slushy +slut +sluts +sluttish +sluttishly +sluttishness +slutty +sly +slyboots +slyer +slyest +slyly +slyness +slype +slypes +smack +smacked +smacker +smackers +smacking +smacks +small +smallclothes +smaller +smallest +smallholder +smallholders +smallholding +smallholdings +smallish +smallmouth +smallness +smallpox +smalls +smallsword +smallswords +smalltime +smalltimer +smalltimers +smalt +smalti +smaltine +smaltines +smaltite +smaltites +smalto +smalts +smaragd +smaragdine +smaragdite +smaragdites +smarm +smarmier +smarmiest +smarmily +smarminess +smarmy +smart +smarted +smarten +smartened +smartening +smartens +smarter +smartest +smartie +smarties +smarting +smartly +smartness +smarts +smartweed +smartweeds +smarty +smash +smashed +smasher +smashers +smashes +smashing +smashingly +smashup +smashups +smatter +smattered +smatterer +smatterers +smattering +smatterings +smatters +smaze +smazes +smear +smearcase +smearcases +smeared +smearer +smearers +smearier +smeariest +smeariness +smearing +smears +smeary +smectic +smectite +smectites +smectitic +smegma +smell +smelled +smeller +smellers +smellier +smelliest +smelling +smells +smelly +smelt +smelted +smelter +smelteries +smelters +smeltery +smelting +smelts +smetana +smew +smews +smidge +smidgen +smidgens +smidgeon +smidgeons +smidgin +smidgins +smiercase +smilax +smilaxes +smile +smiled +smileless +smiler +smilers +smiles +smiley +smiling +smilingly +smilingness +smilodons +smilodonss +smily +smirch +smirched +smirches +smirching +smirk +smirked +smirker +smirkers +smirkily +smirking +smirkingly +smirks +smirky +smite +smiter +smiters +smites +smith +smithereens +smitheries +smithery +smithfield +smithies +smiths +smithsonian +smithsonite +smithsonites +smithy +smiting +smitten +smock +smocked +smocking +smockings +smocks +smog +smoggier +smoggiest +smoggy +smogless +smokable +smoke +smokeable +smoked +smokehouse +smokehouses +smokejack +smokejacks +smokejumper +smokejumpers +smokeless +smokelike +smoker +smokers +smokes +smokescreen +smokescreens +smokestack +smokestacks +smokey +smokier +smokiest +smokily +smokiness +smoking +smoky +smolder +smoldered +smoldering +smolderingly +smolders +smolensk +smollett +smolt +smolts +smooch +smooched +smooches +smooching +smoochy +smooth +smoothbore +smoothbores +smoothed +smoothen +smoothened +smoothening +smoothens +smoother +smoothers +smoothes +smoothest +smoothie +smoothies +smoothing +smoothly +smoothness +smooths +smoothy +smorgasbord +smorgasbords +smote +smother +smothered +smothering +smothers +smothery +smoulder +smouldered +smouldering +smoulders +smudge +smudged +smudges +smudgier +smudgiest +smudgily +smudginess +smudging +smudgy +smug +smugger +smuggest +smuggle +smuggled +smuggler +smugglers +smuggles +smuggling +smugly +smugness +smut +smutch +smutched +smutches +smutching +smutchy +smuts +smutted +smuttier +smuttiest +smuttily +smuttiness +smutting +smutty +smyrna +snack +snacked +snacker +snackers +snacking +snacks +snaffle +snaffled +snaffles +snaffling +snafu +snafued +snafuing +snafus +snag +snagged +snagging +snaggleteeth +snaggletooth +snaggletoothed +snaggy +snags +snail +snaillike +snails +snake +snake's +snakebird +snakebirds +snakebit +snakebite +snakebites +snakebitten +snaked +snakefish +snakefishes +snakehead +snakeheads +snakelike +snakemouth +snakemouths +snakeroot +snakeroots +snakes +snakeskin +snakeskins +snakestone +snakestones +snakeweed +snakeweeds +snakey +snakier +snakiest +snakily +snakiness +snaking +snaky +snap +snapback +snapbacks +snapdragon +snapdragons +snapped +snapper +snappers +snappier +snappiest +snappily +snappiness +snapping +snappish +snappishly +snappishness +snappy +snaps +snapshoot +snapshooter +snapshooters +snapshooting +snapshoots +snapshot +snapshots +snare +snared +snarer +snarers +snares +snaring +snarky +snarl +snarled +snarler +snarlers +snarling +snarlingly +snarls +snarly +snatch +snatched +snatcher +snatchers +snatches +snatchier +snatchiest +snatching +snatchy +snath +snathe +snathes +snaths +snazzier +snazziest +snazziness +snazzy +sneak +sneaked +sneaker +sneakered +sneakers +sneakier +sneakiest +sneakily +sneakiness +sneaking +sneakingly +sneaks +sneaky +sneer +sneered +sneerer +sneerers +sneerful +sneering +sneeringly +sneers +sneery +sneeze +sneezed +sneezer +sneezers +sneezes +sneezeweed +sneezeweeds +sneezewort +sneezeworts +sneezing +sneezy +snell +snellen +snells +snib +snibbed +snibbing +snibs +snick +snicked +snicker +snickered +snickerer +snickerers +snickering +snickeringly +snickers +snickersnee +snickersnees +snickery +snicking +snicks +snide +snidely +snideness +snider +snidest +sniff +sniffable +sniffed +sniffer +sniffers +sniffier +sniffiest +sniffily +sniffiness +sniffing +sniffish +sniffishly +sniffishness +sniffle +sniffled +sniffler +snifflers +sniffles +sniffling +sniffly +sniffs +sniffy +snifter +snifters +snigger +sniggered +sniggerer +sniggerers +sniggering +sniggers +sniggle +sniggled +sniggles +sniggling +snip +snipe +sniped +snipefish +snipefishes +sniper +snipers +sniperscope +sniperscopes +snipes +sniping +snipped +snipper +snippers +snippersnapper +snippersnappers +snippet +snippetier +snippetiest +snippets +snippety +snippier +snippiest +snippily +snippiness +snipping +snippy +snips +snit +snitch +snitched +snitcher +snitchers +snitches +snitching +snits +snivel +sniveled +sniveler +snivelers +sniveling +snivelled +snivelling +snivels +snob +snobberies +snobbery +snobbier +snobbiest +snobbish +snobbishly +snobbishness +snobbism +snobby +snobs +snoek +snoeks +snollygoster +snollygosters +snood +snooded +snooding +snoods +snook +snooker +snookered +snookering +snookers +snooks +snoop +snooped +snooper +snoopers +snoopier +snoopiest +snoopily +snoopiness +snooping +snoops +snoopy +snoot +snooted +snootier +snootiest +snootily +snootiness +snooting +snoots +snooty +snooze +snoozed +snoozer +snoozers +snoozes +snoozing +snoozle +snoozled +snoozles +snoozling +snore +snored +snorer +snorers +snores +snoring +snorkel +snorkeled +snorkeler +snorkelers +snorkeling +snorkels +snort +snorted +snorter +snorters +snorting +snorts +snot +snots +snottier +snottiest +snottily +snottiness +snotty +snout +snouted +snoutish +snouts +snouty +snow +snowball +snowballed +snowballing +snowballs +snowbank +snowbanks +snowbell +snowbells +snowbelt +snowbelts +snowberries +snowberry +snowbird +snowbirds +snowblink +snowblinks +snowblower +snowblowers +snowboard +snowboarded +snowboarder +snowboarders +snowboarding +snowboards +snowbound +snowbrush +snowbrushes +snowbush +snowbushes +snowcap +snowcapped +snowcaps +snowdrift +snowdrifts +snowdrop +snowdrops +snowed +snowfall +snowfalls +snowfield +snowfields +snowflake +snowflakes +snowier +snowiest +snowily +snowiness +snowing +snowless +snowmaker +snowmakers +snowmaking +snowmakings +snowman +snowmelt +snowmelts +snowmen +snowmobile +snowmobiler +snowmobilers +snowmobiles +snowmobiling +snowmobilist +snowmobilists +snowpack +snowpacks +snowplough +snowploughs +snowplow +snowplowed +snowplowing +snowplows +snows +snowscape +snowscapes +snowshed +snowsheds +snowshoe +snowshoed +snowshoeing +snowshoer +snowshoers +snowshoes +snowslide +snowslides +snowstorm +snowstorms +snowsuit +snowsuits +snowy +snub +snubbed +snubber +snubbers +snubbiness +snubbing +snubby +snubness +snubs +snuck +snuff +snuffbox +snuffboxes +snuffed +snuffer +snuffers +snuffing +snuffle +snuffled +snuffler +snufflers +snuffles +snuffling +snuffly +snuffs +snuffy +snug +snugged +snugger +snuggeries +snuggery +snuggest +snugging +snuggle +snuggled +snuggles +snuggling +snuggly +snugly +snugness +snugs +so +soak +soakage +soaked +soaker +soakers +soaking +soaks +soap +soapbark +soapbarks +soapberries +soapberry +soapbox +soapboxed +soapboxes +soapboxing +soaped +soaper +soapers +soapier +soapiest +soapily +soapiness +soaping +soaps +soapstone +soapsuds +soapwort +soapworts +soapy +soar +soared +soarer +soarers +soaring +soaringly +soarings +soars +soave +soaves +sob +sobbed +sobbing +sobbingly +sober +sobered +soberer +soberest +sobering +soberize +soberized +soberizes +soberizing +soberly +soberness +sobers +sobersided +sobersidedness +sobersides +sobriety +sobriquet +sobriquets +sobs +soca +socage +socager +socagers +socages +socas +soccage +soccages +soccer +sociabilities +sociability +sociable +sociableness +sociables +sociably +social +socialism +socialist +socialistic +socialistically +socialists +socialite +socialites +socialities +sociality +socialization +socializations +socialize +socialized +socializer +socializers +socializes +socializing +socially +socials +societal +societally +societies +society +socinian +socinianism +socinians +sociobiological +sociobiologist +sociobiologists +sociobiology +sociocultural +socioculturally +socioeconomic +socioeconomically +sociogram +sociograms +sociohistorical +sociolinguist +sociolinguistic +sociolinguistics +sociolinguists +sociologese +sociologic +sociological +sociologically +sociologist +sociologists +sociology +sociometric +sociometry +sociopath +sociopathic +sociopaths +sociopolitical +sociopsychological +socioreligious +sociosexual +sock +sockdolager +sockdolagers +sockdologer +sockdologers +socked +socket +socketed +socketing +sockets +sockeye +sockeyes +socking +sockless +socko +socks +socle +socles +socotra +socrates +socratic +socratically +sod +soda +sodalist +sodalists +sodalite +sodalites +sodalities +sodality +sodas +sodbuster +sodbusters +sodded +sodden +soddened +soddening +soddenly +soddenness +soddens +sodding +sodic +sodium +sodom +sodomist +sodomists +sodomite +sodomites +sodomitic +sodomitical +sodomize +sodomized +sodomizes +sodomizing +sodomy +sods +soever +sofa +sofar +sofars +sofas +soffit +soffits +sofia +soft +softback +softbacks +softball +softballer +softballers +softballs +softbound +softcover +soften +softened +softener +softeners +softening +softens +softer +softest +softhead +softheaded +softheadedly +softheadedness +softheads +softhearted +softheartedly +softheartedness +softie +softies +softish +softly +softness +softnesses +softshell +softshells +software +softwood +softwoods +softy +sogdian +sogdians +soggier +soggiest +soggily +sogginess +soggy +sognafjord +soho +soigné +soignée +soil +soilage +soilborne +soiled +soiler +soiling +soilism +soilless +soils +soilure +soiree +soirees +soirée +soirées +soixante +sojourn +sojourned +sojourner +sojourners +sojourning +sojourns +soke +sokeman +sokemen +sokes +sol +sola +solace +solaced +solacement +solacer +solacers +solaces +solacing +solan +solanaceous +solanin +solanine +solanines +solanins +solans +solanum +solanums +solar +solaria +solarimeter +solarimeters +solarium +solariums +solarization +solarizations +solarize +solarized +solarizes +solarizing +solatia +solation +solatium +sold +soldan +soldans +solder +solderability +soldered +solderer +solderers +soldering +solders +soldi +soldier +soldiered +soldieries +soldiering +soldierly +soldiers +soldiership +soldiery +soldo +sole +solecism +solecisms +solecist +solecistic +solecists +soled +solei +solely +solemn +solemner +solemnest +solemnified +solemnifies +solemnify +solemnifying +solemnities +solemnity +solemnization +solemnizations +solemnize +solemnized +solemnizes +solemnizing +solemnly +solemnness +soleness +solenodon +solenodons +solenoid +solenoidal +solenoidally +solenoids +soleplate +soleplates +soleprint +soleprints +soles +soleus +solfatara +solfataras +solfataric +solfeggi +solfeggio +solfeggios +solferino +solferinos +solfège +solgel +solicit +solicitant +solicitants +solicitation +solicitations +solicited +soliciting +solicitor +solicitors +solicitorship +solicitous +solicitously +solicitousness +solicits +solicitude +solicitudes +solid +solidago +solidagos +solidarism +solidarist +solidaristic +solidarists +solidarity +solider +solidest +solidi +solidification +solidifications +solidified +solidifier +solidifiers +solidifies +solidify +solidifying +solidity +solidly +solidness +solids +solidus +solifluction +soliloquies +soliloquist +soliloquists +soliloquize +soliloquized +soliloquizer +soliloquizers +soliloquizes +soliloquizing +soliloquy +soliman +soling +solipsism +solipsist +solipsistic +solipsistically +solipsists +solitaire +solitaires +solitarian +solitarians +solitaries +solitarily +solitariness +solitary +soliton +solitons +solitude +solitudinarian +solitudinarians +solleret +sollerets +solmization +solmizations +solo +soloed +soloing +soloist +soloistic +soloists +solomon +solomonic +solomons +solon +solonchak +solonchaks +solonetz +solonetzic +solons +solos +sols +solstice +solstices +solstitial +solubilities +solubility +solubilization +solubilizations +solubilize +solubilized +solubilizes +solubilizing +soluble +solubleness +solubly +solum +solums +solus +solute +solutes +solution +solutions +solutrean +solutrian +solvability +solvable +solvableness +solvate +solvated +solvates +solvating +solvation +solvations +solvay +solve +solved +solvency +solvent +solventless +solvently +solvents +solver +solvers +solves +solving +solvolysis +solvolytic +soma +somali +somalia +somalian +somalians +somaliland +somalis +somas +somata +somatic +somatically +somatogenetic +somatogenic +somatologic +somatological +somatologist +somatologists +somatology +somatomedin +somatomedins +somatoplasm +somatoplasms +somatoplastic +somatopleural +somatopleure +somatopleures +somatopleuric +somatosensory +somatostatin +somatostatins +somatotherapies +somatotherapy +somatotrophin +somatotrophins +somatotropic +somatotropin +somatotropins +somatotype +somatotypes +somatotypic +somber +somberly +somberness +sombre +sombrero +sombreros +sombrous +some +somebodies +somebody +somebody's +someday +somehow +someone +someone's +someplace +somersault +somersaulted +somersaulting +somersaults +somerset +somersets +somersetted +somersetting +somesthetic +something +sometime +sometimes +someway +someways +somewhat +somewhen +somewhere +somewheres +somewhither +somite +somites +somitic +somme +sommelier +sommeliers +somnambulant +somnambular +somnambulate +somnambulated +somnambulates +somnambulating +somnambulation +somnambulations +somnambulism +somnambulist +somnambulistic +somnambulistically +somnambulists +somnifacient +somnifacients +somniferous +somniferously +somnific +somniloquies +somniloquist +somniloquists +somniloquy +somnolence +somnolent +somnolently +son +sonance +sonances +sonant +sonants +sonar +sonata +sonatas +sonatina +sonatinas +sonde +sondes +sone +sones +song +songbird +songbirds +songbook +songbooks +songfest +songfests +songful +songfully +songfulness +songless +songlessly +songlike +songs +songsmith +songsmiths +songster +songsters +songstress +songstresses +songwriter +songwriters +songwriting +sonhood +sonic +sonically +sonicate +sonicated +sonicates +sonicating +sonication +sonications +sonless +sonly +sonnet +sonneteer +sonneteering +sonneteers +sonnets +sonnies +sonny +sonobuoy +sonobuoys +sonogram +sonograms +sonograph +sonographer +sonographers +sonographic +sonographs +sonography +sonometer +sonometers +sonorant +sonorants +sonorities +sonority +sonorous +sonorously +sonorousness +sons +sonship +soochong +soochongs +soon +sooner +sooners +soonest +soot +sooted +sooth +soothe +soothed +soother +soothers +soothes +soothfast +soothing +soothingly +soothingness +soothly +sooths +soothsaid +soothsay +soothsayer +soothsayers +soothsaying +soothsayings +soothsays +sootier +sootiest +sootily +sootiness +sooting +soots +sooty +sop +sopaipilla +sopapilla +sophism +sophisms +sophist +sophistic +sophistical +sophistically +sophisticate +sophisticated +sophisticatedly +sophisticates +sophisticating +sophistication +sophistications +sophisticator +sophisticators +sophistries +sophistry +sophists +sophoclean +sophocles +sophomore +sophomores +sophomoric +sophomorically +sophonias +sopor +soporiferous +soporiferously +soporiferousness +soporific +soporifically +soporifics +sopors +sopped +soppier +soppiest +soppiness +sopping +soppy +sopranino +sopraninos +soprano +sopranos +sops +sora +soras +sorb +sorbability +sorbable +sorbate +sorbates +sorbed +sorbefacient +sorbefacients +sorbent +sorbents +sorbet +sorbets +sorbian +sorbians +sorbic +sorbing +sorbitol +sorbonne +sorbose +sorboses +sorbs +sorcerer +sorcerers +sorceress +sorceresses +sorcerous +sorcerously +sorcery +sordid +sordidly +sordidness +sordini +sordino +sords +sore +sored +soredia +soredial +soredium +sorehead +soreheaded +soreheads +sorely +soreness +sorer +sores +sorest +sorgho +sorghos +sorghum +sorghums +sorgo +sorgos +sori +soricine +soring +sorites +soroptimist +soroptimists +sororal +sororate +sororates +sororicidal +sororicide +sororicides +sororities +sorority +sorption +sorptive +sorrel +sorrels +sorrento +sorrier +sorriest +sorrily +sorriness +sorrow +sorrowed +sorrower +sorrowers +sorrowful +sorrowfully +sorrowfulness +sorrowing +sorrows +sorry +sort +sortable +sortation +sortations +sorted +sorter +sorters +sortie +sortied +sortieing +sorties +sortilege +sortileges +sorting +sortition +sortitions +sorts +sorus +sos +sostenuti +sostenuto +sostenutos +sot +soteriologic +soteriological +soteriology +sothic +sotho +sotol +sotols +sots +sotted +sottedly +sottedness +sottish +sottishly +sottishness +sotto +sou +sou'wester +sou'westers +souari +soubise +soubises +soubrette +soubrettes +soubriquet +soubriquets +souchong +souchongs +souci +soudan +soudans +soufflé +souffléd +soufflés +soufrière +sough +soughed +soughing +soughs +sought +souk +souks +soul +souled +soulful +soulfully +soulfulness +soulless +soullessly +soullessness +soulmate +soulmates +souls +sound +soundable +soundalike +soundboard +soundboards +sounded +sounder +sounders +soundest +sounding +soundingly +soundings +soundless +soundlessly +soundlessness +soundly +soundman +soundmen +soundness +soundproof +soundproofed +soundproofing +soundproofs +sounds +soundstage +soundstages +soundtrack +soundtracks +soup +souped +soupier +soupiest +soups +soupspoon +soupspoons +soupy +soupçon +soupçons +sour +sourball +sourballs +source +sourcebook +sourcebooks +sourced +sourceless +sources +sourcing +sourdine +sourdines +sourdough +sourdoughs +soured +sourer +sourest +souring +sourish +sourly +sourness +sourpuss +sourpusses +sours +soursop +soursops +sourwood +sourwoods +sous +sousa +sousaphone +sousaphones +souse +soused +souses +sousing +souslik +sousliks +soutache +soutaches +soutane +soutanes +south +southampton +southbound +southdown +southeast +southeaster +southeasterly +southeastern +southeasterner +southeasterners +southeasternmost +southeasters +southeastward +southeastwardly +southeastwards +souther +southerlies +southerly +southern +southerner +southerners +southernism +southernisms +southernmost +southernness +southernwood +southernwoods +southers +southey +southing +southings +southland +southlander +southlanders +southlands +southpaw +southpaws +southron +southrons +southward +southwardly +southwards +southwest +southwester +southwesterly +southwestern +southwesterner +southwesterners +southwesternmost +southwesters +southwestward +southwestwardly +southwestwards +souvenir +souvenirs +souvlaki +souvlakia +sovereign +sovereignly +sovereigns +sovereignties +sovereignty +soviet +sovietism +sovietization +sovietizations +sovietize +sovietized +sovietizes +sovietizing +sovietologist +sovietologists +sovietology +soviets +sovkhoz +sovkhozes +sovkhozy +sovran +sovrans +sovranties +sovranty +sow +sowbellies +sowbelly +sowbread +sowbreads +sowed +sowens +sower +sowers +sowetan +sowetans +soweto +sowing +sowings +sown +sows +sox +soxer +soxers +soy +soya +soybean +soybeans +soymilk +sozzled +spa +space +spaceband +spacebands +spacebar +spacebars +spaceborne +spacebridge +spacebridges +spacecraft +spaced +spacefarer +spacefarers +spacefaring +spacefarings +spaceflight +spaceflights +spaceless +spaceman +spacemen +spaceport +spaceports +spacer +spacers +spaces +spaceship +spaceships +spacesick +spacesuit +spacesuits +spacewalk +spacewalked +spacewalker +spacewalkers +spacewalking +spacewalks +spaceward +spacey +spacial +spacier +spaciest +spacing +spacings +spacious +spaciously +spaciousness +spackle +spackled +spackles +spackling +spacy +spade +spaded +spadefish +spadefishes +spadefoot +spadeful +spadefuls +spader +spaders +spades +spadework +spadices +spadille +spading +spadix +spaetzle +spaetzles +spaghetti +spaghettilike +spaghettini +spaghettis +spagyric +spagyrical +spahi +spahis +spain +spall +spallable +spallation +spallations +spalled +spalling +spalls +spalpeen +spalpeens +spam +spammed +spamming +spams +span +spanakopita +spanakopitas +spandau +spandex +spandrel +spandrels +spandril +spandrils +spang +spangle +spangled +spangles +spangling +spanglish +spangly +spaniard +spaniards +spaniel +spaniels +spanish +spanishness +spank +spanked +spanker +spankers +spanking +spankingly +spankings +spanks +spanned +spanner +spanners +spanning +spanokopita +spans +spanworm +spanworms +spar +spare +spareable +spared +sparely +spareness +sparer +sparerib +spareribs +sparers +spares +sparest +sparge +sparged +sparger +spargers +sparges +sparging +sparid +sparids +sparing +sparingly +sparingness +spark +sparked +sparker +sparkers +sparkier +sparkiest +sparkily +sparking +sparkish +sparkle +sparkleberries +sparkleberry +sparkled +sparkler +sparklers +sparkles +sparklier +sparkliest +sparkling +sparklingly +sparkly +sparkplug +sparkplugged +sparkplugging +sparkplugs +sparks +sparky +sparling +sparlings +sparred +sparring +sparrow +sparrowgrass +sparrowlike +sparrows +spars +sparse +sparsely +sparseness +sparser +sparsest +sparsity +sparta +spartacist +spartacists +spartacus +spartan +spartanism +spartanly +spartans +sparteine +sparteines +spas +spasm +spasmodic +spasmodically +spasmolytic +spasmolytics +spasms +spastic +spastically +spasticity +spastics +spat +spatchcock +spatchcocked +spatchcocking +spatchcocks +spate +spates +spathe +spathes +spathic +spathulate +spatial +spatiality +spatially +spatiotemporal +spatiotemporally +spats +spatted +spatter +spatterdock +spatterdocks +spattered +spattering +spatters +spatting +spatula +spatular +spatulas +spatulate +spatzle +spatzles +spavin +spavined +spawn +spawned +spawner +spawners +spawning +spawns +spay +spayed +spaying +spays +spaz +spazzes +speak +speakable +speakeasies +speakeasy +speaker +speakerphone +speakerphones +speakers +speakership +speakerships +speaking +speaks +spear +speared +spearer +spearers +spearfish +spearfished +spearfisher +spearfishers +spearfishes +spearfishing +speargun +spearguns +spearhead +spearheaded +spearheading +spearheads +spearing +spearlike +spearman +spearmen +spearmint +spearmints +spears +spearwort +spearworts +spec +spec'd +spec'er +spec'ers +spec'ing +specced +speccing +special +specialism +specialisms +specialist +specialistic +specialists +specialities +speciality +specialization +specializations +specialize +specialized +specializes +specializing +specially +specialness +specials +specialties +specialty +speciate +speciated +speciates +speciating +speciation +speciational +speciations +specie +species +speciesism +speciesist +speciesists +specifiable +specific +specifically +specification +specifications +specificity +specificness +specifics +specified +specifier +specifiers +specifies +specify +specifying +specimen +specimens +speciosity +specious +speciously +speciousness +speck +specked +specking +speckle +speckled +speckles +speckling +specks +specs +spectacle +spectacled +spectacles +spectacular +spectacularity +spectacularly +spectaculars +spectate +spectated +spectates +spectating +spectator +spectatorial +spectators +spectatorship +spectatorships +specter +specters +spectinomycin +spectinomycins +spectra +spectral +spectrality +spectrally +spectralness +spectre +spectres +spectrin +spectrins +spectrofluorimeter +spectrofluorimeters +spectrofluorometer +spectrofluorometers +spectrofluorometric +spectrofluorometry +spectrogram +spectrograms +spectrograph +spectrographic +spectrographically +spectrographs +spectrography +spectroheliogram +spectroheliograms +spectroheliograph +spectroheliographic +spectroheliographs +spectroheliography +spectrohelioscope +spectrohelioscopes +spectrohelioscopic +spectrometer +spectrometers +spectrometric +spectrometry +spectrophotometer +spectrophotometers +spectrophotometric +spectrophotometrical +spectrophotometrically +spectrophotometry +spectroscope +spectroscopes +spectroscopic +spectroscopical +spectroscopically +spectroscopies +spectroscopist +spectroscopists +spectroscopy +spectrum +spectrums +specula +specular +specularity +specularly +speculate +speculated +speculates +speculating +speculation +speculations +speculative +speculatively +speculativeness +speculator +speculators +speculum +speculums +sped +speech +speeches +speechified +speechifier +speechifiers +speechifies +speechify +speechifying +speechless +speechlessly +speechlessness +speechmaker +speechmakers +speechmaking +speechwriter +speechwriters +speechwriting +speed +speedball +speedballs +speedboat +speedboater +speedboaters +speedboating +speedboatings +speedboats +speeded +speeder +speeders +speedier +speediest +speedily +speediness +speeding +speedings +speedo +speedometer +speedometers +speedos +speeds +speedster +speedsters +speedup +speedups +speedway +speedways +speedwell +speedwells +speedwriter +speedwriters +speedwriting +speedwritings +speedy +speiss +speisses +speleological +speleologist +speleologists +speleology +spell +spellbind +spellbinder +spellbinders +spellbinding +spellbindingly +spellbinds +spellbound +spellchecker +spellcheckers +spelldown +spelldowns +spelled +speller +spellers +spelling +spellings +spells +spelt +spelter +spelters +spelunker +spelunkers +spelunking +spencer +spencerian +spencerianism +spencerians +spencerism +spencers +spend +spendable +spender +spenders +spending +spends +spendthrift +spendthrifts +spenglerian +spenglerians +spenser +spenserian +spent +sperm +spermaceti +spermacetis +spermagonia +spermagonium +spermaries +spermary +spermatheca +spermathecas +spermatia +spermatial +spermatic +spermatid +spermatids +spermatium +spermatocyte +spermatocytes +spermatogenesis +spermatogenetic +spermatogenic +spermatogonia +spermatogonial +spermatogonium +spermatophore +spermatophores +spermatophyte +spermatophytes +spermatophytic +spermatozoa +spermatozoal +spermatozoan +spermatozoid +spermatozoids +spermatozoon +spermicidal +spermicide +spermicides +spermiogenesis +spermogonia +spermogonium +spermophile +spermophiles +spermous +sperms +sperrylite +sperrylites +spessartine +spessartines +spessartite +spessartites +spew +spewed +spewer +spewers +spewing +spews +sphagnous +sphagnum +sphalerite +sphalerites +sphene +sphenes +sphenic +sphenodon +sphenodons +sphenodont +sphenogram +sphenograms +sphenoid +sphenoidal +sphenoids +sphenopsid +sphenopsids +spheral +sphere +sphered +spheres +spheric +spherical +spherically +sphericalness +sphericity +spherics +spherier +spheriest +sphering +spheroid +spheroidal +spheroidally +spheroidic +spheroidicity +spheroids +spherometer +spherometers +spheroplast +spheroplasts +spherular +spherule +spherules +spherulite +spherulites +spherulitic +sphery +sphincter +sphincteral +sphincteric +sphincters +sphinges +sphingid +sphingids +sphingosine +sphingosines +sphinx +sphinxes +sphinxlike +sphragistics +sphygmic +sphygmogram +sphygmograms +sphygmograph +sphygmographic +sphygmographs +sphygmography +sphygmoid +sphygmomanometer +sphygmomanometers +sphygmomanometric +sphygmomanometrically +sphygmomanometry +sphygmometer +sphygmometers +spic +spica +spicae +spicas +spicate +spiccato +spiccatos +spice +spiceberries +spiceberry +spicebush +spicebushes +spiced +spiceless +spiceries +spicery +spices +spicier +spiciest +spicily +spiciness +spicing +spick +spicks +spics +spicula +spiculae +spicular +spiculate +spiculation +spiculations +spicule +spicules +spiculum +spicy +spider +spiderish +spiderlike +spiders +spiderweb +spiderwebs +spiderwort +spiderworts +spidery +spied +spiegel +spiegeleisen +spiegeleisens +spiegels +spiel +spieled +spieler +spielers +spieling +spiels +spier +spiers +spies +spiff +spiffed +spiffied +spiffier +spiffies +spiffiest +spiffily +spiffiness +spiffing +spiffs +spiffy +spiffying +spigot +spigots +spik +spike +spiked +spikelet +spikelets +spikelike +spikenard +spikenards +spiker +spikers +spikes +spikey +spikier +spikiest +spikily +spikiness +spiking +spiks +spiky +spile +spiled +spiles +spiling +spill +spillable +spillage +spillback +spillbacks +spilled +spiller +spillers +spillikin +spillikins +spilling +spillover +spillovers +spills +spillway +spillways +spilt +spilth +spilths +spin +spina +spinach +spinachlike +spinachy +spinal +spinally +spinals +spindle +spindled +spindler +spindlers +spindles +spindlier +spindliest +spindling +spindly +spindrift +spine +spined +spinel +spineless +spinelessly +spinelessness +spinelike +spinelle +spinelles +spinels +spines +spinescence +spinescent +spinet +spinets +spinier +spiniest +spiniferous +spinifex +spinifexes +spininess +spinless +spinnaker +spinnakers +spinner +spinneret +spinnerets +spinnerette +spinnerettes +spinners +spinney +spinneys +spinning +spinnings +spinocerebellar +spinoff +spinoffs +spinor +spinors +spinose +spinosely +spinosity +spinous +spinout +spinouts +spinoza +spinozism +spinozist +spinozistic +spinozists +spins +spinster +spinsterhood +spinsterish +spinsterly +spinsters +spinthariscope +spinthariscopes +spinthariscopic +spinto +spintos +spinule +spinules +spinulose +spinulous +spiny +spiracle +spiracles +spiracular +spiraea +spiraeas +spiral +spiraled +spiraling +spirality +spiralled +spiralling +spirally +spirals +spirant +spirants +spire +spirea +spireas +spired +spirem +spireme +spiremes +spirems +spires +spiriferous +spirilla +spirillum +spiring +spirit +spirited +spiritedly +spiritedness +spiriting +spiritism +spiritist +spiritistic +spiritists +spiritless +spiritlessly +spiritlessness +spiritoso +spiritous +spirits +spiritual +spiritualism +spiritualist +spiritualistic +spiritualists +spiritualities +spirituality +spiritualization +spiritualizations +spiritualize +spiritualized +spiritualizer +spiritualizers +spiritualizes +spiritualizing +spiritually +spiritualness +spirituals +spiritualties +spiritualty +spirituel +spirituelle +spirituosity +spirituous +spirituousness +spirochaete +spirochaetes +spirochetal +spirochete +spirochetes +spirochetoses +spirochetosis +spirograph +spirographic +spirographically +spirographs +spirography +spirogyra +spirogyras +spiroid +spirometer +spirometers +spirometric +spirometry +spironolactone +spironolactones +spiroplasma +spiroplasmas +spirt +spirted +spirting +spirts +spirula +spirulae +spiry +spit +spital +spitals +spitball +spitballs +spite +spited +spiteful +spitefully +spitefulness +spites +spitfire +spitfires +spithead +spiting +spits +spitsbergen +spitted +spitter +spitters +spitting +spittle +spittlebug +spittlebugs +spittoon +spittoons +spitz +spitzes +spiv +spivs +splanchnic +splanchnology +splanchnopleure +splanchnopleures +splanchnopleuric +splash +splashboard +splashboards +splashdown +splashdowns +splashed +splasher +splashers +splashes +splashguard +splashguards +splashier +splashiest +splashily +splashiness +splashing +splashy +splat +splats +splatter +splattered +splattering +splatters +splay +splayed +splayfeet +splayfoot +splayfooted +splaying +splays +spleen +spleenful +spleens +spleenwort +spleenworts +spleeny +splendent +splendid +splendidly +splendidness +splendiferous +splendiferously +splendiferousness +splendor +splendorous +splendors +splendrous +splenectomies +splenectomize +splenectomized +splenectomizes +splenectomizing +splenectomy +splenetic +splenetical +splenetically +spleneticals +splenetics +splenial +splenic +splenii +splenius +splenomegalies +splenomegaly +splice +spliced +splicer +splicers +splices +splicing +spliff +spline +splines +splint +splinted +splinter +splintered +splintering +splinters +splintery +splinting +splints +split +splits +splitter +splitters +splitting +splotch +splotched +splotches +splotchiness +splotching +splotchy +splurge +splurged +splurges +splurging +splurgy +splutter +spluttered +splutterer +spluttering +splutters +spluttery +spock +spode +spodumene +spodumenes +spoil +spoilable +spoilage +spoiled +spoiler +spoilers +spoiling +spoils +spoilsman +spoilsmen +spoilsport +spoilsports +spoilt +spokane +spoke +spoked +spoken +spokes +spokeshave +spokeshaves +spokesman +spokesmanship +spokesmen +spokespeople +spokesperson +spokespersons +spokeswoman +spokeswomen +spoking +spoleto +spoliate +spoliated +spoliates +spoliating +spoliation +spoliator +spoliators +spondaic +spondee +spondees +spondylitis +spondylitises +spondyloses +spondylosis +sponge +sponged +sponger +spongers +sponges +spongeware +spongier +spongiest +spongiform +spongin +sponginess +sponging +spongins +spongioblast +spongioblasts +spongiocyte +spongiocytes +spongocoel +spongocoels +spongy +sponson +sponsons +sponsor +sponsored +sponsorial +sponsoring +sponsors +sponsorship +sponsorships +spontaneities +spontaneity +spontaneous +spontaneously +spontaneousness +spontoon +spontoons +spoof +spoofed +spoofery +spoofing +spoofs +spoofy +spook +spooked +spookeries +spookery +spookier +spookiest +spookily +spookiness +spooking +spookish +spooks +spooky +spool +spooled +spooling +spoolings +spools +spoon +spoonable +spoonbill +spoonbills +spoondrift +spoondrifts +spooned +spoonerism +spoonerisms +spooney +spoonful +spoonfuls +spoonier +spooniest +spooning +spoons +spoonsful +spoony +spoor +spoored +spooring +spoors +sporaceous +sporades +sporadic +sporadical +sporadically +sporadicalness +sporangia +sporangial +sporangiophore +sporangiophores +sporangium +spore +spored +sporeling +sporelings +spores +sporicidal +sporicide +sporicides +sporiferous +sporing +sporocarp +sporocarps +sporocyst +sporocysts +sporocyte +sporocytes +sporogenesis +sporogenic +sporogenous +sporogonia +sporogonic +sporogonium +sporogonous +sporogony +sporont +sporonts +sporophore +sporophores +sporophyll +sporophylls +sporophyte +sporophytes +sporophytic +sporoplasm +sporoplasms +sporopollenin +sporopollenins +sporotrichoses +sporotrichosis +sporozoan +sporozoans +sporozoite +sporozoites +sporran +sporrans +sport +sported +sportfisherman +sportfishermen +sportfishing +sportful +sportfully +sportfulness +sportier +sportiest +sportif +sportily +sportiness +sporting +sportingly +sportive +sportively +sportiveness +sports +sportscast +sportscaster +sportscasters +sportscasts +sportsman +sportsmanlike +sportsmanly +sportsmanship +sportsmen +sportswear +sportswoman +sportswomen +sportswriter +sportswriters +sportswriting +sporty +sporular +sporulate +sporulated +sporulates +sporulating +sporulation +sporulations +sporulative +spot +spotless +spotlessly +spotlessness +spotlight +spotlighted +spotlighting +spotlights +spotlit +spots +spottable +spotted +spotter +spotters +spottier +spottiest +spottily +spottiness +spotting +spotty +spousal +spousals +spouse +spoused +spouseless +spouses +spousing +spout +spouted +spouter +spouters +spouting +spoutings +spouts +sprachgefühl +spraddle +spraddled +spraddles +spraddling +sprag +sprags +sprain +sprained +spraining +sprains +sprang +sprat +sprats +sprawl +sprawled +sprawler +sprawlers +sprawling +sprawls +spray +sprayed +sprayer +sprayers +spraying +sprays +spread +spreadability +spreadable +spreadably +spreader +spreaders +spreading +spreads +spreadsheet +spreadsheets +sprechstimme +sprechstimmes +spree +sprees +sprier +spriest +sprig +sprigged +sprigger +spriggers +sprigging +spright +sprightful +sprightfully +sprightfulness +sprightlier +sprightliest +sprightliness +sprightly +sprights +sprigs +sprigtail +sprigtails +spring +springal +springald +springalds +springals +springboard +springboards +springbok +springboks +springbuck +springbucks +springe +springer +springers +springes +springfield +springform +springhalt +springhalts +springhare +springhares +springhead +springheads +springhouse +springhouses +springier +springiest +springily +springiness +springing +springlet +springlets +springlike +springs +springtail +springtails +springtide +springtides +springtime +springwater +springwood +springwoods +springy +sprinkle +sprinkled +sprinkler +sprinklered +sprinklering +sprinklers +sprinkles +sprinkling +sprinklings +sprint +sprinted +sprinter +sprinters +sprinting +sprints +sprit +sprite +sprites +sprits +spritsail +spritsails +spritz +spritzed +spritzer +spritzers +spritzes +spritzing +sprocket +sprockets +sprout +sprouted +sprouting +sprouts +spruce +spruced +sprucely +spruceness +sprucer +spruces +sprucest +sprucier +spruciest +sprucing +sprucy +sprue +sprues +sprung +spry +spryer +spryest +spryly +spryness +spud +spudded +spudding +spuds +spumante +spume +spumed +spumes +spuming +spumone +spumones +spumoni +spumonis +spumous +spumy +spun +spunbonded +spunk +spunkier +spunkiest +spunkily +spunkiness +spunky +spur +spurge +spurges +spurious +spuriously +spuriousness +spurn +spurned +spurner +spurners +spurning +spurns +spurred +spurrey +spurreys +spurries +spurring +spurry +spurs +spurt +spurted +spurting +spurts +sputa +sputnik +sputniks +sputter +sputtered +sputterer +sputterers +sputtering +sputters +sputtery +sputum +spy +spyglass +spyglasses +spying +spymaster +spymasters +squab +squabble +squabbled +squabbler +squabblers +squabbles +squabbling +squabs +squad +squadded +squadding +squadron +squadrons +squads +squalamine +squalene +squalenes +squalid +squalidity +squalidly +squalidness +squall +squalled +squaller +squallers +squallier +squalliest +squalling +squalls +squally +squalor +squalors +squama +squamae +squamate +squamation +squamations +squamiform +squamosal +squamosals +squamose +squamous +squamously +squamousness +squamule +squamules +squamulose +squander +squandered +squanderer +squanderers +squandering +squanderingly +squanders +square +squared +squarely +squareness +squarer +squarers +squares +squarest +squaretail +squaretails +squaring +squarish +squarishly +squarishness +squarrose +squash +squashed +squasher +squashers +squashes +squashier +squashiest +squashily +squashiness +squashing +squashy +squat +squatly +squatness +squats +squatted +squatter +squatters +squattest +squattier +squattiest +squatting +squatty +squaw +squawfish +squawfishes +squawk +squawked +squawker +squawkers +squawkier +squawkiest +squawkily +squawking +squawks +squawky +squawroot +squawroots +squaws +squeak +squeaked +squeaker +squeakers +squeakier +squeakiest +squeakily +squeakiness +squeaking +squeaks +squeaky +squeal +squealed +squealer +squealers +squealing +squeals +squeamish +squeamishly +squeamishness +squeegee +squeegeed +squeegeeing +squeegees +squeezability +squeezable +squeeze +squeezebox +squeezeboxes +squeezed +squeezer +squeezers +squeezes +squeezing +squelch +squelched +squelcher +squelchers +squelches +squelching +squelchy +squeteague +squib +squibbed +squibbing +squibs +squid +squidded +squidding +squids +squiffed +squiffier +squiffiest +squiffy +squiggle +squiggled +squiggles +squiggling +squiggly +squill +squilla +squillae +squillas +squills +squinch +squinched +squinches +squinching +squinnied +squinnies +squinny +squinnying +squint +squinted +squinter +squinting +squintingly +squints +squinty +squirarchies +squirarchy +squire +squirearchies +squirearchy +squired +squires +squiring +squirish +squirm +squirmed +squirmer +squirmers +squirmier +squirmiest +squirminess +squirming +squirms +squirmy +squirrel +squirreled +squirrelfish +squirrelfishes +squirreling +squirrelled +squirrelling +squirrelly +squirrels +squirt +squirted +squirter +squirters +squirting +squirts +squish +squished +squishes +squishier +squishiest +squishiness +squishing +squishy +squoosh +squooshed +squooshes +squooshing +squush +squushed +squushes +squushing +sranan +sranantongo +srebrenica +sri +srinagar +st +stab +stabat +stabbed +stabber +stabbers +stabbing +stabile +stabiles +stabilities +stability +stabilization +stabilizations +stabilize +stabilized +stabilizer +stabilizers +stabilizes +stabilizing +stable +stabled +stableman +stablemate +stablemates +stablemen +stableness +stabler +stables +stablest +stabling +stablish +stablished +stablishes +stablishing +stably +stabs +staccati +staccato +staccatos +stack +stackable +stacked +stacker +stackers +stacking +stacks +stackup +stackups +stacte +stactes +staddle +staddles +stade +stades +stadholder +stadholders +stadia +stadium +stadiums +stadtholder +stadtholderate +stadtholders +stadtholdership +staff +staffed +staffer +staffers +staffing +staffordshire +staffs +stag +stage +stageable +stagecoach +stagecoaches +stagecraft +stagecrafts +staged +stageful +stagefuls +stagehand +stagehands +stagelike +stager +stagers +stages +stagestruck +stagey +stagflation +stagflationary +staggard +staggards +stagged +stagger +staggerbush +staggerbushes +staggered +staggerer +staggerers +staggering +staggeringly +staggers +staggery +stagging +staggy +staghorn +staghound +staghounds +stagier +stagiest +stagily +staginess +staging +stagings +stagirite +stagirites +stagnancy +stagnant +stagnantly +stagnate +stagnated +stagnates +stagnating +stagnation +stagnations +stags +stagy +staid +staidly +staidness +stain +stainability +stainable +stained +stainer +stainers +staining +stainless +stainlessly +stainproof +stains +stair +staircase +staircases +stairs +stairway +stairways +stairwell +stairwells +stake +staked +stakeholder +stakeholders +stakeout +stakeouts +stakes +stakhanovism +stakhanovite +stakhanovites +staking +stalactiform +stalactite +stalactites +stalactitic +stalag +stalagmite +stalagmites +stalagmitic +stalags +stale +staled +stalely +stalemate +stalemated +stalemates +stalemating +staleness +staler +stales +stalest +stalin +staling +stalingrad +stalinism +stalinist +stalinists +stalinization +stalinize +stalinized +stalinizes +stalinizing +stalinoid +stalk +stalked +stalker +stalkers +stalking +stalkless +stalks +stalky +stall +stalled +stallholder +stallholders +stalling +stallion +stallions +stalls +stalwart +stalwartly +stalwartness +stalwarts +stamen +stamens +stamina +staminal +staminate +staminode +staminodes +staminodia +staminodies +staminodium +staminody +stammel +stammels +stammer +stammered +stammerer +stammerers +stammering +stammeringly +stammers +stamp +stamped +stampede +stampeded +stampeder +stampeders +stampedes +stampeding +stamper +stampers +stamping +stampless +stamps +stance +stances +stanch +stanched +stancher +stanchers +stanches +stanching +stanchion +stanchioned +stanchioning +stanchions +stanchly +stanchness +stand +standalone +standard +standardbred +standardbreds +standardizable +standardization +standardizations +standardize +standardized +standardizer +standardizers +standardizes +standardizing +standardless +standardly +standards +standaway +standby +standbys +standdown +standdowns +standee +standees +stander +standers +standing +standings +standish +standishes +standoff +standoffish +standoffishly +standoffishness +standoffs +standout +standouts +standpat +standpatter +standpatters +standpattism +standpipe +standpipes +standpoint +standpoints +stands +standstill +standstills +standup +stanford +stanhope +stanhopes +stanine +stanines +stanislavski +stanislavskian +stanislavsky +stank +stanley +stannaries +stannary +stannic +stannite +stannites +stannous +stanovoi +stanovoy +stanza +stanzaic +stanzas +stapedectomies +stapedectomy +stapedes +stapedial +stapelia +stapelias +stapes +staph +staphs +staphylinid +staphylinids +staphylococcal +staphylococci +staphylococcic +staphylococcus +staphyloplastic +staphyloplasties +staphyloplasty +staphyloraphies +staphyloraphy +staphylorrhaphies +staphylorrhaphy +staple +stapled +stapler +staplers +staples +stapling +star +starboard +starboards +starburst +starbursts +starch +starched +starches +starchier +starchiest +starchily +starchiness +starching +starchy +stardom +stardoms +stardust +stare +stared +starer +starers +stares +starets +starfish +starfishes +starflower +starflowers +stargaze +stargazed +stargazer +stargazers +stargazes +stargazing +staring +stark +starker +starkers +starkest +starkly +starkness +starless +starlet +starlets +starlight +starlike +starling +starlings +starlit +starred +starrier +starriest +starriness +starring +starry +stars +starship +starships +starstruck +start +started +starter +starters +starting +startle +startled +startlement +startles +startling +startlingly +startlingness +starts +startsy +startup +startups +starvation +starve +starved +starveling +starvelings +starves +starving +starwort +starworts +stases +stash +stashed +stashes +stashing +stasis +stat +statable +statant +state +statecraft +stated +statedly +statehood +statehooder +statehooders +statehouse +statehouses +stateless +statelessness +statelet +statelets +statelier +stateliest +stateliness +stately +statement +statements +staten +stater +stateroom +staterooms +staters +states +stateside +statesman +statesmanlike +statesmanly +statesmanship +statesmen +stateswoman +stateswomen +statewide +static +statical +statically +statice +statices +staticky +statics +stating +station +stational +stationaries +stationary +stationed +stationer +stationers +stationery +stationhouse +stationhouses +stationing +stationmaster +stationmasters +stations +statism +statist +statistic +statistical +statistically +statistician +statisticians +statistics +statists +stative +statives +statoblast +statoblasts +statocyst +statocysts +statolith +statoliths +stator +stators +statoscope +statoscopes +stats +statuaries +statuary +statue +statues +statuesque +statuesquely +statuette +statuettes +stature +statures +status +statuses +statusy +statutable +statute +statutes +statutorily +statutory +staunch +staunched +stauncher +staunchers +staunches +staunching +staunchly +staunchness +staurolite +staurolites +staurolitic +stavanger +stave +staved +staves +stavesacre +stavesacres +staving +stay +stayed +stayer +stayers +staying +stays +staysail +staysails +staël +stead +steaded +steadfast +steadfastly +steadfastness +steadied +steadier +steadiers +steadies +steadiest +steadily +steadiness +steading +steadings +steads +steady +steadying +steak +steakhouse +steakhouses +steaks +steal +stealable +stealer +stealers +stealing +steals +stealth +stealthier +stealthiest +stealthily +stealthiness +stealthy +steam +steamboat +steamboats +steamed +steamer +steamers +steamfitter +steamfitters +steamfitting +steamier +steamiest +steamily +steaminess +steaming +steamroll +steamrolled +steamroller +steamrollered +steamrollering +steamrollers +steamrolling +steamrolls +steams +steamship +steamships +steamy +steapsin +steapsins +stearate +stearates +stearic +stearin +stearine +stearines +stearins +stearoptene +stearoptenes +steatite +steatites +steatitic +steatolysis +steatopygia +steatopygias +steatopygic +steatopygous +steatorrhea +steatorrheas +steatorrhoea +steatorrhoeas +steatoses +steatosis +stedfast +steed +steeds +steel +steele +steeled +steelhead +steelheads +steelie +steelier +steelies +steeliest +steeliness +steeling +steelmaker +steelmakers +steelmaking +steels +steelwork +steelworker +steelworkers +steelworks +steely +steelyard +steelyards +steenbok +steenboks +steep +steeped +steepen +steepened +steepening +steepens +steeper +steepers +steepest +steeping +steepish +steeple +steeplebush +steeplebushes +steeplechase +steeplechaser +steeplechasers +steeplechases +steeplechasing +steepled +steeplejack +steeplejacks +steeples +steeply +steepness +steeps +steer +steerable +steerage +steerageway +steerageways +steered +steerer +steerers +steering +steers +steersman +steersmen +steeve +steeved +steeves +steeving +steganographic +steganography +stegodon +stegodons +stegosaur +stegosaurs +stegosaurus +stegosauruses +stein +steinbeck +steinbok +steinboks +steins +steinway +stela +stelae +stelar +stele +steles +stella +stellar +stellas +stellate +stellated +stellately +stellenbosch +steller +stelliform +stellular +stem +stemless +stemma +stemmas +stemmata +stemmatic +stemmed +stemmer +stemmers +stemmier +stemmiest +stemming +stemmy +stems +stemson +stemsons +stemware +sten +stench +stenches +stenchful +stenchy +stencil +stenciled +stenciler +stencilers +stenciling +stencilled +stenciller +stencillers +stencilling +stencils +stendhal +steno +stenobath +stenobathic +stenobaths +stenograph +stenographer +stenographers +stenographic +stenographical +stenographically +stenographs +stenography +stenohaline +stenophagous +stenos +stenosed +stenoses +stenosis +stenotherm +stenothermal +stenothermic +stenothermous +stenotherms +stenotic +stenotopic +stenotype +stenotyped +stenotypes +stenotypies +stenotyping +stenotypist +stenotypists +stenotypy +stentor +stentorian +stentors +step +stepbrother +stepbrothers +stepchild +stepchildren +stepdaughter +stepdaughters +stepfamilies +stepfamily +stepfather +stepfathers +stephanotis +stephanotises +stephen +stephenson +stepladder +stepladders +steplike +stepmother +stepmothers +stepparent +stepparenting +stepparents +steppe +stepped +stepper +steppers +steppes +stepping +steppingstone +steppingstones +steps +stepsibling +stepsiblings +stepsister +stepsisters +stepson +stepsons +stepwise +steradian +steradians +stercoraceous +stercorous +sterculia +stere +stereo +stereobate +stereobates +stereochemical +stereochemistry +stereochrome +stereochromes +stereochromic +stereochromically +stereochromies +stereochromy +stereogram +stereograms +stereograph +stereographed +stereographic +stereographical +stereographically +stereographing +stereographs +stereography +stereoisomer +stereoisomeric +stereoisomerism +stereoisomerisms +stereoisomers +stereologic +stereological +stereologically +stereologist +stereologists +stereology +stereomicroscope +stereomicroscopes +stereomicroscopic +stereomicroscopically +stereomicroscopy +stereophonic +stereophonically +stereophony +stereophotographic +stereophotography +stereopsis +stereopticon +stereopticons +stereoregular +stereoregularity +stereos +stereoscope +stereoscopes +stereoscopic +stereoscopically +stereoscopist +stereoscopists +stereoscopy +stereospecific +stereospecifically +stereospecificity +stereotactic +stereotactical +stereotactically +stereotaxic +stereotaxical +stereotaxically +stereotaxies +stereotaxis +stereotaxises +stereotaxy +stereotropic +stereotropism +stereotropisms +stereotype +stereotyped +stereotyper +stereotypers +stereotypes +stereotypic +stereotypical +stereotypically +stereotypies +stereotyping +stereotypy +stereovision +stereovisions +steres +steric +sterical +sterically +sterigma +sterigmata +sterigmatic +sterilant +sterilants +sterile +sterilely +sterileness +sterility +sterilization +sterilizations +sterilize +sterilized +sterilizer +sterilizers +sterilizes +sterilizing +sterlet +sterlets +sterling +sterlingly +sterlingness +stern +sterna +sternal +sterner +sternest +sternforemost +sternite +sternites +sternly +sternmost +sternness +sternoclavicular +sternocleidomastoid +sternocleidomastoids +sternocostal +sternpost +sternposts +sterns +sternson +sternsons +sternum +sternums +sternutation +sternutations +sternutator +sternutatories +sternutators +sternutatory +sternward +sternwards +sternway +sternways +sternwheeler +sternwheelers +steroid +steroidal +steroidogenesis +steroidogenic +steroids +sterol +sterols +sterope +steropes +stertor +stertorous +stertorously +stertors +stet +stethoscope +stethoscopes +stethoscopic +stethoscopical +stethoscopically +stethoscopy +stets +stetson +stetsons +stetted +stetting +stevedore +stevedored +stevedores +stevedoring +stevengraph +stevengraphs +stevensgraph +stevensgraphs +stew +steward +stewarded +stewardess +stewardesses +stewarding +stewards +stewardship +stewardships +stewartia +stewartias +stewed +stewing +stewpan +stewpans +stewpot +stewpots +stews +stewy +sthenia +sthenias +sthenic +stibine +stibines +stibnite +stibnites +stich +stiches +stichic +stichometric +stichometry +stichomythia +stichomythias +stichomythic +stichomythies +stichomythy +stick +stickball +stickballer +stickballers +sticked +sticker +stickers +stickful +stickfuls +stickhandle +stickhandled +stickhandler +stickhandlers +stickhandles +stickhandling +stickier +stickiest +stickily +stickiness +sticking +stickle +stickleback +sticklebacks +stickled +stickler +sticklers +stickles +sticklike +stickling +stickman +stickmen +stickpin +stickpins +sticks +stickseed +stickseeds +sticktail +sticktails +sticktight +sticktights +stickum +stickums +stickup +stickups +stickweed +stickweeds +stickwork +sticky +stiction +stied +sties +stiff +stiffed +stiffen +stiffened +stiffener +stiffeners +stiffening +stiffens +stiffer +stiffest +stiffing +stiffish +stiffly +stiffness +stiffs +stifle +stifled +stifler +stiflers +stifles +stifling +stiflingly +stigma +stigmal +stigmas +stigmasterol +stigmasterols +stigmata +stigmatic +stigmatically +stigmatics +stigmatism +stigmatist +stigmatists +stigmatization +stigmatizations +stigmatize +stigmatized +stigmatizer +stigmatizers +stigmatizes +stigmatizing +stilbene +stilbenes +stilbestrol +stilbestrols +stilbite +stilbites +stile +stiles +stiletto +stilettoes +stilettos +still +stillbirth +stillbirths +stillborn +stilled +stiller +stillest +stillier +stilliest +stilliform +stilling +stillman +stillmen +stillness +stillroom +stillrooms +stills +stillson +stillsons +stilly +stilt +stilted +stiltedly +stiltedness +stilting +stilton +stilts +stimulant +stimulants +stimulate +stimulated +stimulater +stimulaters +stimulates +stimulating +stimulatingly +stimulation +stimulations +stimulative +stimulator +stimulators +stimulatory +stimuli +stimulus +sting +stingaree +stingarees +stinger +stingers +stingier +stingiest +stingily +stinginess +stinging +stingingly +stingless +stingray +stingrays +stings +stingy +stink +stinkard +stinkards +stinkaroo +stinkaroos +stinkball +stinkballs +stinkbug +stinkbugs +stinker +stinkeroo +stinkeroos +stinkers +stinkhorn +stinkhorns +stinking +stinkingly +stinkingness +stinko +stinkpot +stinkpots +stinks +stinkstone +stinkstones +stinkweed +stinkweeds +stinkwood +stinkwoods +stinky +stint +stinted +stinter +stinters +stinting +stintingly +stints +stipe +stiped +stipel +stipellate +stipels +stipend +stipendiaries +stipendiary +stipends +stipes +stipiform +stipitate +stipites +stipitiform +stipple +stippled +stippler +stipplers +stipples +stippling +stipular +stipulate +stipulated +stipulates +stipulating +stipulation +stipulations +stipulator +stipulators +stipulatory +stipule +stipuled +stipules +stir +stirabout +stirabouts +stirk +stirks +stirling +stirp +stirpes +stirps +stirred +stirrer +stirrers +stirring +stirringly +stirrings +stirrup +stirrups +stirs +stishovite +stishovites +stitch +stitched +stitcher +stitchers +stitchery +stitches +stitching +stitchwort +stitchworts +stithies +stithy +stiver +stivers +stoa +stoae +stoas +stoat +stoats +stoccado +stoccados +stochastic +stochastically +stock +stockade +stockaded +stockades +stockading +stockage +stockbreeder +stockbreeders +stockbreeding +stockbreedings +stockbroker +stockbrokerage +stockbrokers +stockbroking +stockcar +stockcars +stocked +stocker +stockers +stockfish +stockfishes +stockholder +stockholders +stockholding +stockholdings +stockholm +stockier +stockiest +stockily +stockiness +stockinet +stockinets +stockinette +stockinettes +stocking +stockinged +stockings +stockish +stockist +stockists +stockjobber +stockjobbers +stockjobbery +stockjobbing +stockkeeper +stockkeepers +stockless +stockman +stockmar +stockmen +stockowner +stockowners +stockownership +stockpile +stockpiled +stockpiler +stockpilers +stockpiles +stockpiling +stockpot +stockpots +stockroom +stockrooms +stocks +stocktaking +stocktakings +stocky +stockyard +stockyards +stodgier +stodgiest +stodgily +stodginess +stodgy +stogie +stogies +stogy +stoic +stoical +stoically +stoicalness +stoichiometric +stoichiometrically +stoichiometry +stoicism +stoics +stoke +stoked +stokehold +stokeholds +stokehole +stokeholes +stoker +stokers +stokes +stoking +stole +stolen +stoles +stolid +stolider +stolidest +stolidity +stolidly +stolidness +stollen +stollens +stolon +stolonate +stoloniferous +stoloniferously +stoma +stomach +stomachache +stomachaches +stomached +stomacher +stomachers +stomachic +stomachically +stomachics +stomaching +stomachs +stomachy +stomal +stomas +stomata +stomatal +stomate +stomates +stomatic +stomatitis +stomatitises +stomatologic +stomatological +stomatologist +stomatologists +stomatology +stomatopod +stomatopods +stomatous +stomodaea +stomodaeal +stomodaeum +stomodea +stomodeal +stomodeum +stomp +stomped +stomper +stompers +stomping +stompingly +stomps +stone +stoneboat +stoneboats +stonecat +stonecats +stonechat +stonechats +stonecrop +stonecrops +stonecutter +stonecutters +stonecutting +stoned +stonefish +stonefishes +stoneflies +stonefly +stonehearted +stonehenge +stonemason +stonemasonry +stonemasons +stoner +stoneroller +stonerollers +stoners +stones +stonewall +stonewalled +stonewaller +stonewallers +stonewalling +stonewalls +stoneware +stonewash +stonewashed +stonewashes +stonewashing +stonework +stoneworker +stoneworkers +stonewort +stoneworts +stoney +stonier +stoniest +stonily +stoniness +stoning +stony +stonyhearted +stonyheartedly +stonyheartedness +stood +stooge +stooged +stooges +stooging +stool +stooled +stoolie +stoolies +stooling +stools +stoop +stoopball +stoopballs +stooped +stooper +stoopers +stooping +stoops +stop +stopcock +stopcocks +stope +stoped +stoper +stopers +stopes +stopgap +stopgaps +stoping +stoplight +stoplights +stopover +stopovers +stoppable +stoppage +stoppages +stopped +stopper +stoppered +stoppering +stoppers +stopping +stopple +stoppled +stopples +stoppling +stops +stopwatch +stopwatches +storable +storage +storax +storaxes +store +stored +storefront +storefronts +storehouse +storehouses +storekeeper +storekeepers +storekeeping +storeowner +storeowners +storer +storeroom +storerooms +storers +stores +storeship +storeships +storewide +storey +storeyed +storeys +storied +stories +storing +stork +storks +storksbill +storksbills +storm +stormbound +stormed +stormier +stormiest +stormily +storminess +storming +storms +stormy +story +storyboard +storyboarded +storyboarding +storyboards +storybook +storybooks +storying +storyteller +storytellers +storytelling +storywriter +storywriters +stoss +stotinka +stotinki +stound +stounds +stoup +stoups +stout +stouten +stoutened +stoutening +stoutens +stouter +stoutest +stouthearted +stoutheartedly +stoutheartedness +stoutish +stoutly +stoutness +stouts +stove +stovepipe +stovepipes +stover +stovers +stoves +stovetop +stovetops +stow +stowage +stowaway +stowaways +stowed +stowing +stows +strabismal +strabismic +strabismus +strabo +strabotomies +strabotomy +strachey +strad +straddle +straddled +straddler +straddlers +straddles +straddling +stradivari +stradivarius +strads +strafe +strafed +strafer +strafers +strafes +strafing +straggle +straggled +straggler +stragglers +straggles +stragglier +straggliest +straggling +straggly +straight +straightarrow +straightaway +straightaways +straightbred +straightedge +straightedged +straightedges +straighten +straightened +straightener +straighteners +straightening +straightens +straighter +straightest +straightforward +straightforwardly +straightforwardness +straightforwards +straightish +straightjacket +straightjacketed +straightjacketing +straightjackets +straightlaced +straightly +straightness +straights +straightway +strain +strained +strainer +strainers +straining +strainometer +strainometers +strains +strait +straiten +straitened +straitening +straitens +straitjacket +straitjacketed +straitjacketing +straitjackets +straitlaced +straitlacedly +straitlacedness +straitly +straitness +straits +strake +strakes +stramonium +stramoniums +strand +stranded +strandedness +stranding +strandline +strandlines +strands +strange +strangely +strangeness +stranger +strangers +strangest +strangle +strangled +stranglehold +strangleholds +strangler +stranglers +strangles +strangling +strangulate +strangulated +strangulates +strangulating +strangulation +strangulations +stranguries +strangury +strap +straphang +straphanger +straphangers +straphanging +straphangs +straphung +strapless +straplesses +strappado +strappadoes +strapped +strapper +strappers +strapping +straps +strasbourg +strass +strasses +strata +stratagem +stratagems +stratal +strategic +strategical +strategically +strategics +strategies +strategist +strategists +strategize +strategized +strategizes +strategizing +strategy +stratford +strath +strathclyde +straths +strathspey +strathspeys +strati +straticulate +straticulation +straticulations +stratification +stratificational +stratified +stratifies +stratiform +stratify +stratifying +stratigraphic +stratigraphical +stratigraphically +stratigraphy +stratocracies +stratocracy +stratocratic +stratocumuli +stratocumulus +stratopause +stratopauses +stratosphere +stratospheres +stratospheric +stratospherically +stratovolcano +stratovolcanos +stratum +stratums +stratus +strauss +stravinsky +straw +strawberries +strawberry +strawboard +strawboards +strawflower +strawflowers +strawhat +straws +strawworm +strawworms +strawy +stray +strayed +strayer +strayers +straying +strays +streak +streaked +streaker +streakers +streakier +streakiest +streakily +streakiness +streaking +streaks +streaky +stream +streambed +streambeds +streamed +streamer +streamers +streaming +streamlet +streamlets +streamline +streamlined +streamliner +streamliners +streamlines +streamlining +streams +streamside +streamsides +streamy +street +streetcar +streetcars +streeter +streeters +streetlight +streetlights +streets +streetscape +streetscapes +streetwalker +streetwalkers +streetwalking +streetwise +strength +strengthen +strengthened +strengthener +strengtheners +strengthening +strengthens +strengths +strenuosity +strenuous +strenuously +strenuousness +strep +streps +streptobacilli +streptobacillus +streptocarpus +streptocarpuses +streptococcal +streptococci +streptococcic +streptococcus +streptodornase +streptodornases +streptokinase +streptokinases +streptolysin +streptolysins +streptomyces +streptomycete +streptomycetes +streptomycin +streptomycins +streptonigrin +streptonigrins +streptothricin +streptothricins +streptovaricin +streptovaricins +streptozotocin +streptozotocins +stresa +stress +stressed +stresses +stressful +stressfully +stressfulness +stressing +stressless +stresslessness +stressor +stressors +stretch +stretchability +stretchable +stretched +stretcher +stretchers +stretches +stretchier +stretchiest +stretchiness +stretching +stretchy +stretta +strettas +strette +stretti +stretto +strettos +streusel +streusels +strew +strewed +strewing +strewn +strews +stria +striae +striata +striate +striated +striates +striating +striation +striations +striatum +strick +stricken +strickle +strickled +strickles +strickling +stricks +strict +stricter +strictest +strictly +strictness +stricture +strictures +stridden +stride +stridence +stridency +strident +stridently +strider +striders +strides +striding +stridor +stridors +stridulate +stridulated +stridulates +stridulating +stridulation +stridulations +stridulatory +stridulous +stridulously +strife +strifeless +strigil +strigils +strigose +strike +strikebound +strikebreaker +strikebreakers +strikebreaking +strikeout +strikeouts +strikeover +strikeovers +striker +strikers +strikes +striking +strikingly +strikingness +strindberg +string +stringboard +stringboards +stringcourse +stringcourses +stringed +stringencies +stringency +stringendo +stringent +stringently +stringer +stringers +stringhalt +stringhalted +stringhalts +stringier +stringiest +stringily +stringiness +stringing +stringless +stringpiece +stringpieces +strings +stringy +stringybark +stringybarks +strip +stripe +striped +stripeless +striper +stripers +stripes +stripfilm +stripfilms +stripier +stripiest +striping +stripings +stripling +striplings +strippable +stripped +stripper +strippers +stripping +strips +stript +striptease +stripteaser +stripteasers +stripteases +stripy +strive +strived +striven +striver +strivers +strives +striving +strivingly +strivings +strobe +strobes +strobila +strobilaceous +strobilae +strobilar +strobilation +strobilations +strobile +strobiles +strobili +strobilus +stroboscope +stroboscopes +stroboscopic +stroboscopically +strobotron +strobotrons +strode +stroganoff +stroke +stroked +stroker +strokers +strokes +stroking +stroll +strolled +stroller +strollers +strolling +strolls +stroma +stromal +stromata +stromatic +stromatolite +stromatolites +stromatolitic +stromboli +strong +strongbox +strongboxes +stronger +strongest +stronghold +strongholds +strongish +strongly +strongman +strongmen +strongpoint +strongpoints +strongyl +strongyle +strongyles +strongyloidiasis +strongyloidosis +strongylosis +strongyls +strontianite +strontianites +strontium +strop +strophanthin +strophanthins +strophe +strophes +strophic +strophoid +strophoids +strophuli +strophulus +stropped +stroppier +stroppiest +stropping +stroppy +strops +stroud +strouding +strouds +strove +struck +structural +structuralism +structuralist +structuralists +structuralization +structuralizations +structuralize +structuralized +structuralizes +structuralizing +structurally +structurals +structuration +structure +structured +structureless +structurelessness +structures +structuring +strudel +strudels +struggle +struggled +struggler +strugglers +struggles +struggling +strugglingly +strum +struma +strumae +strumas +strumatic +strummed +strummer +strummers +strumming +strumose +strumous +strumpet +strumpets +strums +strung +strut +struthious +struts +strutted +strutter +strutters +strutting +struttingly +strychnine +strychninism +strychninisms +stuart +stuarts +stub +stubbed +stubbier +stubbiest +stubbily +stubbiness +stubbing +stubble +stubbled +stubbly +stubborn +stubborner +stubbornest +stubbornly +stubbornness +stubbs +stubby +stubs +stucco +stuccoed +stuccoes +stuccoing +stuccos +stuccowork +stuccoworker +stuccoworkers +stuck +stud +studbook +studbooks +studded +studding +studdingsail +studdingsails +student +students +studentship +studentships +studfish +studfishes +studhorse +studhorses +studied +studiedly +studiedness +studier +studiers +studies +studio +studios +studious +studiously +studiousness +studly +studs +studwork +study +studying +stuff +stuffed +stuffer +stuffers +stuffier +stuffiest +stuffily +stuffiness +stuffing +stuffless +stuffs +stuffy +stukeley +stull +stulls +stultification +stultifications +stultified +stultifier +stultifiers +stultifies +stultify +stultifying +stum +stumble +stumblebum +stumblebums +stumbled +stumbler +stumblers +stumbles +stumbling +stumblingly +stummed +stumming +stump +stumpage +stumped +stumper +stumpers +stumpiness +stumping +stumps +stumpy +stums +stun +stung +stunk +stunned +stunner +stunners +stunning +stunningly +stuns +stunt +stunted +stuntedness +stunting +stuntman +stuntmen +stunts +stuntwoman +stuntwomen +stupa +stupas +stupe +stupefacient +stupefacients +stupefaction +stupefactions +stupefactive +stupefactives +stupefied +stupefier +stupefiers +stupefies +stupefy +stupefying +stupefyingly +stupendous +stupendously +stupendousness +stupes +stupid +stupider +stupidest +stupidities +stupidity +stupidly +stupidness +stupids +stupor +stuporous +stupors +sturdier +sturdiest +sturdily +sturdiness +sturdy +sturgeon +sturgeons +sturm +stutter +stuttered +stutterer +stutterers +stuttering +stutteringly +stutters +stuttgart +sty +stye +styes +stygian +stying +stylar +stylate +style +stylebook +stylebooks +styled +styler +stylers +styles +stylet +stylets +styli +styliform +styling +stylings +stylish +stylishly +stylishness +stylist +stylistic +stylistically +stylistics +stylists +stylite +stylites +stylitic +stylitism +stylization +stylizations +stylize +stylized +stylizer +stylizers +stylizes +stylizing +stylobate +stylobates +stylography +styloid +stylolite +stylolites +stylopodia +stylopodium +stylus +styluses +stymie +stymied +stymieing +stymies +stymy +stymying +stypsis +styptic +stypticity +styptics +styrax +styraxes +styrene +styria +styrofoam +styx +suability +suable +suably +suasion +suasions +suasive +suasively +suasiveness +suave +suavely +suaveness +suaver +suavest +suavity +sub +subabdominal +subacid +subacidly +subacidness +subacute +subacutely +subadar +subadars +subaddress +subaddresses +subadolescent +subadult +subadults +subaerial +subaerially +subagencies +subagency +subagent +subagents +subahdar +subahdars +suballocation +suballocations +subalpine +subaltern +subalternate +subalternation +subalternations +subalterns +subantarctic +subapical +subapically +subaquatic +subaqueous +subarachnoid +subarachnoidal +subarctic +subarea +subareas +subarid +subassemblies +subassembly +subatmospheric +subatomic +subaudible +subaudition +subauditions +subaverage +subaxillary +subbase +subbasement +subbasements +subbases +subbasin +subbasins +subbass +subbasses +subbed +subbing +subbituminous +subblock +subblocks +subbranch +subbranches +subcabinet +subcaliber +subcapsular +subcarrier +subcarriers +subcartilaginous +subcaste +subcastes +subcategories +subcategorization +subcategorizations +subcategorize +subcategorized +subcategorizes +subcategorizing +subcategory +subceiling +subceilings +subcelestial +subcellar +subcellars +subcellular +subcenter +subcenters +subcentral +subcentrally +subchannel +subchannels +subchapter +subchapters +subchaser +subchasers +subchief +subchiefs +subclan +subclans +subclass +subclasses +subclassification +subclassifications +subclassified +subclassifies +subclassify +subclassifying +subclavian +subclavians +subclimactic +subclimax +subclimaxes +subclinical +subclinically +subcluster +subclusters +subcode +subcodes +subcollection +subcollections +subcollege +subcolleges +subcollegiate +subcolonies +subcolony +subcommand +subcommands +subcommission +subcommissions +subcommittee +subcommittees +subcommunities +subcommunity +subcompact +subcompacts +subcomponent +subcomponents +subconference +subconferences +subconscious +subconsciously +subconsciousness +subcontinent +subcontinental +subcontinents +subcontract +subcontracted +subcontracting +subcontractor +subcontractors +subcontracts +subcontraoctave +subcontraoctaves +subcontraries +subcontrary +subcool +subcooled +subcooling +subcools +subcordate +subcoriaceous +subcortex +subcortical +subcortically +subcortices +subcounties +subcounty +subcritical +subcrustal +subcult +subcults +subcultural +subculturally +subculture +subcultures +subcurative +subcutaneous +subcutaneously +subcutis +subcutises +subdeacon +subdeacons +subdean +subdeans +subdeb +subdebs +subdebutante +subdebutantes +subdecision +subdecisions +subdepartment +subdepartments +subdermal +subdermally +subdevelopment +subdevelopments +subdiaconal +subdiaconate +subdiaconates +subdialect +subdialects +subdirector +subdirectories +subdirectors +subdirectory +subdiscipline +subdisciplines +subdistrict +subdistricts +subdividable +subdivide +subdivided +subdivider +subdividers +subdivides +subdividing +subdivision +subdivisional +subdivisions +subdominant +subdominants +subduable +subduct +subducted +subducting +subduction +subductions +subducts +subdue +subdued +subduedly +subduer +subduers +subdues +subduing +subdural +subeconomies +subeconomy +subedit +subedited +subediting +subeditor +subeditorial +subeditors +subedits +subemployed +subemployment +subentries +subentry +subepidermal +subequatorial +suberect +suberin +suberins +suberization +suberizations +suberize +suberized +suberizes +suberizing +suberose +suberous +subexpression +subexpressions +subfamilies +subfamily +subfield +subfields +subfigure +subfigures +subfile +subfiles +subfloor +subflooring +subfloorings +subfloors +subfolder +subfolders +subfossil +subfossils +subframe +subframes +subfreezing +subfusc +subfuscs +subgenera +subgeneration +subgenerations +subgeneric +subgenre +subgenres +subgenus +subglacial +subglacially +subgoal +subgoals +subgovernment +subgovernments +subgrade +subgrades +subgraph +subgraphs +subgroup +subgroups +subgum +subgums +subharmonic +subhead +subheading +subheadings +subheads +subhuman +subhumans +subhumid +subindex +subindexes +subindices +subindustries +subindustry +subinfeud +subinfeudate +subinfeudated +subinfeudates +subinfeudating +subinfeudation +subinfeudations +subinfeudatory +subinfeuded +subinfeuding +subinfeuds +subinhibitory +subinterval +subintervals +subirrigate +subirrigated +subirrigates +subirrigating +subirrigation +subirrigations +subito +subjacency +subjacent +subjacently +subject +subjected +subjecting +subjection +subjections +subjective +subjectively +subjectiveness +subjectivism +subjectivist +subjectivistic +subjectivists +subjectivity +subjectivization +subjectivizations +subjectivize +subjectivized +subjectivizes +subjectivizing +subjectless +subjects +subjoin +subjoinder +subjoinders +subjoined +subjoining +subjoins +subjugate +subjugated +subjugates +subjugating +subjugation +subjugations +subjugator +subjugators +subjunction +subjunctions +subjunctive +subjunctives +subkingdom +subkingdoms +sublanguage +sublanguages +sublate +sublated +sublates +sublating +sublation +sublations +sublease +subleased +subleases +subleasing +sublet +sublethal +sublethally +sublets +subletting +sublevel +sublevels +sublibrarian +sublibrarians +sublicense +sublicensed +sublicensee +sublicensees +sublicenses +sublicensing +sublieutenant +sublieutenants +sublimable +sublimate +sublimated +sublimates +sublimating +sublimation +sublimations +sublime +sublimed +sublimely +sublimeness +sublimer +sublimers +sublimes +subliminal +subliminally +subliming +sublimit +sublimities +sublimits +sublimity +subline +sublines +sublingual +sublingually +sublinguals +subliteracy +subliterary +subliterate +subliterature +sublittoral +sublot +sublots +sublunar +sublunary +subluxation +subluxations +submachine +submanager +submanagers +submandibular +submarginal +submarine +submarined +submariner +submariners +submarines +submarining +submarket +submarkets +submaxilla +submaxillae +submaxillaries +submaxillary +submaximal +submediant +submediants +submenu +submenus +submerge +submerged +submergence +submerges +submergibility +submergible +submerging +submerse +submersed +submerses +submersible +submersibles +submersing +submersion +submersions +submetacentric +submetacentrics +submicrogram +submicron +submicroscopic +submicroscopically +submillimeter +subminiature +subminiaturization +subminiaturizations +subminiaturize +subminiaturized +subminiaturizes +subminiaturizing +subminimal +subminimum +subminister +subministered +subministering +subministers +submiss +submission +submissions +submissive +submissively +submissiveness +submit +submitochondrial +submits +submittal +submittals +submitted +submitter +submitters +submitting +submontane +submucosa +submucosal +submucosally +submucosas +submultiple +submultiples +submunition +submunitions +subnational +subnet +subnets +subnetwork +subnetworks +subniche +subniches +subnormal +subnormality +subnormally +subnormals +subnuclear +suboceanic +suboptimal +suboptimization +suboptimizations +suboptimize +suboptimized +suboptimizes +suboptimizing +suboptimum +suboptimums +suborbicular +suborbital +suborbitals +suborder +suborders +subordinate +subordinated +subordinately +subordinateness +subordinates +subordinating +subordination +subordinations +subordinative +subordinator +subordinators +suborganization +suborganizations +suborn +subornation +subornations +suborned +suborner +suborners +suborning +suborns +suboxide +suboxides +subpanel +subpanels +subpar +subparagraph +subparagraphs +subparallel +subpart +subparts +subperiod +subperiods +subperiosteal +subphase +subphases +subphyla +subphylum +subplot +subplots +subpoena +subpoenaed +subpoenaing +subpoenas +subpolar +subpopulation +subpopulations +subpotency +subpotent +subprimate +subprimates +subprincipal +subprincipals +subproblem +subproblems +subprocess +subprocesses +subproduct +subproducts +subprofessional +subprofessionals +subprogram +subprograms +subproject +subprojects +subproletariat +subproletariats +subrational +subregion +subregional +subregions +subreption +subreptions +subreptitious +subreptitiously +subring +subrings +subrogate +subrogated +subrogates +subrogating +subrogation +subrogations +subroutine +subroutines +subs +subsample +subsampled +subsamples +subsampling +subsatellite +subsatellites +subsaturated +subsaturation +subscale +subscales +subscapular +subscapulars +subscience +subsciences +subscribe +subscribed +subscriber +subscribers +subscribes +subscribing +subscript +subscripted +subscripting +subscription +subscriptions +subscriptive +subscriptively +subscripts +subsea +subsecretaries +subsecretary +subsection +subsections +subsector +subsectors +subsegment +subsegments +subseizure +subsense +subsenses +subsentence +subsentences +subsequence +subsequences +subsequent +subsequently +subsequentness +subsere +subseres +subseries +subserve +subserved +subserves +subservience +subserviency +subservient +subserviently +subserving +subset +subsets +subshell +subshells +subshrub +subshrubs +subside +subsided +subsidence +subsides +subsidiaries +subsidiarily +subsidiarity +subsidiary +subsidies +subsiding +subsidization +subsidizations +subsidize +subsidized +subsidizer +subsidizers +subsidizes +subsidizing +subsidy +subsist +subsisted +subsistence +subsistent +subsister +subsisters +subsisting +subsists +subsite +subsites +subskill +subskills +subsocial +subsocieties +subsociety +subsoil +subsoiled +subsoiler +subsoilers +subsoiling +subsoils +subsolar +subsonic +subsonically +subspace +subspaces +subspecialist +subspecialists +subspecialization +subspecializations +subspecialize +subspecialized +subspecializes +subspecializing +subspecialties +subspecialty +subspecies +subspecific +substage +substages +substance +substanceless +substances +substandard +substantia +substantiae +substantial +substantiality +substantially +substantialness +substantials +substantiate +substantiated +substantiates +substantiating +substantiation +substantiations +substantiative +substantival +substantivally +substantive +substantively +substantiveness +substantives +substantivize +substantivized +substantivizes +substantivizing +substate +substates +substation +substations +substituent +substituents +substitutability +substitutable +substitute +substituted +substitutes +substituting +substitution +substitutional +substitutionally +substitutionary +substitutions +substitutive +substitutively +substrata +substrate +substrates +substrative +substratosphere +substratospheres +substratospheric +substratum +substratums +substructural +substructure +substructures +subsumable +subsume +subsumed +subsumes +subsuming +subsumption +subsumptions +subsumptive +subsurface +subsystem +subsystems +subtask +subtasks +subtaxa +subtaxon +subtaxons +subteen +subteens +subtemperate +subtenancy +subtenant +subtenants +subtend +subtended +subtending +subtends +subterfuge +subterfuges +subterminal +subterranean +subterraneanly +subterraneous +subterraneously +subterrestrial +subtest +subtests +subtext +subtexts +subtextual +subtheme +subthemes +subtherapeutic +subtherapeutically +subthreshold +subtile +subtilely +subtileness +subtiler +subtilest +subtilin +subtilins +subtilisin +subtilisins +subtility +subtilization +subtilizations +subtilize +subtilized +subtilizes +subtilizing +subtilty +subtitle +subtitled +subtitles +subtitling +subtle +subtleness +subtler +subtlest +subtleties +subtlety +subtly +subtonic +subtonics +subtopic +subtopics +subtorrid +subtotal +subtotaled +subtotaling +subtotalled +subtotalling +subtotally +subtotals +subtract +subtracted +subtracter +subtracters +subtracting +subtraction +subtractions +subtractive +subtracts +subtrahend +subtrahends +subtreasuries +subtreasury +subtrend +subtrends +subtribe +subtribes +subtropic +subtropical +subtropics +subtype +subtypes +subulate +subumbrella +subumbrellas +subunit +subunits +suburb +suburban +suburbanite +suburbanites +suburbanization +suburbanizations +suburbanize +suburbanized +suburbanizes +suburbanizing +suburbans +suburbia +suburbs +subvarieties +subvariety +subvassal +subvassals +subvention +subventionary +subventions +subversion +subversionary +subversions +subversive +subversively +subversiveness +subversives +subvert +subverted +subverter +subverters +subverting +subverts +subviral +subvirus +subviruses +subvisible +subvisual +subvocal +subvocalization +subvocalizations +subvocalize +subvocalized +subvocalizer +subvocalizers +subvocalizes +subvocalizing +subvocally +subway +subways +subworld +subworlds +subwriter +subwriters +subzero +subzone +subzones +succedanea +succedaneous +succedaneum +succedaneums +succedent +succeed +succeeded +succeeder +succeeders +succeeding +succeeds +success +successes +successful +successfully +successfulness +succession +successional +successionally +successions +successive +successively +successiveness +successor +successors +succi +succinate +succinates +succinct +succincter +succinctest +succinctly +succinctness +succinic +succinyl +succinylcholine +succinylcholines +succinyls +succinylsulfathiazole +succinylsulfathiazoles +succor +succorable +succored +succorer +succorers +succories +succoring +succors +succory +succotash +succoth +succuba +succubae +succubi +succubus +succubuses +succulence +succulency +succulent +succulently +succulents +succumb +succumbed +succumbing +succumbs +succus +succussatory +succussion +succussions +succès +such +suchlike +suck +sucked +sucker +suckered +suckerfish +suckerfishes +suckering +suckers +suckfish +suckfishes +sucking +suckle +suckled +suckler +sucklers +suckles +suckling +sucklings +sucks +sucrase +sucrases +sucre +sucres +sucrose +suction +suctional +suctioned +suctioning +suctions +suctorial +suctorian +suctorians +sudan +sudanese +sudanic +sudatoria +sudatories +sudatorium +sudatory +sudd +sudden +suddenly +suddenness +sudds +sudeten +sudetenland +sudetes +sudoriferous +sudorific +sudorifics +sudra +sudras +suds +sudser +sudsers +sudsier +sudsiest +sudsless +sudsy +sue +sued +suede +sueded +suedes +sueding +suer +suers +sues +suet +suety +suey +sueys +suez +suffer +sufferable +sufferableness +sufferably +sufferance +suffered +sufferer +sufferers +suffering +sufferingly +sufferings +suffers +suffice +sufficed +sufficer +sufficers +suffices +sufficiencies +sufficiency +sufficient +sufficiently +sufficing +sufficingly +sufficingness +suffix +suffixal +suffixation +suffixations +suffixed +suffixes +suffixing +suffixion +suffixions +suffocate +suffocated +suffocates +suffocating +suffocatingly +suffocation +suffocations +suffocative +suffolk +suffragan +suffragans +suffraganship +suffraganships +suffrage +suffrages +suffragette +suffragettes +suffragettism +suffragism +suffragist +suffragists +suffrutescent +suffruticose +suffuse +suffused +suffuses +suffusing +suffusion +suffusions +suffusive +sufi +sufic +sufis +sufism +sufistic +sugar +sugarberries +sugarberry +sugarbird +sugarbirds +sugarcane +sugarcanes +sugarcoat +sugarcoated +sugarcoating +sugarcoats +sugared +sugarer +sugarers +sugarhouse +sugarhouses +sugarier +sugariest +sugariness +sugaring +sugarless +sugarloaf +sugarloaves +sugarplum +sugarplums +sugars +sugary +suggest +suggested +suggester +suggesters +suggestibility +suggestible +suggesting +suggestion +suggestions +suggestive +suggestively +suggestiveness +suggests +sui +suicidal +suicidally +suicide +suicided +suicides +suiciding +suicidologist +suicidologists +suicidology +suing +suint +suints +suit +suitability +suitable +suitableness +suitably +suitcase +suitcases +suite +suited +suiter +suiters +suites +suiting +suitings +suitor +suitors +suits +sukiyaki +sukiyakis +sukkah +sukkot +sukkoth +sulawesi +sulcal +sulcate +sulci +sulcus +suleiman +sulfa +sulfadiazine +sulfadiazines +sulfanilamide +sulfanilamides +sulfanilic +sulfatase +sulfatases +sulfate +sulfated +sulfates +sulfathiazole +sulfathiazoles +sulfating +sulfhydryl +sulfhydryls +sulfide +sulfides +sulfinpyrazone +sulfinpyrazones +sulfinyl +sulfinyls +sulfite +sulfites +sulfitic +sulfonamide +sulfonamides +sulfonate +sulfonated +sulfonates +sulfonating +sulfonation +sulfonations +sulfone +sulfones +sulfonic +sulfonium +sulfoniums +sulfonmethane +sulfonmethanes +sulfonyl +sulfonyls +sulfonylurea +sulfonylureas +sulfoxide +sulfoxides +sulfur +sulfurate +sulfurated +sulfurates +sulfurating +sulfuration +sulfurations +sulfured +sulfureous +sulfuret +sulfureted +sulfureting +sulfurets +sulfuretted +sulfuretting +sulfuric +sulfuring +sulfurization +sulfurizations +sulfurize +sulfurized +sulfurizes +sulfurizing +sulfurous +sulfurously +sulfurousness +sulfurs +sulfury +sulfuryl +sulfuryls +sulk +sulked +sulkers +sulkier +sulkies +sulkiest +sulkily +sulkiness +sulking +sulks +sulky +sulla +sullage +sullen +sullener +sullenest +sullenly +sullenness +sullied +sullies +sullivan +sully +sullying +sulphur +sulphured +sulphureous +sulphuric +sulphuring +sulphurous +sulphurs +sulphury +sulpician +sulpicians +sultan +sultana +sultanas +sultanate +sultanates +sultaness +sultanesses +sultanic +sultans +sultrier +sultriest +sultrily +sultriness +sultry +sulu +sulus +sum +sumac +sumach +sumacs +sumatra +sumatran +sumatrans +sumba +sumbawa +sumer +sumerian +sumerians +sumerologist +sumerologists +sumerology +summa +summability +summable +summae +summand +summands +summaries +summarily +summariness +summarizable +summarization +summarizations +summarize +summarized +summarizer +summarizers +summarizes +summarizing +summary +summate +summated +summates +summating +summation +summational +summations +summative +summed +summer +summercater +summercaters +summered +summerhouse +summerhouses +summering +summerlike +summerlong +summerly +summers +summersault +summersaulted +summersaulting +summersaults +summerset +summersets +summersetted +summersetting +summertime +summerwood +summery +summing +summings +summit +summiteer +summiteers +summitries +summitry +summits +summon +summonable +summoned +summoner +summoners +summoning +summons +summonsed +summonses +summonsing +summum +sumo +sump +sumps +sumpter +sumpters +sumptuary +sumptuous +sumptuously +sumptuousness +sums +sun +sunbaked +sunbath +sunbathe +sunbathed +sunbather +sunbathers +sunbathes +sunbathing +sunbaths +sunbeam +sunbeams +sunbelt +sunbelts +sunbird +sunbirds +sunblind +sunblock +sunbonnet +sunbonnets +sunbow +sunbows +sunburn +sunburned +sunburning +sunburns +sunburnt +sunburst +sunbursts +sunchoke +sunchokes +sundae +sundaes +sunday +sundays +sundeck +sundecks +sunder +sunderance +sundered +sundering +sunders +sundew +sundews +sundial +sundials +sundog +sundogs +sundown +sundowner +sundowners +sundress +sundresses +sundries +sundrops +sundry +sunfish +sunfishes +sunflower +sunflowers +sung +sunglass +sunglasses +sunglow +sunglows +sunk +sunken +sunlamp +sunlamps +sunless +sunlessness +sunlight +sunlike +sunlit +sunn +sunna +sunnah +sunned +sunni +sunnier +sunniest +sunnily +sunniness +sunning +sunnis +sunnism +sunnite +sunnites +sunns +sunny +sunporch +sunporches +sunray +sunrays +sunrise +sunrises +sunroof +sunroofs +sunroom +sunrooms +suns +sunscald +sunscalds +sunscreen +sunscreening +sunscreens +sunseeker +sunseekers +sunset +sunsets +sunshade +sunshades +sunshine +sunshiny +sunspace +sunspaces +sunspot +sunspots +sunstone +sunstones +sunstroke +sunstrokes +sunstruck +sunsuit +sunsuits +suntan +suntanned +suntans +sunup +sunward +sunwards +sunwise +sup +super +superable +superableness +superably +superabound +superabounded +superabounding +superabounds +superabsorbent +superabsorbents +superabundance +superabundant +superabundantly +superachiever +superachievers +superactivities +superactivity +superadd +superadded +superadding +superaddition +superadditions +superadds +superadministrator +superadministrators +superagencies +superagency +superagent +superagents +superalloy +superalloys +superaltern +superalterns +superambitious +superannuate +superannuated +superannuates +superannuating +superannuation +superannuations +superathlete +superb +superbad +superball +superbank +superbillionaire +superbitch +superblock +superblocks +superbly +superbness +superboard +superbomb +superbomber +superbright +superbureaucrat +supercabinet +supercalender +supercalendered +supercalendering +supercalenders +supercar +supercargo +supercargoes +supercargos +supercarrier +supercautious +supercenter +supercharge +supercharged +supercharger +superchargers +supercharges +supercharging +superchic +superchurch +superciliary +supercilious +superciliously +superciliousness +supercities +supercity +supercivilization +supercivilized +superclass +superclasses +superclean +superclub +supercluster +superclusters +supercoil +supercoiled +supercoiling +supercoils +supercollider +supercolliders +supercolossal +supercolumnar +supercomfortable +supercompetitive +supercomputer +supercomputers +supercomputing +superconduct +superconducted +superconducting +superconductive +superconductivity +superconductor +superconductors +superconducts +superconfident +superconglomerate +superconservative +supercontinent +supercontinents +superconvenient +supercool +supercooled +supercooling +supercools +supercop +supercorporation +supercriminal +supercritical +supercurrent +supercurrents +supercute +superdelegate +superdelegates +superdeluxe +superdiplomat +superdominant +superdominants +superduper +supered +supereffective +superefficiency +superefficient +superego +superegoist +superegoists +superegos +superelevate +superelevated +superelevates +superelevating +superelevation +superelevations +superelite +supereminence +supereminent +supereminently +supererogate +supererogated +supererogates +supererogating +supererogation +supererogations +supererogative +supererogatory +superexcellent +superexpensive +superexpress +superfamilies +superfamily +superfan +superfarm +superfast +superfatted +superfecta +superfectas +superfecundation +superfecundations +superfetate +superfetated +superfetates +superfetating +superfetation +superfetations +superficial +superficialities +superficiality +superficially +superficialness +superficies +superfine +superfineness +superfirm +superfix +superfixes +superflack +superfluid +superfluidity +superfluids +superfluities +superfluity +superfluous +superfluously +superfluousness +superfund +supergalactic +supergalaxies +supergalaxy +supergene +supergenes +supergiant +supergiants +superglue +superglues +supergood +supergovernment +supergraphics +supergravity +supergroup +supergroups +supergrowth +superharden +superheat +superheated +superheater +superheaters +superheating +superheats +superheavy +superheavyweight +superheavyweights +superhelical +superhelically +superhelices +superhelix +superhelixes +superhero +superheroes +superheroine +superheterodyne +superheterodynes +superhigh +superhighway +superhighways +superhit +superhot +superhuman +superhumanity +superhumanly +superhumanness +superhype +superimposable +superimpose +superimposed +superimposes +superimposing +superimposition +superimpositions +superincumbence +superincumbency +superincumbent +superincumbently +superindividual +superinduce +superinduced +superinduces +superinducing +superinduction +superinductions +superinfect +superinfected +superinfecting +superinfection +superinfections +superinfects +supering +superinsulated +superintellectual +superintelligence +superintelligent +superintend +superintended +superintendence +superintendences +superintendencies +superintendency +superintendent +superintendents +superintending +superintends +superintensity +superior +superiority +superiorly +superiors +superjacent +superjet +superjets +superjock +superjumbo +superlarge +superlative +superlatively +superlativeness +superlatives +superlawyer +superlight +superlinear +superliner +superliners +superlobbyist +superlobbyists +superloyalist +superloyalists +superlunar +superlunary +superluxurious +superluxury +supermacho +supermagnetic +supermajorities +supermajority +supermale +superman +supermarket +supermarketer +supermarketers +supermarkets +supermasculine +supermassive +supermen +supermicro +supermicros +supermilitant +supermillionaire +supermind +superminicomputer +superminicomputers +superminister +supermodel +supermodels +supermodern +supermolecule +supermolecules +supermom +supermoms +supernal +supernally +supernatant +supernatants +supernation +supernational +supernatural +supernaturalism +supernaturalist +supernaturalistic +supernaturalists +supernaturally +supernaturalness +supernaturals +supernature +supernormal +supernormality +supernormally +supernova +supernovae +supernovas +supernumeraries +supernumerary +supernutrition +superorder +superorders +superordinate +superordinated +superordinates +superordinating +superordination +superordinations +superorganic +superorganism +superorganisms +superorgasm +superovulate +superovulated +superovulates +superovulating +superovulation +superovulations +superoxide +superoxides +superparasitic +superparasitism +superparasitisms +superpatriot +superpatriotic +superpatriotism +superperson +superpersonal +superphenomenon +superphosphate +superphosphates +superphysical +superpimp +superplane +superplastic +superplasticity +superplayer +superpolite +superport +superposable +superpose +superposed +superposes +superposing +superposition +superpower +superpowered +superpowerful +superpowers +superpremium +superpro +superprofit +superquality +superrace +superreal +superrealism +superrealist +superrealistic +superrealists +superregional +superrich +superroad +superromantic +superromanticism +supers +supersafe +supersale +supersalesman +supersaturate +supersaturated +supersaturates +supersaturating +supersaturation +supersaturations +supersaver +supersavers +superscale +superschool +superscout +superscribe +superscribed +superscribes +superscribing +superscript +superscripted +superscripting +superscription +superscripts +supersecrecy +supersecret +supersede +supersedeas +supersedeases +superseded +superseder +superseders +supersedes +superseding +supersedure +supersedures +supersell +superseller +supersensible +supersensibly +supersensitive +supersensitively +supersensitivity +supersensory +superserviceable +supersession +supersessions +superset +supersets +supersexuality +supersharp +supershow +supersinger +supersize +supersized +supersleuth +superslick +supersmart +supersmooth +supersoft +supersonic +supersonically +supersonics +supersophisticated +superspecial +superspecialist +superspecialists +superspecialization +superspecialized +superspectacle +superspectacular +superspeculation +superspy +superstar +superstardom +superstars +superstate +superstates +superstation +superstations +superstimulate +superstition +superstitions +superstitious +superstitiously +superstitiousness +superstock +superstore +superstores +superstrata +superstratum +superstrength +superstrike +superstring +superstrings +superstrong +superstructural +superstructure +superstructures +superstud +supersubstantial +supersubtle +supersubtlety +supersurgeon +supersweet +supersymmetric +supersymmetry +supersystem +supersystems +supertanker +supertankers +supertax +supertaxes +superterrific +superthick +superthin +superthriller +supertight +supertitle +supertitled +supertitles +supertonic +supertonics +supervene +supervened +supervenes +supervenient +supervening +supervention +superventions +supervirile +supervirtuoso +supervise +supervised +supervises +supervising +supervision +supervisions +supervisor +supervisors +supervisory +superwave +superweapon +superwide +superwife +superwoman +superwomen +supinate +supinated +supinates +supinating +supination +supinations +supinator +supinators +supine +supinely +supineness +supped +supper +suppers +suppertime +suppertimes +supping +supplant +supplantation +supplantations +supplanted +supplanter +supplanters +supplanting +supplants +supple +suppled +supplejack +supplejacks +supplely +supplement +supplemental +supplementarity +supplementary +supplementation +supplementations +supplemented +supplementer +supplementers +supplementing +supplements +suppleness +suppler +supples +supplest +suppletion +suppletions +suppletive +suppletory +suppliance +suppliant +suppliantly +suppliants +supplicant +supplicants +supplicate +supplicated +supplicates +supplicating +supplication +supplications +supplicatory +supplied +supplier +suppliers +supplies +suppling +supply +supplying +support +supportability +supportable +supportably +supported +supporter +supporters +supporting +supportive +supportively +supportiveness +supports +supposable +supposably +supposal +supposals +suppose +supposed +supposedly +supposes +supposing +supposition +suppositional +suppositionally +suppositions +suppositious +supposititious +supposititiously +supposititiousness +suppositive +suppositively +suppositives +suppositories +suppository +suppress +suppressant +suppressants +suppressed +suppresser +suppressers +suppresses +suppressibility +suppressible +suppressing +suppression +suppressions +suppressive +suppressiveness +suppressor +suppressors +suppurate +suppurated +suppurates +suppurating +suppuration +suppurations +suppurative +supra +supracellular +supragenic +supraglottal +supraliminal +supramaxilla +supramaxillae +supramaxillary +supramolecular +supranational +supranationalism +supranationalist +supranationalists +supranationality +supraoptic +supraorbital +suprarational +suprarenal +suprarenals +suprascapular +suprasegmental +supraventricular +supravital +supravitally +supremacies +supremacist +supremacists +supremacy +suprematism +suprematist +suprematists +supreme +supremely +supremeness +supremer +supremest +supremo +supremos +suprême +sups +suquamish +suquamishes +sura +surah +surahs +sural +suras +surat +surbase +surbased +surbases +surcease +surceased +surceases +surceasing +surcharge +surcharged +surcharges +surcharging +surcingle +surcingled +surcingles +surcingling +surcoat +surcoats +surculose +surd +surds +sure +surefire +surefooted +surefootedly +surefootedness +surely +sureness +surer +surest +sureties +surety +suretyship +surf +surface +surfaced +surfacer +surfacers +surfaces +surfacing +surfactant +surfactants +surfbird +surfbirds +surfboard +surfboarder +surfboarders +surfboarding +surfboardings +surfboards +surfboat +surfboats +surfcaster +surfcasters +surfcasting +surfcastings +surfed +surfeit +surfeited +surfeiter +surfeiters +surfeiting +surfeits +surfer +surfers +surficial +surfing +surfperch +surfperches +surfs +surfside +surfy +surge +surged +surgeon +surgeonfish +surgeonfishes +surgeons +surgeries +surgery +surges +surgical +surgically +surgicenter +surgicenters +surging +suribachi +suricate +suricates +surimi +surimis +surinam +suriname +surinamer +surinamers +surinamese +surjection +surjections +surjective +surlier +surliest +surlily +surliness +surly +surmise +surmised +surmises +surmising +surmount +surmountable +surmounted +surmounter +surmounters +surmounting +surmounts +surmullet +surmullets +surname +surnamed +surnames +surnaming +surpass +surpassable +surpassed +surpasses +surpassing +surpassingly +surplice +surplices +surplus +surplusage +surplusages +surpluses +surprint +surprinted +surprinting +surprints +surprisal +surprisals +surprise +surprised +surpriser +surprisers +surprises +surprising +surprisingly +surprize +surprized +surprizes +surprizing +surra +surreal +surrealism +surrealist +surrealistic +surrealistically +surrealists +surreally +surrebuttal +surrebuttals +surrebutter +surrebutters +surrejoinder +surrejoinders +surrender +surrendered +surrendering +surrenders +surreptitious +surreptitiously +surreptitiousness +surrey +surreys +surrogacies +surrogacy +surrogate +surrogated +surrogates +surrogating +surround +surrounded +surrounding +surroundings +surrounds +surroyal +surroyals +surtax +surtaxed +surtaxes +surtaxing +surtitle +surtitles +surtout +surtouts +surveil +surveillance +surveillant +surveillants +surveilled +surveilling +surveils +survey +surveyed +surveying +surveyor +surveyors +surveys +survivability +survivable +survival +survivalist +survivalists +survivals +survivance +survive +survived +survives +surviving +survivor +survivors +survivorship +susan +susanna +susceptance +susceptances +susceptibilities +susceptibility +susceptible +susceptibleness +susceptibly +susceptive +susceptiveness +susceptivity +sushi +susiana +suslik +susliks +suspect +suspected +suspecting +suspects +suspend +suspended +suspender +suspendered +suspenders +suspending +suspends +suspense +suspenseful +suspensefully +suspensefulness +suspenseless +suspenser +suspensers +suspension +suspensions +suspensive +suspensively +suspensiveness +suspensor +suspensories +suspensors +suspensory +suspicion +suspicional +suspicioned +suspicioning +suspicions +suspicious +suspiciously +suspiciousness +suspiration +suspirations +suspire +suspired +suspires +suspiring +susquehanna +susquehannas +susquehannock +susquehannocks +suss +sussed +susses +sussex +sussing +sustain +sustainability +sustainable +sustainably +sustained +sustainedly +sustainer +sustainers +sustaining +sustainment +sustainments +sustains +sustenance +sustentacular +sustentation +sustentations +sustentative +susu +susurrant +susurration +susurrations +susurrous +susurrus +susurruses +susus +sutler +sutlers +sutra +sutras +suttee +suttees +sutural +suturally +suture +sutured +sutures +suturing +suzerain +suzerains +suzerainties +suzerainty +suzette +suzettes +suède +svalbard +svedberg +svedbergs +svelte +sveltely +svelteness +svelter +sveltest +svengali +svengalis +sverdlovsk +sverdrup +sw +swab +swabbed +swabber +swabbers +swabbie +swabbies +swabbing +swabby +swabia +swabian +swabians +swabs +swaddle +swaddled +swaddles +swaddling +swag +swage +swaged +swages +swagged +swagger +swaggered +swaggerer +swaggerers +swaggering +swaggeringly +swaggers +swagging +swaging +swagman +swagmen +swags +swahili +swahilian +swahilis +swain +swainish +swainishness +swains +swainson +swale +swales +swallow +swallowable +swallowed +swallower +swallowers +swallowing +swallows +swallowtail +swallowtails +swallowwort +swallowworts +swam +swami +swamis +swamp +swamped +swamper +swampers +swampier +swampiest +swampiness +swamping +swampland +swamplands +swamps +swampy +swan +swank +swanked +swanker +swankest +swankier +swankiest +swankily +swankiness +swanking +swanks +swanky +swanlike +swanned +swanneries +swannery +swanning +swans +swansdown +swanskin +swanskins +swap +swappable +swapped +swapper +swappers +swapping +swaps +swaraj +swarajist +swarajists +sward +swarded +swards +swarf +swarfs +swarm +swarmed +swarmer +swarmers +swarming +swarms +swart +swarth +swarthier +swarthiest +swarthily +swarthiness +swarths +swarthy +swartness +swash +swashbuckle +swashbuckled +swashbuckler +swashbucklers +swashbuckles +swashbuckling +swashed +swasher +swashers +swashes +swashing +swastika +swastikas +swat +swatch +swatches +swath +swathe +swathed +swather +swathers +swathes +swathing +swaths +swats +swatted +swatter +swatters +swatting +sway +swayback +swaybacked +swaybacks +swayed +swayer +swayers +swaying +swayingly +sways +swazi +swaziland +swazis +swear +swearer +swearers +swearing +swears +swearword +swearwords +sweat +sweatband +sweatbands +sweatbox +sweatboxes +sweated +sweater +sweaterdress +sweaterdresses +sweaters +sweathouse +sweathouses +sweatier +sweatiest +sweatily +sweatiness +sweating +sweatpants +sweats +sweatshirt +sweatshirts +sweatshop +sweatshops +sweaty +swede +sweden +swedenborg +swedenborgian +swedenborgianism +swedenborgians +swedes +swedish +sweep +sweepback +sweepbacks +sweeper +sweepers +sweepier +sweepiest +sweeping +sweepingly +sweepingness +sweepings +sweeps +sweepstake +sweepstakes +sweepy +sweet +sweetbread +sweetbreads +sweetbriar +sweetbriars +sweetbrier +sweetbriers +sweeten +sweetened +sweetener +sweeteners +sweetening +sweetenings +sweetens +sweeter +sweetest +sweetheart +sweethearts +sweetie +sweeties +sweeting +sweetings +sweetish +sweetishly +sweetly +sweetmeat +sweetmeats +sweetness +sweets +sweetshop +sweetshops +sweetsop +sweetsops +swell +swelled +sweller +swellest +swellfish +swellfishes +swellhead +swellheaded +swellheadedness +swellheads +swelling +swellings +swells +swelter +sweltered +sweltering +swelteringly +swelters +sweltrier +sweltriest +sweltry +swept +sweptback +sweptwing +sweptwings +swerve +swerved +swerves +swerving +swidden +swiddens +swift +swifter +swiftest +swiftlet +swiftlets +swiftly +swiftness +swifts +swig +swigged +swigger +swiggers +swigging +swigs +swill +swilled +swiller +swillers +swilling +swills +swim +swimmable +swimmer +swimmeret +swimmerets +swimmers +swimmier +swimmiest +swimmily +swimming +swimmingly +swimmy +swims +swimsuit +swimsuits +swimwear +swindle +swindled +swindler +swindlers +swindles +swindling +swine +swineherd +swineherds +swinepox +swinepoxes +swing +swinge +swinged +swingeing +swinger +swingers +swinges +swingier +swingiest +swinging +swingingly +swingletree +swingletrees +swingman +swingmen +swings +swingy +swinish +swinishly +swinishness +swipe +swiped +swipes +swiping +swirl +swirled +swirlier +swirliest +swirling +swirlingly +swirls +swirly +swish +swished +swisher +swishers +swishes +swishier +swishiest +swishing +swishingly +swishy +swiss +swissair +switch +switchable +switchback +switchbacks +switchblade +switchblades +switchboard +switchboards +switched +switcher +switcheroo +switcheroos +switchers +switches +switchgrass +switching +switchman +switchmen +switchover +switchovers +switchyard +switchyards +switzer +switzerland +switzers +swivel +swiveled +swiveling +swivelled +swivelling +swivels +swivet +swivets +swizzle +swizzled +swizzler +swizzlers +swizzles +swizzling +swob +swobbed +swobbing +swobs +swollen +swoon +swooned +swooner +swooners +swooning +swooningly +swoons +swoop +swooped +swooper +swoopers +swooping +swoops +swoosh +swooshed +swooshes +swooshing +swop +swopped +swopping +swops +sword +swordbill +swordbills +swordfish +swordfishes +swordlike +swordplay +swordplayer +swordplayers +swords +swordsman +swordsmanship +swordsmen +swordtail +swordtails +swore +sworn +swum +swung +sybarite +sybarites +sybaritic +sybaritically +sybaritism +sycamine +sycamines +sycamore +sycamores +syce +sycee +sycees +syces +sycomore +sycomores +syconia +syconium +sycophancies +sycophancy +sycophant +sycophantic +sycophantical +sycophantically +sycophantish +sycophantishly +sycophantism +sycophantly +sycophants +sycosis +sydenham +sydney +syenite +syenites +syenitic +syli +sylis +syllabaries +syllabary +syllabi +syllabic +syllabically +syllabicate +syllabicated +syllabicates +syllabicating +syllabication +syllabications +syllabicity +syllabics +syllabification +syllabifications +syllabified +syllabifies +syllabify +syllabifying +syllabism +syllabisms +syllabize +syllabized +syllabizes +syllabizing +syllable +syllabled +syllables +syllabling +syllabub +syllabubs +syllabus +syllabuses +syllepses +syllepsis +sylleptic +syllogism +syllogisms +syllogist +syllogistic +syllogistical +syllogistically +syllogistics +syllogists +syllogization +syllogizations +syllogize +syllogized +syllogizer +syllogizers +syllogizes +syllogizing +sylph +sylphid +sylphids +sylphlike +sylphs +sylva +sylvan +sylvanite +sylvanites +sylvanus +sylvatic +sylviculture +sylvine +sylvines +sylvinite +sylvinites +sylvite +sylvites +symbiont +symbiontic +symbionts +symbioses +symbiosis +symbiote +symbiotes +symbiotic +symbiotical +symbiotically +symbol +symboled +symbolic +symbolical +symbolically +symbolicalness +symboling +symbolism +symbolist +symbolistic +symbolistically +symbolists +symbolization +symbolizations +symbolize +symbolized +symbolizer +symbolizers +symbolizes +symbolizing +symbology +symbols +symmetallism +symmetric +symmetrical +symmetrically +symmetricalness +symmetries +symmetrization +symmetrizations +symmetrize +symmetrized +symmetrizes +symmetrizing +symmetry +sympathectomies +sympathectomized +sympathectomy +sympathetic +sympathetically +sympathies +sympathin +sympathins +sympathize +sympathized +sympathizer +sympathizers +sympathizes +sympathizing +sympathizingly +sympatholytic +sympathomimetic +sympathomimetics +sympathy +sympatric +sympatrically +sympatries +sympatry +sympetalous +sympetaly +symphonic +symphonically +symphonies +symphonious +symphoniously +symphonist +symphonists +symphony +symphyseal +symphyses +symphysial +symphysis +sympodia +sympodial +sympodially +sympodium +symposia +symposiac +symposiacs +symposiarch +symposiarchs +symposiast +symposiasts +symposium +symposiums +symptom +symptomatic +symptomatically +symptomatize +symptomatized +symptomatizes +symptomatizing +symptomatologic +symptomatological +symptomatologically +symptomatology +symptomize +symptomized +symptomizes +symptomizing +symptomless +symptoms +synaeresis +synaesthesia +synaesthesias +synaesthesis +synagog +synagogal +synagogical +synagogs +synagogue +synagogues +synalepha +synalephas +synaloepha +synaloephas +synapse +synapsed +synapses +synapsid +synapsing +synapsis +synaptic +synaptically +synaptinemal +synaptonemal +synaptosomal +synaptosome +synaptosomes +synarthrodia +synarthrodiae +synarthrodial +synarthrodially +synarthroses +synarthrosis +sync +syncarp +syncarpous +syncarps +syncarpy +syncategorematic +syncategorematically +synced +synch +synched +synching +synchondroses +synchondrosis +synchro +synchrocyclotron +synchrocyclotrons +synchroflash +synchroflashes +synchromesh +synchromeshes +synchronal +synchroneity +synchronic +synchronical +synchronically +synchronicities +synchronicity +synchronies +synchronism +synchronistic +synchronistical +synchronistically +synchronization +synchronizations +synchronize +synchronized +synchronizer +synchronizers +synchronizes +synchronizing +synchronous +synchronously +synchronousness +synchrony +synchros +synchroscope +synchroscopes +synchrotron +synchrotrons +synchs +syncing +synclinal +syncline +synclines +syncopal +syncopate +syncopated +syncopates +syncopating +syncopation +syncopations +syncopative +syncopator +syncopators +syncope +syncopes +syncopic +syncretic +syncretism +syncretist +syncretistic +syncretists +syncretize +syncretized +syncretizes +syncretizing +syncs +syncytia +syncytial +syncytium +syndactyl +syndactylism +syndactylous +syndactyls +syndactyly +syndesmoses +syndesmosis +syndesmotic +syndetic +syndetically +syndic +syndical +syndicalism +syndicalist +syndicalistic +syndicalists +syndicate +syndicated +syndicates +syndicating +syndication +syndications +syndicator +syndicators +syndics +syndrome +syndromes +syndromic +syne +synecdoche +synecdoches +synecdochic +synecdochical +synecdochically +synecologic +synecological +synecology +synereses +syneresis +synergetic +synergic +synergically +synergid +synergids +synergies +synergism +synergist +synergistic +synergistically +synergists +synergy +synesis +synesthesia +synesthesias +synesthete +synesthetes +synesthetic +synfuel +synfuels +syngamic +syngamies +syngamous +syngamy +syngas +syngases +syngeneic +syngeneically +syngenesis +syngenetic +synizeses +synizesis +synkaryon +synkaryonic +synkaryons +synkineses +synkinesis +synkinetic +synod +synodal +synodic +synodical +synodically +synods +synonym +synonymic +synonymical +synonymies +synonymist +synonymists +synonymity +synonymize +synonymized +synonymizes +synonymizing +synonymous +synonymously +synonyms +synonymy +synopses +synopsis +synopsize +synopsized +synopsizes +synopsizing +synoptic +synoptical +synoptically +synostoses +synostosis +synostotic +synovia +synovial +synovias +synovitis +synovitises +synsepalous +syntactic +syntactical +syntactically +syntactics +syntagma +syntagmas +syntagmata +syntagmatic +syntax +syntaxes +syntenic +syntenies +synteny +synth +syntheses +synthesis +synthesist +synthesists +synthesize +synthesized +synthesizer +synthesizers +synthesizes +synthesizing +synthetase +synthetases +synthetic +synthetically +synthetics +synths +syntonic +syntrophies +syntrophism +syntrophisms +syntrophy +sypher +syphered +syphering +syphers +syphilis +syphilitic +syphilitics +syphiloid +syphon +syphoned +syphoning +syphons +syracusan +syracuse +syrette +syria +syriac +syrian +syrians +syringa +syringas +syringe +syringeal +syringed +syringes +syringing +syringomyelia +syringomyelias +syringomyelic +syrinx +syrinxes +syros +syrphid +syrphids +syrphus +syrup +syrups +syrupy +sysop +sysops +syssarcoses +syssarcosis +systaltic +system +systematic +systematical +systematically +systematicness +systematics +systematism +systematist +systematists +systematization +systematizations +systematize +systematized +systematizer +systematizers +systematizes +systematizing +systemic +systemically +systemization +systemizations +systemize +systemized +systemizer +systemizers +systemizes +systemizing +systemless +systems +systole +systoles +systolic +syzygial +syzygies +syzygy +szechuan +szechwan +sào +são +séance +séances +sémillon +sémillons +sérac +sèvres +síros +sûreté +süleyman +t +t'other +taal +tab +tabanid +tabanids +tabard +tabards +tabaret +tabarets +tabasco +tabbed +tabbies +tabbing +tabbouleh +tabby +tabernacle +tabernacled +tabernacles +tabernacling +tabernacular +tabes +tabescence +tabescent +tabetic +tabi +tabis +tabla +tablas +tablature +tablatures +table +tableau +tableaus +tableaux +tablecloth +tablecloths +tabled +tableful +tablefuls +tableland +tablelands +tablemat +tablemate +tablemates +tablemats +tables +tableside +tablesides +tablespoon +tablespoonful +tablespoonfuls +tablespoons +tablespoonsful +tablet +tableted +tableting +tabletop +tabletops +tablets +tableware +tabling +tabloid +tabloids +taboo +tabooed +tabooing +tabooli +taboos +tabor +taborer +taborers +taboret +taborets +tabors +tabouli +tabour +tabourer +tabourers +tabouret +tabourets +tabours +tabriz +tabs +tabu +tabued +tabuing +tabula +tabulae +tabular +tabularization +tabularizations +tabularize +tabularized +tabularizes +tabularizing +tabularly +tabulate +tabulated +tabulates +tabulating +tabulation +tabulations +tabulator +tabulators +tabun +tabuns +tabus +tac +tacamahac +tacamahacs +tacan +tacet +tach +tachina +tachinid +tachinids +tachism +tachisme +tachist +tachiste +tachistes +tachistoscope +tachistoscopes +tachistoscopic +tachistoscopically +tachists +tachograph +tachographs +tachometer +tachometers +tachometric +tachometry +tachyarrhythmia +tachyarrhythmias +tachycardia +tachycardiac +tachycardiacs +tachycardias +tachygraphy +tachylite +tachylites +tachylyte +tachylytes +tachylytic +tachymeter +tachymeters +tachymetry +tachyon +tachyonic +tachyons +tachyphylaxes +tachyphylaxis +tachypnea +tachypneas +tachysterol +tachysterols +tacit +tacitly +tacitness +taciturn +taciturnity +taciturnly +tacitus +tack +tackboard +tackboards +tacked +tacker +tackers +tackier +tackies +tackiest +tackified +tackifier +tackifiers +tackifies +tackify +tackifying +tackily +tackiness +tacking +tackle +tackled +tackler +tacklers +tackles +tackless +tackling +tacks +tacky +taco +tacoma +taconite +taconites +tacos +tact +tactful +tactfully +tactfulness +tactic +tactical +tactically +tactician +tacticians +tactics +tactile +tactilely +tactility +taction +tactions +tactless +tactlessly +tactlessness +tactoreceptor +tactoreceptors +tactual +tactually +tad +tadema +tadjik +tadjiks +tadpole +tadpoles +tads +tadzhik +tadzhiki +tadzhikistan +tadzhiks +tael +taels +taenia +taeniacide +taeniacides +taeniae +taeniafuge +taeniafuges +taenias +taeniasis +taeniasises +taffeta +taffetas +taffetized +taffia +taffias +taffies +taffrail +taffrails +taffy +tafia +tafias +tag +tagalog +tagalogs +tagalong +tagalongs +tagboard +tagboards +tagged +tagger +taggers +tagging +taggle +tagliatelle +tagline +taglines +tagma +tagmata +tagore +tagrag +tags +tagus +tahini +tahiti +tahitian +tahitians +tahoe +tahr +tahrs +tahseeldar +tahseeldars +tahsil +tahsildar +tahsildars +tai +taiga +taigas +tail +tailback +tailbacks +tailboard +tailboards +tailbone +tailbones +tailcoat +tailcoated +tailcoats +tailed +tailender +tailenders +tailer +tailers +tailfin +tailfins +tailgate +tailgated +tailgater +tailgaters +tailgates +tailgating +tailing +tailings +taille +tailles +tailless +taillight +taillights +taillike +tailor +tailorbird +tailorbirds +tailored +tailoring +tailors +tailpiece +tailpieces +tailpipe +tailpipes +tailplane +tailplanes +tailrace +tailraces +tails +tailskid +tailskids +tailslide +tailslides +tailspin +tailspins +tailstock +tailstocks +tailwater +tailwind +tailwinds +tain +taino +tainos +tains +taint +tainted +tainting +taintless +taintlessly +taintlessness +taints +taipan +taipans +taipeh +taipei +tais +taiwan +taiwanese +taj +tajik +tajiki +tajikistan +tajiks +tajs +taka +takable +takahe +takahes +takas +take +takeaway +takeaways +takedown +takedowns +taken +takeoff +takeoffs +takeout +takeouts +takeover +takeovers +taker +takers +takes +takin +taking +takings +takins +takkakaw +taklamakan +taklimakan +tala +talapoin +talapoins +talaria +talas +talaud +talaur +talbot +talc +talced +talcing +talcked +talcking +talcky +talcose +talcous +talcs +talcum +tale +talebearer +talebearers +talebearing +talent +talented +talentless +talentlessness +talents +taler +talers +tales +talesman +talesmen +taleteller +taletellers +taletelling +tali +talion +talions +taliped +talipeds +talipes +talipot +talipots +talisman +talismanic +talismanical +talismanically +talismans +talk +talkathon +talkathons +talkative +talkatively +talkativeness +talkback +talkbacks +talked +talker +talkers +talkfest +talkfests +talkie +talkier +talkies +talkiest +talkiness +talking +talks +talky +tall +tallage +tallaged +tallages +tallaging +tallahassee +tallboy +tallboys +taller +tallest +talleyrand +tallgrass +tallied +tallies +tallis +tallish +tallisim +tallith +tallithim +talliths +tallness +tallow +tallowed +tallowing +tallows +tallowy +tally +tallyho +tallyhoed +tallyhoing +tallyhos +tallying +tallyman +tallymen +talmi +talmud +talmudic +talmudical +talmudism +talmudist +talmudists +talon +taloned +talons +talus +taluses +tam +tamable +tamale +tamales +tamandua +tamanduas +tamarack +tamaracks +tamarao +tamaraos +tamarau +tamaraus +tamari +tamarillo +tamarillos +tamarin +tamarind +tamarinds +tamarins +tamarisk +tamarisks +tambac +tambacs +tambak +tambaks +tambala +tambalas +tambour +tamboura +tambouras +tamboured +tambourer +tambourers +tambourin +tambourine +tambourines +tambouring +tambourins +tambours +tambura +tamburas +tamburitza +tamburitzas +tamburlaine +tame +tameable +tamed +tameless +tamely +tameness +tamer +tamerlane +tamers +tames +tamest +tamil +tamils +taming +tammany +tammanyism +tammuz +tammy +tamora +tamoxifen +tamp +tampa +tamped +tamper +tampered +tamperer +tamperers +tampering +tamperproof +tampers +tamping +tampion +tampions +tampon +tamponed +tamponing +tampons +tamps +tams +tamworth +tan +tanager +tanagers +tanagrine +tanbark +tanbarks +tanbur +tanburs +tancred +tandem +tandems +tandoor +tandoori +tandoors +tang +tanganyika +tanganyikan +tanganyikans +tanged +tangelo +tangelos +tangence +tangency +tangent +tangental +tangential +tangentiality +tangentially +tangents +tangerine +tangerines +tangibility +tangible +tangibleness +tangibles +tangibly +tangier +tangiest +tanginess +tanging +tangle +tangled +tanglement +tangles +tangling +tangly +tango +tangoed +tangoing +tangolike +tangoreceptor +tangoreceptors +tangos +tangram +tangrams +tangs +tangy +tanimbar +tanist +tanistry +tanists +tank +tanka +tankage +tankages +tankard +tankards +tankas +tanked +tanker +tankers +tankful +tankfuls +tanking +tankless +tanklike +tanks +tannage +tannate +tannates +tanned +tanner +tanneries +tanners +tannery +tannest +tannhäuser +tannic +tanniferous +tannin +tanning +tannings +tannins +tannish +tanoak +tanoaks +tanoan +tanrec +tanrecs +tans +tansies +tansy +tantalate +tantalic +tantalite +tantalites +tantalization +tantalizations +tantalize +tantalized +tantalizer +tantalizers +tantalizes +tantalizing +tantalizingly +tantalum +tantalums +tantalus +tantaluses +tantamount +tantara +tantaras +tantivies +tantivy +tantra +tantras +tantric +tantrism +tantrist +tantrists +tantrum +tantrums +tanuki +tanyard +tanyards +tanzania +tanzanian +tanzanians +tanzanite +tanzanites +tao +taoiseach +taoism +taoist +taoistic +taoists +taormina +taos +tap +tapa +tapas +tape +tapeable +taped +tapeless +tapeline +tapelines +taper +tapered +taperer +taperers +tapering +taperingly +tapers +taperstick +tapersticks +tapes +tapestried +tapestries +tapestry +tapestrying +tapeta +tapetal +tapetum +tapeworm +tapeworms +taphole +tapholes +taphonomic +taphonomist +taphonomists +taphonomy +taping +tapings +tapioca +tapiocas +tapir +tapirs +tapis +tapped +tapper +tappers +tappet +tappets +tapping +tappings +taproom +taprooms +taproot +taproots +taps +tapster +tapsters +tapénade +tar +taradiddle +taradiddles +tarahumara +tarahumaras +taramasalata +taramasalatas +taramosalata +taramosalatas +tarantella +tarantellas +tarantism +tarantisms +taranto +tarantula +tarantulae +tarantulas +tarascan +tarascans +tarawa +tarboosh +tarbooshes +tarbush +tarbushes +tardenois +tardenoisean +tardier +tardiest +tardigrade +tardigrades +tardily +tardiness +tardive +tardo +tardy +tare +tared +tarentum +tares +targe +targes +target +targetable +targeted +targeting +targets +targum +targums +tarheel +tarheels +tariff +tariffed +tariffing +tariffs +taring +tarlatan +tarlatans +tarletan +tarletans +tarmac +tarmacadam +tarmacadams +tarmacked +tarmacking +tarmacs +tarn +tarnal +tarnally +tarnation +tarnations +tarnish +tarnishable +tarnished +tarnishes +tarnishing +tarns +taro +taroc +tarocs +tarok +taroks +taros +tarot +tarots +tarp +tarpaper +tarpapered +tarpapers +tarpaulin +tarpaulins +tarpon +tarpons +tarps +tarquin +tarquins +tarradiddle +tarradiddles +tarragon +tarragona +tarre +tarred +tarres +tarriance +tarriances +tarried +tarrier +tarriers +tarries +tarriest +tarring +tarry +tarrying +tars +tarsal +tarsi +tarsier +tarsiers +tarsometatarsal +tarsometatarsi +tarsometatarsus +tarsus +tart +tartan +tartans +tartar +tartare +tartarean +tartareous +tartarian +tartaric +tartarization +tartarizations +tartarize +tartarized +tartarizes +tartarizing +tartarous +tartars +tartarus +tartary +tarter +tartest +tartier +tartiest +tartily +tartine +tartines +tartiness +tartish +tartlet +tartlets +tartly +tartness +tartrate +tartrated +tartrates +tarts +tartufe +tartufes +tartuffe +tartuffery +tartuffes +tarty +tarvia +tarweed +tarweeds +tarzan +tarzans +tashkent +task +tasked +tasking +taskmaster +taskmasters +taskmistress +taskmistresses +tasks +tasman +tasmania +tasmanian +tasmanians +tass +tasse +tassel +tasseled +tasseling +tasselled +tasselling +tassels +tasses +tasset +tassets +tasso +tastable +taste +tasted +tasteful +tastefully +tastefulness +tasteless +tastelessly +tastelessness +tastemaker +tastemakers +taster +tasters +tastes +tastier +tastiest +tastily +tastiness +tasting +tastings +tasty +tat +tatami +tatamis +tatar +tatars +tatary +tater +taters +tats +tatted +tatter +tatterdemalion +tatterdemalions +tattered +tattering +tatters +tattersall +tattersalls +tattier +tattiest +tattiness +tatting +tattle +tattled +tattler +tattlers +tattles +tattletale +tattletales +tattling +tattlingly +tattoo +tattooed +tattooer +tattooers +tattooing +tattooist +tattooists +tattoos +tatty +tau +taught +taunt +taunted +taunter +taunters +taunting +tauntingly +taunts +taupe +taurean +taureans +taurine +taurines +taurocholic +taurus +tausug +taut +tautaug +tautaugs +tauten +tautened +tautening +tautens +tauter +tautest +tautly +tautness +tautog +tautogs +tautologic +tautological +tautologically +tautologies +tautologist +tautologists +tautologize +tautologized +tautologizes +tautologizing +tautologous +tautologously +tautology +tautomer +tautomeric +tautomerism +tautomerisms +tautomers +tautonym +tautonymic +tautonymous +tautonyms +tautonymy +tav +tavern +taverna +tavernas +taverner +taverners +taverns +taw +tawdrier +tawdriest +tawdrily +tawdriness +tawdry +tawed +tawer +tawers +tawing +tawnier +tawnies +tawniest +tawniness +tawny +taws +tawse +tax +taxa +taxability +taxable +taxableness +taxables +taxably +taxation +taxed +taxeme +taxemes +taxemic +taxer +taxers +taxes +taxi +taxicab +taxicabs +taxidermal +taxidermic +taxidermist +taxidermists +taxidermy +taxied +taxies +taxiing +taximan +taximen +taximeter +taximeters +taximetrics +taxing +taxingly +taxis +taxiway +taxiways +taxman +taxmen +taxon +taxonomic +taxonomical +taxonomically +taxonomies +taxonomist +taxonomists +taxonomy +taxons +taxpayer +taxpayers +taxpaying +taxus +taxying +taygeta +taylor +tayra +tayras +tayside +tazza +tazzas +tbilisi +tchaikovskian +tchaikovsky +tchaikovskyan +tchotchke +tchotchkes +te +tea +teabag +teabags +teaberry +teacake +teacakes +teacart +teacarts +teach +teachability +teachable +teachableness +teachably +teacher +teacherly +teachers +teaches +teaching +teachings +teacup +teacupful +teacupfuls +teacups +teahouse +teahouses +teak +teakettle +teakettles +teaks +teakwood +teal +tealike +teals +team +teamed +teaming +teammate +teammates +teams +teamster +teamsters +teamwork +teapot +teapots +teapoy +teapoys +tear +tearable +tearaway +tearaways +teardown +teardowns +teardrop +teardrops +teared +tearer +tearers +tearful +tearfully +tearfulness +teargas +teargases +teargassed +teargasses +teargassing +tearier +teariest +tearily +teariness +tearing +tearjerker +tearjerkers +tearless +tearlessly +tearoom +tearooms +tears +tearstain +tearstained +tearstains +teary +teas +tease +teased +teasel +teaseled +teaseling +teaselled +teaselling +teasels +teaser +teasers +teases +teashop +teashops +teasing +teasingly +teaspoon +teaspoonful +teaspoonfuls +teaspoons +teaspoonsful +teat +teated +teatime +teatimes +teats +tebet +tebeth +tech +teched +techie +techies +technetium +technetronic +technic +technical +technicalities +technicality +technicalization +technicalizations +technicalize +technicalized +technicalizes +technicalizing +technically +technicalness +technicals +technician +technicians +technicolor +technics +technique +techniques +technobabble +technocracies +technocracy +technocrat +technocratic +technocrats +technologic +technological +technologically +technologies +technologist +technologists +technologize +technologized +technologizes +technologizing +technology +technophile +technophiles +technophobe +technophobes +technophobia +technophobic +technostructure +technostructures +techy +tecta +tectal +tectonic +tectonically +tectonics +tectonism +tectonisms +tectrices +tectrix +tectum +ted +tedded +tedder +tedders +teddies +tedding +teddy +tedious +tediously +tediousness +tedium +teds +tee +teed +teeing +teem +teemed +teemer +teemers +teeming +teemingly +teemingness +teems +teen +teenage +teenaged +teenager +teenagers +teener +teeners +teenier +teeniest +teens +teensier +teensiest +teensy +teeny +teenybop +teenybopper +teenyboppers +teeoff +teeoffs +teepee +teepees +tees +teeter +teeterboard +teeterboards +teetered +teetering +teeters +teeth +teethe +teethed +teether +teethers +teethes +teething +teethridge +teethridges +teetotal +teetotaler +teetotalers +teetotalism +teetotalist +teetotalists +teetotaller +teetotallers +teetotally +teetotum +teetotums +teff +tefillin +teflon +teg +tegg +teggs +tegmen +tegmental +tegmentum +tegmentums +tegmina +tegs +tegu +tegua +teguas +tegucigalpa +tegular +tegularly +tegulated +tegument +tegumental +tegumentary +teguments +tegus +tehachapi +teheran +tehran +tehuantepec +tehuelche +tehuelchean +tehuelches +teiglach +teiid +teiids +tekkie +tekkies +tektite +tektites +tektitic +tektronix +tel +telaesthesia +telaesthesias +telamon +telamones +telangiectases +telangiectasia +telangiectasias +telangiectasis +telangiectatic +telecamera +telecameras +telecast +telecasted +telecaster +telecasters +telecasting +telecasts +telecom +telecommunicate +telecommunicated +telecommunicates +telecommunicating +telecommunication +telecommunications +telecommunicator +telecommunicators +telecommute +telecommuted +telecommuter +telecommuters +telecommutes +telecommuting +telecoms +teleconference +teleconferenced +teleconferences +teleconferencing +telecopier +telecourse +telecourses +teledrama +teledramas +teledu +teledus +telefacsimile +telefacsimiles +telefilm +telefilms +telegenic +telegenically +telegonic +telegonous +telegony +telegram +telegrammed +telegramming +telegrams +telegraph +telegraphed +telegrapher +telegraphers +telegraphese +telegraphic +telegraphical +telegraphically +telegraphing +telegraphist +telegraphists +telegraphs +telegraphy +telegu +telegus +telekinesis +telekinetic +telekinetically +telemachus +telemark +telemarked +telemarker +telemarkers +telemarketer +telemarketers +telemarketing +telemarking +telemarks +telemedicine +telemeter +telemetered +telemetering +telemeters +telemetric +telemetrical +telemetrically +telemetry +telencephalic +telencephalon +telencephalons +teleologic +teleological +teleologically +teleologies +teleologist +teleologists +teleology +teleonomic +teleonomy +teleost +teleostean +teleosteans +teleosts +telepath +telepathic +telepathically +telepathist +telepathists +telepaths +telepathy +telephone +telephoned +telephoner +telephoners +telephones +telephonic +telephonically +telephoning +telephonist +telephonists +telephony +telephoto +telephotograph +telephotographed +telephotographic +telephotographing +telephotographs +telephotography +telephotos +teleplay +teleplays +teleport +teleportation +teleported +teleporting +teleports +teleprinter +teleprinters +teleprocessing +teleprompter +teleprompters +teleran +telerans +telescope +telescoped +telescopes +telescopic +telescopically +telescoping +telescopist +telescopists +telescopium +telescopy +teleses +teleshopping +teleshoppings +telesis +telestereoscope +telestereoscopes +telesthesia +telesthesias +telesthetic +telesto +teletext +teletexts +teletheater +teletheaters +telethermoscope +telethermoscopes +telethon +telethons +teletranscription +teletranscriptions +teletype +teletyped +teletypes +teletypesetter +teletypewriter +teletypewriters +teletyping +teleutospore +teleutospores +teleutosporic +televangelism +televangelist +televangelists +teleview +televiewed +televiewer +televiewers +televiewing +televiews +televise +televised +televises +televising +television +televisions +televisor +televisors +televisual +telex +telexed +telexes +telexing +telford +telia +telial +telic +telically +teliospore +teliospores +teliosporic +telium +tell +tellable +teller +tellers +tellership +tellies +telling +tellingly +tells +telltale +telltales +tellurian +tellurians +telluric +telluride +tellurion +tellurions +tellurium +tellurometer +tellurometers +tellurous +telly +tellys +telnet +telocentric +telolecithal +telome +telomere +telomeres +telophase +telophases +telophasic +telos +telotaxis +telotaxises +telpher +telphered +telphering +telphers +telson +telsons +telugu +telugus +tem +temblor +temblors +temerarious +temerariously +temerariousness +temerity +temne +temnes +temp +tempeh +tempehs +temper +tempera +temperability +temperable +temperament +temperamental +temperamentally +temperaments +temperance +temperas +temperate +temperately +temperateness +temperature +temperatures +tempered +temperedly +temperedness +temperer +temperers +tempering +tempers +tempest +tempested +tempesting +tempests +tempestuous +tempestuously +tempestuousness +tempi +templar +templars +template +templates +temple +templed +temples +templet +templets +tempo +temporal +temporalities +temporality +temporalize +temporalized +temporalizes +temporalizing +temporally +temporaries +temporarily +temporariness +temporary +tempore +temporization +temporizations +temporize +temporized +temporizer +temporizers +temporizes +temporizing +temporomandibular +tempos +temps +tempt +temptable +temptation +temptations +tempted +tempter +tempters +tempting +temptingly +temptingness +temptress +temptresses +tempts +tempura +tempuras +ten +tenability +tenable +tenableness +tenably +tenace +tenaces +tenacious +tenaciously +tenaciousness +tenacity +tenacula +tenaculum +tenancies +tenancy +tenant +tenantable +tenanted +tenanting +tenantless +tenantry +tenants +tench +tenches +tend +tendance +tended +tendencies +tendencious +tendency +tendentious +tendentiously +tendentiousness +tender +tendered +tenderer +tenderers +tenderest +tenderfeet +tenderfoot +tenderfoots +tenderhearted +tenderheartedly +tenderheartedness +tendering +tenderization +tenderizations +tenderize +tenderized +tenderizer +tenderizers +tenderizes +tenderizing +tenderloin +tenderloins +tenderly +tenderness +tendernesses +tenderometer +tenderometers +tenders +tending +tendinitis +tendinous +tendon +tendonitis +tendons +tendresse +tendril +tendriled +tendrilled +tendrilous +tendrils +tends +tenebrae +tenebrific +tenebrionid +tenebrionids +tenebrious +tenebrism +tenebrist +tenebrists +tenebrosity +tenebrous +tenebrously +tenement +tenemental +tenementary +tenements +tenens +tenerife +tenesmus +tenesmuses +tenet +tenets +tenfold +tenia +teniacide +teniacides +teniae +teniafuge +teniafuges +tenias +teniasis +teniasises +tenner +tenners +tennessean +tennesseans +tennessee +tenniel +tennies +tennis +tennist +tennists +tennyson +tennysonian +tenochtitlán +tenon +tenoned +tenoning +tenonitis +tenons +tenor +tenorist +tenorists +tenorrhaphies +tenorrhaphy +tenors +tenos +tenosynovitis +tenosynovitises +tenotomies +tenotomy +tenpenny +tenpin +tenpins +tenpounder +tenpounders +tenrec +tenrecs +tens +tense +tensed +tensely +tenseness +tenser +tenses +tensest +tensile +tensility +tensimeter +tensimeters +tensing +tensiometer +tensiometers +tensiometric +tensiometry +tension +tensional +tensioned +tensioner +tensioners +tensioning +tensionless +tensions +tensities +tensity +tensive +tensor +tensorial +tensors +tent +tentacle +tentacled +tentacles +tentacular +tentage +tentages +tentative +tentatively +tentativeness +tented +tenter +tentered +tenterhook +tenterhooks +tentering +tenters +tenth +tenthly +tenths +tenting +tentless +tentlike +tentmaker +tentmakers +tents +tenues +tenuis +tenuity +tenuous +tenuously +tenuousness +tenurable +tenure +tenured +tenures +tenurial +tenurially +tenuto +teocalli +teocallis +teosinte +teosintes +teotihuacán +tepa +tepal +tepals +tepary +tepas +tepee +tepees +tephra +tephras +tepid +tepidity +tepidly +tepidness +tequila +tequilas +teraampere +teraamperes +terabecquerel +terabecquerels +terabit +terabits +terabyte +terabytes +teracandela +teracandelas +teracoulomb +teracoulombs +terafarad +terafarads +teraflop +teraflops +teragram +teragrams +terahenries +terahenry +terahenrys +terahertz +terai +terais +terajoule +terajoules +terakelvin +terakelvins +teralumen +teralumens +teralux +terameter +terameters +teramole +teramoles +teranewton +teranewtons +teraohm +teraohms +terapascal +terapascals +teraph +teraphim +teraradian +teraradians +terasecond +teraseconds +terasiemens +terasievert +terasieverts +terasteradian +terasteradians +teratesla +terateslas +teratism +teratisms +teratocarcinoma +teratocarcinomas +teratocarcinomata +teratogen +teratogenesis +teratogenic +teratogenicity +teratogens +teratoid +teratologic +teratological +teratologist +teratologists +teratology +teratoma +teratomas +teratomata +teratomatous +teravolt +teravolts +terawatt +terawatts +teraweber +terawebers +terbium +terce +terceira +tercel +tercels +tercentenaries +tercentenary +tercentennial +tercentennials +tercet +tercets +terebene +terebenes +terebic +terebinth +terebinthic +terebinthine +terebinths +teredines +teredo +teredos +terence +terephthalate +terephthalates +terephthalic +teresa +terete +tereus +terga +tergal +tergite +tergites +tergiversate +tergiversated +tergiversates +tergiversating +tergiversation +tergiversations +tergiversator +tergiversators +tergum +teriyaki +teriyakis +term +termagant +termagants +termed +termer +termers +terminability +terminable +terminableness +terminably +terminal +terminally +terminals +terminate +terminated +terminates +terminating +termination +terminational +terminations +terminative +terminatively +terminator +terminators +terminer +terming +termini +terminological +terminologically +terminologies +terminologist +terminologists +terminology +terminus +terminuses +termitaria +termitaries +termitarium +termitary +termite +termites +termitic +termless +terms +tern +ternaries +ternary +ternate +ternately +terne +terneplate +terneplates +ternes +terns +terpene +terpeneless +terpenes +terpenic +terpenoid +terpenoids +terpin +terpineol +terpineols +terpolymer +terpolymers +terpsichore +terpsichorean +terpsichoreans +terpsichores +terr +terra +terrace +terraced +terraces +terracing +terracotta +terrae +terrain +terrains +terramycin +terran +terrane +terranes +terrapin +terrapins +terraqueous +terraria +terrarium +terrariums +terrazzo +terrene +terrenes +terreplein +terrepleins +terrestrial +terrestrially +terrestrialness +terrestrials +terret +terrets +terrible +terribleness +terribles +terribly +terricolous +terrier +terriers +terries +terrific +terrifically +terrified +terrifier +terrifiers +terrifies +terrify +terrifying +terrifyingly +terrigenous +terrine +terrines +territorial +territorialism +territorialist +territorialists +territorialities +territoriality +territorialization +territorializations +territorialize +territorialized +territorializes +territorializing +territorially +territorials +territories +territory +terror +terrorism +terrorist +terroristic +terrorists +terrorization +terrorizations +terrorize +terrorized +terrorizer +terrorizers +terrorizes +terrorizing +terrorless +terrors +terrs +terry +terse +tersely +terseness +terser +tersest +tertial +tertials +tertian +tertians +tertiaries +tertiary +tertium +tertullian +tervalent +tervuren +terza +terze +tesla +teslas +tessellate +tessellated +tessellates +tessellating +tessellation +tessellations +tessera +tesseract +tesseracts +tesserae +tessitura +tessituras +test +testa +testability +testable +testacean +testaceans +testaceous +testacy +testae +testament +testamentary +testaments +testate +testator +testators +testatrices +testatrix +testatrixes +testcross +testcrossed +testcrosses +testcrossing +tested +testee +testees +tester +testers +testes +testicle +testicles +testicular +testiculate +testier +testiest +testificandum +testification +testifications +testified +testifier +testifiers +testifies +testify +testifying +testily +testimonial +testimonials +testimonies +testimony +testiness +testing +testis +teston +testons +testoon +testoons +testosterone +tests +testudinal +testudinate +testudinates +testudo +testudos +testy +tetanal +tetanic +tetanically +tetanies +tetanization +tetanizations +tetanize +tetanized +tetanizes +tetanizing +tetanus +tetany +tetartohedral +tetched +tetchier +tetchiest +tetchily +tetchiness +tetchy +teth +tether +tetherball +tetherballs +tethered +tethering +tethers +tethys +teton +tetons +tetra +tetrabasic +tetrabasicity +tetrabranchiate +tetrabranchiates +tetracaine +tetracaines +tetrachloride +tetrachlorides +tetrachloroethylene +tetrachord +tetrachordal +tetrachords +tetracid +tetracids +tetracyclic +tetracycline +tetracyclines +tetrad +tetradactylous +tetradic +tetradrachm +tetradrachms +tetrads +tetradymite +tetradymites +tetradynamous +tetraethyl +tetraethyllead +tetraethylleads +tetrafluoride +tetrafluorides +tetragon +tetragonal +tetragonally +tetragons +tetragrammaton +tetragynous +tetrahedra +tetrahedral +tetrahedrally +tetrahedrite +tetrahedrites +tetrahedron +tetrahedrons +tetrahydrocannabinol +tetrahydrocannabinols +tetrahydrofuran +tetrahydrofurans +tetrahydroxy +tetrahymena +tetrahymenas +tetralogies +tetralogy +tetramer +tetrameric +tetramerism +tetramerous +tetramers +tetrameter +tetrameters +tetramethyllead +tetramethylleads +tetrandrous +tetraplegic +tetraploid +tetraploids +tetraploidy +tetrapod +tetrapodous +tetrapods +tetrapterous +tetrapyrrole +tetrapyrroles +tetrarch +tetrarchate +tetrarchates +tetrarchic +tetrarchical +tetrarchies +tetrarchs +tetrarchy +tetras +tetrasporangia +tetrasporangium +tetraspore +tetraspores +tetrasporic +tetrastyle +tetrasyllabic +tetratomic +tetravalent +tetrazolium +tetrazoliums +tetrazzini +tetrode +tetrodes +tetrodotoxin +tetrodotoxins +tetroxide +tetroxides +tetryl +tetryls +tetter +tetterbush +tetterbushes +tetters +teuton +teutonic +teutonically +teutonicism +teutonicisms +teutonism +teutonisms +teutonist +teutonists +teutonization +teutonizations +teutonize +teutonized +teutonizes +teutonizing +teutons +tevet +tewa +tewas +tex +texaco +texan +texans +texas +texel +text +textbook +textbookish +textbooks +textile +textiles +texts +textual +textualism +textualisms +textualist +textualists +textually +textuaries +textuary +textural +texturally +texture +textured +textureless +textures +texturing +texturize +texturized +texturizer +texturizers +texturizes +texturizing +thackeray +thai +thailand +thais +thalamencephalic +thalamencephalon +thalamencephalons +thalami +thalamic +thalamically +thalamus +thalassemia +thalassemias +thalassemic +thalassic +thalassocracies +thalassocracy +thalassocrat +thalassocrats +thaler +thalers +thales +thalesian +thalia +thalidomide +thalli +thallic +thallium +thalloid +thalloidal +thallophyte +thallophytes +thallophytic +thallous +thallus +thalluses +thammuz +than +thanage +thanages +thanatological +thanatologist +thanatologists +thanatology +thanatopsis +thanatos +thanatotic +thane +thanes +thaneship +thanet +thank +thanked +thanker +thankers +thankful +thankfully +thankfulness +thanking +thankless +thanklessly +thanklessness +thanks +thanksgiving +thanksgivings +thankworthier +thankworthiest +thankworthy +that +that'd +that'll +that's +thataway +thatch +thatched +thatcher +thatchers +thatches +thatching +thatchy +thaumatologies +thaumatology +thaumaturge +thaumaturges +thaumaturgic +thaumaturgical +thaumaturgist +thaumaturgists +thaumaturgy +thaw +thawed +thawing +thaws +the +theanthropic +theanthropical +theanthropism +theanthropisms +theanthropist +theanthropists +thearchies +thearchy +theater +theatergoer +theatergoers +theatergoing +theaters +theatine +theatines +theatre +theatres +theatric +theatrical +theatricalism +theatricalisms +theatricality +theatricalization +theatricalizations +theatricalize +theatricalized +theatricalizer +theatricalizers +theatricalizes +theatricalizing +theatrically +theatricalness +theatricals +theatrics +thebaine +thebaines +theban +thebans +thebe +thebes +theca +thecae +thecal +thecate +thecodont +thecodonts +thee +theelin +theelins +theelol +theelols +theft +thefts +thegn +thegnly +their +theirs +theirselves +theism +theist +theistic +theistical +theistically +theists +them +thematic +thematically +theme +themed +themeless +themes +themistocles +themselves +then +thenar +thenars +thence +thenceforth +thenceforward +thenceforwards +theobald +theobromine +theobromines +theocentric +theocentricity +theocentrism +theocracies +theocracy +theocrat +theocratic +theocratical +theocratically +theocrats +theocritus +theodicies +theodicy +theodolite +theodolites +theodolitic +theodora +theodore +theodoric +theodosius +theogonic +theogonies +theogony +theolog +theologian +theologians +theologic +theological +theologically +theologies +theologize +theologized +theologizer +theologizers +theologizes +theologizing +theologs +theologue +theologues +theology +theomachies +theomachy +theomorphic +theomorphism +theomorphisms +theonomous +theonomy +theophanic +theophanies +theophany +theophrastus +theophylline +theophyllines +theorbo +theorbos +theorem +theorematic +theorems +theoretic +theoretical +theoretically +theoretician +theoreticians +theoretics +theories +theorist +theorists +theorization +theorizations +theorize +theorized +theorizer +theorizers +theorizes +theorizing +theory +theosophic +theosophical +theosophically +theosophies +theosophist +theosophists +theosophy +theotokos +therapeusis +therapeutic +therapeutical +therapeutically +therapeutics +therapeutist +therapeutists +therapies +therapist +therapists +therapsid +therapsids +therapy +theravada +there +there'd +there'll +there's +thereabout +thereabouts +thereafter +thereagainst +thereat +thereby +therefor +therefore +therefrom +therein +thereinafter +thereinto +theremin +theremins +thereof +thereon +theresa +thereto +theretofore +thereunder +thereunto +thereupon +therewith +therewithal +theriac +theriaca +theriacal +theriacs +theriomorphic +theriomorphous +therm +thermal +thermalization +thermalizations +thermalize +thermalized +thermalizes +thermalizing +thermally +thermals +thermanesthesia +thermanesthesias +thermesthesia +thermesthesias +thermic +thermically +thermidor +thermion +thermionic +thermionics +thermions +thermistor +thermistors +thermit +thermite +thermocauteries +thermocautery +thermochemical +thermochemist +thermochemistry +thermochemists +thermocline +thermoclines +thermocoagulation +thermocoagulations +thermocouple +thermocouples +thermoduric +thermodynamic +thermodynamical +thermodynamically +thermodynamicist +thermodynamicists +thermodynamics +thermoelectric +thermoelectrical +thermoelectrically +thermoelectricity +thermoelectron +thermoelectrons +thermoelement +thermoelements +thermoform +thermoformable +thermoformed +thermoforming +thermoforms +thermogenesis +thermogenetic +thermogenic +thermogram +thermograms +thermograph +thermographic +thermographically +thermographies +thermographs +thermography +thermohaline +thermojunction +thermojunctions +thermolabile +thermolability +thermoluminescence +thermoluminescences +thermoluminescent +thermolyses +thermolysis +thermolytic +thermomagnetic +thermometer +thermometers +thermometric +thermometrically +thermometry +thermomotor +thermomotors +thermonuclear +thermoperiodicities +thermoperiodicity +thermoperiodism +thermoperiodisms +thermophile +thermophiles +thermophilic +thermophilous +thermopile +thermopiles +thermoplastic +thermoplasticity +thermoplastics +thermoreceptor +thermoreceptors +thermoregulate +thermoregulated +thermoregulates +thermoregulating +thermoregulation +thermoregulations +thermoregulator +thermoregulators +thermoregulatory +thermoremanence +thermoremanent +thermos +thermoscope +thermoscopes +thermoses +thermoset +thermosets +thermosetting +thermosphere +thermospheric +thermostabile +thermostability +thermostable +thermostat +thermostatic +thermostatically +thermostats +thermotactic +thermotaxes +thermotaxic +thermotaxis +thermotherapies +thermotherapy +thermotropic +thermotropism +therms +theropod +theropodan +theropodans +theropods +thersites +thesaural +thesauri +thesaurus +thesauruses +these +these'd +these'll +theses +theseus +thesis +thespian +thespians +thespis +thessalian +thessalians +thessalonian +thessalonians +thessalonica +thessaloniki +thessaloníki +thessaly +theta +thetas +thetic +thetical +thetically +thetis +theurgic +theurgical +theurgically +theurgies +theurgist +theurgists +theurgy +thew +thews +thewy +they +they'd +they'll +they're +they've +thiabendazole +thiabendazoles +thiamin +thiaminase +thiaminases +thiamine +thiamines +thiamins +thiazide +thiazides +thiazine +thiazines +thiazole +thiazoles +thick +thicken +thickened +thickener +thickeners +thickening +thickenings +thickens +thicker +thickest +thicket +thicketed +thickets +thickety +thickhead +thickheaded +thickheads +thickish +thickly +thickness +thicknesses +thickset +thickskulled +thief +thieve +thieved +thieveries +thievery +thieves +thieving +thievish +thievishly +thievishness +thigh +thighbone +thighbones +thighed +thighs +thigmotactic +thigmotactically +thigmotaxis +thigmotaxises +thigmotropic +thigmotropism +thigmotropisms +thill +thills +thimble +thimbleberries +thimbleberry +thimbleful +thimblefuls +thimblerig +thimblerigged +thimblerigger +thimbleriggers +thimblerigging +thimblerigs +thimbles +thimbleweed +thimbleweeds +thimbu +thimerosal +thimerosals +thimphu +thin +thine +thing +thingamabob +thingamabobs +thingamajig +thingamajigs +thingness +things +thingumabob +thingumabobs +thingumajig +thingumajigs +thingumbob +thingumbobs +thingummies +thingummy +think +thinkable +thinkableness +thinkably +thinker +thinkers +thinking +thinkingly +thinkingness +thinkings +thinks +thinly +thinned +thinner +thinners +thinness +thinnest +thinning +thinnish +thins +thio +thiocarbamide +thiocarbamides +thiocyanate +thiocyanates +thiocyanic +thiokol +thiol +thiolic +thiols +thionic +thionyl +thionyls +thiopental +thiophene +thiophenes +thioridazine +thioridazines +thiosulfate +thiosulfates +thiosulfuric +thiotepa +thiotepas +thiouracil +thiouracils +thiourea +thioureas +thiram +thirams +third +thirdhand +thirdly +thirds +thirst +thirsted +thirster +thirsters +thirstier +thirstiest +thirstily +thirstiness +thirsting +thirsts +thirsty +thirteen +thirteenfold +thirteens +thirteenth +thirteenths +thirties +thirtieth +thirtieths +thirty +thirtyfold +thirtyish +this +this'd +this'll +thisaway +thisbe +thistle +thistledown +thistles +thistly +thither +thitherto +thitherward +thitherwards +thixotropic +thixotropy +tho +thohoyandou +thole +tholeiite +tholeiitic +tholepin +tholepins +tholes +thomas +thomism +thomist +thomistic +thomists +thompson +thomson +thong +thonged +thongs +thor +thoraces +thoracic +thoracically +thoracolumbar +thoracoplasties +thoracoplasty +thoracotomies +thoracotomy +thorax +thoraxes +thorazine +thoreau +thoreauvian +thoria +thorianite +thorias +thoric +thorite +thorites +thorium +thorn +thornback +thornbacks +thornbush +thornbushes +thorndike +thorned +thornier +thorniest +thornily +thorniness +thornless +thornlike +thorns +thorny +thoron +thorons +thorough +thoroughbass +thoroughbasses +thoroughbrace +thoroughbraces +thoroughbred +thoroughbreds +thoroughfare +thoroughfares +thoroughgoing +thoroughly +thoroughness +thoroughpaced +thoroughpin +thoroughpins +thoroughwort +thoroughworts +thorp +thorps +those +those'd +those'll +thou +though +thought +thoughtful +thoughtfully +thoughtfulness +thoughtless +thoughtlessly +thoughtlessness +thoughts +thoughtway +thoughtways +thousand +thousandfold +thousands +thousandth +thousandths +thrace +thracian +thracians +thraldom +thrall +thralldom +thralled +thralling +thralls +thrash +thrashed +thrasher +thrashers +thrashes +thrashing +thrashings +thrasonical +thrasonically +thread +threadbare +threadbareness +threaded +threader +threaders +threadfin +threadfins +threadier +threadiest +threadiness +threading +threadless +threadlike +threads +threadworm +threadworms +thready +threat +threated +threaten +threatened +threatener +threateners +threatening +threateningly +threatens +threating +threats +three +threefold +threepence +threepences +threepenny +threes +threescore +threesome +threesomes +thremmatology +threnode +threnodes +threnodial +threnodic +threnodies +threnodist +threnodists +threnody +threonine +threonines +thresh +threshed +thresher +threshers +threshes +threshing +threshold +thresholds +threw +thrice +thrift +thriftier +thriftiest +thriftily +thriftiness +thriftless +thriftlessly +thriftlessness +thrifts +thrifty +thrill +thrilled +thriller +thrillers +thrilling +thrillingly +thrills +thrips +thrive +thrived +thriven +thriver +thrivers +thrives +thriving +thrivingly +throat +throated +throatier +throatiest +throatily +throatiness +throating +throatlatch +throatlatches +throats +throaty +throb +throbbed +throbber +throbbers +throbbing +throbbingly +throbs +throe +throes +thrombi +thrombin +thrombocyte +thrombocytes +thrombocytic +thrombocytopenia +thrombocytopenias +thrombocytopenic +thromboembolic +thromboembolism +thromboembolisms +thrombokinase +thrombokinases +thrombolyses +thrombolysis +thrombolytic +thrombophlebitis +thrombophlebitises +thromboplastic +thromboplastically +thromboplastin +thromboplastins +thromboses +thrombosis +thrombosthenin +thrombosthenins +thrombotic +thromboxane +thromboxanes +thrombus +throne +throned +thrones +throng +thronged +thronging +throngs +throning +throstle +throstles +throttle +throttleable +throttled +throttlehold +throttleholds +throttler +throttlers +throttles +throttling +through +throughly +throughout +throughput +throughway +throughways +throve +throw +throwaway +throwaways +throwback +throwbacks +thrower +throwers +throwing +thrown +throws +throwster +throwsters +thru +thrum +thrummed +thrumming +thrums +thrush +thrushes +thrust +thruster +thrusters +thrustful +thrusting +thrustor +thrustors +thrusts +thruway +thruways +thucydides +thud +thudded +thudding +thuds +thug +thuggery +thuggish +thugs +thuja +thujas +thule +thulium +thumb +thumbed +thumbhole +thumbholes +thumbing +thumbnail +thumbnails +thumbnut +thumbnuts +thumbprint +thumbprints +thumbs +thumbscrew +thumbscrews +thumbtack +thumbtacked +thumbtacking +thumbtacks +thumbwheel +thumbwheels +thummim +thump +thumped +thumper +thumpers +thumping +thumpingly +thumps +thunder +thunderbird +thunderbirds +thunderbolt +thunderbolts +thunderclap +thunderclaps +thundercloud +thunderclouds +thundered +thunderer +thunderers +thunderhead +thunderheads +thundering +thunderingly +thunderous +thunderously +thunders +thundershower +thundershowers +thunderstone +thunderstones +thunderstorm +thunderstorms +thunderstricken +thunderstrike +thunderstrikes +thunderstriking +thunderstroke +thunderstrokes +thunderstruck +thunk +thunked +thunking +thunks +thurber +thurible +thuribles +thurifer +thurifers +thuringer +thuringia +thuringian +thuringians +thurl +thurls +thursday +thursdays +thus +thusly +thwack +thwacked +thwacking +thwacks +thwart +thwarted +thwarter +thwarters +thwarting +thwartly +thwarts +thwartwise +thy +thyestean +thyestes +thylacine +thylacines +thylakoid +thylakoids +thyme +thymectomies +thymectomize +thymectomized +thymectomizes +thymectomizing +thymectomy +thymey +thymic +thymidine +thymidines +thymine +thymines +thymocyte +thymocytes +thymol +thymols +thymoma +thymomas +thymosin +thymosins +thymus +thymuses +thymy +thyratron +thyratrons +thyristor +thyristors +thyroactive +thyrocalcitonin +thyrocalcitonins +thyroglobulin +thyroglobulins +thyroid +thyroidal +thyroidectomies +thyroidectomize +thyroidectomized +thyroidectomizes +thyroidectomizing +thyroidectomy +thyroiditis +thyroiditises +thyroids +thyrotoxicosis +thyrotrophic +thyrotrophin +thyrotrophins +thyrotropic +thyrotropin +thyrotropins +thyroxin +thyroxine +thyroxines +thyroxins +thyrse +thyrses +thyrsi +thyrsoid +thyrsoidal +thyrsus +thysanuran +thysanurans +thyself +thásos +théatre +thíra +ti +tiahuanaco +tiara +tiaras +tiber +tiberian +tiberius +tibet +tibetan +tibetans +tibeto +tibia +tibiae +tibial +tibias +tibiofibula +tibiofibular +tibiofibulas +tibiotarsus +tibiotarsuses +tic +tical +ticals +ticced +ticcing +tick +tickbird +tickbirds +ticked +ticker +tickers +ticket +ticketed +ticketing +ticketless +tickets +ticking +tickle +tickled +tickler +ticklers +tickles +tickling +ticklish +ticklishly +ticklishness +ticks +tickseed +tickseeds +ticktack +ticktacks +ticktacktoe +ticktacktoes +ticktock +ticktocks +ticky +ticqueur +ticqueurs +tics +tictac +tidal +tidally +tidbit +tidbits +tiddledywinks +tiddler +tiddlers +tiddly +tiddlywinks +tide +tided +tideland +tidelands +tideless +tidemark +tidemarks +tiderip +tiderips +tides +tidewaiter +tidewaiters +tidewater +tidewaters +tideway +tideways +tidied +tidier +tidies +tidiest +tidily +tidiness +tiding +tidings +tidy +tidying +tidytips +tie +tieback +tiebacks +tiebreaker +tiebreakers +tiebreaking +tied +tieing +tieless +tiemannite +tiemannites +tientsin +tiepin +tiepins +tiepolo +tier +tierce +tiercel +tiercels +tierces +tiered +tiering +tierra +tiers +ties +tietze +tiff +tiffanies +tiffany +tiffed +tiffin +tiffing +tiffins +tiffs +tiger +tigereye +tigereyes +tigerish +tigerishly +tigerishness +tigerlike +tigers +tight +tighten +tightened +tightener +tighteners +tightening +tightens +tighter +tightest +tightfisted +tightfistedness +tightlipped +tightlippedness +tightly +tightness +tightrope +tightropes +tights +tightwad +tightwads +tightwire +tightwires +tiglic +tiglon +tiglons +tigon +tigons +tigre +tigress +tigresses +tigrinya +tigris +tigré +tike +tikes +tiki +tikis +til +tilapia +tilapias +tilburies +tilbury +tilde +tildes +tile +tiled +tilefish +tilefishes +tiler +tilers +tiles +tiling +till +tillable +tillage +tillamook +tillandsia +tillandsias +tilled +tiller +tillered +tillering +tillerman +tillermen +tillers +tilling +tills +tils +tilsit +tilsiter +tilt +tiltable +tilted +tilter +tilters +tilth +tilting +tiltmeter +tiltmeters +tilts +tiltyard +tiltyards +tim +timbal +timbale +timbales +timbals +timber +timberdoodle +timberdoodles +timbered +timberhead +timberheads +timbering +timberings +timberland +timberlands +timberline +timberlines +timberman +timbermen +timbers +timberwork +timberworks +timbral +timbre +timbrel +timbrelled +timbrels +timbres +timbuktu +time +timecard +timecards +timed +timekeeper +timekeepers +timekeeping +timeless +timelessly +timelessness +timelier +timeliest +timeline +timelines +timeliness +timely +timeous +timeously +timeout +timeouts +timepiece +timepieces +timepleaser +timepleasers +timer +timers +times +timesaver +timesavers +timesaving +timescale +timescales +timeserver +timeservers +timeserving +timeshare +timeshared +timeshares +timesharing +timetable +timetables +timework +timeworker +timeworkers +timeworn +timid +timider +timidest +timidity +timidly +timidness +timing +timings +timocracies +timocracy +timocratic +timocratical +timolol +timolols +timon +timor +timorese +timorous +timorously +timorousness +timothies +timothy +timpani +timpanist +timpanists +timpanogos +timpanum +timucua +timucuas +tin +tinamou +tinamous +tinbergen +tincal +tincals +tinct +tinctorial +tinctorially +tincts +tincture +tinctured +tinctures +tincturing +tinder +tinderbox +tinderboxes +tine +tinea +tineal +tineas +tined +tines +tinfoil +tinful +tinfuls +ting +tinge +tinged +tingeing +tinges +tinging +tingle +tingled +tingler +tinglers +tingles +tingling +tinglingly +tingly +tings +tinhorn +tinhorns +tinian +tinier +tiniest +tinily +tininess +tinker +tinkered +tinkerer +tinkerers +tinkering +tinkers +tinkertoy +tinkle +tinkled +tinkles +tinkling +tinkly +tinned +tinner +tinners +tinnier +tinniest +tinnily +tinniness +tinning +tinnitus +tinnituses +tinny +tinplate +tinplates +tins +tinsel +tinseled +tinseling +tinselled +tinselling +tinselly +tinsels +tinsmith +tinsmithing +tinsmiths +tinstone +tinstones +tint +tinted +tinter +tinters +tinting +tintinnabula +tintinnabular +tintinnabulary +tintinnabulation +tintinnabulations +tintinnabulous +tintinnabulum +tintless +tintoretto +tints +tintype +tintypes +tinware +tinwork +tinworks +tiny +tip +tipcart +tipcarts +tipcat +tipi +tipis +tippecanoe +tipped +tipper +tippers +tippet +tippets +tippier +tippiest +tipping +tipple +tippled +tippler +tipplers +tipples +tippling +tippy +tips +tipsier +tipsiest +tipsily +tipsiness +tipstaff +tipstaffs +tipstaves +tipster +tipsters +tipsy +tiptoe +tiptoed +tiptoeing +tiptoes +tiptop +tiptops +tirade +tirades +tiramisu +tirana +tiranë +tire +tired +tiredly +tiredness +tireless +tirelessly +tirelessness +tires +tiresias +tiresome +tiresomely +tiresomeness +tiring +tiro +tirol +tiros +tirpitz +tiryns +tis +tisane +tisanes +tishri +tisiphone +tissot +tissue +tissues +tissuey +tissular +tit +titan +titanate +titanates +titaness +titanesses +titania +titanic +titanically +titaniferous +titanism +titanisms +titanite +titanites +titanium +titanosaur +titanosaurs +titanothere +titanotheres +titanous +titans +titbit +titbits +titer +titers +titfer +titfers +tithable +tithe +tithed +tither +tithers +tithes +tithing +tithings +tithonia +tithonias +titi +titian +titianesque +titicaca +titillate +titillated +titillater +titillaters +titillates +titillating +titillatingly +titillation +titillations +titillative +titis +titivate +titivated +titivates +titivating +titivation +titivations +titlark +titlarks +title +titled +titleholder +titleholders +titles +titling +titlist +titlists +titmice +titmouse +tito +titoism +titoist +titoists +titrant +titrants +titratable +titrate +titrated +titrates +titrating +titration +titrations +titrator +titrators +titre +titres +titrimetric +titrimetrically +tits +titter +tittered +titterer +titterers +tittering +titteringly +titters +tittivate +tittivated +tittivates +tittivating +tittle +tittles +tittup +tittuped +tittuping +tittupped +tittupping +tittups +titubation +titubations +titular +titularies +titularly +titulars +titulary +titus +tivoli +tiwa +tiwas +tizzies +tizzy +tko +tlingit +tlingits +tmeses +tmesis +tnt +to +toad +toadeater +toadeaters +toadfish +toadfishes +toadflax +toadflaxes +toadied +toadies +toads +toadstone +toadstones +toadstool +toadstools +toady +toadying +toadyish +toadyism +toast +toasted +toaster +toasters +toastier +toastiest +toasting +toastmaster +toastmasters +toastmistress +toastmistresses +toasts +toasty +tobacco +tobaccoes +tobacconist +tobacconists +tobaccos +tobagan +tobagans +tobago +tobagonian +tobagonians +tobias +tobies +tobit +toboggan +tobogganed +tobogganer +tobogganers +tobogganing +tobogganist +tobogganists +toboggans +tobruk +toby +toccata +toccatas +tocharian +tocharians +tocology +tocopherol +tocopherols +tocqueville +tocsin +tocsins +today +todays +toddies +toddle +toddled +toddler +toddlerhood +toddlers +toddles +toddling +toddy +todies +tody +toe +toea +toecap +toecaps +toed +toehold +toeholds +toeing +toeless +toenail +toenailed +toenailing +toenails +toepiece +toepieces +toeplate +toeplates +toes +toffee +toffees +toffies +toffy +tofu +tog +toga +togaed +togas +together +togetherness +togged +toggenburg +toggeries +toggery +togging +toggle +toggled +toggles +toggling +togo +togolese +togs +togue +togues +toheroa +toheroas +toil +toile +toiled +toiler +toilers +toilet +toiletries +toiletry +toilets +toilette +toilettes +toilful +toilfully +toiling +toils +toilsome +toilsomely +toilsomeness +toilworn +toity +tokamak +tokamaks +tokara +tokay +tokays +toke +toked +tokelau +token +tokened +tokening +tokenism +tokenize +tokenized +tokenizes +tokenizing +tokens +tokes +tokharian +tokharians +toking +tokology +tokomak +tokomaks +tokonoma +tokonomas +tokyo +tola +tolas +tolbutamide +tolbutamides +told +tole +toled +toledo +toledos +tolerability +tolerable +tolerableness +tolerably +tolerance +tolerances +tolerant +tolerantly +tolerate +tolerated +tolerates +tolerating +toleration +tolerative +tolerator +tolerators +toles +tolidine +tolidines +toling +toll +tollbooth +tollbooths +tolled +tollgate +tollgates +tollhouse +tollhouses +tolling +tolls +tollway +tollways +tolstoian +tolstoy +tolstoyan +toltec +toltecan +toltecs +tolu +toluate +toluates +toluene +toluenes +toluic +toluidine +toluidines +toluol +toluols +tolus +tolyl +tolyls +tom +tomahawk +tomahawked +tomahawking +tomahawks +tomalley +tomalleys +tomatillo +tomatillos +tomato +tomatoes +tomatoey +tomb +tombac +tombacs +tombless +tomblike +tombolo +tombolos +tomboy +tomboyish +tomboyishness +tomboys +tombs +tombstone +tombstones +tomcat +tomcats +tomcatted +tomcatting +tomcod +tomcods +tome +tomenta +tomentose +tomentum +tomes +tomfool +tomfooleries +tomfoolery +tomfools +tomism +tommed +tommies +tomming +tommy +tommyrot +tomogram +tomograms +tomograph +tomographic +tomographs +tomography +tomorrow +tomorrows +tompion +tompions +toms +tomsk +tomtit +tomtits +tomé +ton +tonal +tonalities +tonality +tonally +tondi +tondo +tondos +tone +tonearm +tonearms +toned +toneless +tonelessly +tonelessness +toneme +tonemes +tonemic +toner +toners +tones +tonetic +tonetically +tonetics +tonette +tonettes +toney +tong +tonga +tongan +tongans +tonged +tonger +tongers +tonging +tongs +tongue +tongued +tonguefish +tonguefishes +tongueless +tonguelike +tongues +tonguing +tonguings +tonic +tonically +tonicities +tonicity +tonics +tonier +toniest +tonight +tonights +toning +tonk +tonka +tonkin +tonkinese +tonks +tonnage +tonnages +tonne +tonneau +tonneaus +tonner +tonners +tonnes +tonometer +tonometers +tonometric +tonometry +tonoplast +tonoplasts +tons +tonsil +tonsillar +tonsillectomies +tonsillectomy +tonsillitic +tonsillitis +tonsillotomies +tonsillotomy +tonsils +tonsorial +tonsure +tonsured +tonsures +tonsuring +tontine +tontines +tonus +tonuses +tony +tonys +too +tooer +tooers +tooism +took +tool +toolbox +toolboxes +tooled +toolholder +toolholders +toolhouse +toolhouses +tooling +toolings +toolkit +toolkits +toolmaker +toolmakers +toolmaking +toolroom +toolrooms +tools +toolshed +toolsheds +toon +toons +toot +tooted +tooter +tooters +tooth +toothache +toothaches +toothbrush +toothbrushes +toothbrushing +toothed +toothier +toothiest +toothily +toothing +toothless +toothlessly +toothlessness +toothlike +toothpaste +toothpick +toothpicks +toothpowder +toothpowders +tooths +toothsome +toothsomely +toothsomeness +toothwort +toothworts +toothy +tooting +tootle +tootled +tootler +tootlers +tootles +tootling +toots +tootsie +tootsies +tootsy +top +topaz +topazes +topcoat +topcoats +topcross +topcrosses +topdressing +topdressings +tope +topectomies +topectomy +toped +topee +topees +topeka +toper +topers +topes +topflight +topful +topfull +topgallant +topgallants +tophet +tophets +tophi +tophus +topi +topiaries +topiary +topic +topical +topicality +topically +topics +toping +topis +topkick +topkicks +topknot +topknots +topless +toplessness +topline +toplines +toploftical +toploftier +toploftiest +toploftily +toploftiness +toplofty +topmast +topmasts +topminnow +topminnows +topmost +topnotch +topnotcher +topnotchers +topocentric +topograph +topographer +topographers +topographic +topographical +topographically +topographies +topographs +topography +topoi +topologic +topological +topologically +topologies +topologist +topologists +topology +toponym +toponymic +toponymical +toponymies +toponymist +toponymists +toponyms +toponymy +topos +topotype +topotypes +topped +topper +toppers +topping +toppings +topple +toppled +topples +toppling +tops +topsail +topsails +topside +topsider +topsiders +topsides +topsoil +topsoiled +topsoiling +topsoils +topspin +topstitch +topstitched +topstitches +topstitching +topsy +topwork +topworked +topworking +topworks +toque +toques +tor +torah +torahs +torbernite +torbernites +torch +torchbearer +torchbearers +torched +torches +torchier +torchiere +torchieres +torchiers +torchiest +torching +torchlight +torchlights +torchon +torchwood +torchwoods +torchy +torchère +torchères +tore +toreador +toreadors +torero +toreros +toreutic +toreutics +tori +toric +tories +torii +torino +torment +tormented +tormenter +tormenters +tormentil +tormentils +tormenting +tormentingly +tormentor +tormentors +torments +torn +tornadic +tornado +tornadoes +tornados +tornillo +tornillos +toroid +toroidal +toroidally +toroids +toronto +torose +torpedo +torpedoed +torpedoes +torpedoing +torpid +torpidity +torpidly +torpor +torporific +torquate +torque +torqued +torquemada +torquer +torquers +torques +torqueses +torquey +torquing +torr +torrefaction +torrefied +torrefies +torrefy +torrefying +torremolinos +torrens +torrent +torrential +torrentially +torrents +torres +torrid +torrider +torridest +torridity +torridly +torridness +tors +torsade +torsades +torsi +torsion +torsional +torsionally +torso +torsos +tort +torte +tortellini +torten +tortes +torticollar +torticollis +torticollises +tortilla +tortillas +tortious +tortiously +tortoise +tortoises +tortoiseshell +tortoiseshells +tortola +tortoni +tortricid +tortricids +tortrix +torts +tortuga +tortuosities +tortuosity +tortuous +tortuously +tortuousness +torture +tortured +torturer +torturers +tortures +torturing +torturous +torturously +torula +torulae +torulas +torus +tory +toryism +tosca +toscanini +tosh +toss +tossed +tosser +tossers +tosses +tossing +tosspot +tosspots +tossup +tossups +tostada +tostadas +tostado +tostados +tot +totable +total +totaled +totaling +totalism +totalistic +totalitarian +totalitarianism +totalitarianize +totalitarianized +totalitarianizes +totalitarianizing +totalitarians +totalities +totality +totalization +totalizations +totalizator +totalizators +totalize +totalized +totalizer +totalizers +totalizes +totalizing +totalled +totalling +totally +totals +tote +toted +totem +totemic +totemism +totemisms +totemist +totemistic +totemists +totems +toter +toters +totes +tother +toting +totipalmate +totipalmation +totipalmations +totipotence +totipotences +totipotencies +totipotency +totipotent +toto +tots +totted +totter +tottered +totterer +totterers +tottering +totteringly +totters +tottery +totting +touareg +toucan +toucanet +toucanets +toucans +touch +touchable +touchableness +touchback +touchbacks +touchdown +touchdowns +touched +toucher +touchers +touches +touchhole +touchholes +touchier +touchiest +touchily +touchiness +touching +touchingly +touchingness +touchline +touchlines +touchmark +touchmarks +touchstone +touchstones +touchtone +touchup +touchups +touchwood +touchwoods +touchy +touché +tough +toughen +toughened +toughener +tougheners +toughening +toughens +tougher +toughest +toughie +toughies +toughly +toughness +toughs +toughy +toulon +toulouse +toupee +toupees +touquet +tour +touraco +touracos +touraine +tourbillion +tourbillions +tourbillon +tourbillons +toured +tourer +tourers +tourette +tourette's +touring +tourings +tourism +tourist +touristic +touristically +tourists +touristy +tourmaline +tourmalines +tournament +tournaments +tournedos +tourney +tourneyed +tourneying +tourneys +tourniquet +tourniquets +tours +touse +toused +touses +tousing +tousle +tousled +tousles +tousling +toussaint +tout +touted +touter +touters +touting +touts +tovarich +tovariches +tovarish +tovarishes +tow +towable +towage +toward +towardliness +towardly +towards +towboat +towboats +towed +towel +toweled +towelette +towelettes +toweling +towelings +towelled +towelling +towellings +towels +tower +towered +towering +toweringly +towerish +towerlike +towers +towhead +towheaded +towheads +towhee +towhees +towing +towline +towlines +town +townhouse +townhouses +townie +townies +townlet +townlets +towns +townscape +townscapes +townsend +townsfolk +townshend +township +townships +townsman +townsmen +townspeople +townswoman +townswomen +towny +towpath +towpaths +towrope +towropes +tows +toxalbumin +toxalbumins +toxaphene +toxaphenes +toxemia +toxemic +toxic +toxically +toxicant +toxicants +toxicities +toxicity +toxicogenic +toxicologic +toxicological +toxicologically +toxicologist +toxicologists +toxicology +toxicoses +toxicosis +toxics +toxigenic +toxigenicity +toxin +toxins +toxoid +toxoids +toxophilite +toxophilites +toxophily +toxoplasma +toxoplasmas +toxoplasmic +toxoplasmoses +toxoplasmosis +toy +toyed +toyer +toyers +toying +toylike +toynbee +toyon +toyons +toyota +toyotas +toys +toyshop +toyshops +trabeate +trabeated +trabeation +trabeations +trabecula +trabeculae +trabecular +trabeculas +trabeculate +trace +traceability +traceable +traceableness +traceably +traced +traceless +tracer +traceried +traceries +tracers +tracery +traces +trachea +tracheae +tracheal +tracheary +tracheas +tracheate +tracheated +tracheates +tracheid +tracheidal +tracheids +tracheitis +tracheitises +tracheobronchial +tracheoesophageal +tracheolar +tracheole +tracheoles +tracheophyte +tracheophytes +tracheoscopic +tracheoscopies +tracheoscopy +tracheostomies +tracheostomy +tracheotomies +tracheotomy +trachoma +trachomatous +trachyte +trachytic +tracing +tracings +track +trackable +trackage +trackages +trackball +trackballs +tracked +tracker +trackers +tracking +tracklayer +tracklayers +tracklaying +trackless +trackman +trackmen +tracks +trackside +tracksides +tracksuit +tracksuits +trackwalker +trackwalkers +trackway +trackways +tract +tractability +tractable +tractableness +tractably +tractarian +tractarianism +tractarians +tractate +tractates +tractile +tractility +traction +tractional +tractive +tractor +tractors +tracts +tracy +tradable +trade +tradeable +tradecraft +tradecrafts +traded +trademark +trademarked +trademarking +trademarks +tradeoff +tradeoffs +trader +traders +trades +tradescantia +tradescantias +tradesman +tradesmen +tradespeople +trading +tradition +traditional +traditionalism +traditionalist +traditionalistic +traditionalists +traditionalize +traditionalized +traditionalizes +traditionalizing +traditionally +traditionary +traditionless +traditions +traditor +traditores +traduce +traduced +traducement +traducements +traducer +traducers +traduces +traducianism +traducianist +traducianistic +traducianists +traducing +traducingly +trafalgar +traffic +trafficability +trafficable +trafficked +trafficker +traffickers +trafficking +traffics +tragacanth +tragacanths +tragedian +tragedians +tragedienne +tragediennes +tragedies +tragedy +tragi +tragic +tragical +tragically +tragicalness +tragicomedies +tragicomedy +tragicomic +tragicomical +tragicomically +tragopan +tragopans +tragus +trail +trailblazer +trailblazers +trailblazing +trailbreaker +trailbreakers +trailed +trailer +trailerable +trailered +trailering +trailerist +trailerists +trailerite +trailerites +trailers +trailhead +trailheads +trailing +trailless +trails +trailside +trailsides +train +trainability +trainable +trainband +trainbands +trainbearer +trainbearers +trained +trainee +trainees +traineeship +trainer +trainers +trainful +trainfuls +training +trainload +trainloads +trainman +trainmaster +trainmasters +trainmen +trains +traipse +traipsed +traipses +traipsing +trait +traitor +traitoress +traitoresses +traitorous +traitorously +traitorousness +traitors +traitress +traitresses +traits +trajan +traject +trajected +trajecting +trajection +trajections +trajectories +trajectory +trajects +trakehner +trakehners +tram +tramcar +tramcars +tramline +tramlines +trammed +trammel +trammeled +trammeler +trammelers +trammeling +trammelled +trammelling +trammels +tramming +tramontane +tramontanes +tramp +tramped +tramper +trampers +tramping +trampish +trample +trampled +trampler +tramplers +tramples +trampling +trampoline +trampoliner +trampoliners +trampolines +trampolining +trampolinist +trampolinists +tramps +trampy +trams +tramway +tramways +trance +tranced +trancelike +trances +tranche +trancing +tranquil +tranquility +tranquilization +tranquilizations +tranquilize +tranquilized +tranquilizer +tranquilizers +tranquilizes +tranquilizing +tranquillity +tranquillize +tranquillized +tranquillizer +tranquillizers +tranquillizes +tranquillizing +tranquilly +tranquilness +trans +transact +transacted +transacting +transactinide +transaction +transactional +transactions +transactivate +transactivated +transactivates +transactivating +transactivation +transactivations +transactivator +transactivators +transactor +transactors +transacts +transalpine +transaminase +transaminases +transamination +transaminations +transatlantic +transaxle +transaxles +transcaucasia +transcaucasian +transcaucasians +transceiver +transceivers +transcend +transcended +transcendence +transcendency +transcendent +transcendental +transcendentalism +transcendentalist +transcendentalists +transcendentally +transcendently +transcending +transcends +transconductance +transcontinental +transcribable +transcribe +transcribed +transcriber +transcribers +transcribes +transcribing +transcript +transcriptase +transcriptases +transcription +transcriptional +transcriptionally +transcriptionist +transcriptionists +transcriptions +transcripts +transcultural +transculturation +transculturations +transcurrent +transcutaneous +transdermal +transdermals +transdisciplinary +transduce +transduced +transducer +transducers +transduces +transducing +transductant +transductants +transduction +transductional +transductions +transect +transected +transecting +transection +transections +transects +transept +transeptal +transepts +transeunt +transfect +transfected +transfecting +transfection +transfections +transfects +transfer +transferability +transferable +transferal +transferals +transferase +transferases +transferee +transferees +transference +transferential +transferor +transferors +transferrable +transferred +transferrer +transferrers +transferrin +transferring +transferrins +transfers +transfiguration +transfigurations +transfigure +transfigured +transfigurement +transfigures +transfiguring +transfinite +transfix +transfixed +transfixes +transfixing +transfixion +transfixions +transform +transformable +transformation +transformational +transformationalist +transformationalists +transformationally +transformations +transformative +transformed +transformer +transformers +transforming +transforms +transfusable +transfuse +transfused +transfuser +transfusers +transfuses +transfusible +transfusing +transfusion +transfusional +transfusions +transfusive +transgenic +transgress +transgressed +transgresses +transgressible +transgressing +transgression +transgressions +transgressive +transgressively +transgressor +transgressors +tranship +transhipped +transhipping +tranships +transhistorical +transhumance +transhumant +transhumants +transience +transiency +transient +transiently +transients +transilluminate +transilluminated +transilluminates +transilluminating +transillumination +transilluminations +transilluminator +transilluminators +transistor +transistorization +transistorizations +transistorize +transistorized +transistorizes +transistorizing +transistors +transit +transited +transiting +transition +transitional +transitionally +transitionary +transitions +transitive +transitively +transitiveness +transitives +transitivity +transitorily +transitoriness +transitory +transits +transjordan +transjordanian +transjordanians +transkei +transkeian +transkeians +translatability +translatable +translatableness +translate +translated +translates +translating +translation +translational +translations +translative +translator +translatorial +translators +translatory +transliterate +transliterated +transliterates +transliterating +transliteration +transliterations +translocate +translocated +translocates +translocating +translocation +translocations +translucence +translucency +translucent +translucently +translunar +transmarine +transmembrane +transmigrant +transmigrants +transmigrate +transmigrated +transmigrates +transmigrating +transmigration +transmigrationism +transmigrations +transmigrator +transmigrators +transmigratory +transmissibility +transmissible +transmission +transmissions +transmissive +transmissivity +transmissometer +transmissometers +transmissometry +transmit +transmits +transmittable +transmittal +transmittals +transmittance +transmittances +transmitted +transmitter +transmitters +transmitting +transmogrification +transmogrifications +transmogrified +transmogrifies +transmogrify +transmogrifying +transmontane +transmountain +transmundane +transmutability +transmutable +transmutableness +transmutably +transmutation +transmutational +transmutations +transmutative +transmute +transmuted +transmuter +transmuters +transmutes +transmuting +transnational +transnationalism +transnatural +transoceanic +transom +transoms +transonic +transpacific +transparence +transparencies +transparency +transparent +transparentize +transparentized +transparentizes +transparentizing +transparently +transparentness +transpersonal +transpicuous +transpierce +transpierced +transpierces +transpiercing +transpiration +transpirational +transpire +transpired +transpires +transpiring +transplacental +transplacentally +transplant +transplantability +transplantable +transplantation +transplantations +transplanted +transplanter +transplanters +transplanting +transplants +transpolar +transponder +transponders +transpontine +transport +transportability +transportable +transportation +transportational +transported +transporter +transporters +transporting +transportive +transports +transposable +transpose +transposed +transposes +transposing +transposition +transpositional +transpositions +transposon +transposons +transsexual +transsexualism +transsexuality +transsexuals +transshape +transshaped +transshapes +transshaping +transship +transshipment +transshipments +transshipped +transshipping +transships +transsonic +transthoracic +transthoracically +transubstantial +transubstantiate +transubstantiated +transubstantiates +transubstantiating +transubstantiation +transubstantiationalist +transubstantiationalists +transubstantiations +transudate +transudates +transudation +transudations +transudatory +transude +transuded +transudes +transuding +transuranic +transuranium +transurethral +transvaal +transvaluate +transvaluated +transvaluates +transvaluating +transvaluation +transvaluations +transvalue +transvalued +transvalues +transvaluing +transversal +transversally +transversals +transverse +transversely +transverseness +transverses +transvestism +transvestite +transvestites +transvestitism +transylvania +transylvanian +transylvanians +trap +trapdoor +trapdoors +trapeze +trapezes +trapezia +trapeziform +trapezist +trapezists +trapezium +trapeziums +trapezius +trapeziuses +trapezohedra +trapezohedron +trapezohedrons +trapezoid +trapezoidal +trapezoids +traplight +traplights +trapline +traplines +trapped +trapper +trappers +trapping +trappings +trappist +trappists +traprock +traprocks +traps +trapshooter +trapshooters +trapshooting +trapunto +trapuntos +trash +trashed +trashes +trashier +trashiest +trashily +trashiness +trashing +trashman +trashmen +trashy +trass +trasses +trattoria +trattorias +trattorie +trauma +traumas +traumata +traumatic +traumatically +traumatism +traumatisms +traumatization +traumatizations +traumatize +traumatized +traumatizes +traumatizing +traumatological +traumatologist +traumatologists +traumatology +travail +travailed +travailing +travails +trave +travel +traveled +traveler +traveler's +travelers +traveling +travelled +traveller +travellers +travelling +travelog +travelogs +travelogue +travelogues +travels +traversable +traversal +traversals +traverse +traversed +traverser +traversers +traverses +traversing +travertine +travertines +traves +travestied +travesties +travesty +travestying +traviata +travois +travoise +travoises +trawl +trawled +trawler +trawlerman +trawlermen +trawlers +trawling +trawls +tray +trayful +trayfuls +trays +trazodone +trazodones +treacheries +treacherous +treacherously +treacherousness +treachery +treacle +treacly +tread +treaded +treader +treaders +treading +treadle +treadled +treadler +treadlers +treadles +treadless +treadling +treadmill +treadmills +treads +treason +treasonable +treasonableness +treasonably +treasonous +treasonously +treasurable +treasure +treasured +treasurer +treasurers +treasurership +treasures +treasuries +treasuring +treasury +treat +treatability +treatable +treated +treater +treaters +treaties +treating +treatise +treatises +treatment +treatments +treats +treaty +trebizond +treble +trebled +trebleness +trebles +trebling +trebly +trebuchet +trebuchets +trebucket +trebuckets +trecento +tredecillion +tredecillions +tree +treed +treehopper +treehoppers +treeing +treeless +treelike +treen +treenail +treenails +treens +trees +treetop +treetops +tref +trefoil +trefoils +trehala +trehalas +trehalase +trehalases +trehalose +trehaloses +treillage +treillages +trek +trekked +trekker +trekkers +trekking +treks +trellis +trellised +trellises +trellising +trelliswork +trematode +trematodes +trematodiasis +tremble +trembled +trembler +tremblers +trembles +trembling +tremblingly +trembly +tremendous +tremendously +tremendousness +tremens +tremolite +tremolites +tremolitic +tremolo +tremolos +tremor +tremors +tremulant +tremulous +tremulously +tremulousness +trenail +trenails +trench +trenchancy +trenchant +trenchantly +trenched +trencher +trencherman +trenchermen +trenchers +trenches +trenching +trend +trended +trendier +trendies +trendiest +trendily +trendiness +trending +trends +trendsetter +trendsetters +trendsetting +trendy +trentino +trenton +trepan +trepanation +trepanations +trepang +trepangs +trepanned +trepanning +trepans +trephination +trephinations +trephine +trephined +trephines +trephining +trepid +trepidant +trepidation +treponema +treponemal +treponemas +treponemata +treponematoses +treponematosis +treponematous +treponeme +treponemes +trespass +trespassed +trespasser +trespassers +trespasses +trespassing +tress +tressed +tressel +tressels +tresses +trestle +trestles +trestletree +trestletrees +trestlework +tretinoin +tretinoins +trevallies +trevally +trevelyan +trevithick +trews +trey +treys +triable +triableness +triacetate +triacetates +triacid +triacids +triad +triadelphous +triadic +triadically +triads +triage +triages +trial +trialogue +trialogues +trials +triamcinolone +triamcinolones +triandrous +triangle +triangles +triangular +triangularity +triangularly +triangulate +triangulated +triangulates +triangulating +triangulation +triangulations +triangulum +triarchies +triarchy +triassic +triathlete +triathletes +triathlon +triathlons +triatomic +triaxial +triaxiality +triazine +triazines +triazole +triazoles +tribade +tribades +tribadism +tribal +tribalism +tribalisms +tribalist +tribalistic +tribalists +tribally +tribasic +tribe +tribes +tribesman +tribesmen +tribespeople +tribeswoman +tribeswomen +triboelectric +triboelectricities +triboelectricity +tribological +tribologist +tribologists +tribology +triboluminescence +triboluminescent +tribrach +tribrachic +tribrachs +tribromoethanol +tribromoethanols +tribulate +tribulated +tribulates +tribulating +tribulation +tribulations +tribunal +tribunals +tribunary +tribunate +tribunates +tribune +tribunes +tribuneship +tributaries +tributary +tribute +tributes +tricameral +tricarboxylic +trice +triced +tricentennial +tricentennials +triceps +tricepses +triceratops +triceratopses +trices +trichiasis +trichina +trichinae +trichinal +trichinas +trichinization +trichinizations +trichinize +trichinized +trichinizes +trichinizing +trichinoses +trichinosis +trichinous +trichite +trichites +trichitic +trichlorethylene +trichlorethylenes +trichlorfon +trichlorfons +trichlorid +trichloride +trichlorides +trichlorids +trichloroacetic +trichloroethane +trichloroethylene +trichloroethylenes +trichlorphon +trichlorphons +trichocyst +trichocystic +trichocysts +trichogyne +trichogynes +trichoid +trichologist +trichologists +trichology +trichome +trichomes +trichomic +trichomonacidal +trichomonacide +trichomonacides +trichomonad +trichomonadal +trichomonads +trichomonal +trichomoniases +trichomoniasis +trichopteran +trichopterans +trichoses +trichosis +trichothecene +trichothecenes +trichotomic +trichotomies +trichotomous +trichotomously +trichotomy +trichroic +trichroism +trichroisms +trichromat +trichromatic +trichromatism +trichromats +trichrome +trichromic +trichuriases +trichuriasis +tricing +trick +tricked +tricker +trickeries +trickers +trickery +trickier +trickiest +trickily +trickiness +tricking +trickish +trickishly +trickishness +trickle +trickled +trickles +trickling +tricks +tricksier +tricksiest +tricksiness +trickster +tricksters +tricksy +tricky +triclad +triclads +triclinia +triclinic +triclinium +tricolette +tricolettes +tricolor +tricolored +tricolors +tricorn +tricorne +tricornered +tricornes +tricorns +tricostate +tricot +tricotine +tricotines +tricots +tricrotic +tricrotism +trictrac +tricuspid +tricuspidal +tricuspidate +tricuspids +tricycle +tricycles +tricyclic +tricyclics +tridactyl +tridactylous +trident +tridentate +tridentine +tridentines +tridents +tridimensional +tridimensionality +triduum +tried +triene +trienes +triennia +triennial +triennially +triennials +triennium +trienniums +trier +trierarch +trierarchies +trierarchs +trierarchy +triers +tries +trieste +triethiodide +triethyl +trifacial +trifecta +trifectas +trifid +trifle +trifled +trifler +triflers +trifles +trifling +triflingly +trifluoperazine +trifluoperazines +trifluralin +trifluralins +trifocal +trifocals +trifoliate +trifoliated +trifoliolate +trifolium +triforia +triforium +triform +triformed +trifurcate +trifurcated +trifurcates +trifurcating +trifurcation +trifurcations +trig +trigamous +trigeminal +trigemini +trigeminus +trigged +trigger +triggered +triggerfish +triggerfishes +triggering +triggerman +triggermen +triggers +trigging +trigly +triglyceride +triglycerides +triglyph +triglyphic +triglyphical +triglyphs +trigness +trigon +trigonal +trigonally +trigonometric +trigonometrical +trigonometrically +trigonometry +trigons +trigram +trigrammatic +trigrammatically +trigrams +trigraph +trigraphic +trigraphically +trigraphs +trigs +trigynous +trihalomethane +trihalomethanes +trihedra +trihedral +trihedrals +trihedron +trihedrons +trihybrid +trihybrids +trihydric +trihydroxy +triiodothyronine +triiodothyronines +trijet +trijets +trike +trikes +trilabiate +trilateral +trilateralism +trilateralisms +trilateralist +trilateralists +trilaterally +trilbies +trilby +trilinear +trilingual +trilingualism +trilingually +trilinguals +triliteral +triliteralism +triliterals +trilith +trilithic +trilithon +trilithons +triliths +trill +trilled +triller +trillers +trilling +trillion +trillions +trillionth +trillionths +trillium +trilliums +trills +trilobate +trilobated +trilobed +trilobite +trilobites +trilobitic +trilocular +trilogies +trilogy +trim +trimaran +trimarans +trimer +trimeric +trimerism +trimerous +trimers +trimester +trimesters +trimestral +trimestrial +trimeter +trimeters +trimethadione +trimethadiones +trimethoprim +trimethoprims +trimetric +trimetrical +trimetrogon +trimetrogons +trimly +trimmed +trimmer +trimmers +trimmest +trimming +trimmings +trimness +trimolecular +trimonthly +trimorph +trimorphic +trimorphically +trimorphism +trimorphous +trimorphs +trimotor +trimotors +trims +trimurti +trinal +trinary +trincomalee +trine +trines +trinidad +trinidadian +trinidadians +trinitarian +trinitarianism +trinitarians +trinities +trinitrobenzene +trinitrobenzenes +trinitrocresol +trinitrocresols +trinitrophenol +trinitrophenols +trinitrotoluene +trinitrotoluenes +trinitrotoluol +trinitrotoluols +trinity +trinitytide +trinket +trinketer +trinketers +trinketry +trinkets +trinocular +trinomial +trinomialism +trinomials +trinucleotide +trinucleotides +trio +triode +triodes +triol +triolet +triolets +triols +trios +triose +trioses +trioxid +trioxide +trioxides +trioxids +trip +tripack +tripacks +tripalmitin +tripalmitins +tripartite +tripartitely +tripartition +tripartitions +tripe +tripedal +tripeptide +tripeptides +tripetalous +triphammer +triphammers +triphenylmethane +triphenylmethanes +triphibian +triphibians +triphibious +triphosphatase +triphosphate +triphosphates +triphosphopyridine +triphthong +triphthongal +triphthongs +tripinnate +tripinnately +triplane +triplanes +triple +tripled +tripleheader +tripleheaders +triples +triplet +tripletail +tripletails +triplets +triplex +triplexes +triplicate +triplicated +triplicately +triplicates +triplicating +triplication +triplications +triplicities +triplicity +tripling +triploblastic +triploid +triploids +triploidy +triply +tripod +tripodal +tripods +tripoli +tripolis +tripolitan +tripolitania +tripolitanian +tripolitanians +tripolitans +tripolyphosphate +tripos +triposes +tripped +tripper +trippers +trippet +trippets +tripping +trippingly +trippy +trips +triptane +triptanes +triptych +triptychs +tripura +tripwire +tripwires +triquetra +triquetral +triquetrous +triquetrum +triradiate +trireme +triremes +trisaccharide +trisaccharides +trisagion +trisect +trisected +trisecting +trisection +trisections +trisector +trisectors +trisects +trisepalous +trishaw +trishaws +triskaidekaphobia +triskaidekaphobias +triskele +triskeles +triskelia +triskelion +trismic +trismus +trisoctahedra +trisoctahedral +trisoctahedron +trisoctahedrons +trisodium +trisome +trisomes +trisomic +trisomies +trisomy +tristan +tristate +triste +tristearin +tristearins +tristeza +tristful +tristfully +tristfulness +tristich +tristichs +tristimulus +tristram +trisubstituted +trisulfide +trisulfides +trisyllabic +trisyllabical +trisyllabically +trisyllable +trisyllables +tritanopia +tritanopias +trite +tritely +triteness +triter +tritest +tritheism +tritheist +tritheistic +tritheistical +tritheists +tritiate +tritiated +tritiates +tritiating +tritiation +triticale +triticales +tritium +tritoma +tritomas +triton +tritone +tritones +tritons +triturable +triturate +triturated +triturates +triturating +trituration +triturations +triturator +triturators +triumph +triumphal +triumphalism +triumphalisms +triumphalist +triumphalists +triumphant +triumphantly +triumphed +triumphing +triumphs +triumvir +triumviral +triumvirate +triumvirates +triumviri +triumvirs +triune +triunes +triunities +triunity +trivalence +trivalency +trivalent +trivalve +trivet +trivets +trivia +trivial +trivialist +trivialists +trivialities +triviality +trivialization +trivializations +trivialize +trivialized +trivializes +trivializing +trivially +trivialness +trivium +triweeklies +triweekly +trobriand +trocar +trocars +trochaic +trochaics +trochal +trochanter +trochanteral +trochanteric +trochanters +trochar +trochars +troche +trochee +trochees +troches +trochlea +trochleae +trochlear +trochoid +trochoidal +trochoidally +trochoids +trochophore +trochophores +trod +trodden +troffer +troffers +troglodyte +troglodytes +troglodytic +troglodytical +trogon +trogons +troika +troikas +troilite +troilites +troilus +trois +trojan +trojans +troll +trolled +troller +trollers +trolley +trolleybus +trolleybuses +trolleyed +trolleying +trolleys +trollied +trollies +trolling +trollop +trollope +trollops +trolls +trolly +trollying +trombe +trombiculiasis +trombiculoses +trombiculosis +trombone +trombones +trombonist +trombonists +trommel +trommels +tromp +trompe +tromped +trompes +tromping +tromps +tromsö +trona +tronas +trondheim +troop +trooped +trooper +troopers +trooping +troops +troopship +troopships +troostite +troostites +trop +trope +tropes +tropez +trophallaxes +trophallaxis +trophic +trophically +trophies +trophoblast +trophoblastic +trophoblasts +trophoderm +trophoderms +trophozoite +trophozoites +trophy +tropic +tropical +tropicalize +tropicalized +tropicalizes +tropicalizing +tropically +tropicals +tropicbird +tropicbirds +tropics +tropin +tropine +tropines +tropins +tropism +tropistic +tropistically +tropocollagen +tropocollagens +tropologic +tropological +tropologically +tropologies +tropology +tropomyosin +tropomyosins +troponin +troponins +tropopause +tropopauses +tropophyte +tropophytes +tropophytic +troposphere +tropospheric +tropotactic +tropotactically +tropotaxis +tropotaxises +troppo +trot +troth +trothed +trothing +trothplight +trothplighted +trothplighting +trothplights +troths +trotline +trotlines +trots +trotsky +trotskyism +trotskyist +trotskyists +trotskyite +trotskyites +trotted +trotter +trotters +trotting +troubadour +troubadours +trouble +troubled +troublemaker +troublemakers +troublemaking +troubler +troublers +troubles +troubleshoot +troubleshooter +troubleshooters +troubleshooting +troubleshoots +troubleshot +troublesome +troublesomely +troublesomeness +troubling +troublingly +troublous +troublously +troublousness +trough +troughs +trounce +trounced +trounces +trouncing +troupe +trouped +trouper +troupers +troupes +troupial +troupials +trouping +trouser +trousers +trousseau +trousseaus +trousseaux +trout +troutier +troutiest +troutperch +troutperches +trouts +trouty +trouvere +trouveres +trouveur +trouveurs +trouville +trouvère +trouvères +trove +trover +trovers +troves +trow +trowed +trowel +troweled +troweler +trowelers +troweling +trowelled +troweller +trowellers +trowelling +trowels +trowing +trows +trowser +trowsers +troy +troôdos +truancies +truancy +truant +truanted +truanting +truantries +truantry +truants +truce +trucebreaker +trucebreakers +truced +truces +trucing +truck +truckage +trucked +trucker +truckers +truckful +truckfuls +trucking +truckle +truckled +truckler +trucklers +truckles +truckline +trucklines +truckling +truckload +truckloads +truckman +truckmaster +truckmasters +truckmen +trucks +truculence +truculences +truculencies +truculency +truculent +truculently +trudge +trudged +trudgen +trudgens +trudgeon +trudgeons +trudger +trudgers +trudges +trudging +true +trueborn +trued +truehearted +trueheartedness +trueing +truelove +trueloves +trueness +truepennies +truepenny +truer +trues +truest +truffle +truffled +truffles +truing +truism +truisms +truistic +truk +trull +trulls +truly +trump +trumped +trumperies +trumpery +trumpet +trumpeted +trumpeter +trumpeters +trumpeting +trumpetlike +trumpets +trumping +trumps +truncate +truncated +truncately +truncates +truncating +truncation +truncations +truncheon +truncheoned +truncheoning +truncheons +trundle +trundled +trundler +trundlers +trundles +trundling +trunk +trunked +trunkfish +trunkfishes +trunkful +trunkfuls +trunks +trunnel +trunnels +trunnion +trunnions +truss +trussed +trusser +trussers +trusses +trussing +trust +trustability +trustable +trustbuster +trustbusters +trustbusting +trustbustings +trusted +trustee +trusteed +trusteeing +trustees +trusteeship +trusteeships +truster +trusters +trustful +trustfully +trustfulness +trustier +trusties +trustiest +trustily +trustiness +trusting +trustingly +trustingness +trustless +trusts +trustworthier +trustworthiest +trustworthily +trustworthiness +trustworthy +trusty +truth +truthful +truthfully +truthfulness +truths +try +trying +tryingly +tryout +tryouts +trypanosomal +trypanosome +trypanosomes +trypanosomiases +trypanosomiasis +trypanosomic +tryparsamide +tryparsamides +trypsin +trypsinogen +trypsinogens +trypsins +tryptamine +tryptamines +tryptic +tryptophan +tryptophane +tryptophanes +tryptophans +trysail +trysails +tryst +trysted +tryster +trysters +trysting +trysts +tryworks +tsade +tsades +tsar +tsars +tsarskoye +tsatske +tsatskes +tsetse +tshiluba +tsimmes +tsimmeses +tsimshian +tsimshians +tsinghai +tsk +tsked +tsking +tsks +tsunami +tsunamic +tsunamis +tsuris +tsurises +tsushima +tsutsugamushi +tswana +tswanas +tu +tuamotu +tuan +tuareg +tuaregs +tuatara +tuataras +tub +tuba +tubaist +tubaists +tubal +tubas +tubate +tubbable +tubbed +tubber +tubbers +tubbier +tubbiest +tubbiness +tubbing +tubby +tube +tubectomies +tubectomy +tubed +tubeless +tubelike +tubenose +tubenoses +tuber +tubercle +tubercles +tubercular +tuberculars +tuberculate +tuberculated +tuberculately +tuberculation +tuberculations +tuberculin +tuberculins +tuberculoid +tuberculoses +tuberculosis +tuberculous +tuberculously +tuberose +tuberoses +tuberosities +tuberosity +tuberous +tubers +tuberworm +tuberworms +tubes +tubeworm +tubeworms +tubful +tubfuls +tubicolous +tubifex +tubifexes +tubificid +tubificids +tubing +tubist +tubists +tublike +tubocurarine +tubocurarines +tuboplasties +tuboplasty +tubs +tubuai +tubular +tubularity +tubularly +tubulate +tubulated +tubulation +tubulations +tubulator +tubulators +tubule +tubules +tubuliferous +tubuliflorous +tubulin +tubulins +tubulous +tubulously +tucana +tuchun +tuchuns +tuck +tuckahoe +tuckahoes +tucked +tucker +tuckered +tuckering +tuckers +tucket +tuckets +tucking +tucks +tuckshop +tuckshops +tucson +tudor +tudors +tuesday +tuesdays +tufa +tufaceous +tufas +tuff +tuffaceous +tuffet +tuffets +tuffs +tuft +tufted +tufter +tufters +tufting +tufts +tufty +tug +tugboat +tugboats +tugged +tugger +tuggers +tugging +tughrik +tughriks +tugrik +tugriks +tugs +tui +tuille +tuilles +tuis +tuition +tuitional +tuitionary +tularemia +tularemic +tule +tules +tulip +tulips +tulipwood +tulipwoods +tulle +tulles +tullibee +tullibees +tulsa +tumble +tumblebug +tumblebugs +tumbled +tumbledown +tumblehome +tumblehomes +tumbler +tumblerful +tumblerfuls +tumblers +tumbles +tumbleset +tumblesets +tumbleweed +tumbleweeds +tumbling +tumblings +tumbrel +tumbrels +tumbril +tumbrils +tumefacient +tumefaction +tumefactions +tumefactive +tumefied +tumefies +tumefy +tumefying +tumescence +tumescences +tumescent +tumid +tumidity +tumidly +tumidness +tummies +tummler +tummlers +tummy +tumor +tumoral +tumorigeneses +tumorigenesis +tumorigenic +tumorigenicity +tumorlike +tumorous +tumors +tump +tumpline +tumplines +tumps +tumular +tumuli +tumulose +tumulosity +tumulous +tumult +tumults +tumultuary +tumultuous +tumultuously +tumultuousness +tumulus +tun +tuna +tunability +tunable +tunableness +tunably +tunas +tundish +tundishes +tundra +tundras +tune +tuneable +tuned +tuneful +tunefully +tunefulness +tuneless +tunelessly +tunelessness +tuner +tuners +tunes +tunesmith +tunesmiths +tung +tungstate +tungstates +tungsten +tungstenic +tungstic +tungstite +tungstites +tungus +tunguses +tungusic +tunic +tunica +tunicae +tunicate +tunicated +tunicates +tunicle +tunicles +tunics +tuning +tunings +tunis +tunisia +tunisian +tunisians +tunnel +tunneled +tunneler +tunnelers +tunneling +tunnelled +tunneller +tunnellers +tunnellike +tunnelling +tunnels +tunnies +tunny +tuns +tup +tupelo +tupelos +tupi +tupian +tupians +tupis +tupped +tuppence +tupperware +tupping +tups +tuque +tuques +turaco +turacos +turanian +turanians +turban +turbaned +turbanned +turbans +turbaries +turbary +turbellarian +turbellarians +turbid +turbidimeter +turbidimeters +turbidimetric +turbidimetrically +turbidimetry +turbidite +turbidites +turbidities +turbidity +turbidly +turbidness +turbinal +turbinals +turbinate +turbinated +turbination +turbinations +turbine +turbines +turbit +turbits +turbo +turbocar +turbocars +turbocharged +turbocharger +turbochargers +turboelectric +turbofan +turbofans +turbogenerator +turbogenerators +turbojet +turbojets +turbomachinery +turboprop +turboprops +turboramjet +turboramjets +turbos +turboshaft +turboshafts +turbosupercharger +turbosuperchargers +turbot +turbots +turbulence +turbulencies +turbulency +turbulent +turbulently +turcoman +turcomans +turd +turds +tureen +tureens +turf +turfed +turfing +turfman +turfmen +turfs +turfski +turfskiing +turfskis +turfy +turgenev +turgescence +turgescent +turgid +turgidity +turgidly +turgidness +turgor +turin +turing +turion +turions +turista +turk +turkana +turkestan +turkey +turkeys +turki +turkic +turkics +turkis +turkish +turkism +turkistan +turkmen +turkmenistan +turkmens +turkoman +turkomans +turks +turmaline +turmalines +turmeric +turmoil +turn +turnable +turnabout +turnabouts +turnaround +turnarounds +turnbuckle +turnbuckles +turncoat +turncoats +turndown +turndowns +turned +turner +turneries +turners +turnery +turning +turnings +turnip +turnips +turnkey +turnkeys +turnoff +turnoffs +turnout +turnouts +turnover +turnovers +turnpike +turnpikes +turns +turnsole +turnsoles +turnspit +turnspits +turnstile +turnstiles +turnstone +turnstones +turntable +turntables +turnup +turnups +turnverein +turnvereins +turophile +turophiles +turpentine +turpentined +turpentines +turpentinic +turpentining +turpentinous +turpin +turpitude +turps +turquois +turquoise +turquoises +turret +turreted +turrets +turtle +turtleback +turtlebacked +turtlebacks +turtled +turtledove +turtledoves +turtlehead +turtleheads +turtleneck +turtlenecked +turtlenecks +turtler +turtlers +turtles +turtling +turves +turvier +turvies +turviest +turvily +turviness +turvy +turvydom +tuscan +tuscans +tuscany +tuscarora +tuscaroras +tusche +tusches +tush +tushes +tushie +tushies +tushy +tusk +tusked +tusker +tuskers +tusking +tusklike +tusks +tussah +tussahs +tussal +tussaud +tusser +tusses +tussie +tussis +tussive +tussle +tussled +tussles +tussling +tussock +tussocks +tussocky +tussore +tussores +tut +tutankhamen +tutankhaten +tutee +tutees +tutelage +tutelar +tutelaries +tutelars +tutelary +tutor +tutorage +tutorages +tutored +tutoress +tutoresses +tutorial +tutorials +tutoring +tutors +tutorship +tutorships +tutoyer +tutoyered +tutoyering +tutoyers +tuts +tutsi +tutsis +tutted +tutti +tutting +tuttis +tutty +tutu +tutuila +tutus +tuvalu +tuvaluan +tuvaluans +tux +tuxedo +tuxedoed +tuxedoes +tuxedos +tuxes +tuyere +tuyeres +tuyère +tuyères +tuzzy +twaddle +twaddled +twaddler +twaddlers +twaddles +twaddling +twain +twains +twang +twanged +twanger +twangers +twanging +twangs +twangy +twas +twat +twats +twayblade +twayblades +tweak +tweaked +tweaking +tweaks +tweaky +twee +tweed +tweeddale +tweedier +tweediest +tweediness +tweedledee +tweedledum +tweeds +tweedy +tween +tweet +tweeted +tweeter +tweeters +tweeting +tweets +tweeze +tweezed +tweezer +tweezers +tweezes +tweezing +twelfth +twelfths +twelve +twelvefold +twelvemo +twelvemonth +twelvemonths +twelvemos +twelvepenny +twelves +twenties +twentieth +twentieths +twenty +twentyfold +twere +twerp +twerps +twi +twibill +twibills +twice +twiddle +twiddled +twiddler +twiddlers +twiddles +twiddling +twig +twigged +twiggier +twiggiest +twigging +twiggy +twigs +twilight +twilit +twill +twilled +twilling +twills +twin +twinberries +twinberry +twinborn +twine +twined +twiner +twiners +twines +twinflower +twinflowers +twinge +twinged +twingeing +twinges +twinging +twinight +twining +twinjet +twinjets +twinkle +twinkled +twinkler +twinklers +twinkles +twinkling +twinkly +twinleaf +twinleaves +twinned +twinning +twinnings +twins +twinset +twinsets +twinship +twiny +twirl +twirled +twirler +twirlers +twirling +twirls +twirly +twirp +twirps +twist +twistability +twistable +twisted +twister +twisters +twisting +twistingly +twists +twisty +twit +twitch +twitched +twitcher +twitchers +twitches +twitchier +twitchiest +twitchily +twitchiness +twitching +twitchingly +twitchy +twite +twites +twits +twitted +twitter +twittered +twitterer +twitterers +twittering +twitters +twittery +twitting +twixt +two +twofaced +twofer +twofers +twofold +twomo +twomos +twopence +twopences +twopenny +twos +twosome +twosomes +tyburn +tycho +tycoon +tycoons +tyer +tyers +tying +tyke +tykes +tylectomies +tylectomy +tylenol +tylose +tyloses +tylosin +tylosins +tylosis +tymbal +tymbals +tympan +tympana +tympanal +tympani +tympanic +tympanies +tympanist +tympanists +tympanites +tympanitic +tympanitis +tympanitises +tympanoplasties +tympanoplasty +tympans +tympanum +tympanums +tympany +tyndale +tyndareus +tyne +tynes +typal +type +typeable +typecast +typecasting +typecasts +typed +typeface +typefaces +typefounder +typefounders +typefounding +types +typescript +typescripts +typeset +typesets +typesetter +typesetters +typesetting +typestyle +typestyles +typewrite +typewriter +typewriters +typewrites +typewriting +typewritings +typewritten +typewrote +typey +typhlitic +typhlitis +typhlology +typhlosole +typhlosoles +typhoean +typhoeus +typhogenic +typhoid +typhoidal +typhoidin +typhoidins +typhon +typhoon +typhoons +typhous +typhus +typic +typical +typicality +typically +typicalness +typier +typiest +typification +typifications +typified +typifier +typifiers +typifies +typify +typifying +typing +typist +typists +typo +typograph +typographed +typographer +typographers +typographic +typographical +typographically +typographies +typographing +typographs +typography +typologic +typological +typologically +typologies +typologist +typologists +typology +typos +typy +tyramine +tyramines +tyrannic +tyrannical +tyrannically +tyrannicalness +tyrannicide +tyrannicides +tyrannies +tyrannize +tyrannized +tyrannizer +tyrannizers +tyrannizes +tyrannizing +tyrannizingly +tyrannosaur +tyrannosaurs +tyrannosaurus +tyrannosauruses +tyrannous +tyrannously +tyranny +tyrant +tyrants +tyrian +tyrians +tyro +tyrocidin +tyrocidine +tyrocidines +tyrocidins +tyrol +tyrolean +tyroleans +tyrolese +tyrolian +tyrollean +tyrone +tyros +tyrosinase +tyrosinases +tyrosine +tyrosines +tyrothricin +tyrothricins +tyrrhenian +tzaddik +tzaddikim +tzar +tzars +tzetze +tzigane +tziganes +tzimmes +tzimmeses +tzitzis +tzitzit +tzuris +tzurises +tène +tête +têtes +tínos +tórshavn +tôle +tôles +u +ubangi +ubiety +ubiquinone +ubiquinones +ubiquitous +ubiquitously +ubiquitousness +ubiquity +uccello +udall +udder +udders +udine +udo +udometer +udometers +udos +udzungwa +uffizi +ufo +ufological +ufologist +ufologists +ufology +ufos +uganda +ugandan +ugandans +ugaritic +ugh +ugli +uglier +uglies +ugliest +uglification +uglifications +uglified +uglifier +uglifiers +uglifies +uglify +uglifying +uglily +ugliness +ugly +ugrian +ugrians +ugric +ugsome +ugsomeness +uh +uhf +uhlan +uhlans +uighur +uighurs +uigur +uigurian +uiguric +uigurs +uilleann +uintahite +uintahites +uintaite +uintaites +uitlander +uitlanders +uk +ukase +ukases +uke +ukelele +ukeleles +ukes +ukraine +ukrainian +ukrainians +ukulele +ukuleles +ulama +ulamas +ulan +ulans +ulcer +ulcerate +ulcerated +ulcerates +ulcerating +ulceration +ulcerations +ulcerative +ulcerogenic +ulcerous +ulcerously +ulcerousness +ulcers +ulema +ulexite +ulexites +ullage +ullages +ulna +ulnae +ulnar +ulnas +ulster +ulsters +ulterior +ulteriorly +ultima +ultimacies +ultimacy +ultimas +ultimata +ultimate +ultimately +ultimateness +ultimatum +ultimatums +ultimo +ultimogeniture +ultra +ultrabasic +ultracareful +ultracasual +ultracautious +ultracentrifugal +ultracentrifugally +ultracentrifugation +ultracentrifugations +ultracentrifuge +ultracentrifuges +ultrachic +ultracivilized +ultraclean +ultracold +ultracommercial +ultracompact +ultracompetent +ultraconservatism +ultraconservative +ultraconservatives +ultracontemporary +ultraconvenient +ultracool +ultracritical +ultrademocratic +ultradense +ultradian +ultradistance +ultradistant +ultradry +ultraefficient +ultraenergetic +ultraexclusive +ultrafamiliar +ultrafashionable +ultrafast +ultrafastidious +ultrafeminine +ultrafiche +ultrafiches +ultrafiltrate +ultrafiltrating +ultrafiltration +ultrafiltrations +ultrafine +ultraglamorous +ultrahazardous +ultraheat +ultraheavy +ultrahigh +ultrahip +ultrahot +ultrahuman +ultraism +ultraist +ultraistic +ultraists +ultraleft +ultraleftism +ultraleftist +ultraleftists +ultraliberal +ultraliberalism +ultraliberals +ultralight +ultralights +ultralightweight +ultralow +ultramafic +ultramarathon +ultramarathoner +ultramarathoners +ultramarathons +ultramarine +ultramarines +ultramasculine +ultramicro +ultramicrofiche +ultramicrofiches +ultramicrometer +ultramicrometers +ultramicroscope +ultramicroscopes +ultramicroscopic +ultramicroscopical +ultramicroscopically +ultramicroscopy +ultramicrotome +ultramicrotomes +ultramicrotomy +ultramilitant +ultramilitants +ultraminiature +ultraminiaturization +ultraminiaturizations +ultraminiaturize +ultraminiaturized +ultraminiaturizes +ultraminiaturizing +ultramodern +ultramodernism +ultramodernist +ultramodernistic +ultramodernists +ultramontane +ultramontanes +ultramontanism +ultramontanist +ultramontanists +ultramundane +ultranational +ultranationalism +ultranationalist +ultranationalistic +ultranationalists +ultraorthodox +ultraparadoxical +ultrapatriotic +ultraphysical +ultrapowerful +ultrapractical +ultraprecise +ultraprecision +ultraprofessional +ultraprogressive +ultrapure +ultraquiet +ultraradical +ultrarapid +ultrarare +ultrararefied +ultrarational +ultrarealism +ultrarealist +ultrarealistic +ultrarealists +ultrarefined +ultrareliable +ultrarespectable +ultrarevolutionary +ultrarich +ultraright +ultrarightist +ultrarightists +ultraromantic +ultraroyalist +ultraroyalists +ultras +ultrasafe +ultrasecret +ultrasegregationist +ultrasegregationists +ultrasensitive +ultraserious +ultrasharp +ultrashort +ultrasimple +ultraslick +ultraslow +ultrasmall +ultrasmart +ultrasmooth +ultrasoft +ultrasonic +ultrasonically +ultrasonics +ultrasonogram +ultrasonograms +ultrasonograph +ultrasonographer +ultrasonographers +ultrasonographic +ultrasonographs +ultrasonography +ultrasophisticated +ultrasound +ultrasounds +ultrastructural +ultrastructurally +ultrastructure +ultrastructures +ultrathin +ultravacuum +ultraviolence +ultraviolent +ultraviolet +ultraviolets +ultravirile +ultravirility +ultravirus +ultraviruses +ultrawide +ululant +ululate +ululated +ululates +ululating +ululation +ululations +ulva +ulysses +um +umatilla +umatillas +umbel +umbellate +umbellated +umbellately +umbellet +umbellets +umbellifer +umbelliferous +umbellifers +umbellule +umbellules +umbels +umber +umbered +umbering +umbers +umbilical +umbilically +umbilicals +umbilicate +umbilicated +umbilication +umbilications +umbilici +umbilicus +umbilicuses +umbles +umbo +umbonal +umbonate +umbones +umbonic +umbos +umbra +umbrae +umbrage +umbrageous +umbrageously +umbrageousness +umbral +umbras +umbrella +umbrellaless +umbrellas +umbrette +umbrettes +umbria +umbrian +umbrians +umbriel +umbundu +umiak +umiaks +umlaut +umlauted +umlauting +umlauts +umm +umnak +ump +umped +umping +umpirage +umpirages +umpire +umpired +umpires +umpiring +umps +umpteen +umpteenth +umtata +un +una +unabashed +unabashedly +unabated +unabatedly +unabbreviated +unable +unabraded +unabridged +unabsorbed +unabsorbent +unacademic +unacademically +unaccented +unacceptability +unacceptable +unacceptably +unaccepted +unacclimated +unacclimatized +unaccommodated +unaccommodating +unaccompanied +unaccomplished +unaccountability +unaccountable +unaccountableness +unaccountably +unaccounted +unaccredited +unacculturated +unaccustomed +unaccustomedly +unaccustomedness +unachievable +unachieved +unacknowledged +unacquainted +unacquaintedness +unactable +unacted +unactorish +unadaptable +unadapted +unaddressed +unadjudicated +unadjusted +unadmired +unadmitted +unadoptable +unadorned +unadult +unadulterated +unadulteratedly +unadventurous +unadvertised +unadvised +unadvisedly +unadvisedness +unaesthetic +unaffected +unaffectedly +unaffectedness +unaffecting +unaffectionate +unaffectionately +unaffiliated +unaffluent +unaffordability +unaffordable +unaffordably +unafraid +unageing +unaggressive +unaging +unai +unaided +unais +unakin +unakite +unakites +unalarmed +unalaska +unalienable +unalienated +unaligned +unalike +unalleviated +unallied +unallocated +unallowable +unalloyed +unalloyedly +unalluring +unalterability +unalterable +unalterableness +unalterably +unaltered +unambiguous +unambiguously +unambitious +unambivalent +unambivalently +unamenable +unamended +unami +unamiable +unamis +unamortized +unamplified +unamusing +unanalyzable +unanalyzably +unanalyzed +unanchored +unaneled +unanesthetized +unanimated +unanimity +unanimous +unanimously +unanimousness +unannotated +unannounced +unanswerability +unanswerable +unanswerableness +unanswerably +unanswered +unanticipated +unanticipatedly +unapologetic +unapologetically +unapologizing +unapparent +unappealable +unappealably +unappealing +unappealingly +unappeasable +unappeasably +unappeased +unappetizing +unappetizingly +unapplied +unappreciable +unappreciated +unappreciation +unappreciative +unappreciatively +unapprised +unapproachability +unapproachable +unapproachableness +unapproachably +unappropriated +unapproved +unapt +unaptly +unaptness +unarguable +unarguably +unarm +unarmed +unarming +unarmored +unarms +unarrogant +unarticulated +unartistic +unary +unascertainable +unascertained +unashamed +unashamedly +unashamedness +unasked +unaspirated +unassailability +unassailable +unassailableness +unassailably +unassailed +unassembled +unasserted +unassertive +unassertively +unassertiveness +unassigned +unassimilable +unassimilated +unassisted +unassociated +unassuageable +unassuaged +unassuming +unassumingly +unassumingness +unathletic +unattached +unattainability +unattainable +unattainableness +unattainably +unattained +unattended +unattenuated +unattested +unattractive +unattractively +unattractiveness +unattributable +unattributed +unattuned +unau +unaudited +unaus +unauthentic +unauthenticated +unauthorized +unautomated +unavailability +unavailable +unavailing +unavailingly +unavailingness +unaverage +unavoidability +unavoidable +unavoidableness +unavoidably +unavowed +unawake +unawakened +unawarded +unaware +unawarely +unawareness +unawares +unawesome +unbacked +unbaked +unbalance +unbalanceable +unbalanced +unbalances +unbalancing +unballasted +unban +unbandage +unbandaged +unbandages +unbandaging +unbanned +unbanning +unbans +unbaptized +unbar +unbarbed +unbarbered +unbarred +unbarricaded +unbarring +unbars +unbated +unbearable +unbearableness +unbearably +unbeatable +unbeatably +unbeaten +unbeautiful +unbeautifully +unbecoming +unbecomingly +unbecomingness +unbefitting +unbegotten +unbeholden +unbeknown +unbeknownst +unbelief +unbelievable +unbelievably +unbeliever +unbelievers +unbelieving +unbelievingly +unbelievingness +unbelligerent +unbeloved +unbelted +unbemused +unbend +unbendable +unbending +unbendingly +unbends +unbent +unbeseeming +unbiased +unbiasedly +unbiasedness +unbiassed +unbiblical +unbid +unbidden +unbigoted +unbilled +unbind +unbinding +unbinds +unbitted +unbitten +unbitter +unbleached +unblemished +unblenched +unblended +unblessed +unblessedness +unblest +unblinded +unblinking +unblinkingly +unblock +unblocked +unblocking +unblocks +unblooded +unblushing +unblushingly +unblushingness +unbodied +unbolt +unbolted +unbolting +unbolts +unbonneted +unbookish +unborn +unbosom +unbosomed +unbosomer +unbosomers +unbosoming +unbosoms +unbought +unbound +unbounded +unboundedly +unboundedness +unbowdlerized +unbowed +unbox +unboxed +unboxes +unboxing +unbrace +unbraced +unbraces +unbracing +unbracketed +unbraid +unbraided +unbraiding +unbraids +unbrake +unbraked +unbrakes +unbraking +unbranched +unbranded +unbreachable +unbreakable +unbreakableness +unbreakables +unbreakably +unbreathable +unbred +unbridgeable +unbridgeably +unbridged +unbridle +unbridled +unbridledly +unbridles +unbridling +unbriefed +unbright +unbrilliant +unbroke +unbroken +unbrokenly +unbrokenness +unbruised +unbrushed +unbuckle +unbuckled +unbuckles +unbuckling +unbudgeable +unbudgeably +unbudgeted +unbudging +unbudgingly +unbuffered +unbuild +unbuildable +unbuilding +unbuilds +unbuilt +unbulky +unbundle +unbundled +unbundles +unbundling +unbundlings +unburden +unburdened +unburdening +unburdens +unbureaucratic +unburied +unburnable +unburned +unburnt +unbusinesslike +unbusy +unbuttered +unbutton +unbuttoned +unbuttoning +unbuttons +uncage +uncaged +uncages +uncaging +uncalcified +uncalcined +uncalculated +uncalculating +uncalibrated +uncalled +uncalloused +uncanceled +uncandid +uncandidly +uncannier +uncanniest +uncannily +uncanniness +uncanny +uncanonical +uncap +uncapitalized +uncapped +uncapping +uncaps +uncaptioned +uncapturable +uncared +uncaring +uncaringly +uncarpeted +uncase +uncased +uncases +uncasing +uncastrated +uncataloged +uncatchable +uncatchy +uncategorizable +uncaught +uncaused +unceasing +unceasingly +unceasingness +uncelebrated +uncensored +uncensorious +uncensured +unceremonious +unceremoniously +unceremoniousness +uncertain +uncertainly +uncertainness +uncertainties +uncertainty +uncertified +unchain +unchainable +unchained +unchaining +unchains +unchallengeable +unchallengeably +unchallenged +unchallenging +unchancy +unchangeability +unchangeable +unchangeableness +unchangeably +unchanged +unchanging +unchangingly +unchangingness +unchanneled +unchaperoned +uncharacteristic +uncharacteristically +uncharacterized +uncharged +uncharismatic +uncharitable +uncharitableness +uncharitably +uncharming +uncharted +unchartered +unchaste +unchastely +unchasteness +unchaster +unchastest +unchastity +unchauvinistic +uncheck +uncheckable +unchecked +unchecking +unchecks +uncheerful +unchewable +unchewed +unchic +unchildlike +unchivalrous +unchivalrously +unchlorinated +unchoke +unchoked +unchokes +unchoking +unchoreographed +unchristened +unchristian +unchronicled +unchronological +unchurch +unchurched +unchurches +unchurching +unchurchly +unci +uncial +uncially +uncials +unciform +unciforms +unciliated +uncinaria +uncinarias +uncinariasis +uncinate +uncinematic +uncirculated +uncircumcised +uncircumcision +uncircumcisions +uncivil +uncivilized +uncivilizedly +uncivilizedness +uncivilly +uncivilness +unclad +unclaimed +unclamp +unclamped +unclamping +unclamps +unclarified +unclarities +unclarity +unclasp +unclasped +unclasping +unclasps +unclassical +unclassifiable +unclassified +uncle +unclean +uncleaned +uncleaner +uncleanest +uncleanlier +uncleanliest +uncleanliness +uncleanly +uncleanness +unclear +unclearer +unclearest +unclearly +unclearness +uncleless +unclench +unclenched +unclenches +unclenching +uncles +unclichéd +unclimbable +unclimbableness +unclinch +unclinched +unclinches +unclinching +unclip +unclipped +unclipping +unclips +uncloak +uncloaked +uncloaking +uncloaks +unclog +unclogged +unclogging +unclogs +unclose +unclosed +uncloses +unclosing +unclothe +unclothed +unclothes +unclothing +unclouded +uncloudedly +uncloying +unclubbable +unclutter +uncluttered +uncluttering +unclutters +uncoalesce +uncoalesced +uncoalesces +uncoalescing +uncoated +uncoating +uncock +uncocked +uncocking +uncocks +uncoded +uncodified +uncoerced +uncoercive +uncoercively +uncoffin +uncoffined +uncoffining +uncoffins +uncoil +uncoiled +uncoiling +uncoils +uncoined +uncollected +uncollectible +uncolored +uncombative +uncombed +uncombined +uncomely +uncomfortable +uncomfortableness +uncomfortably +uncomforted +uncomic +uncomment +uncommented +uncommenting +uncomments +uncommercial +uncommercialized +uncommitted +uncommon +uncommoner +uncommonest +uncommonly +uncommonness +uncommunicable +uncommunicative +uncommunicatively +uncommunicativeness +uncompahgre +uncompassionate +uncompelled +uncompelling +uncompensated +uncompetitive +uncompetitively +uncompetitiveness +uncomplacent +uncomplaining +uncomplainingly +uncompleted +uncomplicated +uncomplimentary +uncompounded +uncomprehended +uncomprehending +uncomprehendingly +uncompress +uncompressed +uncompresses +uncompressing +uncompromisable +uncompromising +uncompromisingly +uncompromisingness +uncomputerized +unconcealed +unconceivable +unconceivableness +unconceivably +unconcern +unconcerned +unconcernedly +unconcernedness +unconcluded +uncondensed +unconditional +unconditionality +unconditionally +unconditionalness +unconditioned +unconditionedness +unconfessed +unconfident +unconfidently +unconfined +unconfirmed +unconformability +unconformable +unconformableness +unconformably +unconformities +unconformity +unconfounded +unconfuse +unconfused +unconfuses +unconfusing +uncongealed +uncongenial +uncongeniality +unconjugated +unconnected +unconnectedly +unconnectedness +unconquerable +unconquerably +unconquered +unconscionability +unconscionable +unconscionableness +unconscionably +unconscious +unconsciously +unconsciousness +unconsecrated +unconsidered +unconsolidated +unconstitutional +unconstitutionality +unconstitutionally +unconstrained +unconstraint +unconstricted +unconstructed +unconstructive +unconsumed +unconsummated +uncontainable +uncontaminated +uncontemplated +uncontemporary +uncontentious +uncontested +uncontracted +uncontradicted +uncontrived +uncontrollability +uncontrollable +uncontrollableness +uncontrollably +uncontrolled +uncontrolledness +uncontroversial +uncontroversially +unconventional +unconventionality +unconventionally +unconverted +unconvertible +unconvinced +unconvincing +unconvincingly +unconvincingness +unconvoyed +uncooked +uncool +uncooled +uncooperative +uncooperatively +uncooperativeness +uncoordinated +uncoordinatedly +uncopyrightable +uncork +uncorked +uncorking +uncorks +uncorrectable +uncorrected +uncorrelated +uncorroborated +uncorrupt +uncorrupted +uncorrupting +uncorseted +uncountable +uncounted +uncouple +uncoupled +uncoupler +uncouplers +uncouples +uncoupling +uncourageous +uncouth +uncouthly +uncouthness +uncovenanted +uncover +uncovered +uncovering +uncovers +uncoy +uncracked +uncrate +uncrated +uncrates +uncrating +uncrazy +uncreated +uncreative +uncredentialed +uncredited +uncrewed +uncrippled +uncritical +uncritically +uncropped +uncross +uncrossable +uncrossed +uncrosses +uncrossing +uncrowded +uncrown +uncrowned +uncrowning +uncrowns +uncrumple +uncrumpled +uncrumples +uncrumpling +uncrushable +uncrushed +uncrystallized +unction +unctuosity +unctuous +unctuously +unctuousness +uncuff +uncuffed +uncuffing +uncuffs +uncultivable +uncultivated +uncultured +uncurbed +uncured +uncurious +uncurl +uncurled +uncurling +uncurls +uncurrent +uncurtained +uncus +uncustomarily +uncustomary +uncut +uncute +uncuttable +uncynical +uncynically +und +undamaged +undamped +undanceable +undated +undauntable +undaunted +undauntedly +undauntedness +undead +undebatable +undebatably +undecadent +undecayed +undeceivable +undeceivably +undeceive +undeceived +undeceives +undeceiving +undecidability +undecidable +undecided +undecidedly +undecidedness +undecideds +undecillion +undecillions +undecipherable +undeciphered +undecked +undeclared +undecomposed +undecorated +undecylenic +undedicated +undefeatable +undefeated +undefended +undefiled +undefinable +undefined +undeflected +undefoliated +undeformed +undelegated +undelete +undeleted +undeliverable +undeliverably +undelivered +undeluded +undemanding +undemocratic +undemocratically +undemonstrated +undemonstrative +undemonstratively +undemonstrativeness +undeniable +undeniableness +undeniably +undenominational +undented +undependability +undependable +under +underachieve +underachieved +underachievement +underachiever +underachievers +underachieves +underachieving +underact +underacted +underacting +underactive +underactivity +underacts +underage +underaged +underappreciated +underarm +underarms +underassessment +underbellies +underbelly +underbid +underbidder +underbidders +underbidding +underbids +underbodies +underbody +underboss +underbosses +underbought +underbracing +underbred +underbrim +underbrims +underbrush +underbudgeted +underbuy +underbuying +underbuys +undercapitalization +undercapitalizations +undercapitalize +undercapitalized +undercapitalizes +undercapitalizing +undercard +undercards +undercarriage +undercarriages +undercharge +undercharged +undercharges +undercharging +underclass +underclasses +underclassman +underclassmen +underclothes +underclothing +undercoat +undercoated +undercoating +undercoats +undercook +undercooked +undercooking +undercooks +undercool +undercooled +undercooling +undercools +undercount +undercounted +undercounting +undercounts +undercover +undercroft +undercrofts +undercurrent +undercurrents +undercut +undercuts +undercutting +underdeveloped +underdevelopment +underdid +underdo +underdoes +underdog +underdogs +underdoing +underdone +underdrawers +underdress +underdressed +underdresses +underdressing +underdrive +underdrives +undereducated +underemphasis +underemphasize +underemphasized +underemphasizes +underemphasizing +underemployed +underemployment +underendow +underendowed +underendowing +underendowment +underendows +underestimate +underestimated +underestimates +underestimating +underestimation +underestimations +underexpose +underexposed +underexposes +underexposing +underexposure +underexposures +underfed +underfeed +underfeeding +underfeeds +underfinanced +underflow +underflows +underfoot +underfund +underfunded +underfunding +underfunds +underfur +underfurs +undergarment +undergarments +undergird +undergirded +undergirding +undergirds +undergirt +underglaze +underglazes +undergo +undergoes +undergoing +undergone +undergrad +undergrads +undergraduate +undergraduates +underground +undergrounded +undergrounder +undergrounders +undergrounding +undergrounds +undergrown +undergrowth +underhair +underhairs +underhand +underhanded +underhandedly +underhandedness +underhung +underinflated +underinflation +underinsurance +underinsure +underinsured +underinsures +underinsuring +underinvestment +underkill +underlaid +underlain +underlay +underlaying +underlayment +underlayments +underlays +underlet +underlets +underletting +underlie +underlies +underline +underlined +underlines +underling +underlings +underlining +underlinings +underlip +underlips +underlying +underlyingly +undermanned +undermine +undermined +undermines +undermining +undermodulate +undermodulated +undermodulates +undermodulating +undermodulation +undermodulations +undermost +underneath +underneaths +undernourish +undernourished +undernourishes +undernourishing +undernourishment +undernutrition +undernutritions +underpaid +underpainting +underpants +underpart +underparts +underpass +underpasses +underpay +underpaying +underpayment +underpayments +underpays +underperform +underperformance +underperformances +underperformed +underperformer +underperformers +underperforming +underperforms +underpin +underpinned +underpinning +underpinnings +underpins +underplay +underplayed +underplaying +underplays +underplot +underplots +underpopulated +underpopulation +underpowered +underprepared +underprice +underpriced +underprices +underpricing +underprivileged +underproduce +underproduced +underproduces +underproducing +underproduction +underproductions +underproductive +underproof +underprop +underpropped +underpropping +underprops +underpublicized +underquote +underquoted +underquotes +underquoting +underran +underrate +underrated +underrates +underrating +underreact +underreacted +underreacting +underreaction +underreactions +underreacts +underreport +underreported +underreporting +underreports +underrepresent +underrepresentation +underrepresentations +underrepresented +underrepresenting +underrepresents +underrun +underrunning +underruns +undersaturated +underscore +underscored +underscores +underscoring +undersea +underseas +undersecretariat +undersecretariats +undersecretaries +undersecretary +undersell +underseller +undersellers +underselling +undersells +underserve +underserved +underserves +underserving +underset +undersets +undersexed +undershirt +undershirted +undershirts +undershoot +undershooting +undershoots +undershorts +undershot +undershrub +undershrubs +underside +undersides +undersign +undersigned +undersigning +undersigns +undersize +undersized +underskirt +underskirts +undersleeve +undersleeves +underslung +undersoil +undersoils +undersold +underspin +underspins +understaff +understaffed +understaffing +understaffs +understand +understandability +understandable +understandably +understanding +understandingly +understandings +understands +understate +understated +understatedly +understatement +understatements +understates +understating +understeer +understeered +understeering +understeers +understood +understories +understory +understrapper +understrappers +understrata +understratum +understratums +understrength +understructure +understructures +understudied +understudies +understudy +understudying +undersubscribe +undersubscribed +undersubscribes +undersubscribing +undersubscription +undersubscriptions +undersupplied +undersupplies +undersupply +undersupplying +undersurface +undersurfaces +undertake +undertaken +undertaker +undertakers +undertakes +undertaking +undertakings +undertenant +undertenants +underthings +underthrust +underthrusting +underthrusts +undertint +undertints +undertone +undertones +undertook +undertow +undertows +undertrick +undertricks +undertrump +undertrumped +undertrumping +undertrumps +underused +underutilization +underutilize +underutilized +underutilizes +underutilizing +undervaluation +undervaluations +undervalue +undervalued +undervalues +undervaluing +undervest +undervests +underwater +underway +underwear +underweight +underwent +underwhelm +underwhelmed +underwhelming +underwhelms +underwing +underwings +underwood +underwoods +underwool +underwools +underworld +underworlds +underwrite +underwriter +underwriters +underwrites +underwriting +underwritten +underwrote +undescended +undescribable +undeserved +undeservedly +undeserving +undeservingly +undesignated +undesigning +undesirability +undesirable +undesirableness +undesirables +undesirably +undesired +undestroyed +undetached +undetectable +undetectably +undetected +undeterminable +undetermined +undeterred +undeveloped +undeviating +undeviatingly +undiagnosable +undiagnosed +undialectical +undid +undidactic +undies +undifferentiated +undiffused +undigested +undigestible +undignified +undiluted +undiminished +undimmed +undimpled +undine +undines +undiplomatic +undiplomatically +undirected +undiscerning +undischarged +undisciplined +undisclosed +undiscouraged +undiscoverable +undiscovered +undiscriminating +undiscussed +undisguised +undisguisedly +undismayed +undisposed +undisputable +undisputed +undisputedly +undisrupted +undissociated +undissolved +undistinguished +undistinguishing +undistorted +undistracted +undistributed +undisturbed +undivided +undividedly +undo +undoable +undocile +undock +undocked +undocking +undocks +undoctored +undoctrinaire +undocumented +undocumenteds +undoer +undoers +undoes +undogmatic +undogmatically +undoing +undomestic +undomesticated +undone +undotted +undouble +undoubled +undoubles +undoubling +undoubtable +undoubted +undoubtedly +undoubting +undrained +undramatic +undramatically +undramatized +undrape +undraped +undrapes +undraping +undraw +undrawing +undrawn +undraws +undreamed +undreamt +undress +undressed +undresses +undressing +undrew +undrilled +undrinkable +undrunk +undubbed +undue +undulant +undulate +undulated +undulates +undulating +undulation +undulations +undulatory +undulled +unduly +unduplicated +undusted +undutiful +undutifully +undutifulness +undyed +undying +undyingly +undynamic +uneager +unearmarked +unearned +unearth +unearthed +unearthing +unearthlier +unearthliest +unearthliness +unearthly +unearths +unease +uneasier +uneasiest +uneasily +uneasiness +uneasy +uneatable +uneaten +uneccentric +unecological +uneconomic +uneconomical +uneconomically +unedifying +unedifyingly +unedited +uneducable +uneducated +unelaborate +unelaborated +unelectable +unelected +unelectrified +unembarrassed +unembellished +unembittered +unemotional +unemotionally +unemphatic +unemphatically +unempirical +unemployability +unemployable +unemployables +unemployed +unemployment +unenchanted +unenclosed +unencouraging +unencumbered +unendearing +unending +unendingly +unendorsed +unendurable +unendurableness +unendurably +unenforceable +unenforced +unengaged +unenlarged +unenlightened +unenlightening +unenriched +unenterprising +unentertaining +unenthusiastic +unenthusiastically +unenviable +unenvied +unenvious +unequal +unequaled +unequalize +unequalized +unequalizes +unequalizing +unequalled +unequally +unequals +unequipped +unequivocably +unequivocal +unequivocally +unerotic +unerring +unerringly +unescapable +unesco +unescorted +unessential +unessentials +unestablished +unethical +unethically +unevaluated +uneven +unevener +unevenest +unevenly +unevenness +uneventful +uneventfully +uneventfulness +unexacting +unexaggerated +unexamined +unexampled +unexcelled +unexceptionable +unexceptionableness +unexceptionably +unexceptional +unexceptionally +unexcitable +unexcited +unexciting +unexcused +unexecuted +unexercised +unexhausted +unexotic +unexpanded +unexpected +unexpectedly +unexpectedness +unexpended +unexpired +unexplainable +unexplainably +unexplained +unexploded +unexploited +unexplored +unexposed +unexpressed +unexpressive +unexpressively +unexpressiveness +unexpurgated +unextraordinary +unfading +unfadingly +unfailing +unfailingly +unfailingness +unfair +unfairer +unfairest +unfairly +unfairness +unfaith +unfaithful +unfaithfully +unfaithfulness +unfaked +unfallen +unfalsifiable +unfaltering +unfalteringly +unfamiliar +unfamiliarity +unfamiliarly +unfamous +unfancy +unfashionable +unfashionableness +unfashionably +unfasten +unfastened +unfastening +unfastens +unfastidious +unfathered +unfathomable +unfathomed +unfavorable +unfavorableness +unfavorably +unfavorite +unfazed +unfeasibility +unfeasible +unfecundated +unfeeling +unfeelingly +unfeelingness +unfeigned +unfeignedly +unfelt +unfeminine +unfenced +unfermented +unfertile +unfertilized +unfetter +unfettered +unfettering +unfetters +unfilial +unfilially +unfilled +unfiltered +unfindable +unfinished +unfired +unfit +unfitly +unfitness +unfits +unfitted +unfitting +unfittingly +unfix +unfixable +unfixed +unfixes +unfixing +unflagging +unflaggingly +unflamboyant +unflappability +unflappable +unflappably +unflapped +unflashy +unflattering +unflatteringly +unflavored +unflawed +unfledged +unflinching +unflinchingly +unflinchingness +unflustered +unflyable +unfocused +unfocussed +unfold +unfolded +unfolding +unfoldment +unfolds +unfond +unforced +unforeseeable +unforeseeably +unforeseen +unforested +unforgettability +unforgettable +unforgettableness +unforgettably +unforgivable +unforgivably +unforgiving +unforgivingness +unforgotten +unforked +unformatted +unformed +unformulated +unforthcoming +unfortified +unfortunate +unfortunately +unfortunateness +unfortunates +unfossiliferous +unfound +unfounded +unfoundedly +unfoundedness +unframed +unfree +unfreedom +unfreeze +unfreezes +unfreezing +unfrequented +unfriended +unfriendlier +unfriendliest +unfriendliness +unfriendly +unfrivolous +unfrock +unfrocked +unfrocking +unfrocks +unfrosted +unfroze +unfrozen +unfruitful +unfruitfully +unfruitfulness +unfulfillable +unfulfilled +unfulfilling +unfunded +unfunny +unfurl +unfurled +unfurling +unfurls +unfurnished +unfused +unfussily +unfussy +ungainlier +ungainliest +ungainliness +ungainly +ungallant +ungallantly +ungarnished +ungava +ungenerosity +ungenerous +ungenerously +ungenial +ungenteel +ungentle +ungentlemanly +ungentrified +ungerminated +ungifted +ungimmicky +ungird +ungirded +ungirding +ungirds +ungirt +unglamorized +unglamorous +unglamorously +unglazed +unglue +unglued +unglues +ungluing +ungodlier +ungodliest +ungodliness +ungodly +ungot +ungotten +ungovernable +ungovernableness +ungovernably +ungoverned +ungraceful +ungracefully +ungracious +ungraciously +ungraciousness +ungraded +ungrammatical +ungrammaticality +ungrammatically +ungraspable +ungrateful +ungratefully +ungratefulness +ungratified +unground +ungrounded +ungrouped +ungrudging +ungrudgingly +ungual +unguard +unguarded +unguardedly +unguardedness +unguarding +unguards +unguent +unguentary +unguents +ungues +unguessable +unguiculate +unguiculated +unguided +unguis +ungula +ungulate +ungulates +unguligrade +unguligrades +unhackneyed +unhallow +unhallowed +unhallowing +unhallows +unhampered +unhand +unhanded +unhandier +unhandiest +unhandily +unhandiness +unhanding +unhands +unhandsome +unhandsomely +unhandsomeness +unhandy +unhappier +unhappiest +unhappily +unhappiness +unhappinesses +unhappy +unhardened +unharmed +unharmonious +unharness +unharnessed +unharnesses +unharnessing +unharvested +unhatched +unhealed +unhealthful +unhealthier +unhealthiest +unhealthily +unhealthiness +unhealthy +unheard +unhearing +unheated +unhedged +unheeded +unheeding +unheedingly +unhelpful +unhelpfully +unheralded +unheroic +unhesitant +unhesitating +unhesitatingly +unhidden +unhighlight +unhighlighted +unhighlighting +unhighlights +unhindered +unhinge +unhinged +unhinges +unhinging +unhip +unhistorical +unhitch +unhitched +unhitches +unhitching +unholier +unholiest +unholily +unholiness +unholy +unhomogenized +unhonored +unhood +unhooded +unhooding +unhoods +unhook +unhooked +unhooking +unhooks +unhoped +unhopeful +unhorse +unhorsed +unhorses +unhorsing +unhoused +unhouseled +unhumorous +unhurried +unhurriedly +unhurt +unhydrolyzed +unhygienic +unhyphenated +unhysterical +unhysterically +unialgal +uniat +uniate +uniaxial +uniaxially +unicameral +unicamerally +unicef +unicellular +unicellularity +unicolor +unicorn +unicorns +unicostate +unicuspid +unicuspids +unicycle +unicycles +unicyclist +unicyclists +unidentifiable +unidentifiably +unidentified +unideological +unidimensional +unidimensionality +unidiomatic +unidirectional +unidirectionally +unifactorial +unifiable +unification +unifications +unified +unifier +unifiers +unifies +unifilar +uniflow +unifoliate +unifoliolate +uniform +uniformed +uniforming +uniformitarian +uniformitarianism +uniformitarians +uniformity +uniformly +uniformness +uniforms +unify +unifying +unignorable +unilateral +unilateralism +unilateralisms +unilateralist +unilateralists +unilaterally +unilineal +unilinear +unilingual +unilingually +uniliteral +unilluminated +unilluminating +unillusioned +unillustrated +unilobar +unilocular +unimaginable +unimaginably +unimaginative +unimaginatively +unimagined +unimak +unimmunized +unimpaired +unimpassioned +unimpeachable +unimpeachably +unimpeded +unimplemented +unimportance +unimportant +unimposing +unimpressed +unimpressionable +unimpressive +unimpressively +unimproved +unincorporated +unindexed +unindicted +unindustrialized +uninfected +uninflammable +uninflated +uninflected +uninfluenced +uninformative +uninformatively +uninformed +uningratiating +uninhabitability +uninhabitable +uninhabited +uninhibited +uninhibitedly +uninhibitedness +uninitialized +uninitiate +uninitiated +uninitiates +uninjured +uninoculated +uninominal +uninspected +uninspired +uninspiring +uninstalled +uninstructed +uninstructive +uninsulated +uninsurability +uninsurable +uninsured +uninsureds +unintegrated +unintellectual +unintelligence +unintelligent +unintelligently +unintelligibility +unintelligible +unintelligibleness +unintelligibly +unintended +unintentional +unintentionally +uninterest +uninterested +uninterestedly +uninterestedness +uninteresting +uninterestingly +uninterrupted +uninterruptedly +unintimidated +unintuitive +uninucleate +uninventive +uninvestigated +uninvited +uninviting +uninvitingly +uninvolved +union +unionism +unionist +unionistic +unionists +unionization +unionizations +unionize +unionized +unionizer +unionizers +unionizes +unionizing +unions +uniparental +uniparentally +uniparous +uniped +unipersonal +uniplanar +unipolar +unipolarity +unipotent +unique +uniquely +uniqueness +unironically +unirradiated +unirrigated +uniserial +uniseriate +unisex +unisexual +unisexuality +unisexually +unison +unisonant +unisonous +unisons +unissued +unit +unitage +unitard +unitards +unitarian +unitarianism +unitarians +unitarily +unitary +unite +united +unitedly +unitedness +uniter +uniters +unites +unities +uniting +unitive +unitization +unitizations +unitize +unitized +unitizes +unitizing +unitrust +unitrusts +units +unity +univalent +univalents +univalve +univalves +univariate +universal +universalism +universalist +universalistic +universalists +universalities +universality +universalizability +universalization +universalizations +universalize +universalized +universalizes +universalizing +universally +universalness +universals +universe +universes +universities +university +univocal +univocally +univocals +unix +unjacketed +unjaded +unjoined +unjoint +unjointed +unjointing +unjoints +unjust +unjustifiable +unjustifiably +unjustified +unjustly +unjustness +unjustnesses +unkempt +unkennel +unkenneled +unkenneling +unkennelled +unkennelling +unkennels +unkept +unkind +unkinder +unkindest +unkindlier +unkindliest +unkindliness +unkindly +unkindness +unkindnesses +unkink +unkinked +unkinking +unkinks +unknit +unknits +unknitted +unknitting +unknot +unknots +unknotted +unknotting +unknowability +unknowable +unknowableness +unknowably +unknowing +unknowingly +unknowingness +unknowledgeable +unknown +unknowns +unkosher +unlabeled +unlabored +unlace +unlaced +unlaces +unlacing +unlade +unladed +unladen +unlades +unlading +unladylike +unlaid +unlamented +unlash +unlashed +unlashes +unlashing +unlatch +unlatched +unlatches +unlatching +unlaundered +unlawful +unlawfully +unlawfulness +unlay +unlaying +unlays +unlead +unleaded +unleading +unleads +unlearn +unlearnable +unlearned +unlearnedly +unlearning +unlearns +unlearnt +unleash +unleashed +unleashes +unleashing +unleavened +unless +unlettered +unleveled +unliberated +unlicensed +unlicked +unlighted +unlikable +unlike +unlikelier +unlikeliest +unlikelihood +unlikeliness +unlikely +unlikeness +unlimber +unlimbered +unlimbering +unlimbers +unlimited +unlimitedly +unlimitedness +unlined +unlink +unlinked +unlinking +unlinks +unliquidated +unlisted +unlistenable +unlit +unliterary +unlivable +unlive +unlived +unlives +unliving +unload +unloaded +unloader +unloaders +unloading +unloads +unlocalized +unlock +unlocked +unlocking +unlocks +unlooked +unloose +unloosed +unloosen +unloosened +unloosening +unloosens +unlooses +unloosing +unlovable +unloved +unlovelier +unloveliest +unloveliness +unlovely +unloving +unluckier +unluckiest +unluckily +unluckiness +unlucky +unlyrical +unmacho +unmade +unmagnified +unmake +unmakes +unmaking +unmalicious +unmaliciously +unman +unmanageability +unmanageable +unmanageably +unmanaged +unmanipulated +unmanlier +unmanliest +unmanliness +unmanly +unmanned +unmannered +unmanneredly +unmannerliness +unmannerly +unmanning +unmans +unmapped +unmarked +unmarketable +unmarred +unmarriageable +unmarried +unmarrieds +unmasculine +unmask +unmasked +unmasking +unmasks +unmatchable +unmatched +unmated +unmeaning +unmeaningly +unmeant +unmeasurable +unmeasured +unmechanical +unmechanically +unmechanized +unmediated +unmedicated +unmeet +unmelodic +unmelodious +unmelodiousness +unmemorable +unmemorably +unmentionable +unmentionableness +unmentionables +unmentionably +unmentioned +unmerciful +unmercifully +unmercifulness +unmerited +unmeritorious +unmerry +unmeshed +unmet +unmetabolized +unmethodical +unmethodically +unmilitary +unmilled +unmindful +unmindfully +unmindfulness +unmined +unmingled +unmissed +unmistakable +unmistakably +unmitigated +unmitigatedly +unmitigatedness +unmix +unmixable +unmixed +unmixedly +unmixes +unmixing +unmodernized +unmodified +unmodish +unmold +unmolded +unmolding +unmolds +unmolested +unmonitored +unmoor +unmoored +unmooring +unmoors +unmoral +unmorality +unmorally +unmortise +unmortised +unmortises +unmortising +unmotivated +unmounted +unmovable +unmoved +unmoving +unmuffle +unmuffled +unmuffles +unmuffling +unmurmuring +unmusical +unmusically +unmusicalness +unmuzzle +unmuzzled +unmuzzles +unmuzzling +unmyelinated +unnail +unnailed +unnailing +unnails +unnamable +unnameable +unnamed +unnatural +unnaturally +unnaturalness +unnecessarily +unnecessary +unneeded +unnegotiable +unnerve +unnerved +unnerves +unnerving +unnervingly +unneurotic +unnewsworthy +unnilhexium +unnilpentium +unnilquadium +unnilquintium +unnormalized +unnoted +unnoticeable +unnoticeably +unnoticed +unnoticing +unnourished +unnourishing +unnumbered +unobjectionable +unobscured +unobservable +unobservant +unobserved +unobserving +unobstructed +unobtainable +unobtrusive +unobtrusively +unobtrusiveness +unoccupied +unoffending +unofficial +unofficially +unopenable +unopened +unopposed +unordered +unordinary +unorganized +unoriginal +unornament +unornamented +unornamenting +unornaments +unorthodox +unorthodoxly +unorthodoxy +unostentatious +unostentatiously +unostentatiousness +unowned +unoxygenated +unpack +unpacked +unpacker +unpackers +unpacking +unpacks +unpadded +unpaged +unpaginated +unpaid +unpainted +unpaired +unpalatability +unpalatable +unpalatably +unparalleled +unparasitized +unpardonable +unparliamentary +unparsed +unparticular +unpartisan +unpassable +unpasteurized +unpastoral +unpatentable +unpatriotic +unpatriotically +unpatronizing +unpaved +unpedantic +unpeeled +unpeg +unpegged +unpegging +unpegs +unpeople +unpeopled +unpeoples +unpeopling +unperceived +unperceiving +unperceptive +unperfect +unperfected +unperforated +unperformable +unperformed +unperson +unpersuaded +unpersuasive +unperturbed +unphysical +unpick +unpicked +unpicking +unpicks +unpicturesque +unpile +unpiled +unpiles +unpiling +unpin +unpinned +unpinning +unpins +unpitying +unpityingly +unplaced +unplanned +unplanted +unplausible +unplayable +unpleasant +unpleasantly +unpleasantness +unpleasantries +unpleasantry +unpleased +unpleasing +unplowed +unplug +unplugged +unplugging +unplugs +unplumbed +unpoetic +unpolarized +unpoliced +unpolished +unpolitical +unpolled +unpolluted +unpopular +unpopularity +unpopulated +unposed +unpractical +unpracticed +unprecedented +unprecedentedly +unpredictability +unpredictable +unpredictables +unpredictably +unpredicted +unpregnant +unprejudiced +unpremeditated +unpremeditatedly +unprepared +unpreparedly +unpreparedness +unprepossessing +unprepossessingly +unpressed +unpressured +unpressurized +unpresuming +unpretending +unpretentious +unpretentiously +unpretentiousness +unpretty +unpriced +unprimed +unprincipled +unprincipledness +unprintable +unprintably +unprivileged +unproblematic +unprocessed +unprocurable +unproduced +unproductive +unproductively +unproductiveness +unprofaned +unprofessed +unprofessional +unprofessionalism +unprofessionally +unprofitability +unprofitable +unprofitableness +unprofitably +unprogrammable +unprogrammed +unprogressive +unprolific +unpromising +unpromisingly +unprompted +unpronounceable +unpronounced +unpropitious +unpropitiously +unprosperous +unprotected +unprovable +unproved +unproven +unprovided +unprovidedly +unprovoked +unpruned +unpublicized +unpublishable +unpublished +unpunctual +unpunctuality +unpunctuated +unpunished +unpurified +unputdownable +unqualified +unqualifiedly +unquantifiable +unquantified +unquenchable +unquenchably +unquenched +unquestionability +unquestionable +unquestionableness +unquestionably +unquestioned +unquestioning +unquestioningly +unquiet +unquieter +unquietest +unquietly +unquietness +unquotable +unquote +unquoted +unraised +unranked +unrated +unravel +unraveled +unraveling +unravelled +unravelling +unravels +unravished +unreachability +unreachable +unreachably +unreached +unread +unreadability +unreadable +unreadier +unreadiest +unreadily +unreadiness +unready +unreal +unrealistic +unrealistically +unrealities +unreality +unrealizable +unrealized +unreason +unreasonable +unreasonableness +unreasonably +unreasoned +unreasoning +unreasoningly +unreassuringly +unrecalled +unreceptive +unreckonable +unreclaimable +unreclaimed +unrecognizable +unrecognizableness +unrecognizably +unrecognized +unrecognizing +unrecompensed +unreconcilable +unreconciled +unreconstructed +unrecorded +unrecoverable +unrecovered +unrectified +unrecyclable +unredeemable +unredeemed +unredressed +unreduced +unreel +unreeled +unreeling +unreels +unreeve +unreeved +unreeves +unreeving +unrefined +unreflecting +unreflectingly +unreflective +unreflectively +unreformed +unrefrigerated +unregenerable +unregeneracy +unregenerate +unregenerately +unregimented +unregistered +unregulated +unrehearsed +unreinforced +unrelated +unrelaxed +unreleased +unrelenting +unrelentingly +unreliability +unreliable +unreliableness +unreliably +unrelieved +unrelievedly +unreligious +unreluctant +unremarkable +unremarkably +unremarked +unremembered +unreminiscent +unremitting +unremittingly +unremittingness +unremovable +unremunerated +unremunerative +unrenowned +unrepaired +unrepeatable +unrepentant +unrepentantly +unreported +unrepresentative +unrepresentativeness +unrepresented +unrepressed +unreproved +unrequited +unrequitedly +unreserve +unreserved +unreservedly +unreservedness +unresistant +unresisting +unresistingly +unresolvable +unresolved +unrespectable +unresponsive +unresponsively +unresponsiveness +unrest +unrestful +unrestored +unrestrained +unrestrainedly +unrestrainedness +unrestraint +unrestraints +unrestricted +unrestrictedly +unretouched +unreturnable +unrevealed +unrevealing +unrevealingly +unreviewable +unreviewed +unrevised +unrevolutionary +unrewarded +unrewarding +unrhetorical +unrhymed +unrhythmic +unridable +unriddle +unriddled +unriddler +unriddlers +unriddles +unriddling +unrifled +unrig +unrigged +unrigging +unrighteous +unrighteously +unrighteousness +unrightfully +unrigs +unrip +unripe +unripened +unripeness +unriper +unripest +unripped +unripping +unrips +unrivaled +unrivalled +unrobed +unroll +unrolled +unrolling +unrolls +unromantic +unromantically +unromanticized +unroof +unroofed +unroofing +unroofs +unroot +unrooted +unrooting +unroots +unround +unrounded +unrounding +unrounds +unrove +unroven +unruffled +unruled +unrulier +unruliest +unruliness +unruly +unrushed +uns +unsacred +unsaddle +unsaddled +unsaddles +unsaddling +unsafe +unsafer +unsafest +unsaid +unsalable +unsalaried +unsalted +unsalvageable +unsanctified +unsanctioned +unsanitary +unsatisfactorily +unsatisfactoriness +unsatisfactory +unsatisfied +unsatisfiedness +unsatisfying +unsatisfyingly +unsaturate +unsaturated +unsaturates +unsaved +unsavorily +unsavoriness +unsavory +unsay +unsayable +unsayables +unsaying +unsays +unscalable +unscarred +unscathed +unscented +unscheduled +unscholarly +unschooled +unscientific +unscientifically +unscramble +unscrambled +unscrambler +unscramblers +unscrambles +unscrambling +unscratched +unscreened +unscrew +unscrewed +unscrewing +unscrews +unscripted +unscriptural +unscrupulous +unscrupulously +unscrupulousness +unseal +unsealed +unsealing +unseals +unseam +unseamed +unseaming +unseams +unsearchable +unsearchably +unseasonable +unseasonableness +unseasonably +unseasoned +unseat +unseated +unseating +unseats +unseaworthy +unsecured +unseeded +unseeing +unseeingly +unseemlier +unseemliest +unseemliness +unseemly +unseen +unsegmented +unsegregated +unselected +unselective +unselectively +unself +unselfconscious +unselfconsciously +unselfconsciousness +unselfish +unselfishly +unselfishness +unsell +unsellable +unselling +unsells +unsensational +unsensitized +unsent +unsentimental +unsentimentally +unseparated +unserious +unseriousness +unserved +unserviceable +unset +unsetting +unsettle +unsettled +unsettledness +unsettlement +unsettles +unsettling +unsettlingly +unsew +unsewed +unsewing +unsewn +unsex +unsexed +unsexes +unsexing +unsexual +unsexy +unshackle +unshackled +unshackles +unshackling +unshaded +unshakable +unshakably +unshaken +unshaped +unshapely +unshapen +unshared +unsharp +unsharpened +unshaved +unshaven +unsheathe +unsheathed +unsheathes +unsheathing +unshed +unshell +unshelled +unshelling +unshells +unsheltered +unshielded +unshift +unshifted +unshifting +unshifts +unship +unshipped +unshipping +unships +unshockable +unshod +unshorn +unshowy +unshrinking +unsight +unsighted +unsighting +unsightlier +unsightliest +unsightliness +unsightly +unsights +unsigned +unsinkable +unsized +unskilled +unskillful +unskillfully +unskillfulness +unslakable +unslaked +unsleeping +unsling +unslinging +unslings +unslung +unsmart +unsmiling +unsmilingly +unsmoothed +unsnag +unsnagged +unsnagging +unsnags +unsnap +unsnapped +unsnapping +unsnaps +unsnarl +unsnarled +unsnarling +unsnarls +unsociability +unsociable +unsociableness +unsociably +unsocial +unsocially +unsoiled +unsold +unsolder +unsoldered +unsoldering +unsolders +unsoldierly +unsolicited +unsolvable +unsolved +unsophisticated +unsophisticatedly +unsophisticatedness +unsophistication +unsorted +unsought +unsound +unsounded +unsounder +unsoundest +unsoundly +unsoundness +unsowed +unsown +unsparing +unsparingly +unsparingness +unspeak +unspeakable +unspeakableness +unspeakably +unspeaking +unspeaks +unspecialized +unspecifiable +unspecific +unspecified +unspectacular +unspectacularly +unspent +unsphere +unsphered +unspheres +unsphering +unspiritual +unsplit +unspoiled +unspoilt +unspoke +unspoken +unsporting +unsportsmanlike +unspotted +unspottedness +unsprayed +unsprung +unstable +unstableness +unstabler +unstablest +unstably +unstained +unstamped +unstandardized +unstapled +unstaring +unstartling +unstated +unstaunched +unstayed +unsteadied +unsteadier +unsteadies +unsteadiest +unsteadily +unsteadiness +unsteady +unsteadying +unsteel +unsteeled +unsteeling +unsteels +unstep +unstepped +unstepping +unsteps +unsterile +unsterilized +unstick +unsticking +unsticks +unstilted +unstinted +unstinting +unstintingly +unstirred +unstitch +unstitched +unstitches +unstitching +unstop +unstoppable +unstoppably +unstopped +unstopper +unstopping +unstops +unstrained +unstrap +unstrapped +unstrapping +unstraps +unstratified +unstressed +unstriated +unstring +unstringing +unstrings +unstructured +unstrung +unstuck +unstudied +unstuffy +unstylish +unsubdued +unsubscribe +unsubscribed +unsubscribes +unsubscribing +unsubsidized +unsubstantial +unsubstantiality +unsubstantially +unsubstantiated +unsubtle +unsubtly +unsuccess +unsuccessful +unsuccessfully +unsuccessfulness +unsuitability +unsuitable +unsuitableness +unsuitably +unsuited +unsullied +unsung +unsupervised +unsupportable +unsupported +unsuppressed +unsure +unsurpassable +unsurpassed +unsurprised +unsurprising +unsurprisingly +unsusceptible +unsuspected +unsuspectedly +unsuspecting +unsuspectingly +unsuspended +unsuspicious +unsustainable +unswathe +unswathed +unswathes +unswathing +unswayable +unswear +unswearing +unswears +unsweetened +unswerving +unswervingly +unswore +unsworn +unsymmetrical +unsymmetrically +unsympathetic +unsympathetically +unsynchronized +unsystematic +unsystematically +unsystematized +untactful +untagged +untainted +untalented +untamable +untamed +untangle +untangled +untangles +untangling +untanned +untapped +untarnished +untaught +untaxed +unteach +unteachable +unteaches +unteaching +untechnical +untellable +untempered +untenability +untenable +untenableness +untenably +untenanted +untended +untented +untenured +untestable +untested +untether +untethered +untethering +untethers +unthankful +unthankfully +unthankfulness +unthawed +unthawing +untheoretical +untheorized +unthink +unthinkability +unthinkable +unthinkableness +unthinkably +unthinking +unthinkingly +unthinkingness +unthinks +unthought +unthread +unthreaded +unthreading +unthreads +unthreatening +unthrift +unthrifty +unthrone +unthroned +unthrones +unthroning +untidier +untidiest +untidily +untidiness +untidy +untie +untied +unties +until +untillable +untilled +untimelier +untimeliest +untimeliness +untimely +untiring +untiringly +untitled +unto +untogether +untold +untouchability +untouchable +untouchables +untouchably +untouched +untoward +untowardly +untowardness +untraceable +untracked +untraditional +untraditionally +untrained +untrammeled +untransformed +untranslatability +untranslatable +untranslated +untraveled +untraversed +untread +untreading +untreads +untreatable +untreatably +untreated +untrendy +untried +untrimmed +untrod +untrodden +untroubled +untroubledness +untrue +untruer +untruest +untruly +untruss +untrussed +untrusses +untrussing +untrusting +untrustworthily +untrustworthiness +untrustworthy +untruth +untruthful +untruthfully +untruthfulness +untruths +untuck +untucked +untucking +untucks +untufted +untune +untuned +untunes +untuning +unturned +untutored +untwine +untwined +untwines +untwining +untwist +untwisted +untwisting +untwists +untying +untypical +untypically +ununderstandable +unusable +unused +unusual +unusually +unusualness +unutilized +unutterable +unutterableness +unutterably +unuttered +unvaccinated +unvalued +unvanquished +unvaried +unvarnished +unvarying +unvaryingly +unveil +unveiled +unveiling +unveilings +unveils +unventilated +unverbalized +unverifiable +unverified +unversed +unvested +unviable +unviewed +unvigilant +unviolated +unvisited +unvocal +unvoice +unvoiced +unvoices +unvoicing +unwanted +unwarier +unwariest +unwarily +unwariness +unwarlike +unwarned +unwarrantable +unwarrantably +unwarranted +unwarrantedly +unwary +unwashed +unwashedness +unwatchable +unwatched +unwatchful +unwavering +unwaveringly +unwaxed +unweakened +unweaned +unwearable +unwearied +unweariedly +unweathered +unweave +unweaves +unweaving +unwed +unwedded +unweeting +unweetingly +unweight +unweighted +unweighting +unweights +unwelcome +unwell +unwept +unwhite +unwholesome +unwholesomely +unwholesomeness +unwieldier +unwieldiest +unwieldily +unwieldiness +unwieldy +unwilled +unwilling +unwillingly +unwillingness +unwind +unwinding +unwinds +unwinnable +unwire +unwired +unwires +unwiring +unwisdom +unwisdoms +unwise +unwisely +unwiser +unwisest +unwish +unwished +unwishes +unwishing +unwitting +unwittingly +unwomanly +unwon +unwonted +unwontedly +unwontedness +unworkability +unworkable +unworkableness +unworkably +unworked +unworldlier +unworldliest +unworldliness +unworldly +unworn +unworried +unworthier +unworthiest +unworthily +unworthiness +unworthy +unwound +unwounded +unwove +unwoven +unwrap +unwrapped +unwrapping +unwraps +unwreathe +unwreathed +unwreathes +unwreathing +unwrinkled +unwritten +unyielding +unyieldingly +unyieldingness +unyoke +unyoked +unyokes +unyoking +unyoung +unzip +unzipped +unzipping +unzips +up +upanishad +upanishadic +upanishads +upas +upbeat +upbeats +upbraid +upbraided +upbraider +upbraiders +upbraiding +upbraidingly +upbraids +upbringing +upbringings +upbuild +upbuilder +upbuilders +upbuilding +upbuilds +upbuilt +upcast +upcasts +upchuck +upchucked +upchucking +upchucks +upcoast +upcoming +upcountry +update +updated +updates +updating +updo +updos +updraft +updrafts +upend +upended +upending +upends +upfield +upfront +upgrade +upgraded +upgrades +upgrading +upgrowth +upgrowths +upheaval +upheavals +upheave +upheaved +upheaver +upheavers +upheaves +upheaving +upheld +uphill +uphills +uphold +upholder +upholders +upholding +upholds +upholster +upholstered +upholsterer +upholsterers +upholsteries +upholstering +upholsters +upholstery +upityness +upkeep +upland +uplander +uplanders +uplands +uplift +uplifted +uplifter +uplifters +uplifting +uplifts +uplink +uplinks +upload +uploaded +uploading +uploads +upmanship +upmanships +upmarket +upmost +upolu +upon +upped +upper +uppercase +uppercased +uppercases +uppercasing +upperclassman +upperclassmen +uppercut +uppercuts +uppermost +upperpart +upperparts +uppers +upping +uppish +uppishly +uppishness +uppitiness +uppity +uppityness +uppsala +upraise +upraised +upraises +upraising +uprate +uprated +uprates +uprating +uprear +upreared +uprearing +uprears +upright +uprightly +uprightness +uprights +uprise +uprisen +upriser +uprisers +uprises +uprising +uprisings +upriver +uproar +uproarious +uproariously +uproariousness +uproars +uproot +uprooted +uprootedness +uprooter +uprooters +uprooting +uproots +uprose +uprush +uprushes +ups +upscale +upscaled +upscales +upscaling +upset +upsets +upsetter +upsetters +upsetting +upsettingly +upshift +upshifted +upshifting +upshifts +upshot +upshots +upside +upsides +upsilon +upsmanship +upsprang +upspring +upspringing +upsprings +upsprung +upstage +upstaged +upstager +upstagers +upstages +upstaging +upstairs +upstanding +upstandingness +upstart +upstarted +upstarting +upstarts +upstate +upstater +upstaters +upstream +upstroke +upstrokes +upsurge +upsurged +upsurges +upsurging +upsweep +upsweeping +upsweeps +upswept +upswing +upswings +uptake +uptakes +uptempo +uptempos +upthrow +upthrows +upthrust +upthrusting +upthrusts +uptick +upticks +uptight +uptightness +uptilt +uptilted +uptilting +uptilts +uptime +uptimes +uptown +uptowner +uptowners +uptowns +uptrend +uptrended +uptrending +uptrends +upturn +upturned +upturning +upturns +upward +upwardly +upwardness +upwards +upwell +upwelled +upwelling +upwells +upwind +uracil +uraei +uraemia +uraemias +uraeus +uraeuses +ural +uralian +uralic +urals +urania +uranian +uranias +uranic +uraninite +uraninites +uranium +uranography +uranous +uranus +uranyl +urase +urases +urate +urates +uratic +urban +urbane +urbanely +urbaner +urbanest +urbanism +urbanist +urbanistic +urbanistically +urbanists +urbanite +urbanites +urbanities +urbanity +urbanization +urbanizations +urbanize +urbanized +urbanizes +urbanizing +urbanologist +urbanologists +urbanology +urbino +urceolate +urchin +urchins +urd +urds +urdu +urea +urease +ureases +uredia +uredinia +uredinial +urediniospore +urediniospores +uredinium +urediospore +urediospores +uredium +uredospore +uredospores +uredostage +uredostages +ureide +ureides +uremia +uremias +uremic +ureotelic +ureotelism +ureter +ureteral +ureteric +ureters +urethan +urethane +urethanes +urethans +urethra +urethrae +urethral +urethras +urethrectomies +urethrectomy +urethritis +urethritises +urethroscope +urethroscopes +urethroscopy +uretic +urge +urged +urgencies +urgency +urgent +urgently +urger +urgers +urges +urging +urgings +urial +uric +uricosuric +uricotelic +uricotelism +uridine +uridines +urim +urinal +urinals +urinalyses +urinalysis +urinary +urinate +urinated +urinates +urinating +urination +urinations +urinative +urinator +urinators +urine +uriniferous +urinogenital +urinometer +urinometers +urinose +urinous +urn +urns +urocanic +urochord +urochordate +urochordates +urochords +urochrome +urochromes +urodele +urodeles +urogenital +urogenous +urogram +urograms +urographic +urographies +urography +urokinase +urokinases +urolith +urolithiasis +urolithic +uroliths +urologic +urological +urologist +urologists +urology +uronic +uropod +uropods +uropygial +uropygium +uropygiums +uroscopies +uroscopy +urostomies +urostomy +urostyle +urostyles +ursa +ursine +ursprache +ursula +ursuline +ursulines +urtext +urtexts +urticant +urticants +urticaria +urticarial +urticate +urticated +urticates +urticating +urtication +urtications +uruguay +uruguayan +uruguayans +urus +uruses +urushiol +urushiols +us +usa +usability +usable +usableness +usably +usage +usages +usance +usances +use +useable +used +useful +usefully +usefulness +useless +uselessly +uselessness +user +users +uses +ushak +ushant +usher +ushered +usherette +usherettes +ushering +ushers +using +usnea +usneas +usnic +usquebaugh +usquebaughs +usual +usually +usualness +usufruct +usufructs +usufructuaries +usufructuary +usurer +usurers +usuries +usurious +usuriously +usuriousness +usurp +usurpation +usurpations +usurped +usurper +usurpers +usurping +usurpingly +usurps +usury +ut +utah +utahan +utahans +ute +utensil +utensils +uteri +uterine +utero +uterus +uteruses +utes +utile +utilitarian +utilitarianism +utilitarians +utilities +utility +utilizable +utilization +utilizations +utilize +utilized +utilizer +utilizers +utilizes +utilizing +utmost +utopia +utopian +utopianism +utopians +utopias +utopism +utopist +utopistic +utopists +utrecht +utricle +utricles +utricular +utriculi +utriculus +utrillo +uttar +utter +utterable +utterance +utterances +uttered +utterer +utterers +uttering +utterly +uttermost +utters +uvarovite +uvarovites +uvea +uveal +uveas +uveitis +uvula +uvulae +uvular +uvulas +uvulitis +uvulitises +uxorial +uxorially +uxoricide +uxoricides +uxorious +uxoriously +uxoriousness +uzbeg +uzbek +uzbekistan +uzbeks +uzès +v +vac +vacancies +vacancy +vacant +vacantly +vacantness +vacatable +vacate +vacated +vacates +vacating +vacation +vacationed +vacationeer +vacationeers +vacationer +vacationers +vacationing +vacationist +vacationists +vacationland +vacationlands +vacationless +vacations +vaccinal +vaccinate +vaccinated +vaccinates +vaccinating +vaccination +vaccinations +vaccinator +vaccinators +vaccine +vaccinee +vaccinees +vaccines +vaccinia +vaccinial +vaccinias +vacillant +vacillate +vacillated +vacillates +vacillating +vacillatingly +vacillation +vacillations +vacillator +vacillators +vacillatory +vacs +vacua +vacuities +vacuity +vacuo +vacuolar +vacuolate +vacuolated +vacuolation +vacuole +vacuoles +vacuolization +vacuous +vacuously +vacuousness +vacuum +vacuumed +vacuumes +vacuuming +vacuums +vade +vadose +vaduz +vagabond +vagabondage +vagabondages +vagabonded +vagabonding +vagabondish +vagabondism +vagabonds +vagal +vagally +vagaries +vagarious +vagariously +vagary +vagi +vagile +vagility +vagina +vaginae +vaginal +vaginally +vaginas +vaginate +vaginated +vaginectomies +vaginectomy +vaginismus +vaginismuses +vaginitis +vaginitises +vagotomies +vagotomy +vagotonia +vagotonic +vagotropic +vagrancies +vagrancy +vagrant +vagrantly +vagrants +vagrom +vague +vaguely +vagueness +vaguer +vaguest +vagus +vahine +vahines +vail +vailed +vailing +vails +vain +vainer +vainest +vainglories +vainglorious +vaingloriously +vaingloriousness +vainglory +vainly +vainness +vair +vairs +vaishnava +vaishnavas +vaishnavism +vaisya +vaisyas +valance +valanced +valances +valancing +vale +valediction +valedictions +valedictorian +valedictorians +valedictories +valedictory +valence +valences +valencia +valenciennes +valency +valentine +valentines +valera +valerate +valerates +valerian +valerians +valeric +vales +valet +valeted +valeting +valets +valetudinarian +valetudinarianism +valetudinarians +valetudinaries +valetudinary +valgoid +valgus +valhalla +valiance +valiancy +valiant +valiantly +valiantness +valiants +valid +validate +validated +validates +validating +validation +validations +validity +validly +validness +valine +valines +valinomycin +valinomycins +valise +valises +valium +valkyrie +valkyries +vallate +vallation +vallations +vallatory +vallecula +valleculae +vallecular +valleculate +vallences +vallencies +valletta +valley +valleyed +valleys +valois +valonia +valonias +valor +valorem +valorization +valorizations +valorize +valorized +valorizes +valorizing +valorous +valorously +valorousness +valors +valparaiso +valpolicella +valproate +valproates +valsalva +valse +valses +valuable +valuableness +valuables +valuably +valuate +valuated +valuates +valuating +valuation +valuational +valuationally +valuations +valuator +valuators +value +valued +valueless +valuelessness +valuer +valuers +values +valuing +valuta +valvar +valvate +valve +valved +valveless +valves +valving +valvula +valvulae +valvular +valvule +valvules +valvulitis +valvulitises +valvuloplasties +valvuloplasty +vambrace +vambraces +vamoose +vamoosed +vamooses +vamoosing +vamp +vamped +vamper +vampers +vamping +vampire +vampires +vampirical +vampirish +vampirism +vampish +vampishly +vamps +vampy +van +vanadate +vanadates +vanadic +vanadinite +vanadinites +vanadium +vanaspati +vanbrugh +vancomycin +vancomycins +vancouver +vanda +vandal +vandalic +vandalism +vandalistic +vandalization +vandalizations +vandalize +vandalized +vandalizes +vandalizing +vandals +vanderbilt +vandyke +vandyked +vandykes +vane +vaned +vanes +vang +vangs +vanguard +vanguardism +vanguardist +vanguardists +vanguards +vanilla +vanillas +vanillic +vanillin +vanir +vanish +vanished +vanisher +vanishers +vanishes +vanishing +vanishingly +vanishment +vanities +vanity +vanload +vanloads +vanned +vanner +vanners +vanning +vanpool +vanpooled +vanpooler +vanpoolers +vanpooling +vanpools +vanquish +vanquishable +vanquished +vanquisher +vanquishers +vanquishes +vanquishing +vanquishment +vans +vansittart +vantage +vantages +vanuatu +vanuatuan +vanuatuans +vanward +vapid +vapidity +vapidly +vapidness +vapor +vapored +vaporer +vaporers +vaporescence +vaporetti +vaporetto +vaporettos +vaporific +vaporing +vaporingly +vaporings +vaporish +vaporishness +vaporizable +vaporization +vaporizations +vaporize +vaporized +vaporizer +vaporizers +vaporizes +vaporizing +vaporosity +vaporous +vaporously +vaporousness +vapors +vaporware +vapory +vaquero +vaqueros +vara +varactor +varactors +varas +varia +variabilities +variability +variable +variableness +variables +variably +variance +variances +variant +variants +varias +variate +variates +variation +variational +variationally +variations +variceal +varicella +varicellas +varicellate +varicelloid +varices +varicocele +varicoceles +varicolored +varicose +varicosed +varicoses +varicosis +varicosities +varicosity +varicotomies +varicotomy +varied +variedly +variegate +variegated +variegates +variegating +variegation +variegations +variegator +variegators +varier +variers +varies +varietal +varietally +varietals +varieties +variety +variform +variola +variolas +variolate +variolated +variolates +variolating +variole +varioles +variolite +variolites +varioloid +varioloids +variolous +variometer +variometers +variorum +variorums +various +variously +variousness +varisized +varistor +varistors +varitype +varityped +varitypes +varityping +varix +varlet +varletry +varlets +varlettries +varmint +varmints +varnish +varnished +varnisher +varnishers +varnishes +varnishing +varnishy +varoom +varoomed +varooming +varooms +varsities +varsity +varsovian +varuna +varus +varve +varved +varves +vary +varying +varyingly +vas +vasa +vasal +vascula +vascular +vascularity +vascularization +vascularizations +vascularize +vascularized +vascularizes +vascularizing +vasculature +vasculatures +vasculitis +vasculitises +vasculum +vase +vasectomies +vasectomize +vasectomized +vasectomizes +vasectomizing +vasectomy +vaselike +vaseline +vases +vashon +vasoactive +vasoactivity +vasoconstriction +vasoconstrictions +vasoconstrictive +vasoconstrictor +vasoconstrictors +vasodilatation +vasodilatations +vasodilation +vasodilations +vasodilator +vasodilators +vasoligate +vasoligated +vasoligates +vasoligating +vasoligation +vasoligations +vasomotor +vasopressin +vasopressins +vasopressor +vasopressors +vasospasm +vasospasms +vasospastic +vasotocin +vasotocins +vasovagal +vassal +vassalage +vassals +vast +vaster +vastest +vastier +vastiest +vastities +vastitude +vastitudes +vastity +vastly +vastness +vasty +vat +vatic +vatical +vatican +vaticanism +vaticinal +vaticinate +vaticinated +vaticinates +vaticinating +vaticination +vaticinations +vaticinator +vaticinators +vats +vatted +vatting +vatu +vatus +vau +vaudeville +vaudevilles +vaudevillian +vaudevillians +vaudois +vaughan +vault +vaulted +vaulter +vaulters +vaulting +vaultingly +vaultings +vaults +vaulty +vaunt +vaunted +vaunter +vaunters +vauntful +vaunting +vauntingly +vaunts +vav +vavasor +vavasors +vavasour +vavasours +vcr +vd +ve +veadar +veal +vealer +vealers +vealy +vector +vectored +vectorial +vectorially +vectoring +vectorization +vectorizations +vectorize +vectorized +vectorizes +vectorizing +vectors +veda +vedalia +vedalias +vedanta +vedantic +vedantism +vedantist +vedantists +vedas +vedda +veddah +veddahs +veddas +veddoid +veddoids +vedette +vedettes +vedic +vee +veejay +veejays +veena +veenas +veep +veeps +veer +veered +veeries +veering +veeringly +veers +veery +vees +vega +vegan +veganism +vegans +vegas +vegetable +vegetables +vegetably +vegetal +vegetarian +vegetarianism +vegetarians +vegetate +vegetated +vegetates +vegetating +vegetation +vegetational +vegetations +vegetative +vegetatively +vegetativeness +vegetive +vegged +veggie +veggies +vegging +vegie +vegies +vehemence +vehemency +vehement +vehemently +vehicle +vehicles +vehicular +veil +veiled +veiling +veilings +veils +vein +veinal +veined +veiner +veiners +veinier +veiniest +veining +veinings +veinlet +veinlets +veins +veinstone +veinstones +veinule +veinules +veiny +vela +velamen +velamentous +velamina +velar +velaria +velarium +velarization +velarizations +velarize +velarized +velarizes +velarizing +velars +velasquez +velate +velcro +veld +velds +veldt +veldts +veliger +veligers +velleities +velleity +vellum +vellums +veloce +velocimeter +velocimeters +velocipede +velocipedes +velocities +velocity +velodrome +velodromes +velour +velours +velouté +velum +velums +velure +velures +velutinous +velvet +velveteen +velveteens +velvetier +velvetiest +velvetleaf +velvetleafs +velvetlike +velvets +velvety +vena +venae +venal +venalities +venality +venally +venatic +venatical +venation +venational +vend +venda +vendable +vendace +vendaces +vended +vendee +vendees +vender +venders +vendetta +vendettas +vendeuse +vendeuses +vendibility +vendible +vending +vendor +vendors +vends +vendue +vendues +vendôme +veneer +veneered +veneerer +veneerers +veneering +veneers +venenation +venenations +venene +venenes +venepuncture +venepunctures +venerability +venerable +venerableness +venerably +venerate +venerated +venerates +venerating +veneration +venerational +venerator +venerators +venereal +venereological +venereologist +venereologists +venereology +venereum +veneries +veneris +venery +venesection +venesections +veneti +venetia +venetian +venetians +venetic +veneto +venezia +venezuela +venezuelan +venezuelans +venge +vengeance +venged +vengeful +vengefully +vengefulness +venges +venging +venial +veniality +venially +venialness +venice +venin +venins +venipuncture +venipunctures +venire +venireman +veniremen +venires +venison +venisons +venite +venites +venn +venogram +venograms +venography +venom +venomous +venomously +venomousness +venose +venosity +venosus +venous +venously +venousness +vent +ventage +ventages +ventail +ventails +vented +venter +venters +ventifact +ventifacts +ventilate +ventilated +ventilates +ventilating +ventilation +ventilations +ventilator +ventilators +ventilatory +venting +ventless +ventrad +ventral +ventrally +ventrals +ventricle +ventricles +ventricose +ventricosity +ventricous +ventricular +ventriculi +ventriculus +ventriloquial +ventriloquially +ventriloquism +ventriloquist +ventriloquistic +ventriloquists +ventriloquize +ventriloquized +ventriloquizes +ventriloquizing +ventriloquy +ventrodorsal +ventrodorsally +ventrolateral +ventrolaterally +ventromedial +ventromedially +vents +venture +ventured +venturer +venturers +ventures +venturesome +venturesomely +venturesomeness +venturi +venturing +venturis +venturous +venturously +venturousness +venue +venues +venular +venule +venules +venus +venusberg +venushair +venusian +venusians +vera +veracious +veraciously +veraciousness +veracities +veracity +veranda +verandaed +verandah +verandahed +verandahs +verandas +verapamil +verapamils +veratridine +veratridines +veratrine +veratrines +veratrum +verb +verba +verbal +verbalism +verbalisms +verbalist +verbalistic +verbalists +verbalizable +verbalization +verbalizations +verbalize +verbalized +verbalizer +verbalizers +verbalizes +verbalizing +verbally +verbals +verbatim +verbaux +verbena +verbenas +verbiage +verbicide +verbicides +verbid +verbified +verbifies +verbify +verbifying +verbigeration +verbigerations +verbless +verbose +verbosely +verboseness +verbosity +verboten +verbs +verbum +verd +verdancy +verdant +verdantly +verde +verdean +verdeans +verderer +verderers +verderor +verderors +verdi +verdict +verdicts +verdigris +verdin +verdins +verditer +verditers +verdun +verdure +verdured +verdurous +verdurousness +verge +verged +verger +vergers +verges +verging +verglas +verglases +veridic +veridical +veridicality +veridically +verier +veriest +verifiability +verifiable +verifiableness +verifiably +verification +verifications +verificative +verified +verifier +verifiers +verifies +verify +verifying +verily +verisimilar +verisimilarly +verisimilitude +verisimilitudes +verisimilitudinous +verism +verismo +verismos +verist +veristic +verists +veritable +veritableness +veritably +verities +verity +verjuice +verjuices +verkhoyansk +verlaine +vermeer +vermeil +vermicelli +vermicidal +vermicide +vermicides +vermicular +vermicularly +vermiculate +vermiculated +vermiculates +vermiculating +vermiculation +vermiculations +vermiculite +vermiculites +vermiform +vermifuge +vermifuges +vermilion +vermilioned +vermilioning +vermilions +vermillion +vermillioned +vermillioning +vermillions +vermin +vermination +verminations +verminous +verminously +vermivorous +vermont +vermonter +vermonters +vermouth +vermouths +vernacle +vernacular +vernacularism +vernacularisms +vernacularize +vernacularized +vernacularizes +vernacularizing +vernacularly +vernaculars +vernal +vernalization +vernalizations +vernalize +vernalized +vernalizes +vernalizing +vernally +vernation +vernations +verner +vernicle +vernier +verniers +vernissage +vernissages +vernix +vernon +verona +veronese +veronica +veronicas +verruca +verrucae +verrucose +verrucous +vers +versa +versailles +versant +versants +versatile +versatilely +versatileness +versatility +verse +versed +verses +verset +versets +versicle +versicles +versicolor +versicolored +versicular +versification +versifications +versified +versifier +versifiers +versifies +versify +versifying +versine +versing +version +versional +versions +verso +versos +verst +versts +versus +vert +verte +vertebra +vertebrae +vertebral +vertebrally +vertebras +vertebrate +vertebrates +vertebration +vertebrations +vertex +vertexes +vertical +verticality +vertically +verticalness +verticals +vertices +verticil +verticillaster +verticillasters +verticillastrate +verticillate +verticillated +verticillately +verticillation +verticillations +verticillium +verticils +vertiginous +vertiginously +vertiginousness +vertigo +vertigoes +vertigos +verts +vertu +vertus +vervain +vervains +verve +vervet +vervets +very +vesalius +vesica +vesicae +vesical +vesicant +vesicants +vesicate +vesicated +vesicates +vesicating +vesication +vesications +vesicatories +vesicatory +vesicle +vesicles +vesicular +vesicularity +vesicularly +vesiculate +vesiculated +vesiculates +vesiculating +vesiculation +vesiculations +vespasian +vesper +vesperal +vesperals +vespers +vespertilian +vespertilionid +vespertilionids +vespertinal +vespertine +vespiaries +vespiary +vespid +vespids +vespine +vespucci +vessel +vessels +vest +vesta +vestal +vestals +vestas +vested +vestee +vestees +vestiaries +vestiary +vestibular +vestibule +vestibuled +vestibules +vestibulocochlear +vestige +vestiges +vestigia +vestigial +vestigially +vestigium +vesting +vestings +vestlike +vestment +vestmental +vestments +vestries +vestry +vestryman +vestrymen +vestrywoman +vestrywomen +vests +vesture +vestured +vestures +vesturing +vesuvian +vesuvianite +vesuvianites +vesuvians +vesuvius +vet +vetch +vetches +vetchling +vetchlings +veteran +veterans +veterinarian +veterinarians +veterinaries +veterinary +vetiver +vetivers +vetivert +vetiverts +veto +vetoed +vetoer +vetoers +vetoes +vetoing +vets +vetted +vetting +vex +vexation +vexations +vexatious +vexatiously +vexatiousness +vexed +vexedly +vexer +vexers +vexes +vexilla +vexillaries +vexillary +vexillate +vexillologic +vexillological +vexillologist +vexillologists +vexillology +vexillum +vexing +vexingly +vext +vhf +via +viability +viable +viably +viaduct +viaducts +vial +vialed +vialing +vialled +vialling +vials +viand +viands +viatic +viatica +viatical +viaticum +viaticums +vibe +vibes +vibist +vibists +vibracula +vibracular +vibraculoid +vibraculum +vibraharp +vibraharpist +vibraharpists +vibraharps +vibrance +vibrancy +vibrant +vibrantly +vibraphone +vibraphones +vibraphonist +vibraphonists +vibrate +vibrated +vibrates +vibratile +vibratility +vibrating +vibration +vibrational +vibrationless +vibrations +vibrative +vibrato +vibratoless +vibrator +vibrators +vibratory +vibratos +vibrio +vibrioid +vibrion +vibrionic +vibrions +vibrios +vibrioses +vibriosis +vibrissa +vibrissae +vibronic +viburnum +vicar +vicarage +vicarages +vicarate +vicarates +vicarial +vicariance +vicariances +vicariant +vicariants +vicariate +vicariates +vicarious +vicariously +vicariousness +vicars +vicarship +vice +viced +vicegeral +vicegerencies +vicegerency +vicegerent +vicegerents +vicenary +vicennial +vicenza +viceregal +viceregally +vicereine +vicereines +viceroy +viceroyalties +viceroyalty +viceroys +viceroyship +viceroyships +vices +vichy +vichyssoise +vichyssoises +vicinage +vicinal +vicing +vicinities +vicinity +vicious +viciously +viciousness +vicissitude +vicissitudes +vicissitudinary +vicissitudinous +victim +victimhood +victimization +victimizations +victimize +victimized +victimizer +victimizers +victimizes +victimizing +victimless +victimologist +victimologists +victimology +victims +victor +victoria +victorian +victoriana +victorianism +victorianisms +victorianization +victorianizations +victorianize +victorianized +victorianizes +victorianizing +victorians +victorias +victories +victorious +victoriously +victoriousness +victors +victory +victrola +victual +victualed +victualer +victualers +victualing +victualled +victualler +victuallers +victualling +victuals +vicuna +vicunas +vicuña +vicuñas +vidalia +vide +videlicet +video +videocassette +videocassettes +videoconference +videoconferences +videoconferencing +videodisc +videodiscs +videodisk +videodisks +videogenic +videographer +videographers +videography +videoland +videophile +videophiles +videophone +videophones +videos +videotape +videotaped +videotapes +videotaping +videotex +videotexs +videotext +videotexts +vidette +videttes +vidicon +vidicons +viduity +vie +vied +vienna +viennese +vientiane +vier +viers +vies +vietcong +vietminh +vietnam +vietnamese +vietnamization +vietnamize +vietnamized +vietnamizes +vietnamizing +view +viewable +viewdata +viewed +viewer +viewers +viewership +viewfinder +viewfinders +viewier +viewiest +viewing +viewings +viewless +viewlessly +viewpoint +viewpoints +views +viewy +vig +viga +vigas +vigesimal +vigil +vigilance +vigilant +vigilante +vigilanteism +vigilantes +vigilantism +vigilantly +vigils +vigintillion +vigneron +vignerons +vignette +vignetted +vignetter +vignetters +vignettes +vignetting +vignettist +vignettists +vigor +vigorish +vigoroso +vigorous +vigorously +vigorousness +viking +vikings +vilayet +vilayets +vile +vilely +vileness +viler +vilest +vilification +vilifications +vilified +vilifier +vilifiers +vilifies +vilify +vilifying +vilipend +vilipended +vilipending +vilipends +vill +villa +villadom +village +villager +villagers +villagery +villages +villain +villainage +villainages +villainess +villainies +villainous +villainously +villainousness +villains +villainy +villanella +villanelle +villanelles +villanueva +villas +villatic +villein +villeinage +villeinages +villeins +villenage +villeneuve +villi +villiers +villiform +villon +villose +villosities +villosity +villous +villously +vills +villus +vim +viminal +vin +vina +vinaceous +vinaigrette +vinaigrettes +vinal +vinas +vinasse +vinasses +vinblastine +vinblastines +vinca +vincent +vincentian +vincentians +vinci +vincibility +vincible +vincibly +vincristine +vincristines +vincula +vinculum +vinculums +vindaloo +vindicable +vindicate +vindicated +vindicates +vindicating +vindication +vindications +vindicator +vindicators +vindicatory +vindictive +vindictively +vindictiveness +vine +vined +vinedresser +vinedressers +vinegar +vinegared +vinegarish +vinegarone +vinegarones +vinegarroon +vinegarroons +vinegars +vinegary +vineries +vinery +vines +vineyard +vineyardist +vineyardists +vineyards +vinic +vinicultural +viniculture +vinicultures +viniculturist +viniculturists +vinier +viniest +vinifera +viniferous +vinification +vinifications +vinified +vinifies +vinify +vinifying +vining +vino +vinogradoff +vinometer +vinometers +vinos +vinosities +vinosity +vinous +vinously +vintage +vintager +vintagers +vintages +vintner +vintners +viny +vinyl +vinylic +vinylidene +vinylidenes +vinyls +viol +viola +violability +violable +violableness +violably +violaceous +violas +violate +violated +violates +violating +violation +violations +violative +violator +violators +viole +violence +violent +violently +violet +violets +violin +violinist +violinistic +violinists +violinmaker +violinmakers +violinmaking +violins +violist +violists +violoncellist +violoncellists +violoncello +violoncellos +violone +violones +viols +viomycin +viomycins +viosterol +viosterols +viper +viperfish +viperfishes +viperine +viperish +viperous +viperously +vipers +viraginous +virago +viragoes +viragos +viral +virally +virelay +virelays +viremia +viremias +viremic +vireo +vireos +vires +virescence +virescent +virga +virgas +virgate +virgates +virgil +virgilia +virgilian +virgin +virginal +virginalist +virginalists +virginally +virginals +virginia +virginiamycin +virginiamycins +virginian +virginians +virginities +virginity +virgins +virgo +virgoan +virgoans +virgos +virgulate +virgule +virgules +viricidal +viricide +viricides +virid +viridescence +viridescent +viridian +viridity +virile +virilely +viriles +virilis +virilism +virilisms +virility +virilization +virilizations +virilize +virilized +virilizes +virilizing +virion +virions +virogene +virogenes +virogeneses +virogenesis +virogenetic +virogenic +viroid +viroids +virologic +virological +virologically +virologist +virologists +virology +viroses +virosis +virtu +virtual +virtuality +virtualizes +virtually +virtue +virtueless +virtues +virtuosa +virtuosas +virtuosi +virtuosic +virtuosically +virtuosities +virtuosity +virtuoso +virtuosos +virtuous +virtuously +virtuousness +virtus +virucidal +virucide +virucides +virulence +virulency +virulent +virulently +viruliferous +virus +viruses +vis +visa +visaed +visage +visaged +visages +visaing +visard +visards +visas +visayan +visayans +viscacha +viscachas +viscera +visceral +viscerally +visceromotor +viscid +viscidity +viscidly +viscidness +viscoelastic +viscoelasticity +viscometer +viscometers +viscometric +viscometry +visconti +viscose +viscosimeter +viscosimeters +viscosimetric +viscosities +viscosity +viscount +viscountcies +viscountcy +viscountess +viscountesses +viscounties +viscounts +viscounty +viscous +viscously +viscousness +viscus +vise +vised +viseed +viseing +viselike +vises +vishnu +visibilities +visibility +visible +visibleness +visibly +visigoth +visigothic +visigoths +vising +vision +visional +visionally +visionaries +visionariness +visionary +visioned +visioning +visionless +visions +visit +visitable +visitant +visitants +visitation +visitational +visitations +visitatorial +visited +visiting +visitor +visitors +visits +visor +visored +visoring +visorless +visors +vista +vistaed +vistas +vistula +visual +visuality +visualizable +visualization +visualizations +visualize +visualized +visualizer +visualizers +visualizes +visualizing +visually +visualness +visuals +visuomotor +visuomotors +visuospatial +vita +vitae +vitaes +vital +vitalism +vitalist +vitalistic +vitalists +vitalities +vitality +vitalization +vitalizations +vitalize +vitalized +vitalizer +vitalizers +vitalizes +vitalizing +vitally +vitalness +vitals +vitamer +vitameric +vitamers +vitamin +vitaminic +vitamins +vitellaria +vitellarium +vitellariums +vitellin +vitelline +vitellines +vitellins +vitellogenesis +vitellogenetic +vitellogenic +vitellus +vitelluses +viterbo +vitiable +vitiate +vitiated +vitiates +vitiating +vitiation +vitiations +vitiator +vitiators +viticultural +viticulturally +viticulture +viticulturist +viticulturists +vitiligo +vitiligos +vitrectomies +vitrectomy +vitreosity +vitreous +vitreousness +vitrescence +vitrescent +vitrifaction +vitrifactions +vitrifiability +vitrifiable +vitrification +vitrifications +vitrified +vitrifies +vitrify +vitrifying +vitrine +vitrines +vitriol +vitrioled +vitriolic +vitrioling +vitriolled +vitriolling +vitriols +vitro +vitruvius +vitta +vittae +vittate +vittle +vittles +vituline +vituperate +vituperated +vituperates +vituperating +vituperation +vituperations +vituperative +vituperatively +vituperativeness +vituperator +vituperators +vituperatory +vitus +viva +vivace +vivacious +vivaciously +vivaciousness +vivacity +vivaldi +vivandière +vivandières +vivant +vivants +vivaria +vivarium +vivariums +vivax +vivaxs +vivendi +viverrid +viverrids +viverrine +viverrines +vivian +vivid +vivider +vividest +vividly +vividness +vivific +vivification +vivifications +vivified +vivifier +vivifiers +vivifies +vivify +vivifying +viviparity +viviparous +viviparously +vivisect +vivisected +vivisecting +vivisection +vivisectional +vivisectionally +vivisectionist +vivisectionists +vivisector +vivisectors +vivisects +vivo +vivos +vivre +vixen +vixenish +vixenishly +vixenishness +vixens +viz +vizard +vizards +vizcacha +vizier +vizierate +vizierial +viziers +viziership +vizor +vizored +vizoring +vizors +vizsla +vizslas +vladivostok +vlaminck +vocable +vocables +vocabular +vocabularies +vocabulary +vocal +vocalic +vocalically +vocalism +vocalist +vocalistic +vocalists +vocality +vocalization +vocalizations +vocalize +vocalized +vocalizer +vocalizers +vocalizes +vocalizing +vocally +vocalness +vocals +vocation +vocational +vocationalism +vocationalisms +vocationalist +vocationalists +vocationally +vocations +vocative +vocatively +vocatives +voce +vociferant +vociferate +vociferated +vociferates +vociferating +vociferation +vociferations +vociferator +vociferators +vociferous +vociferously +vociferousness +vocoder +vocoders +vodka +vodkas +vodoun +vodouns +vodun +voduns +vogue +vogues +voguish +voguishly +voguishness +vogul +voguls +voice +voiced +voicedness +voiceful +voicefulness +voiceless +voicelessly +voicelessness +voiceover +voiceovers +voiceprint +voiceprints +voicer +voicers +voices +voicing +voicings +void +voidable +voidableness +voidance +voidances +voided +voider +voiders +voiding +voidness +voids +voile +voiles +voilà +voir +volans +volant +volante +volapük +volar +volatile +volatileness +volatiles +volatility +volatilizable +volatilization +volatilizations +volatilize +volatilized +volatilizer +volatilizers +volatilizes +volatilizing +volcanic +volcanically +volcanicity +volcanism +volcanisms +volcanization +volcanizations +volcanize +volcanized +volcanizes +volcanizing +volcano +volcanoes +volcanogenic +volcanologic +volcanological +volcanologist +volcanologists +volcanology +volcanos +vole +volens +volente +voles +volga +volgograd +volitant +volitantes +volitation +volitational +volitations +volition +volitional +volitionally +volitive +volkslied +volkslieder +volkswagen +volkswagens +volley +volleyball +volleyballer +volleyballers +volleyballs +volleyed +volleyer +volleyers +volleying +volleys +volplane +volplaned +volplanes +volplaning +volpone +volsci +volscian +volscians +volt +volta +voltage +voltages +voltaic +voltaire +volte +voltes +voltmeter +voltmeters +volts +volubility +voluble +volubleness +volubly +volume +volumed +volumes +volumeter +volumeters +volumetric +volumetrically +voluming +voluminosity +voluminous +voluminously +voluminousness +volumnia +voluntaries +voluntarily +voluntariness +voluntarism +voluntarist +voluntaristic +voluntarists +voluntary +voluntaryism +voluntaryist +voluntaryists +volunteer +volunteered +volunteering +volunteerism +volunteers +voluptuaries +voluptuary +voluptuous +voluptuously +voluptuousness +volute +voluted +volutes +volutin +volutins +volution +volutions +volva +volvas +volvate +volvent +volvents +volvox +volvoxes +volvulus +volvuluses +vomer +vomerine +vomers +vomica +vomicae +vomit +vomited +vomiter +vomiters +vomiting +vomitive +vomitives +vomitories +vomitory +vomits +vomiturition +vomituritions +vomitus +vomituses +von +voodoo +voodooed +voodooing +voodooism +voodooist +voodooistic +voodooists +voodoos +voracious +voraciously +voraciousness +voracity +vorlage +vorlages +vortex +vortexes +vortical +vortically +vorticella +vorticellae +vorticellas +vortices +vorticism +vorticist +vorticists +vorticity +vorticose +vortigern +vortiginous +vosges +votable +votaress +votaresses +votaries +votarist +votarists +votary +vote +voteable +voted +voteless +voter +voters +votes +voting +votive +votively +votiveness +voto +votos +vouch +vouched +vouchee +vouchees +voucher +vouchered +vouchering +vouchers +vouches +vouching +vouchsafe +vouchsafed +vouchsafement +vouchsafes +vouchsafing +voussoir +voussoirs +vouvray +vouvrays +vow +vowed +vowel +vowelization +vowelizations +vowelize +vowelized +vowelizes +vowelizing +vowels +vower +vowers +vowing +vows +vox +voyage +voyaged +voyager +voyagers +voyages +voyageur +voyageurs +voyaging +voyeur +voyeurism +voyeuristic +voyeuristically +voyeurs +vroom +vroomed +vrooming +vrooms +vu +vug +vuggy +vugs +vulcan +vulcanian +vulcanicity +vulcanism +vulcanisms +vulcanite +vulcanizable +vulcanizate +vulcanizates +vulcanization +vulcanizations +vulcanize +vulcanized +vulcanizer +vulcanizers +vulcanizes +vulcanizing +vulcanologist +vulcanologists +vulcanology +vulgar +vulgarian +vulgarians +vulgaris +vulgarism +vulgarisms +vulgarities +vulgarity +vulgarization +vulgarizations +vulgarize +vulgarized +vulgarizer +vulgarizers +vulgarizes +vulgarizing +vulgarly +vulgarness +vulgate +vulgates +vulgus +vulnerabilities +vulnerability +vulnerable +vulnerableness +vulnerably +vulneraries +vulnerary +vulpecula +vulpecular +vulpine +vulture +vultures +vulturine +vulturish +vulturous +vulva +vulvae +vulval +vulvar +vulvas +vulvate +vulvectomies +vulvectomy +vulviform +vulvitis +vulvitises +vulvovaginitis +vulvovaginitises +vying +vänern +vättern +vérité +véronique +w +waals +wabanaki +wabanakis +wabble +wabbled +wabbles +wabbling +wac +wack +wacked +wackier +wackiest +wackily +wackiness +wacko +wackos +wacks +wacky +waco +wacs +wad +wadable +wadded +waddenzee +wadder +wadders +waddied +waddies +wadding +waddle +waddled +waddler +waddlers +waddles +waddling +waddy +waddying +wade +wadeable +waded +wader +waders +wades +wadi +wadies +wading +wadis +wadmal +wadmel +wadmol +wads +wady +waf +wafer +wafered +wafering +wafers +waffle +waffled +waffler +wafflers +waffles +wafflestomper +wafflestompers +waffling +wafflingly +waffly +wafs +waft +waftage +wafted +wafter +wafters +wafting +wafts +wafture +wag +wage +waged +wageless +wager +wagered +wagerer +wagerers +wagering +wagers +wages +wageworker +wageworkers +wagged +wagger +waggeries +waggers +waggery +wagging +waggish +waggishly +waggishness +waggle +waggled +waggles +waggling +waggly +waging +wagner +wagnerian +wagnerians +wagnerite +wagnerites +wagon +wagoned +wagoner +wagoners +wagonette +wagonettes +wagoning +wagonload +wagonloads +wagons +wags +wagtail +wagtails +wahabi +wahabis +wahhabi +wahhabis +wahhabism +wahhabite +wahhabites +wahine +wahines +wahoo +wahoos +wahpekute +wahpekutes +wahpeton +wahpetons +wahwah +waianae +waif +waiflike +waifs +waikiki +wail +wailed +wailer +wailers +wailful +wailfully +wailing +wailingly +wails +wain +wains +wainscot +wainscoted +wainscoting +wainscots +wainscotted +wainscotting +wainwright +wainwrights +waist +waistband +waistbands +waistcloth +waistcloths +waistcoat +waistcoated +waistcoats +waisted +waistless +waistline +waistlines +waists +wait +waited +waiter +waiters +waiting +waitings +waitpeople +waitperson +waitpersons +waitress +waitresses +waitron +waitrons +waits +waive +waived +waiver +waivers +waives +waiving +wakame +wakames +wakashan +wake +waked +wakeful +wakefully +wakefulness +wakeless +waken +wakened +wakener +wakeners +wakening +wakens +waker +wakers +wakes +wakeup +waking +walachia +walapai +walapais +walcheren +walden +waldenses +waldensian +waldensians +waldorf +wale +waled +waler +walers +wales +walhalla +waling +walk +walkability +walkable +walkabout +walkabouts +walkathon +walkathons +walkaway +walkaways +walked +walker +walkers +walkie +walking +walkingstick +walkingsticks +walkman +walkout +walkouts +walkover +walkovers +walks +walkup +walkups +walkway +walkways +walky +walkyrie +wall +walla +wallabies +wallaby +wallace +wallachia +wallachian +wallachians +wallah +wallahs +wallaroo +wallaroos +wallas +wallboard +walled +wallenberg +wallet +wallets +walleye +walleyed +walleyes +wallflower +wallflowers +walling +wallis +wallless +wallonia +walloon +walloons +wallop +walloped +walloper +wallopers +walloping +wallopings +wallops +wallow +wallowa +wallowed +wallower +wallowers +wallowing +wallows +wallpaper +wallpapered +wallpapering +wallpapers +walls +walnut +walnuts +walpole +walpurgis +walpurgisnacht +walrus +walruses +walsingham +walsy +walter +walton +waltz +waltzed +waltzer +waltzers +waltzes +waltzing +wamble +wambled +wambles +wambliness +wambling +wamblingly +wambly +wampanoag +wampanoags +wampum +wampumpeag +wan +wand +wander +wandered +wanderer +wanderers +wandering +wanderingly +wanderings +wanderlust +wanderoo +wanderoos +wanders +wandflower +wandflowers +wands +wane +waned +wanes +wangle +wangled +wangler +wanglers +wangles +wangling +wanigan +wanigans +waning +wanion +wankel +wanly +wanna +wanned +wanner +wanness +wannest +wannigan +wannigans +wanning +wans +want +wanted +wanter +wanters +wanting +wantless +wantlessness +wanton +wantoned +wantoner +wantoners +wantoning +wantonly +wantonness +wantons +wants +wapentake +wapentakes +wapiti +wapitis +wappenschawing +wappinger +wappingers +wapsipinicon +war +warble +warbled +warbler +warblers +warbles +warbling +warbonnet +warbonnets +warburg +ward +warded +warden +wardenries +wardenry +wardens +wardenship +warder +warders +wardership +wardian +warding +wardress +wardresses +wardrobe +wardrobes +wardroom +wardrooms +wards +wardship +wardships +ware +wared +warehouse +warehoused +warehouseman +warehousemen +warehouser +warehousers +warehouses +warehousing +wareroom +warerooms +wares +warfare +warfarin +warfront +warfronts +warhead +warheads +warhorse +warhorses +warier +wariest +warily +wariness +waring +warison +warless +warlike +warlock +warlocks +warlord +warlordism +warlords +warm +warmed +warmer +warmers +warmest +warmhearted +warmheartedly +warmheartedness +warming +warmish +warmly +warmness +warmonger +warmongering +warmongers +warmouth +warmouths +warms +warmth +warmup +warmups +warn +warned +warner +warners +warning +warningly +warnings +warns +warp +warpage +warpath +warpaths +warped +warper +warpers +warping +warplane +warplanes +warps +warrant +warrantability +warrantable +warrantableness +warrantably +warranted +warrantee +warrantees +warranter +warranters +warranties +warranting +warrantless +warrantor +warrantors +warrants +warranty +warred +warren +warrener +warreners +warrens +warring +warrior +warriors +wars +warsaw +warship +warships +wart +warted +warthog +warthogs +wartime +wartless +warts +warty +warwickshire +wary +was +wasabi +wasatch +wash +washability +washable +washbasin +washbasins +washboard +washboards +washbowl +washbowls +washcloth +washcloths +washday +washdays +washed +washer +washerman +washermen +washers +washerwoman +washerwomen +washes +washhouse +washhouses +washier +washiest +washiness +washing +washings +washington +washingtonian +washingtonians +washout +washouts +washrag +washrags +washroom +washrooms +washstand +washstands +washtub +washtubs +washup +washups +washwoman +washwomen +washy +wasn +wasn't +wasp +waspdom +waspier +waspiest +waspish +waspishly +waspishness +wasplike +wasps +waspy +wassail +wassailed +wassailer +wassailers +wassailing +wassails +wassermann +wastage +waste +wastebasket +wastebaskets +wasted +wasteful +wastefully +wastefulness +wasteland +wastelands +wastepaper +waster +wasters +wastes +wastewater +wastewaters +wasting +wastingly +wastrel +wastrels +watap +watape +watapes +wataps +watch +watchable +watchband +watchbands +watchcase +watchcases +watchdog +watchdogged +watchdogging +watchdogs +watched +watcher +watchers +watches +watcheye +watcheyes +watchful +watchfully +watchfulness +watching +watchmaker +watchmakers +watchmaking +watchman +watchmen +watchstrap +watchstraps +watchtower +watchtowers +watchword +watchwords +water +waterbed +waterbeds +waterbird +waterbirds +waterborne +waterbuck +waterbucks +waterbus +waterbuses +waterbusses +watercolor +watercolorist +watercolorists +watercolors +watercooler +watercoolers +watercourse +watercourses +watercraft +watercrafts +watercress +waterdog +waterdogging +waterdogs +watered +waterer +waterers +waterfall +waterfalls +waterfinder +waterfinders +waterflood +waterflooded +waterflooding +waterfloods +waterfowl +waterfowler +waterfowlers +waterfowling +waterfowls +waterfront +waterfronts +watergate +watergates +waterhole +waterholes +waterier +wateriest +waterily +wateriness +watering +waterish +waterishness +waterleaf +waterleafs +waterless +waterlessness +waterline +waterlines +waterlog +waterlogged +waterlogging +waterlogs +waterloo +waterloos +waterman +watermanship +watermark +watermarked +watermarking +watermarks +watermelon +watermelons +watermen +waterpower +waterproof +waterproofed +waterproofer +waterproofers +waterproofing +waterproofness +waterproofs +waters +waterscape +waterscapes +watershed +watersheds +waterside +watersides +waterskiing +waterspout +waterspouts +waterthrush +waterthrushes +watertight +watertightness +waterway +waterways +waterweed +waterweeds +waterwheel +waterwheels +waterworks +waterworn +watery +waterzooi +watlings +watson +watt +wattage +wattages +watteau +wattle +wattlebird +wattlebirds +wattled +wattles +wattling +wattmeter +wattmeters +watts +watusi +watusis +waugh +wave +waveband +wavebands +waved +waveform +waveforms +waveguide +waveguides +wavelength +wavelengths +waveless +wavelessly +wavelet +wavelets +wavelike +wavell +waver +wavered +waverer +waverers +wavering +waveringly +waverley +wavers +wavery +waves +waveshape +waveshapes +wavier +waviest +wavily +waviness +waving +wavy +waw +wax +waxberries +waxberry +waxbill +waxbills +waxed +waxen +waxer +waxers +waxes +waxier +waxiest +waxiness +waxing +waxlike +waxwing +waxwings +waxwork +waxworks +waxy +way +waybill +waybills +wayfarer +wayfarers +wayfaring +waylaid +waylay +waylayer +waylayers +waylaying +waylays +wayless +waypoint +waypoints +ways +wayside +waysides +wayward +waywardly +waywardness +wayworn +waziristan +wazoo +wazoos +we +we'd +we'll +we're +we've +weak +weaken +weakened +weakener +weakeners +weakening +weakens +weaker +weakest +weakfish +weakfishes +weakhearted +weakish +weaklier +weakliest +weakliness +weakling +weaklings +weakly +weakness +weaknesses +weakon +weakons +weakside +weal +weald +wealds +wealth +wealthier +wealthiest +wealthily +wealthiness +wealthy +wean +weaned +weaner +weaners +weaning +weanling +weanlings +weans +weapon +weaponed +weaponeer +weaponeering +weaponeers +weaponing +weaponless +weaponry +weapons +wear +wearability +wearable +wearables +wearer +wearers +wearied +wearier +wearies +weariest +weariful +wearifully +wearifulness +weariless +wearilessly +wearilessness +wearily +weariness +wearing +wearingly +wearisome +wearisomely +wearisomeness +wears +weary +wearying +weasand +weasands +weasel +weaseled +weaseling +weaselled +weaselling +weaselly +weasels +weasely +weather +weatherability +weatherboard +weatherboarded +weatherboarding +weathercast +weathercaster +weathercasters +weathercasts +weathercock +weathercocked +weathercocking +weathercocks +weathered +weatherglass +weatherglasses +weathering +weatherization +weatherizations +weatherize +weatherized +weatherizes +weatherizing +weatherliness +weatherly +weatherman +weathermen +weatherperson +weatherproof +weatherproofed +weatherproofing +weatherproofness +weatherproofs +weathers +weathervane +weathervanes +weatherworn +weave +weaved +weaver +weaverbird +weaverbirds +weavers +weaves +weaving +weavings +web +webbed +webbier +webbiest +webbing +webbings +webby +weber +webers +webfed +webfeet +webfoot +weblike +webs +webster +websters +webworm +webworms +weck +wecks +wed +wedded +weddell +wedder +wedders +wedding +weddings +wedel +wedeled +wedelling +wedeln +wedelns +wedels +wedge +wedged +wedges +wedgie +wedgies +wedging +wedgwood +wedgy +wedlock +wednesday +wednesdays +weds +wee +weed +weeded +weeder +weeders +weedier +weediest +weedily +weediness +weeding +weeds +weedy +week +weekday +weekdays +weekend +weekended +weekender +weekenders +weekending +weekends +weeklies +weeklong +weekly +weeknight +weeknights +weeks +weenie +weenier +weenies +weeniest +weensy +weeny +weep +weeper +weepers +weepie +weepier +weepies +weepiest +weeping +weeps +weepy +weer +weest +weever +weevers +weevil +weevilly +weevils +weevily +weft +wefts +wegener +wehrmacht +weigela +weigelas +weigh +weighable +weighed +weigher +weighers +weighing +weighs +weight +weighted +weightier +weightiest +weightily +weightiness +weighting +weightings +weightless +weightlessly +weightlessness +weightlifter +weightlifters +weightlifting +weights +weighty +weil +weil's +weimar +weimaraner +weimaraners +weinberg +weiner +weiners +weir +weird +weirder +weirdest +weirdie +weirdies +weirdly +weirdness +weirdnesses +weirdo +weirdoes +weirdos +weirdy +weirs +weisenheimer +weisenheimers +weismann +weismannism +wejack +wejacks +weka +wekas +welch +welched +welches +welching +welcome +welcomed +welcomely +welcomeness +welcomer +welcomers +welcomes +welcoming +weld +weldable +welded +welder +welders +welding +weldment +weldments +weldor +weldors +welds +welfare +welfarism +welfarist +welfarists +welkin +welkins +well +welladay +wellaway +wellaways +wellbeing +wellborn +welled +wellerism +wellerisms +wellhead +wellheads +wellie +wellies +welling +wellington +wellingtons +wellness +wells +wellspring +wellsprings +welly +welsbach +welsh +welshed +welsher +welshers +welshes +welshing +welshman +welshmen +welshwoman +welshwomen +welt +weltanschauung +weltanschauungen +weltanschauungs +welted +welter +weltered +weltering +welters +welterweight +welterweights +welting +welts +weltschmerz +wen +wenceslas +wench +wenched +wencher +wenchers +wenches +wenching +wend +wended +wending +wendish +wends +wens +went +wentletrap +wentletraps +wept +were +weregild +weregilds +weren +weren't +werewolf +werewolves +wergeld +wergelds +wergild +wergilds +werner +wernerite +wernerites +wernicke +werwolf +werwolves +weser +weskit +weskits +wesley +wesleyan +wesleyanism +wesleyans +west +westbound +wester +westered +westering +westerlies +westerly +western +westerner +westerners +westernization +westernizations +westernize +westernized +westernizes +westernizing +westernmost +westernness +westerns +westers +westing +westinghouse +westings +westphalia +westphalian +westphalians +westward +westwardly +westwards +wet +wetback +wetbacks +wether +wethers +wetland +wetlands +wetly +wetness +wets +wetsuit +wetsuits +wettability +wettable +wetted +wetter +wetterhorn +wetters +wettest +wetting +wettings +wettish +whack +whacked +whacker +whackers +whackier +whackiest +whacking +whacko +whackos +whacks +whacky +whale +whaleback +whalebacks +whaleboat +whaleboats +whalebone +whalebones +whaled +whalelike +whaler +whalers +whales +whaling +wham +whammed +whammies +whamming +whammo +whammy +whams +whang +whanged +whangee +whangees +whanging +whangs +whap +whapped +whapping +whaps +wharf +wharfage +wharfed +wharfing +wharfinger +wharfingers +wharfmaster +wharfmasters +wharfs +wharves +what +what'd +what're +what's +whatchamacallit +whatchamacallum +whatever +whatness +whatnot +whatnots +whatsis +whatsit +whatsits +whatsoever +wheal +wheals +wheat +wheatear +wheatears +wheaten +wheatgrass +wheatstone +wheatworm +wheatworms +whee +wheedle +wheedled +wheedler +wheedlers +wheedles +wheedling +wheedlingly +wheel +wheelbarrow +wheelbarrows +wheelbase +wheelchair +wheelchairs +wheeled +wheeler +wheelers +wheelhorse +wheelhorses +wheelhouse +wheelhouses +wheelie +wheelies +wheeling +wheelings +wheelless +wheelman +wheelmen +wheels +wheelsman +wheelsmen +wheelwork +wheelworks +wheelwright +wheelwrights +wheeze +wheezed +wheezer +wheezers +wheezes +wheezier +wheeziest +wheezily +wheeziness +wheezing +wheezingly +wheezy +whelk +whelks +whelky +whelm +whelmed +whelming +whelms +whelp +whelped +whelping +whelps +when +whence +whencesoever +whenever +whensoever +where +where'd +where're +where's +whereabout +whereabouts +whereas +whereat +whereby +wherefore +wherefores +wherefrom +wherein +whereinto +whereof +whereon +wheresoever +wherethrough +whereto +whereunto +whereupon +wherever +wherewith +wherewithal +wherries +wherry +whet +whether +whets +whetstone +whetstones +whetted +whetter +whetters +whetting +whew +whey +wheyey +wheylike +which +whichever +whichsoever +whicker +whickered +whickering +whickers +whidah +whidahs +whidbey +whiff +whiffed +whiffer +whiffers +whiffet +whiffets +whiffing +whiffle +whiffled +whiffler +whifflers +whiffles +whiffletree +whiffling +whiffs +whig +whiggery +whiggish +whiggism +whigs +while +whiled +whiles +whiling +whilom +whilst +whim +whimbrel +whimbrels +whimper +whimpered +whimperer +whimperers +whimpering +whimperingly +whimpers +whims +whimsey +whimseys +whimsical +whimsicalities +whimsicality +whimsically +whimsicalness +whimsies +whimsy +whin +whinchat +whinchats +whine +whined +whiner +whiners +whines +whiney +whing +whinge +whinged +whingeing +whinges +whinging +whinier +whiniest +whininess +whining +whiningly +whinnied +whinnies +whinny +whinnying +whins +whinstone +whinstones +whiny +whip +whipcord +whipcords +whiplash +whiplashes +whiplike +whipped +whipper +whippers +whippersnapper +whippersnappers +whippet +whippets +whippier +whippiest +whipping +whippings +whippletree +whippletrees +whippoorwill +whippoorwills +whippy +whips +whipsaw +whipsawed +whipsawing +whipsawn +whipsaws +whipstall +whipstalls +whipstitch +whipstitched +whipstitches +whipstitching +whipstock +whipstocks +whipt +whiptail +whiptails +whipworm +whipworms +whir +whirl +whirled +whirler +whirlers +whirlies +whirligig +whirligigs +whirling +whirlpool +whirlpools +whirls +whirlwind +whirlwinds +whirly +whirlybird +whirlybirds +whirr +whirred +whirring +whirrs +whirs +whish +whished +whishes +whishing +whisk +whiskbroom +whiskbrooms +whisked +whisker +whiskered +whiskerless +whiskers +whiskery +whiskey +whiskeys +whiskies +whisking +whisks +whisky +whisper +whispered +whisperer +whisperers +whispering +whisperingly +whisperings +whispers +whispery +whist +whistle +whistleable +whistleblower +whistleblowers +whistled +whistler +whistlers +whistles +whistling +whit +white +whitebait +whitebark +whitebeard +whitebeards +whitecap +whitecaps +whited +whiteface +whitefaces +whitefish +whitefishes +whiteflies +whitefly +whitefriars +whitehall +whitehead +whiteheads +whitehorse +whitely +whiten +whitened +whitener +whiteners +whiteness +whitening +whitens +whiteout +whiteouts +whiteprint +whiteprints +whiter +whites +whitesmith +whitesmiths +whitest +whitetail +whitetails +whitethroat +whitethroats +whitewall +whitewalls +whitewash +whitewashed +whitewasher +whitewashers +whitewashes +whitewashing +whitewater +whitewing +whitewings +whitewood +whitewoods +whitey +whiteys +whither +whithersoever +whitherward +whiting +whitings +whitish +whitleather +whitlow +whitman +whitmonday +whitney +whitsun +whitsunday +whitsuntide +whittington +whittle +whittled +whittler +whittlers +whittles +whittling +whity +whiz +whizbang +whizbangs +whizz +whizzbang +whizzed +whizzer +whizzers +whizzes +whizzing +who +who'd +who'll +who's +who've +whoa +whodunit +whodunits +whodunnit +whodunnits +whoever +whole +wholehearted +wholeheartedly +wholeheartedness +wholeness +wholes +wholesale +wholesaled +wholesaler +wholesalers +wholesales +wholesaling +wholesome +wholesomely +wholesomeness +wholesomer +wholesomest +wholistic +wholly +whom +whomever +whomp +whomped +whomping +whomps +whomso +whomsoever +whoo +whoop +whooped +whoopee +whoopees +whooper +whoopers +whooping +whoopla +whooplas +whoops +whoos +whoosh +whooshed +whooshes +whooshing +whop +whopped +whopper +whoppers +whopping +whops +whore +whored +whoredom +whoredoms +whorehouse +whorehouses +whoremaster +whoremasters +whoremonger +whoremongers +whores +whoreson +whoresons +whorfian +whoring +whorish +whorishly +whorishness +whorl +whorled +whorls +whort +whortle +whortleberries +whortleberry +whortles +whorts +whose +whosesoever +whoso +whosoever +whump +whumped +whumping +whumps +why +whydah +whydahs +whys +wicca +wiccan +wiccans +wichita +wichitas +wick +wicked +wickeder +wickedest +wickedly +wickedness +wicker +wickerwork +wicket +wicketkeeper +wicketkeepers +wickets +wicking +wickiup +wickiups +wicks +wicopies +wicopy +widal +widdershins +wide +wideawake +wideawakes +wideband +widely +widemouthed +widen +widened +widener +wideners +wideness +widening +widens +wideout +wideouts +wider +widespread +widest +widgeon +widgeons +widget +widgets +widish +widow +widowed +widower +widowerhood +widowers +widowhood +widowing +widows +width +widths +widthwise +wiedersehen +wield +wieldable +wielded +wielder +wielders +wieldier +wieldiest +wielding +wields +wieldy +wien +wiener +wieners +wienerwurst +wienerwursts +wienie +wienies +wiesbaden +wiesel +wife +wifehood +wifeless +wifeliness +wifely +wiffle +wifty +wig +wigan +wigans +wigeon +wigeons +wigged +wigging +wiggle +wiggled +wiggler +wigglers +wiggles +wiggling +wiggly +wight +wights +wiglet +wiglets +wigmaker +wigmakers +wigs +wigwag +wigwagged +wigwagger +wigwaggers +wigwagging +wigwags +wigwam +wigwams +wikiup +wikiups +wilberforce +wilco +wild +wildcard +wildcards +wildcat +wildcats +wildcatted +wildcatter +wildcatters +wildcatting +wildebeest +wildebeests +wilder +wildered +wildering +wilderment +wilderness +wildernesses +wilders +wildest +wildfire +wildfires +wildflower +wildflowers +wildfowl +wildfowler +wildfowlers +wildfowling +wildfowls +wilding +wildings +wildish +wildland +wildlands +wildlife +wildling +wildlings +wildly +wildness +wilds +wildwood +wildwoods +wile +wiled +wiles +wilful +wilhelmshaven +wilier +wiliest +wilily +wiliness +wiling +wilkes +will +willamette +willed +willedly +willedness +willemite +willemites +willemstad +willet +willets +willful +willfully +willfulness +william +willies +willing +willingly +willingness +williwaw +williwaws +willow +willowed +willowier +willowiest +willowing +willowlike +willows +willowware +willowy +willpower +wills +willy +wilmington +wilms +wilson +wilt +wilted +wilting +wilton +wilts +wiltshire +wily +wimble +wimbled +wimbledon +wimbles +wimbling +wimp +wimpiness +wimpish +wimpishness +wimple +wimpled +wimples +wimpling +wimps +wimpy +wimshurst +win +wince +winced +wincer +wincers +winces +winch +winched +wincher +winchers +winches +winchester +winchesters +winching +wincing +wind +windage +windbag +windbags +windblast +windblasts +windblown +windbreak +windbreaker +windbreakers +windbreaks +windburn +windburned +windburns +windcheater +windcheaters +windchill +windchills +winded +windedly +windedness +winder +winders +windfall +windfalls +windflaw +windflaws +windflower +windflowers +windgall +windgalls +windhoek +windhover +windhovers +windier +windiest +windily +windiness +winding +windingly +windings +windjammer +windjammers +windjamming +windlass +windlassed +windlasses +windlassing +windless +windlessly +windlestraw +windlestraws +windmill +windmilled +windmilling +windmills +window +windowed +windowing +windowless +windowpane +windowpanes +windows +windowsill +windowsills +windpipe +windpipes +windproof +windrow +windrowed +windrower +windrowers +windrowing +windrows +winds +windsailing +windscreen +windscreens +windshake +windshakes +windshield +windshields +windsock +windsocks +windsor +windstorm +windstorms +windsucker +windsuckers +windsucking +windsurf +windsurfed +windsurfer +windsurfers +windsurfing +windsurfs +windswept +windthrow +windup +windups +windward +windwards +windway +windways +windy +wine +winebibber +winebibbers +winebibbing +winebibbings +wined +wineglass +wineglasses +winegrower +winegrowers +winemaker +winemakers +winemaking +winepress +winepresses +wineries +winery +wines +winesap +winesaps +wineshop +wineshops +wineskin +wineskins +winetasting +winetastings +winey +wing +wingback +wingbacks +wingbow +wingbows +wingchair +wingchairs +wingding +wingdings +winged +winger +wingers +winging +wingless +winglessness +winglet +winglets +winglike +wingman +wingmen +wingover +wingovers +wings +wingspan +wingspans +wingspread +wingspreads +wingtip +wingtips +wingy +winier +winiest +wining +wink +winked +winker +winkers +winking +winkle +winkled +winkles +winkling +winks +winless +winnability +winnable +winnebago +winnebagoes +winnebagos +winner +winners +winnie +winnies +winning +winningest +winningly +winningness +winnings +winnipeg +winnipegosis +winnipesaukee +winnow +winnowed +winnower +winnowers +winnowing +winnows +wino +winos +wins +winsome +winsomely +winsomeness +winter +winterberries +winterberry +wintered +winterer +winterers +wintergreen +wintergreens +winterier +winteriest +wintering +winterish +winterization +winterizations +winterize +winterized +winterizes +winterizing +winterkill +winterkilled +winterkilling +winterkills +winterly +winters +wintertide +wintertime +wintery +wintrier +wintriest +wintrily +wintriness +wintry +winy +winze +winzes +wipe +wiped +wipeout +wipeouts +wiper +wipers +wipes +wiping +wirable +wire +wired +wiredraw +wiredrawer +wiredrawers +wiredrawing +wiredrawn +wiredraws +wiredrew +wiregrass +wiregrasses +wirehair +wirehaired +wirehairs +wireless +wirelessed +wirelesses +wirelessing +wirelike +wireman +wiremen +wirephoto +wirepuller +wirepullers +wirepulling +wirer +wirers +wires +wiretap +wiretapped +wiretapper +wiretappers +wiretapping +wiretaps +wirewalker +wirewalkers +wirework +wireworks +wireworm +wireworms +wirier +wiriest +wirily +wiriness +wiring +wiry +wisconsin +wisconsinite +wisconsinites +wisdom +wise +wiseacre +wiseacres +wiseass +wiseasses +wisecrack +wisecracked +wisecracker +wisecrackers +wisecracking +wisecracks +wised +wisely +wiseness +wisenheimer +wisenheimers +wisent +wisents +wiser +wises +wisest +wisewoman +wisewomen +wish +wishbone +wishbones +wished +wisher +wishers +wishes +wishful +wishfully +wishfulness +wishing +wishy +wising +wisp +wisped +wispily +wispiness +wisping +wispish +wisps +wispy +wistaria +wistarias +wisteria +wisterias +wistful +wistfully +wistfulness +wit +witan +witch +witchcraft +witched +witcher +witcheries +witchers +witchery +witches +witchgrass +witchgrasses +witching +witchingly +witchlike +witchweed +witchweeds +witchy +witenagemot +witenagemote +with +withal +withdraw +withdrawable +withdrawal +withdrawals +withdrawer +withdrawers +withdrawing +withdrawn +withdrawnness +withdraws +withdrew +withe +wither +withered +withering +witheringly +witherite +witherites +withers +withershins +withes +withheld +withhold +withholder +withholders +withholding +withholdings +withholds +withies +within +withindoors +without +withoutdoors +withstand +withstander +withstanders +withstanding +withstands +withstood +withy +witless +witlessly +witlessness +witling +witlings +witloof +witloofs +witness +witnessed +witnesser +witnessers +witnesses +witnessing +wits +witted +wittedly +wittedness +wittenberg +wittgenstein +wittgensteinian +witticism +witticisms +wittier +wittiest +wittily +wittiness +witting +wittingly +wittings +wittol +wittols +witty +witwatersrand +wive +wived +wivern +wiverns +wives +wiving +wiz +wizard +wizardly +wizardries +wizardry +wizards +wizen +wizened +wizening +wizens +wizes +wkly +woad +woads +woadwaxen +woadwaxens +wobble +wobbled +wobbler +wobblers +wobbles +wobblier +wobblies +wobbliest +wobbliness +wobbling +wobbly +wodehouse +woden +wodge +wodges +woe +woebegone +woebegoneness +woeful +woefully +woefulness +woes +woffington +woful +wok +woke +woken +woks +wold +wolds +wolf +wolfberries +wolfberry +wolfed +wolfer +wolfers +wolffian +wolffish +wolfhound +wolfhounds +wolfing +wolfish +wolfishly +wolfishness +wolflike +wolfram +wolframite +wolframites +wolframs +wolfs +wolfsbane +wolfsbanes +wollastonite +wollastonites +wolof +wolsey +wolverine +wolverines +wolves +woman +womanfully +womanhood +womanish +womanishly +womanishness +womanism +womanist +womanists +womanize +womanized +womanizer +womanizers +womanizes +womanizing +womankind +womanless +womanlier +womanliest +womanlike +womanliness +womanly +womanpower +womb +wombat +wombats +wombed +wombs +women +womenfolk +womenfolks +womenkind +womera +womeras +wommera +wommeras +won +won't +wonder +wondered +wonderer +wonderers +wonderful +wonderfully +wonderfulness +wondering +wonderingly +wonderland +wonderlands +wonderment +wonders +wonderwork +wonderworker +wonderworkers +wonderworking +wonderworks +wondrous +wondrously +wondrousness +wonk +wonkier +wonkiest +wonks +wonky +wont +wonted +wontedly +wontedness +wonting +wonton +wontons +wonts +woo +wood +woodbin +woodbine +woodbines +woodbins +woodblock +woodblocks +woodborer +woodborers +woodboring +woodcarver +woodcarvers +woodcarving +woodcarvings +woodchat +woodchats +woodchopper +woodchoppers +woodchopping +woodchuck +woodchucks +woodcock +woodcocks +woodcraft +woodcrafter +woodcrafters +woodcrafting +woodcrafts +woodcut +woodcuts +woodcutter +woodcutters +woodcutting +woodcuttings +wooded +wooden +woodenhead +woodenheaded +woodenheads +woodenly +woodenness +woodenware +woodie +woodier +woodies +woodiest +woodiness +wooding +woodland +woodlander +woodlanders +woodlands +woodlark +woodlarks +woodlore +woodlot +woodlots +woodman +woodmen +woodnote +woodnotes +woodpecker +woodpeckers +woodpile +woodpiles +woodprint +woodprints +woodruff +woodruffs +woods +woodshed +woodshedded +woodshedding +woodsheds +woodshop +woodshops +woodsia +woodsias +woodsier +woodsiest +woodsman +woodsmen +woodstove +woodstoves +woodsy +woodturner +woodturners +woodturning +woodville +woodwaxen +woodwaxens +woodwind +woodwinds +woodwork +woodworker +woodworkers +woodworking +woodworks +woodworm +woodworms +woody +wooed +wooer +wooers +woof +woofed +woofer +woofers +woofing +woofs +woogie +wooing +wool +wooled +woolen +woolens +woolgather +woolgathered +woolgatherer +woolgatherers +woolgathering +woolgathers +woolgrower +woolgrowers +woolgrowing +woolie +woolier +woolies +wooliest +woolled +woollen +woollens +woollier +woollies +woolliest +woollily +woolliness +woolly +woolpack +woolpacks +wools +woolsack +woolsacks +woolsey +woolshed +woolsheds +woolskin +woolskins +woolsorter +woolworker +woolworkers +woolworth +wooly +woomera +woomeras +woops +woos +woozier +wooziest +woozily +wooziness +woozy +wop +wops +worcester +worcestershire +word +wordage +wordbook +wordbooks +worded +wordier +wordiest +wordily +wordiness +wording +wordings +wordless +wordlessly +wordlessness +wordmonger +wordmongering +wordmongers +wordplay +wordplays +words +wordsmith +wordsmithery +wordsmiths +wordsworth +wordsworthian +wordy +wore +work +workability +workable +workableness +workably +workaday +workaholic +workaholics +workaholism +workaround +workarounds +workbag +workbags +workbasket +workbaskets +workbench +workbenches +workboat +workboats +workbook +workbooks +workbox +workboxes +workday +workdays +worked +worker +workers +workfare +workflow +workflows +workfolk +workfolks +workforce +workforces +workhorse +workhorses +workhouse +workhouses +working +workingman +workingmen +workings +workingwoman +workingwomen +workless +worklessness +workload +workloads +workman +workmanlike +workmanly +workmanship +workmate +workmates +workmen +workout +workouts +workpeople +workpiece +workpieces +workplace +workplaces +workroom +workrooms +works +worksheet +worksheets +workshop +workshops +workspace +workspaces +workstation +workstations +worktable +worktables +workup +workups +workweek +workweeks +workwoman +workwomen +world +worlder +worlders +worldlier +worldliest +worldliness +worldling +worldlings +worldly +worlds +worldview +worldviews +worldwide +worm +wormed +wormer +wormers +wormgrass +wormgrasses +wormhole +wormholes +wormier +wormiest +worminess +worming +wormlike +worms +wormseed +wormseeds +wormwood +wormwoods +wormy +worn +worried +worriedly +worrier +worriers +worries +worriment +worriments +worrisome +worrisomely +worrisomeness +worry +worrying +worryingly +worrywart +worrywarts +worse +worsen +worsened +worsening +worsens +worship +worshiped +worshiper +worshipers +worshipful +worshipfully +worshipfulness +worshiping +worshipless +worshipped +worshipper +worshippers +worshipping +worships +worsleya +worsleyas +worst +worsted +worsteds +worsting +worsts +wort +worth +worthed +worthful +worthier +worthies +worthiest +worthily +worthiness +worthing +worthless +worthlessly +worthlessness +worths +worthwhile +worthwhileness +worthy +wot +wotan +wots +wotted +wotting +would +would've +wouldest +wouldn +wouldn't +wouldst +wound +wounded +woundedly +wounding +woundingly +woundless +wounds +woundwort +woundworts +wove +woven +wow +wowed +wowing +wows +wowser +wowsers +wp +wpm +wrack +wracked +wrackful +wracking +wracks +wraith +wraithlike +wraiths +wrangel +wrangell +wrangle +wrangled +wrangler +wranglers +wrangles +wrangling +wrap +wraparound +wraparounds +wrapped +wrapper +wrappers +wrapping +wrappings +wraps +wrapt +wrasse +wrasses +wrath +wrathful +wrathfully +wrathfulness +wrathy +wreak +wreaked +wreaking +wreaks +wreath +wreathe +wreathed +wreathes +wreathing +wreaths +wreathy +wreck +wreckage +wrecked +wrecker +wreckers +wrecking +wrecks +wren +wrench +wrenched +wrenches +wrenching +wrenchingly +wrens +wrest +wrested +wrester +wresters +wresting +wrestle +wrestled +wrestler +wrestlers +wrestles +wrestling +wrests +wretch +wretched +wretcheder +wretchedest +wretchedly +wretchedness +wretches +wried +wrier +wries +wriest +wriggle +wriggled +wriggler +wrigglers +wriggles +wriggling +wriggly +wright +wrights +wrigley +wring +wringer +wringers +wringing +wrings +wrinkle +wrinkled +wrinkles +wrinkling +wrinkly +wrist +wristband +wristbands +wristed +wristier +wristiest +wristlet +wristlets +wristlock +wristlocks +wrists +wristwatch +wristwatches +wristy +writ +writable +write +writer +writerly +writers +writes +writhe +writhed +writhen +writher +writhers +writhes +writhing +writing +writings +writs +written +wrong +wrongdoer +wrongdoers +wrongdoing +wrongdoings +wronged +wronger +wrongers +wrongest +wrongful +wrongfully +wrongfulness +wrongheaded +wrongheadedly +wrongheadedness +wronging +wrongly +wrongness +wrongs +wrote +wroth +wrought +wrung +wry +wryer +wryest +wrying +wryly +wryneck +wrynecks +wryness +wt +wulfenite +wulfenites +wunderbar +wunderkind +wunderkinder +wurst +wurtemburg +wurzburg +wurzel +wurzels +wushu +wyandot +wyandots +wyandotte +wyandottes +wyatt +wych +wycherley +wyclif +wycliffe +wycliffite +wycliffites +wye +wyes +wyn +wynn +wynns +wyoming +wysiwyg +wyvern +wyverns +württemberg +x +xanadu +xanadus +xanthan +xanthate +xanthates +xanthene +xanthenes +xanthic +xanthine +xanthines +xanthippe +xanthochroic +xanthochroid +xanthochroids +xanthoma +xanthomas +xanthomata +xanthomatoses +xanthomatosis +xanthomatous +xanthone +xanthones +xanthophore +xanthophores +xanthophyll +xanthophyllic +xanthophyllous +xanthophylls +xanthopterin +xanthopterins +xanthous +xantippe +xaverian +xavier +xebec +xebecs +xed +xenia +xenias +xenobiotic +xenobiotics +xenoblast +xenoblasts +xenocryst +xenocrysts +xenodiagnoses +xenodiagnosis +xenodiagnostic +xenogamies +xenogamous +xenogamy +xenogeneic +xenogenesis +xenogenetic +xenogenic +xenograft +xenografts +xenolith +xenolithic +xenoliths +xenon +xenophanes +xenophile +xenophiles +xenophilia +xenophilous +xenophobe +xenophobes +xenophobia +xenophobic +xenophobically +xenophon +xenotropic +xerarch +xeric +xerically +xericity +xeriscape +xeroderma +xerodermas +xerodermia +xerodermias +xerographer +xerographers +xerographic +xerographically +xerography +xerophile +xerophilous +xerophily +xerophthalmia +xerophthalmias +xerophthalmic +xerophyte +xerophytes +xerophytic +xerophytically +xerophytism +xeroradiography +xerosere +xeroseres +xeroses +xerosis +xerothermic +xerox +xeroxed +xeroxes +xeroxing +xerxes +xhosa +xhosas +xi +xinjiang +xiphisterna +xiphisternum +xiphoid +xiphoids +xiphosuran +xiphosurans +xis +xizang +xmas +xmases +xosa +xosas +xray +xs +xu +xylan +xylans +xylem +xylene +xylenes +xylidine +xylidines +xylitol +xylitols +xylograph +xylographed +xylographer +xylographers +xylographic +xylographical +xylographically +xylographing +xylographs +xylography +xyloid +xylol +xylols +xylophage +xylophages +xylophagous +xylophone +xylophones +xylophonist +xylophonists +xylose +xyloses +xylotomies +xylotomist +xylotomists +xylotomy +xyster +xysters +y +y'all +yabber +yabbered +yabbering +yabbers +yablonovy +yacht +yachted +yachter +yachters +yachting +yachts +yachtsman +yachtsmen +yachtswoman +yachtswomen +yack +yacked +yackety +yacking +yacks +yag +yagi +yagis +yahoo +yahooism +yahoos +yahveh +yahvist +yahweh +yahwism +yahwist +yahwistic +yak +yakima +yakimas +yakitori +yakitoris +yakked +yakking +yakow +yakows +yaks +yakut +yakuts +yakuza +yale +yalta +yam +yamasee +yamasees +yamen +yamens +yammer +yammered +yammerer +yammerers +yammering +yammers +yams +yang +yangtze +yank +yanked +yankee +yankeedom +yankeeism +yankeeisms +yankees +yanking +yanks +yankton +yanktonai +yanktonais +yanktons +yanqui +yantra +yantras +yao +yaos +yaoundé +yap +yapok +yapoks +yapped +yapper +yappers +yapping +yaps +yaqui +yaquis +yarborough +yarboroughs +yard +yardage +yardarm +yardarms +yardbird +yardbirds +yarded +yarding +yardman +yardmaster +yardmasters +yardmen +yards +yardstick +yardsticks +yare +yarely +yarmelke +yarmelkes +yarmulke +yarmulkes +yarn +yarned +yarner +yarners +yarning +yarns +yarrow +yarrows +yashmac +yashmacs +yashmak +yashmaks +yasmak +yasmaks +yatagan +yatagans +yataghan +yataghans +yaup +yauped +yauping +yaupon +yaupons +yaups +yautia +yavapai +yavapais +yaw +yawed +yawing +yawl +yawls +yawn +yawned +yawner +yawners +yawning +yawningly +yawns +yawp +yawped +yawper +yawpers +yawping +yawps +yaws +ycleped +yclept +yd +ye +yea +yeah +yean +yeaned +yeaning +yeanling +yeanlings +yeans +year +yearbook +yearbooks +yearend +yearends +yearlies +yearling +yearlings +yearlong +yearly +yearn +yearned +yearner +yearners +yearning +yearningly +yearnings +yearns +years +yeas +yeast +yeasted +yeastier +yeastiest +yeastily +yeastiness +yeasting +yeasts +yeasty +yeats +yeatsian +yecch +yech +yegg +yeggs +yell +yelled +yeller +yellers +yelling +yellow +yellowbellied +yellowbellies +yellowbelly +yellowbird +yellowbirds +yellowcake +yellowcakes +yellowed +yellower +yellowest +yellowfin +yellowhammer +yellowhammers +yellowing +yellowish +yellowishness +yellowknife +yellowlegs +yellowness +yellows +yellowstone +yellowtail +yellowtails +yellowthroat +yellowthroats +yellowware +yellowweed +yellowweeds +yellowwood +yellowwoods +yellowy +yells +yelp +yelped +yelper +yelpers +yelping +yelps +yemen +yemeni +yemenis +yemenite +yemenites +yen +yenned +yenning +yens +yenta +yentas +yeoman +yeomanly +yeomanries +yeomanry +yeomen +yep +yerba +yerkish +yersinia +yersiniae +yersinioses +yersiniosis +yes +yeses +yeshiva +yeshivah +yeshivahs +yeshivas +yeshivot +yessed +yessing +yesterday +yesterdays +yestereve +yestereven +yesterevening +yesterevenings +yesterevens +yestereves +yestermorn +yestermorning +yestermornings +yestermorns +yesternight +yesternights +yesteryear +yesteryears +yet +yeti +yetis +yew +yews +ygdrasil +yggdrasil +yid +yiddish +yiddishism +yiddishist +yiddishists +yids +yield +yielded +yielder +yielders +yielding +yieldingly +yieldingness +yields +yikes +yin +yinglish +yip +yipe +yipes +yipped +yippee +yippie +yippies +yipping +yips +ylang +ylem +ylems +ymca +ymir +yo +yock +yocked +yocking +yocks +yod +yodel +yodeled +yodeler +yodelers +yodeling +yodelled +yodelling +yodels +yodh +yoed +yoga +yogh +yoghourt +yoghourts +yoghurt +yoghurts +yogi +yogic +yogin +yogins +yogis +yogurt +yogurts +yohimbine +yohimbines +yoicks +yoing +yoke +yoked +yokefellow +yokefellows +yokel +yokels +yokes +yoking +yokohama +yokuts +yolk +yolked +yolks +yolky +yom +yon +yonder +yoni +yonic +yonis +yoo +yore +yorick +york +yorker +yorkers +yorkie +yorkies +yorkist +yorkists +yorkshire +yoruba +yoruban +yorubas +yos +yosemite +you +you'd +you'll +you're +you've +young +young'un +young'uns +youngberries +youngberry +younger +youngest +youngish +youngling +younglings +youngness +youngster +youngsters +younker +younkers +your +yours +yourself +yourselfer +yourselfers +yourselves +youth +youthful +youthfully +youthfulness +youthquake +youths +yow +yowl +yowled +yowling +yowls +ypres +yquem +yquems +ytterbia +ytterbias +ytterbic +ytterbium +yttria +yttrias +yttric +yttrium +yuan +yuans +yuca +yucatec +yucatecan +yucatecans +yucatecs +yucatán +yucca +yuccas +yuchi +yuchis +yuck +yuckier +yuckiest +yuckiness +yucky +yuga +yugoslav +yugoslavia +yugoslavian +yugoslavians +yugoslavs +yuk +yukon +yulan +yulans +yule +yuletide +yum +yuma +yuman +yumas +yummier +yummiest +yumminess +yummy +yunnan +yup +yupik +yupiks +yuppie +yuppiedom +yuppies +yurok +yuroks +yurt +yurts +ywis +z +zabaglione +zabagliones +zacharias +zaddik +zaddikim +zaffer +zaffers +zaffre +zaffres +zaftig +zag +zagged +zagging +zagreb +zagreus +zagros +zags +zaibatsu +zaikai +zaire +zairean +zaireans +zaires +zairian +zairians +zambesi +zambezi +zambia +zambian +zambians +zamia +zamias +zamindar +zamindari +zamindaris +zamindars +zanana +zananas +zander +zanders +zanier +zanies +zaniest +zanily +zaniness +zany +zanzibar +zap +zapata +zapateado +zapateados +zapateo +zapotec +zapotecs +zapped +zapper +zappers +zappier +zappiest +zapping +zappy +zaps +zarathustra +zareba +zarebas +zareeba +zareebas +zarf +zarfs +zariba +zaribas +zarzuela +zastruga +zastrugas +zauberflöte +zax +zaxes +zayin +zazen +zaïrean +zaïreans +zeal +zealand +zealander +zealanders +zealot +zealotries +zealotry +zealots +zealous +zealously +zealousness +zeatin +zeatins +zebec +zebeck +zebecks +zebecs +zebedee +zebra +zebras +zebrawood +zebrawoods +zebrine +zebroid +zebroids +zebu +zebulon +zebulun +zebus +zecchin +zecchini +zecchino +zecchinos +zecchins +zechariah +zechin +zechins +zed +zedoaries +zedoary +zedonk +zedonks +zeds +zee +zeebrugge +zeeland +zeeman +zees +zeffirelli +zein +zeins +zeitgeber +zeitgebers +zeitgeist +zeitgeists +zek +zeks +zelkova +zelkovas +zemindar +zemindaries +zemindars +zemindary +zemlya +zemstvo +zemstvos +zen +zenana +zenanas +zend +zener +zenist +zenists +zenith +zenithal +zeniths +zeno +zeolite +zeolites +zeolitic +zephaniah +zephyr +zephyrs +zephyrus +zeppelin +zeppelins +zerk +zerks +zermatt +zero +zeroed +zeroes +zeroing +zeros +zeroth +zest +zested +zester +zesters +zestful +zestfully +zestfulness +zestier +zestiest +zesting +zestless +zests +zesty +zeta +zethos +zethus +zeugma +zeugmas +zeus +zeuxis +zhejiang +zibeline +zibelines +zibelline +zibellines +zibet +zibeth +zibeths +zibets +zidovudine +zidovudines +ziegfeld +zig +zigged +zigging +ziggurat +ziggurats +zigs +zigzag +zigzagged +zigzagger +zigzaggers +zigzagging +zigzags +zilch +zilches +zill +zillion +zillionaire +zillionaires +zillions +zillionth +zillionths +zills +zimbabwe +zimbabwean +zimbabweans +zimmermann +zinc +zincate +zincates +zinced +zincing +zincite +zincites +zincked +zinckenite +zinckenites +zincking +zincks +zincograph +zincographer +zincographers +zincographic +zincographical +zincographs +zincography +zincs +zineb +zinebs +zinfandel +zinfandels +zing +zingari +zingaro +zinged +zinger +zingers +zingier +zingiest +zinging +zings +zingy +zinkenite +zinkenites +zinnia +zinnias +zion +zionism +zionist +zionistic +zionists +zip +zipless +zipped +zipper +zippered +zippering +zippers +zippier +zippiest +zipping +zippy +zips +ziram +zirams +zircaloy +zircaloys +zircon +zirconia +zirconias +zirconium +zircons +zit +zither +zitherist +zitherists +zithern +zitherns +zithers +ziti +zits +zizith +zloty +zlotys +zoa +zoantharian +zoantharians +zoaria +zoarial +zoarium +zoariums +zocalo +zocalos +zodiac +zodiacal +zodiacs +zoea +zoeae +zoeas +zoecia +zoecium +zoffany +zoftig +zoisite +zoisites +zola +zombi +zombie +zombielike +zombies +zombification +zombifications +zombified +zombifies +zombify +zombifying +zombiism +zombis +zona +zonae +zonal +zonally +zonary +zonate +zonated +zonation +zone +zoned +zoner +zoners +zones +zonetime +zonetimes +zonian +zonians +zoning +zonk +zonked +zonking +zonks +zontian +zontians +zonule +zonules +zoo +zoochlorella +zoochlorellae +zoochlorellas +zoochore +zoochores +zooecia +zooecium +zooflagellate +zooflagellates +zoogenic +zoogenous +zoogeographer +zoogeographers +zoogeographic +zoogeographical +zoogeographically +zoogeography +zooglea +zoogleae +zoogleal +zoogleas +zoogloea +zoogloeae +zoogloeas +zoographic +zoographical +zoography +zooid +zooidal +zooids +zookeeper +zookeepers +zooks +zoolater +zoolaters +zoolatrous +zoolatry +zoologic +zoological +zoologically +zoologies +zoologist +zoologists +zoology +zoom +zoomed +zoometric +zoometrical +zoometrically +zoometries +zoometry +zooming +zoomorph +zoomorphic +zoomorphism +zoomorphs +zooms +zoon +zoonoses +zoonosis +zoonotic +zoons +zooparasite +zooparasites +zooparasitic +zoophagous +zoophile +zoophiles +zoophilia +zoophilic +zoophilism +zoophilous +zoophily +zoophobe +zoophobes +zoophobia +zoophyte +zoophytes +zoophytic +zoophytical +zooplankter +zooplankters +zooplankton +zooplanktonic +zooplastic +zooplasties +zooplasty +zoos +zoosperm +zoosperms +zoosporangia +zoosporangium +zoospore +zoospores +zoosporic +zoosporous +zoosterol +zoosterols +zoot +zootechnical +zootechnician +zootechnicians +zootechnics +zootechny +zootomic +zootomical +zootomies +zootomist +zootomists +zootomy +zootoxin +zootoxins +zooty +zooxanthella +zooxanthellae +zori +zoril +zorilla +zorillas +zorille +zorilles +zorils +zoris +zorn +zoroaster +zoroastrian +zoroastrianism +zoroastrians +zoster +zosters +zouave +zouaves +zounds +zowie +zoysia +zucchetto +zucchettos +zucchini +zucchinis +zugspitze +zugunruhe +zugzwang +zugzwangs +zulu +zululand +zulus +zuni +zunian +zunis +zuppa +zurich +zutphen +zuñi +zuñian +zuñis +zwieback +zwiebacks +zwingli +zwinglian +zwinglianism +zwinglians +zwitterion +zwitterionic +zwitterions +zydeco +zygapophyseal +zygapophyses +zygapophysial +zygapophysis +zygodactyl +zygodactylous +zygodactyls +zygogeneses +zygogenesis +zygogenetic +zygoma +zygomas +zygomata +zygomatic +zygomorphic +zygomorphism +zygomorphous +zygomorphy +zygoses +zygosis +zygosity +zygospore +zygospores +zygote +zygotene +zygotenes +zygotes +zygotic +zygotically +zymase +zymases +zymogen +zymogenic +zymogenous +zymogens +zymogram +zymograms +zymologic +zymological +zymologist +zymologists +zymology +zymolysis +zymolytic +zymometer +zymometers +zymosan +zymosans +zymoscope +zymoscopes +zymoses +zymosis +zymotic +zymotically +zymurgy +zyzzyva +zyzzyvas +zákros +zöllner +zöllner's +zürich +à +âge +åland +ångstrom +ångstroms +éclair +éclaircissement +éclairs +éclat +éclats +école +écoles +écorché +écrasez +écu +écus +élan +élans +élite +élites +élitism +élitist +élitists +émigré +émigrés +éminence +éminences +époque +épée +épéeist +épéeists +épées +étagère +étagères +état +étienne +étoile +étoiles +étouffée +étouffées +étui +étuis +évian +évêque +être +öland +öre +øresund +œil +œuvre \ No newline at end of file diff --git a/Trie/Trie/TrieTests/Info.plist b/Trie/Trie/TrieTests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Trie/Trie/TrieTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift new file mode 100644 index 000000000..236908ece --- /dev/null +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -0,0 +1,162 @@ +// +// TrieTests.swift +// TrieTests +// +// Created by Rick Zaccone on 2016-12-12. +// Copyright © 2016 Rick Zaccone. All rights reserved. +// + +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() + } + + /// Don't need to do anything here because the wordArrayu 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 trie.count == 0 else { + return + } + let numberOfWordsToInsert = wordArray!.count + for i in 0.. + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Trie/Trie/TrieUITests/TrieUITests.swift b/Trie/Trie/TrieUITests/TrieUITests.swift new file mode 100644 index 000000000..f3da2a67f --- /dev/null +++ b/Trie/Trie/TrieUITests/TrieUITests.swift @@ -0,0 +1,36 @@ +// +// TrieUITests.swift +// TrieUITests +// +// Created by Rick Zaccone on 2016-12-12. +// Copyright © 2016 Rick Zaccone. All rights reserved. +// + +import XCTest + +class TrieUITests: XCTestCase { + + override func setUp() { + super.setUp() + + // 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’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() + } + + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + +} From 1e23b7f859ed83e21dd37941113102af0d8c4d28 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 13 Dec 2016 14:30:07 -0800 Subject: [PATCH 0267/1275] Code updates --- Strassen Matrix Multiplication/Matrix.swift | 237 ++++++++++++++++++ .../MatrixSize.swift | 17 ++ Strassen Matrix Multiplication/Number.swift | 41 +++ 3 files changed, 295 insertions(+) diff --git a/Strassen Matrix Multiplication/Matrix.swift b/Strassen Matrix Multiplication/Matrix.swift index 493e27e06..657cf3c80 100644 --- a/Strassen Matrix Multiplication/Matrix.swift +++ b/Strassen Matrix Multiplication/Matrix.swift @@ -7,3 +7,240 @@ // import Foundation + +enum RowOrColumn { + case row, column +} + +struct Matrix { + + // MARK: - Variables + + let rows: Int, columns: Int + var grid: [T] + + var isSquare: Bool { + return rows == columns + } + + var size: MatrixSize { + return MatrixSize(rows: rows, columns: columns) + } + + // MARK: - Init + + init(rows: Int, columns: Int, initialValue: T = T.zero) { + self.rows = rows + self.columns = columns + self.grid = Array(repeating: initialValue, count: rows * columns) + } + + init(size: Int, initialValue: T = T.zero) { + self.rows = size + self.columns = size + self.grid = Array(repeating: initialValue, count: rows * columns) + } + + // MARK: - Subscript + + subscript(row: Int, column: Int) -> T { + get { + assert(indexIsValid(row: row, column: column), "Index out of range") + return grid[(row * columns) + column] + } + set { + assert(indexIsValid(row: row, column: column), "Index out of range") + grid[(row * columns) + column] = newValue + } + } + + subscript(type: RowOrColumn, value: Int) -> [T] { + get { + switch type { + case .row: + assert(indexIsValid(row: value, column: 0), "Index out of range") + return Array(grid[(value * columns)..<(value * columns) + columns]) + case .column: + assert(indexIsValid(row: 0, column: value), "Index out of range") + var columns: [T] = [] + for row in 0.. Bool { + return row >= 0 && row < rows && column >= 0 && column < columns + } + + private func strassenR(by B: Matrix) -> Matrix { + let A = self + assert(A.isSquare && B.isSquare, "This function requires square matricies!") + guard A.rows > 1 && B.rows > 1 else { return A * B } + + let n = A.rows + let nBy2 = n / 2 + + var a11 = Matrix(size: nBy2) + var a12 = Matrix(size: nBy2) + var a21 = Matrix(size: nBy2) + var a22 = Matrix(size: nBy2) + var b11 = Matrix(size: nBy2) + var b12 = Matrix(size: nBy2) + var b21 = Matrix(size: nBy2) + var b22 = Matrix(size: nBy2) + + for i in 0.. Int { + return Int(pow(2, ceil(log2(Double(n))))) + } + + // MARK: - Functions + + func strassenMatrixMultiply(by B: Matrix) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + let n = max(A.rows, A.columns, B.rows, B.columns) + let m = nextPowerOfTwo(of: n) + + var APrep = Matrix(size: m) + var BPrep = Matrix(size: m) + + A.size.forEach { (i, j) in + APrep[i,j] = A[i,j] + } + + B.size.forEach { (i, j) in + BPrep[i,j] = B[i,j] + } + + let CPrep = APrep.strassenR(by: BPrep) + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term multiply matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0.. Void) rethrows { + for row in 0.. Bool { + return lhs.columns == rhs.columns && lhs.rows == rhs.rows +} diff --git a/Strassen Matrix Multiplication/Number.swift b/Strassen Matrix Multiplication/Number.swift index 1bd6cf634..34c6d5308 100644 --- a/Strassen Matrix Multiplication/Number.swift +++ b/Strassen Matrix Multiplication/Number.swift @@ -7,3 +7,44 @@ // import Foundation + +protocol Number: Multipliable, Addable { + static var zero: Self { get } +} + +protocol Addable { + static func +(lhs: Self, rhs: Self) -> Self + static func -(lhs: Self, rhs: Self) -> Self +} + +protocol Multipliable { + static func *(lhs: Self, rhs: Self) -> Self +} + +extension Int: Number { + static var zero: Int { + return 0 + } +} + +extension Double: Number { + static var zero: Double { + return 0.0 + } +} + +extension Float: Number { + static var zero: Float { + return 0.0 + } +} + + +extension Array where Element: Number { + func dot(_ b: Array) -> Element { + let a = self + assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") + let c = a.indices.map{ a[$0] * b[$0] } + return c.reduce(Element.zero, { $0 + $1 }) + } +} From 31bc4c3159ea7574ee557ad46dbb65be33987395 Mon Sep 17 00:00:00 2001 From: Nagasawa Hiroki Date: Thu, 15 Dec 2016 08:52:41 +0900 Subject: [PATCH 0268/1275] Use lower camel case in enum case --- .../BinaryTree.playground/Contents.swift | 42 +++++++++---------- Binary Tree/BinaryTree.swift | 24 +++++------ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index b35e90c27..b4d65ec1f 100644 --- a/Binary Tree/BinaryTree.playground/Contents.swift +++ b/Binary Tree/BinaryTree.playground/Contents.swift @@ -1,14 +1,14 @@ //: Playground - noun: a place where people can play public indirect enum BinaryTree { - case Node(BinaryTree, T, BinaryTree) - case Empty + case node(BinaryTree, T, BinaryTree) + case empty public var count: Int { switch self { - case let .Node(left, _, right): + case let .node(left, _, right): return left.count + 1 + right.count - case .Empty: + case .empty: return 0 } } @@ -17,9 +17,9 @@ public indirect enum BinaryTree { extension BinaryTree: CustomStringConvertible { public var description: String { switch self { - case let .Node(left, value, right): + case let .node(left, value, right): return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" - case .Empty: + case .empty: return "" } } @@ -28,24 +28,24 @@ extension BinaryTree: CustomStringConvertible { // leaf nodes -let node5 = BinaryTree.Node(.Empty, "5", .Empty) -let nodeA = BinaryTree.Node(.Empty, "a", .Empty) -let node10 = BinaryTree.Node(.Empty, "10", .Empty) -let node4 = BinaryTree.Node(.Empty, "4", .Empty) -let node3 = BinaryTree.Node(.Empty, "3", .Empty) -let nodeB = BinaryTree.Node(.Empty, "b", .Empty) +let node5 = BinaryTree.node(.empty, "5", .empty) +let nodeA = BinaryTree.node(.empty, "a", .empty) +let node10 = BinaryTree.node(.empty, "10", .empty) +let node4 = BinaryTree.node(.empty, "4", .empty) +let node3 = BinaryTree.node(.empty, "3", .empty) +let nodeB = BinaryTree.node(.empty, "b", .empty) // intermediate nodes on the left -let aMinus10 = BinaryTree.Node(nodeA, "-", node10) -let timesLeft = BinaryTree.Node(node5, "*", aMinus10) +let aMinus10 = BinaryTree.node(nodeA, "-", node10) +let timesLeft = BinaryTree.node(node5, "*", aMinus10) // intermediate nodes on the right -let minus4 = BinaryTree.Node(.Empty, "-", node4) -let divide3andB = BinaryTree.Node(node3, "/", nodeB) -let timesRight = BinaryTree.Node(minus4, "*", divide3andB) +let minus4 = BinaryTree.node(.empty, "-", node4) +let divide3andB = BinaryTree.node(node3, "/", nodeB) +let timesRight = BinaryTree.node(minus4, "*", divide3andB) // root node -let tree = BinaryTree.Node(timesLeft, "+", timesRight) +let tree = BinaryTree.node(timesLeft, "+", timesRight) print(tree) tree.count // 12 @@ -54,7 +54,7 @@ tree.count // 12 extension BinaryTree { public func traverseInOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traverseInOrder(process: process) process(value) right.traverseInOrder(process: process) @@ -62,7 +62,7 @@ extension BinaryTree { } public func traversePreOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { process(value) left.traversePreOrder(process: process) right.traversePreOrder(process: process) @@ -70,7 +70,7 @@ extension BinaryTree { } public func traversePostOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traversePostOrder(process: process) right.traversePostOrder(process: process) process(value) diff --git a/Binary Tree/BinaryTree.swift b/Binary Tree/BinaryTree.swift index 0c55af20e..ad5fcfd13 100644 --- a/Binary Tree/BinaryTree.swift +++ b/Binary Tree/BinaryTree.swift @@ -4,14 +4,14 @@ Nodes don't have a reference to their parent. */ public indirect enum BinaryTree { - case Node(BinaryTree, T, BinaryTree) - case Empty + case node(BinaryTree, T, BinaryTree) + case empty public var count: Int { switch self { - case let .Node(left, _, right): + case let .node(left, _, right): return left.count + 1 + right.count - case .Empty: + case .empty: return 0 } } @@ -20,9 +20,9 @@ public indirect enum BinaryTree { extension BinaryTree: CustomStringConvertible { public var description: String { switch self { - case let .Node(left, value, right): + case let .node(left, value, right): return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" - case .Empty: + case .empty: return "" } } @@ -30,7 +30,7 @@ extension BinaryTree: CustomStringConvertible { extension BinaryTree { public func traverseInOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traverseInOrder(process) process(value) right.traverseInOrder(process) @@ -38,7 +38,7 @@ extension BinaryTree { } public func traversePreOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { process(value) left.traversePreOrder(process) right.traversePreOrder(process) @@ -46,7 +46,7 @@ extension BinaryTree { } public func traversePostOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traversePostOrder(process) right.traversePostOrder(process) process(value) @@ -56,10 +56,10 @@ extension BinaryTree { extension BinaryTree { func invert() -> BinaryTree { - if case let .Node(left, value, right) = self { - return .Node(right.invert(), value, left.invert()) + if case let .node(left, value, right) = self { + return .node(right.invert(), value, left.invert()) } else { - return .Empty + return .empty } } } From 95cd7732290fd1b9c100adebe2d52dc96ef12f17 Mon Sep 17 00:00:00 2001 From: Nagasawa Hiroki Date: Thu, 15 Dec 2016 08:57:32 +0900 Subject: [PATCH 0269/1275] Update README in Binary Tree --- Binary Tree/README.markdown | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index 4b5fe7180..52089b8e7 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -20,8 +20,8 @@ Here's how you could implement a general-purpose binary tree in Swift: ```swift public indirect enum BinaryTree { - case Node(BinaryTree, T, BinaryTree) - case Empty + case node(BinaryTree, T, BinaryTree) + case empty } ``` @@ -29,24 +29,24 @@ As an example of how to use this, let's build that tree of arithmetic operations ```swift // leaf nodes -let node5 = BinaryTree.Node(.Empty, "5", .Empty) -let nodeA = BinaryTree.Node(.Empty, "a", .Empty) -let node10 = BinaryTree.Node(.Empty, "10", .Empty) -let node4 = BinaryTree.Node(.Empty, "4", .Empty) -let node3 = BinaryTree.Node(.Empty, "3", .Empty) -let nodeB = BinaryTree.Node(.Empty, "b", .Empty) +let node5 = BinaryTree.node(.empty, "5", .empty) +let nodeA = BinaryTree.node(.empty, "a", .empty) +let node10 = BinaryTree.node(.empty, "10", .empty) +let node4 = BinaryTree.node(.empty, "4", .empty) +let node3 = BinaryTree.node(.empty, "3", .empty) +let nodeB = BinaryTree.node(.empty, "b", .empty) // intermediate nodes on the left -let Aminus10 = BinaryTree.Node(nodeA, "-", node10) -let timesLeft = BinaryTree.Node(node5, "*", Aminus10) +let Aminus10 = BinaryTree.node(nodeA, "-", node10) +let timesLeft = BinaryTree.node(node5, "*", Aminus10) // intermediate nodes on the right -let minus4 = BinaryTree.Node(.Empty, "-", node4) -let divide3andB = BinaryTree.Node(node3, "/", nodeB) -let timesRight = BinaryTree.Node(minus4, "*", divide3andB) +let minus4 = BinaryTree.node(.empty, "-", node4) +let divide3andB = BinaryTree.node(node3, "/", nodeB) +let timesRight = BinaryTree.node(minus4, "*", divide3andB) // root node -let tree = BinaryTree.Node(timesLeft, "+", timesRight) +let tree = BinaryTree.node(timesLeft, "+", timesRight) ``` You need to build up the tree in reverse, starting with the leaf nodes and working your way up to the top. @@ -57,10 +57,10 @@ It will be useful to add a `description` method so you can print the tree: extension BinaryTree: CustomStringConvertible { public var description: String { switch self { - case let .Node(left, value, right): + case let .node(left, value, right): return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" - case .Empty: + case .empty: return "" } } @@ -92,9 +92,9 @@ Another useful method is counting the number of nodes in the tree: ```swift public var count: Int { switch self { - case let .Node(left, _, right): + case let .node(left, _, right): return left.count + 1 + right.count - case .Empty: + case .empty: return 0 } } @@ -112,7 +112,7 @@ Here is how you'd implement that: ```swift public func traverseInOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traverseInOrder(process: process) process(value) right.traverseInOrder(process: process) @@ -120,7 +120,7 @@ Here is how you'd implement that: } public func traversePreOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { process(value) left.traversePreOrder(process: process) right.traversePreOrder(process: process) @@ -128,7 +128,7 @@ Here is how you'd implement that: } public func traversePostOrder(process: (T) -> Void) { - if case let .Node(left, value, right) = self { + if case let .node(left, value, right) = self { left.traversePostOrder(process: process) right.traversePostOrder(process: process) process(value) From 733487f53eadf59a7c702cb8f4db04297db64a0b Mon Sep 17 00:00:00 2001 From: zaccone Date: Wed, 14 Dec 2016 18:58:09 -0500 Subject: [PATCH 0270/1275] Made improvements suggested by others. These changes cause things to be done in a more Swift-like manner. Also updated the project to Xcode 8.2. --- Trie/Trie/Trie.xcodeproj/project.pbxproj | 7 +++++- Trie/Trie/Trie/Trie.swift | 29 ++++++++---------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 70a0626da..8d3611b6d 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -193,7 +193,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Rick Zaccone"; TargetAttributes = { EB798DF91DFEF79900F0628D = { @@ -333,6 +333,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -382,6 +383,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -508,6 +510,7 @@ EB798E211DFEF79900F0628D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; EB798E221DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieTests" */ = { isa = XCConfigurationList; @@ -516,6 +519,7 @@ EB798E241DFEF79900F0628D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; EB798E251DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieUITests" */ = { isa = XCConfigurationList; @@ -524,6 +528,7 @@ EB798E271DFEF79900F0628D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index bd1abc538..ad4e9f2e7 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -81,23 +81,19 @@ extension Trie { return } var currentNode = root - let charactersInWord = Array(word.lowercased().characters) - var index = 0 - while index < charactersInWord.count { - let character = charactersInWord[index] + for character in word.lowercased().characters { if let childNode = currentNode.children[character] { currentNode = childNode } else { currentNode.add(value: character) currentNode = currentNode.children[character]! } - index += 1 } // Word already present? guard !currentNode.isTerminating else { return } - self.wordCount += 1 + wordCount += 1 currentNode.isTerminating = true } @@ -110,13 +106,13 @@ extension Trie { return false } var currentNode = root - let charactersInWord = Array(word.lowercased().characters) - var index = 0 - while index < charactersInWord.count, let childNode = currentNode.children[charactersInWord[index]] { - index += 1 + for character in word.lowercased().characters { + guard let childNode = currentNode.children[character] else { + return false + } currentNode = childNode } - return index == charactersInWord.count && currentNode.isTerminating + return currentNode.isTerminating } /// Attempts to walk to the terminating node of a word. The @@ -127,20 +123,15 @@ extension Trie { /// search failed. private func findTerminalNodeOf(word: String) -> Node? { var currentNode = root - var charactersInWord = Array(word.lowercased().characters) - var index = 0 - while index < charactersInWord.count { - let character = charactersInWord[index] + for character in word.lowercased().characters { guard let childNode = currentNode.children[character] else { return nil } currentNode = childNode - index += 1 } return currentNode.isTerminating ? currentNode : nil } - /// Deletes a word from the trie by starting with the last letter /// and moving back, deleting nodes until either a non-leaf or a /// terminating node is found. @@ -180,7 +171,7 @@ extension Trie { } else { terminalNode.isTerminating = false } - self.wordCount -= 1 + wordCount -= 1 } /// Returns an array of words in a subtrie of the trie @@ -198,7 +189,7 @@ extension Trie { if rootNode.isTerminating { subtrieWords.append(previousLetters) } - for (_, childNode) in rootNode.children { + for childNode in rootNode.children.values { let childWords = wordsInSubtrie(rootNode: childNode, partialWord: previousLetters) subtrieWords += childWords } From f27c4aa6073bf35191d651d6d02459c7b38776cc Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 16 Dec 2016 03:47:34 -0800 Subject: [PATCH 0271/1275] Removes old implementation. Updated README to reflect the new code changes. --- Trie/Old Implementation/trie.swift | 523 ------------------ Trie/ReadMe.md | 86 ++- Trie/Trie.playground/Contents.swift | 16 - Trie/Trie.playground/Sources/Node.swift | 21 - Trie/Trie.playground/Sources/Trie.swift | 83 --- Trie/Trie.playground/contents.xcplayground | 4 - .../contents.xcworkspacedata | 7 - Trie/Trie/Trie/Trie.swift | 334 +++++------ 8 files changed, 201 insertions(+), 873 deletions(-) delete mode 100644 Trie/Old Implementation/trie.swift delete mode 100644 Trie/Trie.playground/Contents.swift delete mode 100644 Trie/Trie.playground/Sources/Node.swift delete mode 100644 Trie/Trie.playground/Sources/Trie.swift delete mode 100644 Trie/Trie.playground/contents.xcplayground delete mode 100644 Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Trie/Old Implementation/trie.swift b/Trie/Old Implementation/trie.swift deleted file mode 100644 index 8227d0243..000000000 --- a/Trie/Old Implementation/trie.swift +++ /dev/null @@ -1,523 +0,0 @@ -/// TODO: - Undergoing refactoring. - -/* - Queue implementation (taken from repository, needed for findPrefix()) -*/ -public struct Queue { - private var array = [T?]() - private var head = 0 - - public var isEmpty: Bool { - return count == 0 - } - - public var count: Int { - return array.count - head - } - - public mutating func enqueue(element: T) { - array.append(element) - } - - public mutating func dequeue() -> T? { - guard head < array.count, let element = array[head] else { return nil } - - array[head] = nil - head += 1 - - let percentage = Double(head)/Double(array.count) - if array.count > 50 && percentage > 0.25 { - array.removeFirst(head) - head = 0 - } - - return element - } -} -/* - A Trie (Pre-fix Tree) - - Some of the functionality of the trie makes use of the Queue implementation for this project. - - - Every node in the Trie stores a bit of information pertainining to what it references: - -Character (letter of an inserted word) - -Parent (Letter that comes before the current letter in some word) - -Children (Words that have more letters than available in the prefix) - -isAWord (Does the current letter mark the end of a known inserted word?) - -visited (Mainly for the findPrefix() function) -*/ -public class Node { - private var character: String? - private var parent: Node? - private var children: [String:Node] - private var isAWord: Bool - private var visited: Bool //only for findPrefix - - init(c: String?, p: Node?) { - self.character = c - self.children = [String:Node]() - self.isAWord = false - self.parent = p - self.visited = false - } - - /* - Function Name: char() - Input: N/A - Output: String - Functionality: Returns the associated value of the node - */ - func char() -> String { - return self.character! - } - - /* - Function Name: update - Input: String - Output: N/A - Functionality: Updates the associated value of the node - */ - func update(c: String?) { - self.character = c - } - - /* - Function Name: isLeaf - Input: N/A - Output: Bool - Functionality: Returns true if the node is a leaf node, false otherwise - */ - func isLeaf() -> Bool { - return self.children.count == 0 - } - - /* - Function Name: getParent - Input: N/A - Output: Node - Functionality: Returns the parent node of the current node - */ - func getParent() -> Node { - return parent! - } - - /* - Function Name: setParent - Input: Node - Output: N/A - Functionality: Changes the parent of the current node to the passed node - */ - - func setParent(node: Node?) { - self.parent = node - } - - /* - Function Name: getChildAt - Input: String - Output: Node - Functionality: returns the child node that holds the specific passed letter - */ - func getChildAt(s: String) -> Node { - return self.children[s]! - } - - /* - Function Name: isValidWord - Input: N/A - Output: Bool - Functionality: Returns whether or not the current node marks the end of a valid word - */ - func isValidWord() -> Bool { - return self.isAWord - } - - /* - Function Name: isWord - Input: N/A - Output: N/A - Functionality: the current node is indeed a word - */ - func isWord() { - self.isAWord = true - } - - /* - Function Name: isNotWord - Input: N/A - Output: N/A - Functionality: marks the current node as not a word - */ - func isNotWord() { - self.isAWord = false - } - - /* - Function Name: isRoot - Input: N/A - Output: Bool - Functionality: Returns whether or not the current node is the root of the trie - */ - func isRoot() -> Bool { - return self.character == "" - } - - /* - Function Name: numChildren - Input: N/A - Output: Int - Functionality: Returns the number of immediate letters that follow the current node - */ - func numChildren() -> Int { - return self.children.count - } - - /* - Function Name: getChildren - Input: N/A - Output: [String: Node] - Functionality: Returns the letters that immediately follow the current node's value for possible word segments that follow - */ - func getChildren() -> [String: Node] { - return self.children - } - - - /* - Function Name: printNode - Input: String, Bool - Output: N/A - Functionality: prints to the console a string representation of the current node in the trie - */ - func printNode(var indent: String, leaf: Bool) { - - print(indent, terminator: "") - if leaf { - print("\\-", terminator: "") - indent += " " - } else { - print("|-", terminator: "") - indent += "| " - } - - print(self.char()) - - var i = 0 - for (_, node) in self.children { - node.printNode(indent, leaf: i == self.getChildren().count-1) - i+=1 - } - - } - -} - - -/* - The Trie class has the following attributes: - -root (the root of the trie) - -wordList (the words that currently exist in the trie) - -wordCount (the number of words in the trie) -*/ -public class Trie { - private var root: Node - private var wordList: [String] - private var wordCount = 0 - - init() { - self.root = Node(c: "", p: nil) - self.wordList = [] - } - - init(wordList: Set) { - - self.root = Node(c: "", p: nil) - self.wordList = [] - - for word in wordList { - self.insert(word) - } - } - - /* - Function Name: merge - Input: Trie - Output: Trie - Functionality: Merges two tries into one and returns the merged trie - */ - func merge(other: Trie) -> Trie { - let newWordList = Set(self.getWords() + other.getWords()) - return Trie(wordList: newWordList) - } - - /* - Function Name: find - Input: String - Output: (Node?, Bool) - Functionality: Looks for a specific key and returns a tuple that - has a reference to the node(if found) and true/false - depending on if it was found - */ - func find(key: String) -> (node: Node?, found: Bool) { - var currentNode = self.root - - for c in key.characters { - if currentNode.children[String(c)] == nil { - return(nil, false) - } - currentNode = currentNode.children[String(c)]! - } - - return(currentNode, currentNode.isValidWord()) - } - - /* - Function Name: isEmpty - Input: N/A - Output: Bool - Functionality: returns true if the trie is empty, false otherwise - */ - func isEmpty() -> Bool { - return wordCount == 0 - } - - /* - Function Name: count - Input: N/A - Output: Int - Functionality: returns the number of words in the trie - */ - func count() -> Int { - return wordCount - } - - /* - Function Name: getWords - Input: N/A - Output: [String] - Functionality: returns the list of words that exist in the trie - */ - func getWords() -> [String] { - return wordList - } - - /* - Function Name: contains - Input: String - Output: Bool - Functionality: returns true if the tries has the word passed, false otherwise - */ - func contains(w: String) -> Bool { - return find(w.lowercaseString).found - } - - /* - Function Name: isPrefix - Input: String - Output: (Node?, Bool) - Functionality: returns a tuple containing a reference to the final - node in the prefix (if it exists) and true/false - depending on whether or not the prefix exists in the trie - */ - func isPrefix(p: String) -> (node: Node?, found: Bool) { - let prefixP = p.lowercaseString - - var currentNode = self.root - - for c in prefixP.characters { - if currentNode.children[String(c)] == nil { - return (nil, false) - } - - currentNode = currentNode.children[String(c)]! - } - - if currentNode.numChildren() > 0 { - return (currentNode, true) - } - - return (nil, false) - } - - /* - Function Name: insert - Input: String - Output: (String, Bool) - Functionality: Inserts a word int othe trie. Returns a tuple containing - the word attempted to be added, and true/false depending on - whether or not the insertion was successful - */ - func insert(w: String) -> (word: String, inserted: Bool) { - - let word = w.lowercaseString - var currentNode = self.root - var length = word.characters.count - - if self.contains(word) { - return (w, false) - } - - var index = 0 - var c = Array(word.characters)[index] - - while let child = currentNode.children[String(c)] { - currentNode = child - length -= 1 - index += 1 - - if length == 0 { - currentNode.isWord() - wordList.append(w) - wordCount += 1 - return (w, true) - } - - c = Array(word.characters)[index] - } - - let remainingChars = String(word.characters.suffix(length)) - for c in remainingChars.characters { - currentNode.children[String(c)] = Node(c: String(c), p: currentNode) - currentNode = currentNode.children[String(c)]! - } - - currentNode.isWord() - wordList.append(w) - wordCount += 1 - return (w, true) - } - - /* - Function Name: insertWords - Input: [String] - Output: ([String], Bool) - Functionality: attempts to insert all words from input array. returns a tuple - containing the input array and true if some of the words were - succesffuly added, false if none were added - */ - - func insertWords(wordList: [String]) -> (wordList: [String], inserted: Bool) { - - var succesful: Bool = false - for word in wordList { - succesful = self.insert(word).inserted || succesful - } - - return(wordList, succesful) - } - - /* - Function Name: remove - Input: String - Output: (String, Bool) - Functionality: Removes the specified key from the trie if it exists, returns - tuple containing the word attempted to be removed and true/false - if the removal was succesful - */ - func remove(w: String) -> (word: String, removed: Bool) { - let word = w.lowercaseString - - if !self.contains(w) { - return (w, false) - } - var currentNode = self.root - - for c in word.characters { - currentNode = currentNode.getChildAt(String(c)) - } - - if currentNode.numChildren() > 0 { - currentNode.isNotWord() - } else { - var character = currentNode.char() - while currentNode.numChildren() == 0 && !currentNode.isRoot() { - currentNode = currentNode.getParent() - currentNode.children[character]!.setParent(nil) - currentNode.children[character]!.update(nil) - currentNode.children[character] = nil - character = currentNode.char() - } - } - - wordCount -= 1 - - var index = 0 - for item in wordList { - if item == w { - wordList.removeAtIndex(index) - } - index += 1 - } - - return (w, true) - } - - /* - Function Name: findPrefix - Input: String - Output: [String] - Functionality: returns a list containing all words in the trie that have the specified prefix - */ - func findPrefix(p: String) -> [String] { - - if !self.isPrefix(p).found { - return [] - } - - var q: Queue = Queue() - var n: Node = self.isPrefix(p).node! - - var wordsWithPrefix: [String] = [] - var word = p - var tmp = "" - q.enqueue(n) - - while let current = q.dequeue() { - for (char, child) in current.getChildren() { - if !child.visited { - q.enqueue(child) - child.visited = true - if child.isValidWord() { - var currentNode = child - while currentNode !== n { - tmp += currentNode.char() - currentNode = currentNode.getParent() - } - tmp = String(tmp.characters.reverse()) - wordsWithPrefix.append(word + tmp) - tmp = "" - } - } - } - } - - - return wordsWithPrefix - } - - - /* - Function Name: removeAll - Input: N/A - Output: N/A - Functionality: removes all nodes in the trie using remove as a subroutine - */ - func removeAll() { - for word in wordList { - self.remove(word) - } - } - - - /* - Function Name: printTrie - Input: N/A - Output: N/A - Functionality: prints all the nodes of the trie to console in a nice and easy to understand format - */ - func printTrie() { - self.root.printNode("", leaf: true) - } - -} diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 6b28dd189..172ff4750 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -64,42 +64,38 @@ Insertion into a `Trie` requires you to walk over the nodes until you either hal ```swift func insert(word: String) { - guard !word.isEmpty else { return } + guard !word.isEmpty else { + return + } // 1 var currentNode = root - - // 2 - var characters = Array(word.lowercased().characters) - var currentIndex = 0 - - // 3 - while currentIndex < characters.count { - let character = characters[currentIndex] - // 4 - if let child = currentNode.children[character] { - currentNode = child + // 2 + for character in word.lowercased().characters { + // 3 + if let childNode = currentNode.children[character] { + currentNode = childNode } else { - currentNode.add(child: character) + currentNode.add(value: character) currentNode = currentNode.children[character]! } - - currentIndex += 1 - - // 5 - if currentIndex == characters.count { - currentNode.isTerminating = true - } } + // Word already present? + guard !currentNode.isTerminating else { + return + } + + // 4 + wordCount += 1 + currentNode.isTerminating = true } ``` 1. Once again, you create a reference to the root node. You'll move this reference down a chain of nodes. -2. Keep track of the word you want to insert. -3. Begin walking through your word letter by letter -4. Sometimes, the required node to insert already exists. That is the case for two words inside the `Trie` that shares letters (i.e "Apple", "App"). If a letter already exists, you'll reuse it, and simply traverse deeper down the chain. Otherwise, you'll create a new node representing the letter. -5. Once you get to the end, you mark `isTerminating` to true to mark that specific node as the end of a word. +2. Begin walking through your word letter by letter +3. Sometimes, the required node to insert already exists. That is the case for two words inside the `Trie` that shares letters (i.e "Apple", "App"). If a letter already exists, you'll reuse it, and simply traverse deeper down the chain. Otherwise, you'll create a new node representing the letter. +4. Once you get to the end, you mark `isTerminating` to true to mark that specific node as the end of a word. ### Removal @@ -109,41 +105,27 @@ If you'd like to remove "Apple", you'll need to take care to leave the "App" cha ```swift func remove(word: String) { - guard !word.isEmpty else { return } + guard !word.isEmpty else { + return + } - // 1 - var currentNode = root - - // 2 - var characters = Array(word.lowercased().characters) - var currentIndex = 0 - - // 3 - while currentIndex < characters.count { - let character = characters[currentIndex] - guard let child = currentNode.children[character] else { return } - currentNode = child - currentIndex += 1 + // 1 + guard let terminalNode = findTerminalNodeOf(word: word) else { + return } - - // 4 - if currentNode.children.count > 0 { - currentNode.isTerminating = false + + // 2 + if terminalNode.isLeaf { + deleteNodesForWordEndingWith(terminalNode: terminalNode) } else { - var character = currentNode.value - while currentNode.children.count == 0, let parent = currentNode.parent, !parent.isTerminating { - currentNode = parent - currentNode.children[character!] = nil - character = currentNode.value - } + terminalNode.isTerminating = false } + wordCount -= 1 } ``` -1. Once again, you create a reference to the root node. -2. Keep track of the word you want to remove. -3. Attempt to walk to the terminating node of the word. The `guard` statement will return if it can't find one of the letters; It's possible to call `remove` on a non-existant entry. -4. If you reach the node representing the last letter of the word you want to remove, you'll have 2 cases to deal with. Either it's a leaf node, or it has more children. If it has more children, it means the node is used for other words. In that case, you'll just mark `isTerminating` to false. In the other case, you'll delete the nodes. +1. `findTerminalNodeOf` traverses through the Trie to find the last node that represents the `word`. If it is unable to traverse through the chain of characters, it returns `nil`. +2. `deleteNodesForWordEndingWith` traverse backwords, deleting the nodes represented by the `word`. ### Time Complexity diff --git a/Trie/Trie.playground/Contents.swift b/Trie/Trie.playground/Contents.swift deleted file mode 100644 index 89a160c8d..000000000 --- a/Trie/Trie.playground/Contents.swift +++ /dev/null @@ -1,16 +0,0 @@ -let trie = Trie() - -trie.insert(word: "apple") -trie.insert(word: "ap") -trie.insert(word: "a") - -trie.contains(word: "apple") -trie.contains(word: "ap") -trie.contains(word: "a") - -trie.remove(word: "apple") -trie.contains(word: "a") -trie.contains(word: "apple") - -trie.insert(word: "apple") -trie.contains(word: "apple") diff --git a/Trie/Trie.playground/Sources/Node.swift b/Trie/Trie.playground/Sources/Node.swift deleted file mode 100644 index 56faed3e5..000000000 --- a/Trie/Trie.playground/Sources/Node.swift +++ /dev/null @@ -1,21 +0,0 @@ -public final class TrieNode { - public var value: T? - public weak var parent: TrieNode? - public var children: [T: TrieNode] = [:] - public var isTerminating = false - - init() {} - - init(value: T, parent: TrieNode? = nil) { - self.value = value - self.parent = parent - } -} - -// MARK: - Insertion -public extension TrieNode { - func add(child: T) { - guard children[child] == nil else { return } - children[child] = TrieNode(value: child, parent: self) - } -} diff --git a/Trie/Trie.playground/Sources/Trie.swift b/Trie/Trie.playground/Sources/Trie.swift deleted file mode 100644 index ddce0ba84..000000000 --- a/Trie/Trie.playground/Sources/Trie.swift +++ /dev/null @@ -1,83 +0,0 @@ -/// The Trie class has the following attributes: -/// -root (the root of the trie) -/// -wordList (the words that currently exist in the trie) -/// -wordCount (the number of words in the trie) -public final class Trie { - typealias Node = TrieNode - fileprivate let root: Node - - public init() { - root = TrieNode() - } -} - -// MARK: - Basic Methods -public extension Trie { - func insert(word: String) { - guard !word.isEmpty else { return } - var currentNode = root - - var characters = Array(word.lowercased().characters) - var currentIndex = 0 - - while currentIndex < characters.count { - let character = characters[currentIndex] - if let child = currentNode.children[character] { - currentNode = child - } else { - currentNode.add(child: character) - currentNode = currentNode.children[character]! - } - - currentIndex += 1 - if currentIndex == characters.count { - currentNode.isTerminating = true - } - } - } - - func contains(word: String) -> Bool { - guard !word.isEmpty else { return false } - var currentNode = root - - var characters = Array(word.lowercased().characters) - var currentIndex = 0 - - while currentIndex < characters.count, let child = currentNode.children[characters[currentIndex]] { - currentNode = child - currentIndex += 1 - } - - if currentIndex == characters.count && currentNode.isTerminating { - return true - } else { - return false - } - } - - func remove(word: String) { - guard !word.isEmpty else { return } - var currentNode = root - - var characters = Array(word.lowercased().characters) - var currentIndex = 0 - - while currentIndex < characters.count { - let character = characters[currentIndex] - guard let child = currentNode.children[character] else { return } - currentNode = child - currentIndex += 1 - } - - if currentNode.children.count > 0 { - currentNode.isTerminating = false - } else { - var character = currentNode.value - while currentNode.children.count == 0, let parent = currentNode.parent, !parent.isTerminating { - currentNode = parent - currentNode.children[character!] = nil - character = currentNode.value - } - } - } -} diff --git a/Trie/Trie.playground/contents.xcplayground b/Trie/Trie.playground/contents.xcplayground deleted file mode 100644 index 5da2641c9..000000000 --- a/Trie/Trie.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata b/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Trie/Trie.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index ad4e9f2e7..d9b3bbed9 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -11,188 +11,188 @@ import Foundation /// A node in the trie class TrieNode { - var value: T? - weak var parentNode: TrieNode? - var children: [T: TrieNode] = [:] - var isTerminating = false - var isLeaf: Bool { - get { - return children.count == 0 - } + var value: T? + weak var parentNode: TrieNode? + var children: [T: TrieNode] = [:] + var isTerminating = false + var isLeaf: Bool { + get { + return children.count == 0 } - - /// Initializes a node. - /// - /// - Parameters: - /// - value: The value that goes into the node - /// - parentNode: A reference to this node's parent - init(value: T? = nil, parentNode: TrieNode? = nil) { - self.value = value - self.parentNode = parentNode - } - - /// Adds a child node to self. If the child is already present, - /// do nothing. - /// - /// - Parameter value: The item to be added to this node. - func add(value: T) { - guard children[value] == nil else { - return - } - children[value] = TrieNode(value: value, parentNode: self) + } + + /// Initializes a node. + /// + /// - Parameters: + /// - value: The value that goes into the node + /// - parentNode: A reference to this node's parent + init(value: T? = nil, parentNode: TrieNode? = nil) { + self.value = value + self.parentNode = parentNode + } + + /// Adds a child node to self. If the child is already present, + /// do nothing. + /// + /// - Parameter value: The item to be added to this node. + func add(value: T) { + guard children[value] == nil else { + return } + children[value] = TrieNode(value: value, parentNode: self) + } } /// A trie data structure containing words. Each node is a single /// character of a word. class Trie { - 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 - - /// Creats an empty trie. - init() { - root = Node() - wordCount = 0 - } + 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 + + /// Creats an empty trie. + init() { + root = Node() + wordCount = 0 + } } // MARK: - Adds methods: insert, remove, contains extension Trie { - - /// Inserts a word into the trie. If the word is already present, - /// there is no change. - /// - /// - Parameter word: the word to be inserted. - func insert(word: String) { - guard !word.isEmpty else { - return - } - var currentNode = root - for character in word.lowercased().characters { - if let childNode = currentNode.children[character] { - currentNode = childNode - } else { - currentNode.add(value: character) - currentNode = currentNode.children[character]! - } - } - // Word already present? - guard !currentNode.isTerminating else { - return - } - wordCount += 1 - currentNode.isTerminating = true + + /// Inserts a word into the trie. If the word is already present, + /// there is no change. + /// + /// - Parameter word: the word to be inserted. + func insert(word: String) { + guard !word.isEmpty else { + return } - - /// Determines whether a word is in the trie. - /// - /// - Parameter word: the word to check for - /// - Returns: true if the word is present, false otherwise. - func contains(word: String) -> Bool { - guard !word.isEmpty else { - return false - } - var currentNode = root - for character in word.lowercased().characters { - guard let childNode = currentNode.children[character] else { - return false - } - currentNode = childNode - } - return currentNode.isTerminating + var currentNode = root + for character in word.lowercased().characters { + if let childNode = currentNode.children[character] { + currentNode = childNode + } else { + currentNode.add(value: character) + currentNode = currentNode.children[character]! + } } - - /// Attempts to walk to the terminating node of a word. The - /// search will fail if the word is not present. - /// - /// - Parameter word: the word in question - /// - Returns: the node where the search ended, nil if the - /// search failed. - private func findTerminalNodeOf(word: String) -> Node? { - var currentNode = root - for character in word.lowercased().characters { - guard let childNode = currentNode.children[character] else { - return nil - } - currentNode = childNode - } - return currentNode.isTerminating ? currentNode : nil + // Word already present? + guard !currentNode.isTerminating else { + return } - - /// Deletes a word from the trie by starting with the last letter - /// and moving back, deleting nodes until either a non-leaf or a - /// terminating node is found. - /// - /// - Parameter terminalNode: the node representing the last node - /// of a word - private func deleteNodesForWordEndingWith(terminalNode: Node) { - var lastNode = terminalNode - var character = lastNode.value - while lastNode.isLeaf, let parentNode = lastNode.parentNode { - lastNode = parentNode - lastNode.children[character!] = nil - character = lastNode.value - if lastNode.isTerminating { - break - } - } + wordCount += 1 + currentNode.isTerminating = true + } + + /// Determines whether a word is in the trie. + /// + /// - Parameter word: the word to check for + /// - Returns: true if the word is present, false otherwise. + func contains(word: String) -> Bool { + guard !word.isEmpty else { + return false } - - /// Removes a word from the trie. If the word is not present or - /// it is empty, just ignore it. If the last node is a leaf, - /// delete that node and higher nodes that are leaves until a - /// terminating node or non-leaf is found. If the last node of - /// the word has more children, the word is part of other words. - /// Mark the last node as non-terminating. - /// - /// - Parameter word: the word to be removed - func remove(word: String) { - guard !word.isEmpty else { - return - } - guard let terminalNode = findTerminalNodeOf(word: word) else { - return - } - if terminalNode.isLeaf { - deleteNodesForWordEndingWith(terminalNode: terminalNode) - } else { - terminalNode.isTerminating = false - } - wordCount -= 1 + var currentNode = root + for character in word.lowercased().characters { + guard let childNode = currentNode.children[character] else { + return false + } + currentNode = childNode } - - /// Returns an array of words in a subtrie of the trie - /// - /// - Parameters: - /// - rootNode: the root node of the subtrie - /// - partialWord: the letters collected by traversing to this node - /// - Returns: the words in the subtrie - func wordsInSubtrie(rootNode: Node, partialWord: String) -> [String] { - var subtrieWords = [String]() - var previousLetters = partialWord - if let value = rootNode.value { - previousLetters.append(value) - } - if rootNode.isTerminating { - subtrieWords.append(previousLetters) - } - for childNode in rootNode.children.values { - let childWords = wordsInSubtrie(rootNode: childNode, partialWord: previousLetters) - subtrieWords += childWords - } - return subtrieWords + return currentNode.isTerminating + } + + /// Attempts to walk to the terminating node of a word. The + /// search will fail if the word is not present. + /// + /// - Parameter word: the word in question + /// - Returns: the node where the search ended, nil if the + /// search failed. + private func findTerminalNodeOf(word: String) -> Node? { + var currentNode = root + for character in word.lowercased().characters { + guard let childNode = currentNode.children[character] else { + return nil + } + currentNode = childNode + } + return currentNode.isTerminating ? currentNode : nil + } + + /// Deletes a word from the trie by starting with the last letter + /// and moving back, deleting nodes until either a non-leaf or a + /// terminating node is found. + /// + /// - Parameter terminalNode: the node representing the last node + /// of a word + private func deleteNodesForWordEndingWith(terminalNode: Node) { + var lastNode = terminalNode + var character = lastNode.value + while lastNode.isLeaf, let parentNode = lastNode.parentNode { + lastNode = parentNode + lastNode.children[character!] = nil + character = lastNode.value + if lastNode.isTerminating { + break + } + } + } + + /// Removes a word from the trie. If the word is not present or + /// it is empty, just ignore it. If the last node is a leaf, + /// delete that node and higher nodes that are leaves until a + /// terminating node or non-leaf is found. If the last node of + /// the word has more children, the word is part of other words. + /// Mark the last node as non-terminating. + /// + /// - Parameter word: the word to be removed + func remove(word: String) { + guard !word.isEmpty else { + return + } + guard let terminalNode = findTerminalNodeOf(word: word) else { + return + } + if terminalNode.isLeaf { + deleteNodesForWordEndingWith(terminalNode: terminalNode) + } else { + terminalNode.isTerminating = false + } + wordCount -= 1 + } + + /// Returns an array of words in a subtrie of the trie + /// + /// - Parameters: + /// - rootNode: the root node of the subtrie + /// - partialWord: the letters collected by traversing to this node + /// - Returns: the words in the subtrie + func wordsInSubtrie(rootNode: Node, partialWord: String) -> [String] { + var subtrieWords = [String]() + var previousLetters = partialWord + if let value = rootNode.value { + previousLetters.append(value) + } + if rootNode.isTerminating { + subtrieWords.append(previousLetters) + } + for childNode in rootNode.children.values { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: previousLetters) + subtrieWords += childWords } + return subtrieWords + } } From e7bc36cf645d11539cac9e2c9ffe098457488ad6 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 17 Dec 2016 19:41:31 +0100 Subject: [PATCH 0272/1275] Fix Skip-List link in readme --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 4c812b0f3..7ac170a65 100644 --- a/README.markdown +++ b/README.markdown @@ -142,7 +142,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types ### Lists - [Linked List](Linked List/). A sequence of data items connected through links. Covers both singly and doubly linked lists. -- Skip List +- [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. ### Trees From a277fed473caf69108eae0aa3276d7a78f01fa90 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Sat, 17 Dec 2016 21:35:42 +0100 Subject: [PATCH 0273/1275] Add AVL tree rotation example image; Update image; Update image; --- AVL Tree/Images/Rotation.jpg | Bin 0 -> 35153 bytes AVL Tree/README.markdown | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 AVL Tree/Images/Rotation.jpg diff --git a/AVL Tree/Images/Rotation.jpg b/AVL Tree/Images/Rotation.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94a55df4e3268d5e9f8ed5b63a443beb9d6dda6e GIT binary patch literal 35153 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

Fbwd9 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 **Note:** If you're a bit fuzzy on the regular operations of a binary search tree, I suggest you [catch up on those first](../Binary Search Tree/). It will make the rest of the AVL tree easier to understand. -The interesting bits are in the `balance()` method which is called after inserting or deleting a node. +The interesting bits are in the `balance()` method which is called after inserting or deleting a node. ## See also From 7050669ebf695f1f5b029812fffbff38b83540e8 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 20 Dec 2016 02:02:10 -0800 Subject: [PATCH 0274/1275] Modified the queue's peek property name to front per naming design guidelines. Computed properties should not imply action. Also checks out on Knuth's Fundamental Algorithms book page 241 where front and rear is the choice for his wording. --- Queue/Queue.playground/Contents.swift | 4 ++-- Queue/Queue.playground/timeline.xctimeline | 6 ------ Queue/README.markdown | 10 +++------- 3 files changed, 5 insertions(+), 15 deletions(-) delete mode 100644 Queue/Queue.playground/timeline.xctimeline diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index a8be21b08..a90fa647e 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -34,7 +34,7 @@ public struct Queue { } } - public var peek: T? { + public var front: T? { return array.first } } @@ -56,7 +56,7 @@ queueOfNames.dequeue() // Return the first element in the queue. // Returns "Lisa" since "Carl" was dequeued on the previous line. -queueOfNames.peek +queueOfNames.front // Check to see if the queue is empty. // Returns "false" since the queue still has elements in it. diff --git a/Queue/Queue.playground/timeline.xctimeline b/Queue/Queue.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Queue/Queue.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Queue/README.markdown b/Queue/README.markdown index f7779aa69..25d6205f8 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -68,7 +68,7 @@ public struct Queue { } } - public func peek() -> T? { + public var front: T? { return array.first } } @@ -166,12 +166,8 @@ public struct Queue { return element } - public func peek() -> T? { - if isEmpty { - return nil - } else { - return array[head] - } + public var front: T? { + return array.first } } ``` From 6a66252ad17ae92b068d8e27356b54a526bb7865 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 20 Dec 2016 02:11:41 -0800 Subject: [PATCH 0275/1275] Updated the peek function of the stack to a computed property instead. This change is inspired by the Swift naming conventions guide and Knuth's fundamental algorithms book page 242 where he states the element at the top of the stack may be denoted by top(A) where A is the stack. --- Stack/README.markdown | 6 +++--- Stack/Stack.playground/Contents.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Stack/README.markdown b/Stack/README.markdown index 9d157f290..a79e2c261 100644 --- a/Stack/README.markdown +++ b/Stack/README.markdown @@ -38,7 +38,7 @@ stack.pop() This returns `3`, and so on. If the stack is empty, popping returns `nil` or in some implementations it gives an error message ("stack underflow"). -A stack is easy to create in Swift. It's just a wrapper around an array that just lets you push, pop, and peek: +A stack is easy to create in Swift. It's just a wrapper around an array that just lets you push, pop, and look at the top element of the stack: ```swift public struct Stack { @@ -60,8 +60,8 @@ public struct Stack { return array.popLast() } - public func peek() -> T? { - return array.last + public var top: T? { + return array.last } } ``` diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index f086ca817..1eb705f20 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -30,7 +30,7 @@ public struct Stack { return array.popLast() } - public func peek() -> T? { + public var top: T? { return array.last } } @@ -49,7 +49,7 @@ stackOfNames.pop() // Look at the first element from the stack. // Returns "Wade" since "Mike" was popped on the previous line. -stackOfNames.peek() +stackOfNames.top // Check to see if the stack is empty. // Returns "false" since the stack still has elements in it. From bfeac916bedcaba9555f49f982d96a1e84ce157a Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 20 Dec 2016 23:40:39 +0100 Subject: [PATCH 0276/1275] Add rotation steps description; --- AVL Tree/README.markdown | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 22ea99f53..bcbbbabbc 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -43,13 +43,32 @@ The difference between the heights of the left and right subtrees is called the If after an insertion or deletion the balance factor becomes greater than 1, then we need to re-balance this part of the AVL tree. And that is done with rotations. ## Rotations - Each tree node keeps track of its current balance factor in a variable. After inserting a new node, we need to update the balance factor of its parent node. If that balance factor becomes greater than 1, we "rotate" part of that tree to restore the balance. -Example of balancing the unbalanced tree using rotation: +Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation : ![Rotation](Images/Rotation.jpg) -Insertion never needs more than 2 rotations. Removal might require up to *log(n)* rotations. +Let's dig into rotation algorithm in detail using the terminology: +* *Root* - the parent not of the subtrees that will be rotated; +* *Pivot* - the node that will become parent (basically will be on the *Root*'s position) after rotation; +* *RotationSubtree* - subtree of the *Pivot* upon the side of rotation +* *OppositeSubtree* - subtree of the *Pivot* opposite the side of rotation + +The steps of rotation on the example image could be described by following: +* Select the *Pivot* as `D` and hence the *Root* as `F`; +* Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; +* Assign the *Root* as a new *RotationSubtree* for the *Pivot*; +* Check the final result + +In pseudocode the algorithm above could be written as follows: +``` +Root.OS = Pivot.RS +Pivot.RS = Root +Root = Pivot +``` + +This is a constant time operation - __O(1)__ +Insertion never needs more than 2 rotations. Removal might require up to __log(n)__ rotations. ## The code From 45b5619710d40c5602cc3f70b2e5fdb3300e22ac Mon Sep 17 00:00:00 2001 From: Antonio081014 Date: Tue, 20 Dec 2016 16:40:49 -0800 Subject: [PATCH 0277/1275] Add missing link for Trie in README. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 7ac170a65..5c769688a 100644 --- a/README.markdown +++ b/README.markdown @@ -156,7 +156,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - 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](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. ### Hashing From 09b74c41364723dbb9b3752765913b13dcb1c6b7 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sat, 26 Nov 2016 17:58:21 -0500 Subject: [PATCH 0278/1275] Mathimatical explination --- Rootish Array Stack/README.md | 90 ++++++++++++++++-- .../images/RootishArrayStackExample2.png | Bin 0 -> 81023 bytes 2 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 Rootish Array Stack/images/RootishArrayStackExample2.png diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index 842439a0c..285f39b14 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -2,18 +2,92 @@ A *Rootish Array Stack* is an ordered array based structure that minimizes wasted space (based on [Gauss's summation technique](https://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/)). A *Rootish Array Stack* consists of an array holding many fixed size arrays in ascending size. -![Rootish Array Stack Intro](/images/RootishArrayStackIntro.png) - +![Rootish Array Stack Intro](images/RootishArrayStackIntro.png) A resizable array holds references to blocks (arrays of fixed size). A block's capacity is the same as it's index in the resizable array. Blocks don't grow/shrink like regular Swift arrays. Instead, when their capacity is reached, a new slightly larger block is created. When a block is emptied the last block is freed. This is a great improvement on what a swift array does in terms of wasted space. -![Rootish Array Stack Intro](/images/RootishArrayStackExample.png) +![Rootish Array Stack Intro](images/RootishArrayStackExample.png) Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). -### How indices map: -| Subscript index | Indices of Blocks| -| :------------- | :------------- | -| `[0]` | `blocks[0][0]` | +## The Math +The data structure is based on Gauss's summation technique: +``` +sum from 1...n = n * (n + 1) / 2 +``` +To understand this imagine `n` blocks where `x` represents `1` unit. In this example let `n` be `5`: +``` +blocks: [x] [x x] [x x x] [x x x x] [x x x x x] +# of x's: 1 2 3 4 5 +``` +_Block `1` has 1 `x`, block `2` as 2 `x`s, block `3` has 3 `x`s, etc..._ -## A Mathematical Explanation +If you wanted to take the sum of all the blocks from `1` to `n` you could go through and count them _one by one_. This is okay, but for a large sequence of blocks that could take a long time! Instead you could arrange the blocks to look like a _half pyramid_: +``` +# | blocks +--|------------- +1 | x +2 | x x +3 | x x x +4 | x x x x +5 | x x x x x + +``` +Then we mirror the _half pyramid_ and rearrange the image so that it fits with the original _half pyramid_ in a rectangular shape: +``` +x o x o o o o o +x x o o x x o o o o +x x x o o o => x x x o o o +x x x x o o o o x x x x o o +x x x x x o o o o o x x x x x o +``` +Here we have `n` rows and `n + 1` columns of units. _5 rows and 6 columns_. + +We could calculate sum just as we would an area! Lets also express width and hight in terms of `n`: +``` +area of a rectangle = height * width = n * (n + 1) +``` +But we only want to calculate the amount of `x`s, not the amount of `o`s. Since there's a 1:1 ratio between `x`s and `o`s we and just divide our area by 2! +``` +area of only x = n * (n + 1) / 2 +``` +And voila! We have an interesting new way to arrange our data! + +## Get/Set with Speed +Next we want to find an efficient way to access a random index. For example which block does `rootishArrayStack[12]` point to? To answer this we will need MORE MATH! +Determining the inner block `index` turns out to be easy. If `index` is in some `block` then: +``` +inner block index = index - block * (block + 1) / 2 +``` + +More difficult is determining which `block` an index points to. The number of elements that have indices less than or equal to the the requested `index` is: `index + 1` elements. The number of elements in blocks `0...block` is `(block + 1) * (block + 2) / 2`. Therefore, `block` is the smaller integer such that: +``` +(block + 1) * (block + 2) / 2 >= index + 1 +``` +This can be rewritten as: +``` +(block)^2 + (3 * block) - (2 * index) >= 0 +``` +Using the quadratic formula we can get: +``` +block = (-3 ± √(9 + 8 * index)) / 2 +``` +A negative block doesn't make sense so we take the positive root instead. In general this solution is not an integer but going back to our inequality, we want the smallest block such that `b => (-3 + √(9 + 8 * index)) / 2`. So we take the ceiling of the result: +``` +block = ⌈(-3 + √(9 + 8 * index)) / 2⌉ +``` + +Now we can figure out that `rootishArrayStack[12]` would point to the block at index `4` and at inner block index `2`. +![Rootish Array Stack Intro](images/RootishArrayStackExample2.png) + +# The Code + +To get the `capacity` of the structure we can use the equation we figured out above: +```swift +var capacity: Int { + return blocks.count * (blocks.count + 1) / 2 +} +``` +Since Swift arrays check `count` in `O(1)` time, this capacity lookup is also `O(1)`. + +To solve the problem of which block holds the block holds the element we are looking for we need diff --git a/Rootish Array Stack/images/RootishArrayStackExample2.png b/Rootish Array Stack/images/RootishArrayStackExample2.png new file mode 100644 index 0000000000000000000000000000000000000000..d032833bc99931702053554e2292d5da988ec419 GIT binary patch literal 81023 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

OSm`O{(p!p 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%0D$((KAk9=Fu|_{$`E=rTF#k_=NFSNA3H+*y;BG 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 literal 0 HcmV?d00001 From df6e54a0c0eadb4edba616430f247edb54b60d32 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sun, 27 Nov 2016 22:32:12 -0500 Subject: [PATCH 0279/1275] Added 'Code' segment --- Rootish Array Stack/README.md | 41 +++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index 285f39b14..3f154629f 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -10,8 +10,9 @@ A resizable array holds references to blocks (arrays of fixed size). A block's c Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). -## The Math -The data structure is based on Gauss's summation technique: +## Gauss's Summation Trick + +This data structure is based on Gauss's summation technique: ``` sum from 1...n = n * (n + 1) / 2 ``` @@ -51,10 +52,10 @@ But we only want to calculate the amount of `x`s, not the amount of `o`s. Since ``` area of only x = n * (n + 1) / 2 ``` -And voila! We have an interesting new way to arrange our data! +And voila! A super fast way to take a sum of all the blocks! This equation is useful for deriving fast `block` and `inner block index` equations. ## Get/Set with Speed -Next we want to find an efficient way to access a random index. For example which block does `rootishArrayStack[12]` point to? To answer this we will need MORE MATH! +Next we want to find an efficient and accurate way to access an element at a random index. For example which block does `rootishArrayStack[12]` point to? To answer this we will need more math! Determining the inner block `index` turns out to be easy. If `index` is in some `block` then: ``` inner block index = index - block * (block + 1) / 2 @@ -81,13 +82,39 @@ Now we can figure out that `rootishArrayStack[12]` would point to the block at i ![Rootish Array Stack Intro](images/RootishArrayStackExample2.png) # The Code +Lets start with instance variables and struct declaration: +```swift +import Darwin + +public struct RootishArrayStack { + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 + + public init() { } -To get the `capacity` of the structure we can use the equation we figured out above: + var count: Int { + return internalCount + } + + +``` +The elements are of generic type `T`, so data of any kind can be stored in the list. `blocks` will be a resizable array to hold fixed sized arrays that take type `T?`. +> The reason for the fixed size arrays taking type `T?` is so that references to elements aren't retained after they've been removed. Eg: if you remove the last element, the last index must be set to `nil` to prevent the last element being held in memory at an inaccessible index. + +`internalCount` is an internal mutable counter that keeps track of the number of elements. `count` is a read only variables that gives the `internalCount` value. `Darwin` is imported here to provide simple math functions such as `ceil()` and `sqrt()`. + +The `capacity` of the structure is simply the Gaussian summation trick: ```swift var capacity: Int { return blocks.count * (blocks.count + 1) / 2 } ``` -Since Swift arrays check `count` in `O(1)` time, this capacity lookup is also `O(1)`. -To solve the problem of which block holds the block holds the element we are looking for we need +To determine which block an index map to: +```swift +fileprivate static func toBlock(index: Int) -> Int { + let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) + return block +} +``` +This comes straight from the equations derived earlier. As mentioned `sqrt()`, and `ceil()` were imported from `Darwin`. From 1d16285c873b4b7e7d31d6a7de611cdc838ecbc2 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 28 Nov 2016 00:32:17 -0500 Subject: [PATCH 0280/1275] Preventing thrashing --- Rootish Array Stack/README.md | 19 ++++++-- Rootish Array Stack/RootishArrayStack.swift | 53 +++++++++++---------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index 3f154629f..f6d55b03a 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -110,11 +110,24 @@ var capacity: Int { } ``` -To determine which block an index map to: +Next lets build what we need to get/set elements: ```swift -fileprivate static func toBlock(index: Int) -> Int { +fileprivate func toBlock(index: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) return block } + +public subscript(index: Int) -> T { + get { + let block = toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + return blocks[block][blockIndex]! + } + set(newValue) { + let block = toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + blocks[block][blockIndex] = newValue + } +} ``` -This comes straight from the equations derived earlier. As mentioned `sqrt()`, and `ceil()` were imported from `Darwin`. +`toBlock` is really just wrapping the `block` equation derived earlier. `superscript` lets us have `get/set` access to the structure with the familiar `[index]` syntax. diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index f17f9620e..6cb1cff06 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -21,11 +21,24 @@ public struct RootishArrayStack { return blocks.count * (blocks.count + 1) / 2 } - fileprivate static func toBlock(index: Int) -> Int { + fileprivate func toBlock(index: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) return block } + public subscript(index: Int) -> T { + get { + let block = toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + return blocks[block][blockIndex]! + } + set(newValue) { + let block = toBlock(index: index) + let blockIndex = index - block * (block + 1) / 2 + blocks[block][blockIndex] = newValue + } + } + fileprivate mutating func grow() { let newArray = [T?](repeating: nil, count: blocks.count + 1) blocks.append(newArray) @@ -39,21 +52,8 @@ public struct RootishArrayStack { } } - public subscript(index: Int) -> T { - get { - let block = RootishArrayStack.toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - return blocks[block][blockIndex]! - } - set(newValue) { - let block = RootishArrayStack.toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - blocks[block][blockIndex] = newValue - } - } - public mutating func insert(element: T, atIndex index: Int) { - if capacity < count + 1 { + if capacity - blocks.count < count + 1 { grow() } internalCount += 1 @@ -70,7 +70,7 @@ public struct RootishArrayStack { } fileprivate mutating func makeNil(atIndex index: Int) { - let block = RootishArrayStack.toBlock(index: index) + let block = toBlock(index: index) let blockIndex = index - block * (block + 1) / 2 blocks[block][blockIndex] = nil } @@ -82,22 +82,22 @@ public struct RootishArrayStack { } internalCount -= 1 makeNil(atIndex: count) - if capacity >= count { + if capacity + blocks.count >= count { shrink() } return element } public var memoryDescription: String { - var s = "{\n" - for i in blocks { - s += "\t[" - for j in i { - s += "\(j), " + var description = "{\n" + for block in blocks { + description += "\t[" + for rawElement in block { + description += "\(rawElement), " } - s += "]\n" + description += "]\n" } - return s + "}" + return description + "}" } } @@ -113,3 +113,8 @@ extension RootishArrayStack: CustomStringConvertible { return s + "]" } } + +var list = RootishArrayStack() +for i in 0...10 { + list.append(element: i) +} From c3d03b9b2d56b17bd66eed450e64b58ef2a469c6 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 28 Nov 2016 22:04:34 -0500 Subject: [PATCH 0281/1275] Finished implementation explination --- Rootish Array Stack/README.md | 69 ++++++++++++++++++++- Rootish Array Stack/RootishArrayStack.swift | 43 ++++++------- 2 files changed, 86 insertions(+), 26 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index f6d55b03a..790eea6da 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -96,6 +96,9 @@ public struct RootishArrayStack { return internalCount } + ... + +} ``` The elements are of generic type `T`, so data of any kind can be stored in the list. `blocks` will be a resizable array to hold fixed sized arrays that take type `T?`. @@ -110,7 +113,7 @@ var capacity: Int { } ``` -Next lets build what we need to get/set elements: +Next lets look at we would `get` and `set` elements: ```swift fileprivate func toBlock(index: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) @@ -130,4 +133,66 @@ public subscript(index: Int) -> T { } } ``` -`toBlock` is really just wrapping the `block` equation derived earlier. `superscript` lets us have `get/set` access to the structure with the familiar `[index]` syntax. +`toBlock(index:)` is really just wrapping the `block` equation derived earlier to return the block that an index maps to. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic: + 1. determine the block that the index points to + 2. determine the inner block index + 3. `get`/`set` the value + +Next lets look at how we would `growIfNeeded()` and `shrinkIfNeeded()` the structure. +```swift +fileprivate mutating func growIfNeeded() { + if capacity - blocks.count < count + 1 { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } +} + +fileprivate mutating func shrinkIfNeeded() { + if capacity + blocks.count >= count { + var numberOfBlocks = blocks.count + while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { + blocks.remove(at: blocks.count - 1) + numberOfBlocks -= 1 + } + } +} +``` +If our data set grows or shrinks in size, we want our data structure to accommodate the change. +Just like a Swift array when a capacity threshold is met we will `grow` or `shrink` the size of our structure. For the Rootish Array Stack we want to `grow` if the second last block is full on an `insert` operation, and `shrink` if the two last blocks are empty. + +Now to the more familiar Swift array behaviour. +```swift +public mutating func insert(element: T, atIndex index: Int) { + growIfNeeded() + internalCount += 1 + var i = count - 1 + while i > index { + self[i] = self[i - 1] + i -= 1 + } + self[index] = element +} + +public mutating func append(element: T) { + insert(element: element, atIndex: count) +} + +public mutating func remove(atIndex index: Int) -> T { + let element = self[index] + for i in index.. Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` wheres setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs). diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 6cb1cff06..4edc58b2f 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -26,6 +26,23 @@ public struct RootishArrayStack { return block } + fileprivate mutating func growIfNeeded() { + if capacity - blocks.count < count + 1 { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } + } + + fileprivate mutating func shrinkIfNeeded() { + if capacity + blocks.count >= count { + var numberOfBlocks = blocks.count + while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { + blocks.remove(at: blocks.count - 1) + numberOfBlocks -= 1 + } + } + } + public subscript(index: Int) -> T { get { let block = toBlock(index: index) @@ -39,23 +56,8 @@ public struct RootishArrayStack { } } - fileprivate mutating func grow() { - let newArray = [T?](repeating: nil, count: blocks.count + 1) - blocks.append(newArray) - } - - fileprivate mutating func shrink() { - var numberOfBlocks = blocks.count - while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { - blocks.remove(at: blocks.count - 1) - numberOfBlocks -= 1 - } - } - public mutating func insert(element: T, atIndex index: Int) { - if capacity - blocks.count < count + 1 { - grow() - } + growIfNeeded() internalCount += 1 var i = count - 1 while i > index { @@ -82,9 +84,7 @@ public struct RootishArrayStack { } internalCount -= 1 makeNil(atIndex: count) - if capacity + blocks.count >= count { - shrink() - } + shrinkIfNeeded() return element } @@ -113,8 +113,3 @@ extension RootishArrayStack: CustomStringConvertible { return s + "]" } } - -var list = RootishArrayStack() -for i in 0...10 { - list.append(element: i) -} From 72c12e92485f49b24c30b61522ae9aff9035cdaf Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 28 Nov 2016 22:32:23 -0500 Subject: [PATCH 0282/1275] Added Gauss' legend Polished example --- Rootish Array Stack/README.md | 36 +++++++++++++++------ Rootish Array Stack/RootishArrayStack.swift | 4 +-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index 790eea6da..5f62cec2c 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -10,9 +10,8 @@ A resizable array holds references to blocks (arrays of fixed size). A block's c Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). -## Gauss's Summation Trick - -This data structure is based on Gauss's summation technique: +## Gauss' Summation Trick +One of the most well known legends about famous mathematician [Carl Friedrich Gauss](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss) goes back to when he was in primary school. One day Gauss' teacher asked his class to add up all the numbers from 1 to 100, hoping that the task would take long enough for the teacher to step out for a smoke break. The teacher was shocked when young Gauss had his hand up with the answer `5050`. So soon? The teacher suspected a cheat, but no. Gauss had found a formula to sidestep the problem of manual adding up all the number 1 by 1. His formula: ``` sum from 1...n = n * (n + 1) / 2 ``` @@ -42,9 +41,9 @@ x x x o o o => x x x o o o x x x x o o o o x x x x o o x x x x x o o o o o x x x x x o ``` -Here we have `n` rows and `n + 1` columns of units. _5 rows and 6 columns_. +Here we have `n` rows and `n + 1` columns. _5 rows and 6 columns_. -We could calculate sum just as we would an area! Lets also express width and hight in terms of `n`: +We could calculate sum just as we would an area! Lets also express the width and hight in terms of `n`: ``` area of a rectangle = height * width = n * (n + 1) ``` @@ -78,10 +77,26 @@ A negative block doesn't make sense so we take the positive root instead. In gen block = ⌈(-3 + √(9 + 8 * index)) / 2⌉ ``` -Now we can figure out that `rootishArrayStack[12]` would point to the block at index `4` and at inner block index `2`. +Now we can figure out that `rootishArrayStack[12]` points to! First lets see which block the `12` points to: +``` +block = ⌈(-3 + √(9 + 8 * (12))) / 2⌉ +block = ⌈(-3 + √105) / 2⌉ +block = ⌈(-3 + (10.246950766)) / 2⌉ +block = ⌈(7.246950766) / 2⌉ +block = ⌈3.623475383⌉ +block = 4 +``` +Next lets see which `innerBlockIndex` `12` points to: +``` +inner block index = (12) - (4) * ((4) + 1) / 2 +inner block index = (12) - (4) * (5) / 2 +inner block index = (12) - 10 +inner block index = 2 +``` +Therefore `rootishArrayStack[12]` points to the block at index `4` and at inner block index `2`. ![Rootish Array Stack Intro](images/RootishArrayStackExample2.png) -# The Code +# Implementation Details Lets start with instance variables and struct declaration: ```swift import Darwin @@ -149,10 +164,8 @@ fileprivate mutating func growIfNeeded() { fileprivate mutating func shrinkIfNeeded() { if capacity + blocks.count >= count { - var numberOfBlocks = blocks.count - while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { + while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 >= count { blocks.remove(at: blocks.count - 1) - numberOfBlocks -= 1 } } } @@ -196,3 +209,6 @@ fileprivate mutating func makeNil(atIndex index: Int) { ``` To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element we set the value using the `subscript` convenience. `append(element:)` is just a convenience method to add to the end. To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. `makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do). > Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` wheres setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs). + +# Runtime Analysis + diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 4edc58b2f..66a681f97 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -35,10 +35,8 @@ public struct RootishArrayStack { fileprivate mutating func shrinkIfNeeded() { if capacity + blocks.count >= count { - var numberOfBlocks = blocks.count - while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count { + while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 >= count { blocks.remove(at: blocks.count - 1) - numberOfBlocks -= 1 } } } From cb673314ee570504f655c3d6d992fe90d3c2425e Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Thu, 8 Dec 2016 22:15:14 -0500 Subject: [PATCH 0283/1275] Added performance explination + cleaned up some implementation details --- Rootish Array Stack/README.md | 27 +++++++++++++-------- Rootish Array Stack/RootishArrayStack.swift | 24 ++++++++++-------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index 5f62cec2c..ee2351d4d 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -102,16 +102,17 @@ Lets start with instance variables and struct declaration: import Darwin public struct RootishArrayStack { - fileprivate var blocks = [Array]() - fileprivate var internalCount = 0 - public init() { } + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 - var count: Int { - return internalCount - } + public init() { } + + var count: Int { + return internalCount + } - ... + ... } @@ -149,7 +150,7 @@ public subscript(index: Int) -> T { } ``` `toBlock(index:)` is really just wrapping the `block` equation derived earlier to return the block that an index maps to. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic: - 1. determine the block that the index points to + 1. determine the block that the index points to 2. determine the inner block index 3. `get`/`set` the value @@ -210,5 +211,11 @@ fileprivate mutating func makeNil(atIndex index: Int) { To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element we set the value using the `subscript` convenience. `append(element:)` is just a convenience method to add to the end. To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. `makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do). > Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` wheres setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs). -# Runtime Analysis - +# Performance +* An internal counter keeps track of the number of elements in the structure. `count` is executed in **O(1)** time. + +* `capacity` can be calculated using Gauss' summation trick in an equation which takes **O(1)** time to execute. + +* Since `subcript[index:]` uses the `block` and `inner block index` equations, which can be executed in **O(1)** time, all get and set operations take **O(1)**. + +* Ignoring the time cost to `grow()` and `shrink()`, `insert()` and `remove()` operations shift all elements right of the specified index resulting in **O(n)** time. diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 66a681f97..842e34f72 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -21,11 +21,15 @@ public struct RootishArrayStack { return blocks.count * (blocks.count + 1) / 2 } - fileprivate func toBlock(index: Int) -> Int { + fileprivate func block(fromIndex index: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) return block } + fileprivate func innerBlockIndex(fromIndex index: Int, fromBlock block: Int) -> Int { + return index - block * (block + 1) / 2 + } + fileprivate mutating func growIfNeeded() { if capacity - blocks.count < count + 1 { let newArray = [T?](repeating: nil, count: blocks.count + 1) @@ -43,14 +47,14 @@ public struct RootishArrayStack { public subscript(index: Int) -> T { get { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - return blocks[block][blockIndex]! + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + return blocks[block][innerBlockIndex]! } set(newValue) { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - blocks[block][blockIndex] = newValue + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = newValue } } @@ -70,9 +74,9 @@ public struct RootishArrayStack { } fileprivate mutating func makeNil(atIndex index: Int) { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - blocks[block][blockIndex] = nil + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = nil } public mutating func remove(atIndex index: Int) -> T { From b8f87bfe07d5268b37ad7e4fb5f2319a94d7d060 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sat, 10 Dec 2016 23:14:15 -0500 Subject: [PATCH 0284/1275] Added performance analysis --- Rootish Array Stack/README.md | 68 ++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index ee2351d4d..c00061082 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -11,7 +11,7 @@ A resizable array holds references to blocks (arrays of fixed size). A block's c Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). ## Gauss' Summation Trick -One of the most well known legends about famous mathematician [Carl Friedrich Gauss](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss) goes back to when he was in primary school. One day Gauss' teacher asked his class to add up all the numbers from 1 to 100, hoping that the task would take long enough for the teacher to step out for a smoke break. The teacher was shocked when young Gauss had his hand up with the answer `5050`. So soon? The teacher suspected a cheat, but no. Gauss had found a formula to sidestep the problem of manual adding up all the number 1 by 1. His formula: +One of the most well known legends about famous mathematician [Carl Friedrich Gauss](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss) goes back to when he was in primary school. One day Gauss' teacher asked his class to add up all the numbers from 1 to 100, hoping that the task would take long enough for the teacher to step out for a smoke break. The teacher was shocked when young Gauss had his hand up with the answer `5050`. So soon? The teacher suspected a cheat, but no. Gauss had found a formula to sidestep the problem of manually adding up all the numbers 1 by 1. His formula: ``` sum from 1...n = n * (n + 1) / 2 ``` @@ -96,6 +96,9 @@ inner block index = 2 Therefore `rootishArrayStack[12]` points to the block at index `4` and at inner block index `2`. ![Rootish Array Stack Intro](images/RootishArrayStackExample2.png) +### Interesting Discovery +Using the `block` equation we can see that the number of `blocks` is proportional to the square root of the number of elements: **O(blocks) = O(√n)**. + # Implementation Details Lets start with instance variables and struct declaration: ```swift @@ -106,10 +109,10 @@ public struct RootishArrayStack { fileprivate var blocks = [Array]() fileprivate var internalCount = 0 - public init() { } + public init() { } - var count: Int { - return internalCount + var count: Int { + return internalCount } ... @@ -131,25 +134,29 @@ var capacity: Int { Next lets look at we would `get` and `set` elements: ```swift -fileprivate func toBlock(index: Int) -> Int { +fileprivate func block(fromIndex: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) return block } +fileprivate func innerBlockIndex(fromIndex index: Int, fromBlock block: Int) -> Int { + return index - block * (block + 1) / 2 +} + public subscript(index: Int) -> T { get { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - return blocks[block][blockIndex]! + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + return blocks[block][innerBlockIndex]! } set(newValue) { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - blocks[block][blockIndex] = newValue + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = newValue } } ``` -`toBlock(index:)` is really just wrapping the `block` equation derived earlier to return the block that an index maps to. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic: +`block(fromIndex:)` and `innerBlockIndex(fromIndex:, fromBlock:)` are wrapping the `block` and `inner block index` equations derived earlier. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic: 1. determine the block that the index points to 2. determine the inner block index 3. `get`/`set` the value @@ -157,18 +164,18 @@ public subscript(index: Int) -> T { Next lets look at how we would `growIfNeeded()` and `shrinkIfNeeded()` the structure. ```swift fileprivate mutating func growIfNeeded() { - if capacity - blocks.count < count + 1 { - let newArray = [T?](repeating: nil, count: blocks.count + 1) - blocks.append(newArray) - } + if capacity - blocks.count < count + 1 { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } } fileprivate mutating func shrinkIfNeeded() { - if capacity + blocks.count >= count { - while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 >= count { - blocks.remove(at: blocks.count - 1) - } - } + if capacity + blocks.count >= count { + while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 > count { + blocks.remove(at: blocks.count - 1) + } + } } ``` If our data set grows or shrinks in size, we want our data structure to accommodate the change. @@ -203,9 +210,9 @@ public mutating func remove(atIndex index: Int) -> T { } fileprivate mutating func makeNil(atIndex index: Int) { - let block = toBlock(index: index) - let blockIndex = index - block * (block + 1) / 2 - blocks[block][blockIndex] = nil + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = nil } ``` To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element we set the value using the `subscript` convenience. `append(element:)` is just a convenience method to add to the end. To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. `makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do). @@ -218,4 +225,15 @@ To `insert(element:, atIndex:)` we move all elements after the `index` to the ri * Since `subcript[index:]` uses the `block` and `inner block index` equations, which can be executed in **O(1)** time, all get and set operations take **O(1)**. -* Ignoring the time cost to `grow()` and `shrink()`, `insert()` and `remove()` operations shift all elements right of the specified index resulting in **O(n)** time. +* Ignoring the time cost to `grow` and `shrink`, `insert(atIndex:)` and `remove(atIndex:)` operations shift all elements right of the specified index resulting in **O(n)** time. + +# Analysis of Growing and Shrinking +The performance analysis doesn't account for the cost to `grow` and `shrink`. Unlike a regular Swift array, `grow` and `shrink` operations don't copy all the elements into a backing array. They only allocate or free an array proportional to the number of `blocks`. The number of `blocks` is proportional to the square root of the number of elements. Growing and shrinking only cost **O(√n)**. + +# Wasted Space +Wasted space is how much memory with respect to the number of elements `n` is unused. The Rootish Array Stack never has more than 2 empty blocks and it never has less than 1 empty block. The last two blocks are proportional to the number of blocks which is proportional to the square root of the number of elements. The number of references needed to point to each block is the same as the number of blocks. Therefore, the amount of wasted space with respect to the number of elements is **O(√n)**. + + +_Written for Swift Algorithm Club by @BenEmdon_ + +_With help from [OpenDataStructures.org](http://opendatastructures.org)_ From 0879118bfdffa6ec3d9f426322b3b751e87e6b85 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sat, 10 Dec 2016 23:44:08 -0500 Subject: [PATCH 0285/1275] Marks in swift file --- Rootish Array Stack/RootishArrayStack.swift | 40 +++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 842e34f72..0d2b15c3c 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -1,18 +1,24 @@ // -// main.swift // RootishArrayStack // -// Created by Benjamin Emdon on 2016-11-07. +// Created by @BenEmdon on 2016-11-07. // import Darwin public struct RootishArrayStack { + + // MARK: - Instance variables + fileprivate var blocks = [Array]() fileprivate var internalCount = 0 + // MARK: - Init + public init() { } + // MARK: - Calculated variables + var count: Int { return internalCount } @@ -21,6 +27,8 @@ public struct RootishArrayStack { return blocks.count * (blocks.count + 1) / 2 } + // MARK: - Equations + fileprivate func block(fromIndex index: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) return block @@ -30,6 +38,8 @@ public struct RootishArrayStack { return index - block * (block + 1) / 2 } + // MARK: - Behavior + fileprivate mutating func growIfNeeded() { if capacity - blocks.count < count + 1 { let newArray = [T?](repeating: nil, count: blocks.count + 1) @@ -89,20 +99,10 @@ public struct RootishArrayStack { shrinkIfNeeded() return element } - - public var memoryDescription: String { - var description = "{\n" - for block in blocks { - description += "\t[" - for rawElement in block { - description += "\(rawElement), " - } - description += "]\n" - } - return description + "}" - } } +// MARK: - Struct to string + extension RootishArrayStack: CustomStringConvertible { public var description: String { var s = "[" @@ -114,4 +114,16 @@ extension RootishArrayStack: CustomStringConvertible { } return s + "]" } + + public var memoryDescription: String { + var description = "{\n" + for block in blocks { + description += "\t[" + for rawElement in block { + description += "\(rawElement), " + } + description += "]\n" + } + return description + "}" + } } From e5dfe6637980b9f425371c0dbe82dedae1100d3e Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sun, 11 Dec 2016 00:25:58 -0500 Subject: [PATCH 0286/1275] Added isEmpty, first, last --- Rootish Array Stack/RootishArrayStack.swift | 16 ++++++++++++++++ .../contents.xcworkspacedata | 3 +++ 2 files changed, 19 insertions(+) diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 0d2b15c3c..4033d75f6 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -27,6 +27,22 @@ public struct RootishArrayStack { return blocks.count * (blocks.count + 1) / 2 } + var isEmpty: Bool { + return blocks.count == 0 + } + + var first: T? { + guard capacity > 0 else { return nil } + return blocks[0][0] + } + + var last: T? { + guard capacity > 0 else { return nil } + let block = self.block(fromIndex: count - 1) + let innerBlockIndex = self.innerBlockIndex(fromIndex: count - 1, fromBlock: block) + return blocks[block][innerBlockIndex] + } + // MARK: - Equations fileprivate func block(fromIndex index: Int) -> Int { diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index ac3a79be9..c2ae29f70 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1529,6 +1529,9 @@ + + Date: Sun, 11 Dec 2016 00:32:20 -0500 Subject: [PATCH 0287/1275] Added playground Finished playground --- Rootish Array Stack/README.md | 58 ++--- .../Contents.swift | 219 ++++++++++++++++++ .../contents.xcplayground | 4 + Rootish Array Stack/RootishArrayStack.swift | 35 +-- 4 files changed, 273 insertions(+), 43 deletions(-) create mode 100644 Rootish Array Stack/RootishArrayStack.playground/Contents.swift create mode 100644 Rootish Array Stack/RootishArrayStack.playground/contents.xcplayground diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md index c00061082..6a45b262a 100644 --- a/Rootish Array Stack/README.md +++ b/Rootish Array Stack/README.md @@ -4,14 +4,14 @@ A *Rootish Array Stack* is an ordered array based structure that minimizes waste ![Rootish Array Stack Intro](images/RootishArrayStackIntro.png) -A resizable array holds references to blocks (arrays of fixed size). A block's capacity is the same as it's index in the resizable array. Blocks don't grow/shrink like regular Swift arrays. Instead, when their capacity is reached, a new slightly larger block is created. When a block is emptied the last block is freed. This is a great improvement on what a swift array does in terms of wasted space. +A resizable array holds references to blocks (arrays of fixed size). A block's capacity is the same as it's index in the resizable array. Blocks don't grow/shrink like regular Swift arrays. Instead, when their capacity is reached, a new slightly larger block is created. When a block is emptied the last block is freed. This is a great improvement on what Swift arrays do in terms of wasted space. ![Rootish Array Stack Intro](images/RootishArrayStackExample.png) Here you can see how insert/remove operations would behave (very similar to how a Swift array handles such operations). ## Gauss' Summation Trick -One of the most well known legends about famous mathematician [Carl Friedrich Gauss](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss) goes back to when he was in primary school. One day Gauss' teacher asked his class to add up all the numbers from 1 to 100, hoping that the task would take long enough for the teacher to step out for a smoke break. The teacher was shocked when young Gauss had his hand up with the answer `5050`. So soon? The teacher suspected a cheat, but no. Gauss had found a formula to sidestep the problem of manually adding up all the numbers 1 by 1. His formula: +One of the most well known legends about famous mathematician [Carl Friedrich Gauss](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss) goes back to when he was in primary school. One day, Gauss' teacher asked his class to add up all the numbers from 1 to 100, hoping that the task would take long enough for him to step out for a smoke break. The teacher was shocked when young Gauss had his hand up with the answer `5050`. So soon? The teacher suspected a cheat, but no. Gauss had found a formula to sidestep the problem of manually adding up all the numbers 1 by 1. His formula: ``` sum from 1...n = n * (n + 1) / 2 ``` @@ -22,7 +22,7 @@ blocks: [x] [x x] [x x x] [x x x x] [x x x x x] ``` _Block `1` has 1 `x`, block `2` as 2 `x`s, block `3` has 3 `x`s, etc..._ -If you wanted to take the sum of all the blocks from `1` to `n` you could go through and count them _one by one_. This is okay, but for a large sequence of blocks that could take a long time! Instead you could arrange the blocks to look like a _half pyramid_: +If you wanted to take the sum of all the blocks from `1` to `n`, you could go through and count them _one by one_. This is okay, but for a large sequence of blocks that could take a long time! Instead, you could arrange the blocks to look like a _half pyramid_: ``` # | blocks --|------------- @@ -43,24 +43,24 @@ x x x x x o o o o o x x x x x o ``` Here we have `n` rows and `n + 1` columns. _5 rows and 6 columns_. -We could calculate sum just as we would an area! Lets also express the width and hight in terms of `n`: +We can calculate the sum just as we would an area! Let's also express the width and height in terms of `n`: ``` area of a rectangle = height * width = n * (n + 1) ``` -But we only want to calculate the amount of `x`s, not the amount of `o`s. Since there's a 1:1 ratio between `x`s and `o`s we and just divide our area by 2! +We only want to calculate the amount of `x`s, not the amount of `o`s. Since there's a 1:1 ratio between `x`s and `o`s we can just divide our area by 2! ``` area of only x = n * (n + 1) / 2 ``` -And voila! A super fast way to take a sum of all the blocks! This equation is useful for deriving fast `block` and `inner block index` equations. +Voila! A super fast way to take a sum of all the blocks! This equation is useful for deriving fast `block` and `inner block index` equations. + ## Get/Set with Speed -Next we want to find an efficient and accurate way to access an element at a random index. For example which block does `rootishArrayStack[12]` point to? To answer this we will need more math! +Next, we want to find an efficient and accurate way to access an element at a random index. For example, which block does `rootishArrayStack[12]` point to? To answer this we will need more math! Determining the inner block `index` turns out to be easy. If `index` is in some `block` then: ``` inner block index = index - block * (block + 1) / 2 ``` - -More difficult is determining which `block` an index points to. The number of elements that have indices less than or equal to the the requested `index` is: `index + 1` elements. The number of elements in blocks `0...block` is `(block + 1) * (block + 2) / 2`. Therefore, `block` is the smaller integer such that: +Determining which `block` an index points to is more difficult. The number of elements up to and including the element requested is: `index + 1` elements. The number of elements in blocks `0...block` is `(block + 1) * (block + 2) / 2` (equation derived above). The relationship between the `block` and the `index` is as follows: ``` (block + 1) * (block + 2) / 2 >= index + 1 ``` @@ -68,16 +68,16 @@ This can be rewritten as: ``` (block)^2 + (3 * block) - (2 * index) >= 0 ``` -Using the quadratic formula we can get: +Using the quadratic formula we get: ``` block = (-3 ± √(9 + 8 * index)) / 2 ``` -A negative block doesn't make sense so we take the positive root instead. In general this solution is not an integer but going back to our inequality, we want the smallest block such that `b => (-3 + √(9 + 8 * index)) / 2`. So we take the ceiling of the result: +A negative block doesn't make sense, so we take the positive root instead. In general, this solution is not an integer. However, going back to our inequality, we want the smallest block such that `block => (-3 + √(9 + 8 * index)) / 2`. Next, we take the ceiling of the result: ``` block = ⌈(-3 + √(9 + 8 * index)) / 2⌉ ``` -Now we can figure out that `rootishArrayStack[12]` points to! First lets see which block the `12` points to: +Now we can figure out what `rootishArrayStack[12]` points to! First, let's see which block the `12` points to: ``` block = ⌈(-3 + √(9 + 8 * (12))) / 2⌉ block = ⌈(-3 + √105) / 2⌉ @@ -93,14 +93,14 @@ inner block index = (12) - (4) * (5) / 2 inner block index = (12) - 10 inner block index = 2 ``` -Therefore `rootishArrayStack[12]` points to the block at index `4` and at inner block index `2`. +Therefore, `rootishArrayStack[12]` points to the block at index `4` and at inner block index `2`. ![Rootish Array Stack Intro](images/RootishArrayStackExample2.png) ### Interesting Discovery -Using the `block` equation we can see that the number of `blocks` is proportional to the square root of the number of elements: **O(blocks) = O(√n)**. +Using the `block` equation, we can see that the number of `blocks` is proportional to the square root of the number of elements: **O(blocks) = O(√n)**. # Implementation Details -Lets start with instance variables and struct declaration: +Let's start with instance variables and struct declaration: ```swift import Darwin @@ -123,7 +123,7 @@ public struct RootishArrayStack { The elements are of generic type `T`, so data of any kind can be stored in the list. `blocks` will be a resizable array to hold fixed sized arrays that take type `T?`. > The reason for the fixed size arrays taking type `T?` is so that references to elements aren't retained after they've been removed. Eg: if you remove the last element, the last index must be set to `nil` to prevent the last element being held in memory at an inaccessible index. -`internalCount` is an internal mutable counter that keeps track of the number of elements. `count` is a read only variables that gives the `internalCount` value. `Darwin` is imported here to provide simple math functions such as `ceil()` and `sqrt()`. +`internalCount` is an internal mutable counter that keeps track of the number of elements. `count` is a read only variable that returns the `internalCount` value. `Darwin` is imported here to provide simple math functions such as `ceil()` and `sqrt()`. The `capacity` of the structure is simply the Gaussian summation trick: ```swift @@ -132,7 +132,7 @@ var capacity: Int { } ``` -Next lets look at we would `get` and `set` elements: +Next, let's look at how we would `get` and `set` elements: ```swift fileprivate func block(fromIndex: Int) -> Int { let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) @@ -156,12 +156,13 @@ public subscript(index: Int) -> T { } } ``` -`block(fromIndex:)` and `innerBlockIndex(fromIndex:, fromBlock:)` are wrapping the `block` and `inner block index` equations derived earlier. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic: - 1. determine the block that the index points to - 2. determine the inner block index - 3. `get`/`set` the value +`block(fromIndex:)` and `innerBlockIndex(fromIndex:, fromBlock:)` are wrapping the `block` and `inner block index` equations we derived earlier. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in `superscript` we use the same logic: + +1. determine the block that the index points to +2. determine the inner block index +3. `get`/`set` the value -Next lets look at how we would `growIfNeeded()` and `shrinkIfNeeded()` the structure. +Next, let's look at how we would `growIfNeeded()` and `shrinkIfNeeded()`. ```swift fileprivate mutating func growIfNeeded() { if capacity - blocks.count < count + 1 { @@ -179,7 +180,7 @@ fileprivate mutating func shrinkIfNeeded() { } ``` If our data set grows or shrinks in size, we want our data structure to accommodate the change. -Just like a Swift array when a capacity threshold is met we will `grow` or `shrink` the size of our structure. For the Rootish Array Stack we want to `grow` if the second last block is full on an `insert` operation, and `shrink` if the two last blocks are empty. +Just like a Swift array, when a capacity threshold is met we will `grow` or `shrink` the size of our structure. For the Rootish Array Stack we want to `grow` if the second last block is full on an `insert` operation, and `shrink` if the two last blocks are empty. Now to the more familiar Swift array behaviour. ```swift @@ -215,8 +216,11 @@ fileprivate mutating func makeNil(atIndex index: Int) { blocks[block][innerBlockIndex] = nil } ``` -To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element we set the value using the `subscript` convenience. `append(element:)` is just a convenience method to add to the end. To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. `makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do). -> Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` wheres setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs). +To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element, we set the value using the `subscript` convenience method. +`append(element:)` is just a convenience method to `insert` to the end. +To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. +`makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do). +> Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` whereas setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs). # Performance * An internal counter keeps track of the number of elements in the structure. `count` is executed in **O(1)** time. @@ -228,10 +232,10 @@ To `insert(element:, atIndex:)` we move all elements after the `index` to the ri * Ignoring the time cost to `grow` and `shrink`, `insert(atIndex:)` and `remove(atIndex:)` operations shift all elements right of the specified index resulting in **O(n)** time. # Analysis of Growing and Shrinking -The performance analysis doesn't account for the cost to `grow` and `shrink`. Unlike a regular Swift array, `grow` and `shrink` operations don't copy all the elements into a backing array. They only allocate or free an array proportional to the number of `blocks`. The number of `blocks` is proportional to the square root of the number of elements. Growing and shrinking only cost **O(√n)**. +The performance analysis doesn't account for the cost to `grow` and `shrink`. Unlike a regular Swift array, `grow` and `shrink` operations don't copy all the elements into a backing array. They only allocate or free an array proportional to the number of `blocks`. The number of `blocks` is proportional to the square root of the number of elements. Growing and shrinking only costs **O(√n)**. # Wasted Space -Wasted space is how much memory with respect to the number of elements `n` is unused. The Rootish Array Stack never has more than 2 empty blocks and it never has less than 1 empty block. The last two blocks are proportional to the number of blocks which is proportional to the square root of the number of elements. The number of references needed to point to each block is the same as the number of blocks. Therefore, the amount of wasted space with respect to the number of elements is **O(√n)**. +Wasted space is how much memory with respect to the number of elements `n` is unused. The Rootish Array Stack never has more than 2 empty blocks and it never has less than 1 empty block. The last two blocks are proportional to the number of blocks, which is proportional to the square root of the number of elements. The number of references needed to point to each block is the same as the number of blocks. Therefore, the amount of wasted space with respect to the number of elements is **O(√n)**. _Written for Swift Algorithm Club by @BenEmdon_ diff --git a/Rootish Array Stack/RootishArrayStack.playground/Contents.swift b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift new file mode 100644 index 000000000..401c773d6 --- /dev/null +++ b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift @@ -0,0 +1,219 @@ +//: Playground - noun: a place where people can play + +import Darwin + +public struct RootishArrayStack { + + // MARK: - Instance variables + + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 + + // MARK: - Init + + public init() { } + + // MARK: - Calculated variables + + var count: Int { + return internalCount + } + + var capacity: Int { + return blocks.count * (blocks.count + 1) / 2 + } + + var isEmpty: Bool { + return blocks.count == 0 + } + + var first: T? { + guard capacity > 0 else { return nil } + return blocks[0][0] + } + + var last: T? { + guard capacity > 0 else { return nil } + let block = self.block(fromIndex: count - 1) + let innerBlockIndex = self.innerBlockIndex(fromIndex: count - 1, fromBlock: block) + return blocks[block][innerBlockIndex] + } + + // MARK: - Equations + + fileprivate func block(fromIndex index: Int) -> Int { + let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) + return block + } + + fileprivate func innerBlockIndex(fromIndex index: Int, fromBlock block: Int) -> Int { + return index - block * (block + 1) / 2 + } + + // MARK: - Behavior + + fileprivate mutating func growIfNeeded() { + if capacity - blocks.count < count + 1 { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } + } + + fileprivate mutating func shrinkIfNeeded() { + if capacity + blocks.count >= count { + while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 >= count { + blocks.remove(at: blocks.count - 1) + } + } + } + + public subscript(index: Int) -> T { + get { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + return blocks[block][innerBlockIndex]! + } + set(newValue) { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = newValue + } + } + + public mutating func insert(element: T, atIndex index: Int) { + growIfNeeded() + internalCount += 1 + var i = count - 1 + while i > index { + self[i] = self[i - 1] + i -= 1 + } + self[index] = element + } + + public mutating func append(element: T) { + insert(element: element, atIndex: count) + } + + fileprivate mutating func makeNil(atIndex index: Int) { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = nil + } + + public mutating func remove(atIndex index: Int) -> T { + let element = self[index] + for i in index..() +list.isEmpty // true +list.first // nil +list.last // nil +list.count // 0 +list.capacity // 0 + +list.memoryDescription +// { +// } + +list.append(element: "Hello") +list.isEmpty // false +list.first // "Hello" +list.last // "hello" +list.count // 1 +list.capacity // 1 + +list.memoryDescription +// { +// [Optional("Hello")] +// } + +list.append(element: "World") +list.isEmpty // false +list.first // "Hello" +list.last // "World" +list.count // 2 +list.capacity // 3 + +list[0] // "Hello" +list[1] // "World" +//list[2] // crash! + + +list.memoryDescription +// { +// [Optional("Hello")] +// [Optional("World"), nil] +// } + + +list.insert(element: "Swift", atIndex: 1) +list.isEmpty // false +list.first // "Hello" +list.last // "World" +list.count // 3 +list.capacity // 6 + +list[0] // "Hello" +list[1] // "Swift" +list[2] // "World" + +list.memoryDescription +// { +// [Optional("Hello")] +// [Optional("Swift"), Optional("World")] +// [nil, nil, nil] +// } + +list.remove(atIndex: 2) // "World" +list.isEmpty // false +list.first // "Hello" +list.last // "Swift" +list.count // 2 +list.capacity // 3 + +list[0] // "Hello" +list[1] // "Swift" +//list[2] // crash! + +list[0] = list[1] +list[1] = "is awesome" +list // ["Swift", "is awesome"] diff --git a/Rootish Array Stack/RootishArrayStack.playground/contents.xcplayground b/Rootish Array Stack/RootishArrayStack.playground/contents.xcplayground new file mode 100644 index 000000000..63b6dd8df --- /dev/null +++ b/Rootish Array Stack/RootishArrayStack.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Rootish Array Stack/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift index 4033d75f6..af95a4316 100644 --- a/Rootish Array Stack/RootishArrayStack.swift +++ b/Rootish Array Stack/RootishArrayStack.swift @@ -115,31 +115,34 @@ public struct RootishArrayStack { shrinkIfNeeded() return element } -} - -// MARK: - Struct to string -extension RootishArrayStack: CustomStringConvertible { - public var description: String { - var s = "[" - for index in 0.. Date: Sun, 18 Dec 2016 16:57:29 -0500 Subject: [PATCH 0288/1275] Added tests template --- Rootish Array Stack/Tests/Info.plist | 24 ++ .../Tests/RootishArrayStack.swift | 148 ++++++++++ .../Tests/RootishArrayStackTests.swift | 251 +++++++++++++++++ .../Tests/Tests.xcodeproj/project.pbxproj | 264 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 90 ++++++ 6 files changed, 784 insertions(+) create mode 100644 Rootish Array Stack/Tests/Info.plist create mode 100644 Rootish Array Stack/Tests/RootishArrayStack.swift create mode 100755 Rootish Array Stack/Tests/RootishArrayStackTests.swift create mode 100644 Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Rootish Array Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/Rootish Array Stack/Tests/Info.plist b/Rootish Array Stack/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Rootish Array Stack/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/Rootish Array Stack/Tests/RootishArrayStack.swift b/Rootish Array Stack/Tests/RootishArrayStack.swift new file mode 100644 index 000000000..af95a4316 --- /dev/null +++ b/Rootish Array Stack/Tests/RootishArrayStack.swift @@ -0,0 +1,148 @@ +// +// RootishArrayStack +// +// Created by @BenEmdon on 2016-11-07. +// + +import Darwin + +public struct RootishArrayStack { + + // MARK: - Instance variables + + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 + + // MARK: - Init + + public init() { } + + // MARK: - Calculated variables + + var count: Int { + return internalCount + } + + var capacity: Int { + return blocks.count * (blocks.count + 1) / 2 + } + + var isEmpty: Bool { + return blocks.count == 0 + } + + var first: T? { + guard capacity > 0 else { return nil } + return blocks[0][0] + } + + var last: T? { + guard capacity > 0 else { return nil } + let block = self.block(fromIndex: count - 1) + let innerBlockIndex = self.innerBlockIndex(fromIndex: count - 1, fromBlock: block) + return blocks[block][innerBlockIndex] + } + + // MARK: - Equations + + fileprivate func block(fromIndex index: Int) -> Int { + let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2)) + return block + } + + fileprivate func innerBlockIndex(fromIndex index: Int, fromBlock block: Int) -> Int { + return index - block * (block + 1) / 2 + } + + // MARK: - Behavior + + fileprivate mutating func growIfNeeded() { + if capacity - blocks.count < count + 1 { + let newArray = [T?](repeating: nil, count: blocks.count + 1) + blocks.append(newArray) + } + } + + fileprivate mutating func shrinkIfNeeded() { + if capacity + blocks.count >= count { + while blocks.count > 0 && (blocks.count - 2) * (blocks.count - 1) / 2 >= count { + blocks.remove(at: blocks.count - 1) + } + } + } + + public subscript(index: Int) -> T { + get { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + return blocks[block][innerBlockIndex]! + } + set(newValue) { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = newValue + } + } + + public mutating func insert(element: T, atIndex index: Int) { + growIfNeeded() + internalCount += 1 + var i = count - 1 + while i > index { + self[i] = self[i - 1] + i -= 1 + } + self[index] = element + } + + public mutating func append(element: T) { + insert(element: element, atIndex: count) + } + + fileprivate mutating func makeNil(atIndex index: Int) { + let block = self.block(fromIndex: index) + let innerBlockIndex = self.innerBlockIndex(fromIndex: index, fromBlock: block) + blocks[block][innerBlockIndex] = nil + } + + public mutating func remove(atIndex index: Int) -> T { + let element = self[index] + for i in index.. LinkedList { + let list = LinkedList() + for number in numbers { + list.append(number) + } + return list + } + + 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 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) + XCTAssertTrue(node === list.first) + } + + func testNodeAtIndex() { + let list = buildList() + + 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]) + + let last = list.node(atIndex: nodeCount - 1) + XCTAssertNotNil(last) + XCTAssertTrue(last === list.last) + XCTAssertEqual(last!.value, numbers[nodeCount - 1]) + + for i in 0..() + list.insert(123, atIndex: 0) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + + let node = list.node(atIndex: 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 nodeCount = list.count + + list.insert(444, atIndex: 3) + + let node = list.node(atIndex: 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 testRemoveAtIndexOnListWithOneElement() { + let list = LinkedList() + list.append(123) + + let value = list.remove(atIndex: 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(atIndex: 2) + let next = list.node(atIndex: 3) + let nodeCount = list.count + + list.insert(444, atIndex: 3) + + let value = list.remove(atIndex: 3) + XCTAssertEqual(value, 444) + + let node = list.node(atIndex: 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) + } +} diff --git a/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj b/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d6fb62c9d --- /dev/null +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,264 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1D059BB21E073CED00391DD1 /* RootishArrayStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D059BB11E073CED00391DD1 /* RootishArrayStack.swift */; }; + 7B80C3FA1C77A61E003CECC7 /* RootishArrayStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F91C77A61E003CECC7 /* RootishArrayStackTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D059BB11E073CED00391DD1 /* RootishArrayStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RootishArrayStack.swift; path = ../RootishArrayStack.swift; sourceTree = ""; }; + 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 7B80C3F91C77A61E003CECC7 /* RootishArrayStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootishArrayStackTests.swift; 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 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 1D059BB11E073CED00391DD1 /* RootishArrayStack.swift */, + 7B80C3F91C77A61E003CECC7 /* RootishArrayStackTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + path = TestsTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* Tests */, + ); + }; +/* 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 = ( + 7B80C3FA1C77A61E003CECC7 /* RootishArrayStackTests.swift in Sources */, + 1D059BB21E073CED00391DD1 /* RootishArrayStack.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_BOOL_CONVERSION = 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_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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"; + }; + 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_BOOL_CONVERSION = 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_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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_VERSION = 3.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/Rootish Array Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Rootish Array Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8ef8d8581 --- /dev/null +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f709ee8d52dbef684e02e6350bd5110c2ffb313b Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Sun, 18 Dec 2016 17:31:52 -0500 Subject: [PATCH 0289/1275] added test scheme to travis --- .travis.yml | 1 + .../contents.xcworkspacedata | 7 + .../Tests/RootishArrayStackTests.swift | 492 +++++++++--------- .../Tests/Tests.xcodeproj/project.pbxproj | 9 +- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../contents.xcworkspacedata | 29 ++ 6 files changed, 293 insertions(+), 247 deletions(-) create mode 100644 Rootish Array Stack/RootishArrayStack.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/.travis.yml b/.travis.yml index 45f0d4beb..695c702c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ script: # - 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.xcodeproj -scheme Tests +- xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Run-Length\ Encoding/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 diff --git a/Rootish Array Stack/RootishArrayStack.playground/playground.xcworkspace/contents.xcworkspacedata b/Rootish Array Stack/RootishArrayStack.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Rootish Array Stack/RootishArrayStack.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Rootish Array Stack/Tests/RootishArrayStackTests.swift b/Rootish Array Stack/Tests/RootishArrayStackTests.swift index 7fa420cb2..8292f3d30 100755 --- a/Rootish Array Stack/Tests/RootishArrayStackTests.swift +++ b/Rootish Array Stack/Tests/RootishArrayStackTests.swift @@ -1,251 +1,255 @@ import XCTest class RootishArrayStackTests: XCTestCase { - let numbers = [8, 2, 10, 9, 7, 5] - - fileprivate func buildList() -> LinkedList { - let list = LinkedList() - for number in numbers { - list.append(number) - } +// let randomNumbers = [8, 2, 10, 9, 7, 5] + + func buildList(withNumbers numbers: [Int]? = nil) -> RootishArrayStack { + var list = RootishArrayStack() + if let numbers = numbers { + for number in numbers { + list.append(element: number) + } + } return list } - 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 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) - XCTAssertTrue(node === list.first) - } - - func testNodeAtIndex() { - let list = buildList() - - 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]) - - let last = list.node(atIndex: nodeCount - 1) - XCTAssertNotNil(last) - XCTAssertTrue(last === list.last) - XCTAssertEqual(last!.value, numbers[nodeCount - 1]) - - for i in 0..() - list.insert(123, atIndex: 0) - - XCTAssertFalse(list.isEmpty) - XCTAssertEqual(list.count, 1) - - let node = list.node(atIndex: 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 nodeCount = list.count - - list.insert(444, atIndex: 3) - - let node = list.node(atIndex: 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 testRemoveAtIndexOnListWithOneElement() { - let list = LinkedList() - list.append(123) - - let value = list.remove(atIndex: 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(atIndex: 2) - let next = list.node(atIndex: 3) - let nodeCount = list.count - - list.insert(444, atIndex: 3) - - let value = list.remove(atIndex: 3) - XCTAssertEqual(value, 444) - - let node = list.node(atIndex: 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 testEmptyList() { + let list = buildList() + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertEqual(list.capacity, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testListWithOneElement() { + let list = buildList(withNumbers: [1]) + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + XCTAssertEqual(list.capacity, 1) + XCTAssertEqual(list.first, 1) + XCTAssertEqual(list.last, 1) + XCTAssertEqual(list.first, list.last) + } + + func testListWithTwoElements() { + let list = buildList(withNumbers: [1, 2]) + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 2) + XCTAssertEqual(list.capacity, 3) + XCTAssertEqual(list.first, 1) + XCTAssertEqual(list.last, 2) + XCTAssertNotEqual(list.first, list.last) + } + +// +// func testListWithTwoElements() { +// var list = RootishArrayStack() +// 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() { +// var list = RootishArrayStack() +// 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 testNodeAtIndexInEmptyList() { +// var list = RootishArrayStack() +// let node = list.node(atIndex: 0) +// XCTAssertNil(node) +// } +// +// func testNodeAtIndexInListWithOneElement() { +// let list = RootishArrayStack() +// list.append(123) +// +// let node = list.node(atIndex: 0) +// XCTAssertNotNil(node) +// XCTAssertEqual(node!.value, 123) +// XCTAssertTrue(node === list.first) +// } +// +// func testNodeAtIndex() { +// let list = buildList() +// +// 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]) +// +// let last = list.node(atIndex: nodeCount - 1) +// XCTAssertNotNil(last) +// XCTAssertTrue(last === list.last) +// XCTAssertEqual(last!.value, numbers[nodeCount - 1]) +// +// for i in 0..() +// list.insert(123, atIndex: 0) +// +// XCTAssertFalse(list.isEmpty) +// XCTAssertEqual(list.count, 1) +// +// let node = list.node(atIndex: 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 nodeCount = list.count +// +// list.insert(444, atIndex: 3) +// +// let node = list.node(atIndex: 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 testRemoveAtIndexOnListWithOneElement() { +// let list = LinkedList() +// list.append(123) +// +// let value = list.remove(atIndex: 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(atIndex: 2) +// let next = list.node(atIndex: 3) +// let nodeCount = list.count +// +// list.insert(444, atIndex: 3) +// +// let value = list.remove(atIndex: 3) +// XCTAssertEqual(value, 444) +// +// let node = list.node(atIndex: 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) +// } } diff --git a/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj b/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj index d6fb62c9d..cdfd35f71 100644 --- a/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 0820; }; }; }; @@ -146,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -190,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; diff --git a/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..dfcf6de42 100644 --- a/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + + + + + + + + + + + From 3a44c0b3c948f43856f0135167934d6ccc6c3077 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Mon, 19 Dec 2016 11:27:18 -0500 Subject: [PATCH 0290/1275] Added tests --- .../Tests/RootishArrayStackTests.swift | 382 ++++++++---------- .../contents.xcworkspacedata | 4 +- 2 files changed, 170 insertions(+), 216 deletions(-) diff --git a/Rootish Array Stack/Tests/RootishArrayStackTests.swift b/Rootish Array Stack/Tests/RootishArrayStackTests.swift index 8292f3d30..f73857d0f 100755 --- a/Rootish Array Stack/Tests/RootishArrayStackTests.swift +++ b/Rootish Array Stack/Tests/RootishArrayStackTests.swift @@ -1,10 +1,22 @@ import XCTest +fileprivate extension RootishArrayStack { + func equal(toArray array: Array) -> Bool{ + for index in 0.. RootishArrayStack { + private func buildList(withNumbers numbers: [Int]? = nil) -> RootishArrayStack { var list = RootishArrayStack() + if let numbers = numbers { for number in numbers { list.append(element: number) @@ -14,242 +26,184 @@ class RootishArrayStackTests: XCTestCase { } func testEmptyList() { + let emptyArray = [Int]() let list = buildList() + XCTAssertTrue(list.isEmpty) XCTAssertEqual(list.count, 0) XCTAssertEqual(list.capacity, 0) XCTAssertNil(list.first) XCTAssertNil(list.last) + XCTAssertTrue(list.equal(toArray: emptyArray)) } func testListWithOneElement() { - let list = buildList(withNumbers: [1]) + let array = [1] + let list = buildList(withNumbers: array) + XCTAssertFalse(list.isEmpty) XCTAssertEqual(list.count, 1) XCTAssertEqual(list.capacity, 1) XCTAssertEqual(list.first, 1) XCTAssertEqual(list.last, 1) XCTAssertEqual(list.first, list.last) + XCTAssertTrue(list.equal(toArray: array)) } func testListWithTwoElements() { - let list = buildList(withNumbers: [1, 2]) + let array = [1, 2] + let list = buildList(withNumbers: array) + XCTAssertFalse(list.isEmpty) XCTAssertEqual(list.count, 2) XCTAssertEqual(list.capacity, 3) XCTAssertEqual(list.first, 1) XCTAssertEqual(list.last, 2) XCTAssertNotEqual(list.first, list.last) + XCTAssertTrue(list.equal(toArray: array)) + } + + func testListWithThreeElements() { + let array = [1, 2, 3] + let list = buildList(withNumbers: array) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 3) + XCTAssertEqual(list.capacity, 6) + XCTAssertEqual(list.first, 1) + XCTAssertEqual(list.last, 3) + XCTAssertNotEqual(list.first, list.last) + XCTAssertTrue(list.equal(toArray: array)) + } + + func testFillThenEmpty() { + let array = [Int](0..<100) + let emptyArray = [Int]() + var list = buildList(withNumbers: array) + + XCTAssertTrue(list.equal(toArray: array)) + + for _ in 0..<100 { + list.remove(atIndex: list.count - 1) + } + + XCTAssertEqual(list.count, 0) + XCTAssertEqual(list.capacity, 0) + XCTAssertTrue(list.equal(toArray: emptyArray)) + } + + func testInsertFront() { + var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + var list = buildList(withNumbers: array) + + XCTAssertEqual(list.count, 10) + XCTAssertEqual(list.capacity, 15) + XCTAssertEqual(list.first, 1) + XCTAssertTrue(list.equal(toArray: array)) + + let newElement = 0 + list.insert(element: newElement, atIndex: 0) + array.insert(newElement, at: 0) + + XCTAssertEqual(list.count, 11) + XCTAssertEqual(list.capacity, 21) + XCTAssertEqual(list.first, newElement) + XCTAssertTrue(list.equal(toArray: array)) } -// -// func testListWithTwoElements() { -// var list = RootishArrayStack() -// 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() { -// var list = RootishArrayStack() -// 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 testNodeAtIndexInEmptyList() { -// var list = RootishArrayStack() -// let node = list.node(atIndex: 0) -// XCTAssertNil(node) -// } -// -// func testNodeAtIndexInListWithOneElement() { -// let list = RootishArrayStack() -// list.append(123) -// -// let node = list.node(atIndex: 0) -// XCTAssertNotNil(node) -// XCTAssertEqual(node!.value, 123) -// XCTAssertTrue(node === list.first) -// } -// -// func testNodeAtIndex() { -// let list = buildList() -// -// 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]) -// -// let last = list.node(atIndex: nodeCount - 1) -// XCTAssertNotNil(last) -// XCTAssertTrue(last === list.last) -// XCTAssertEqual(last!.value, numbers[nodeCount - 1]) -// -// for i in 0..() -// list.insert(123, atIndex: 0) -// -// XCTAssertFalse(list.isEmpty) -// XCTAssertEqual(list.count, 1) -// -// let node = list.node(atIndex: 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 nodeCount = list.count -// -// list.insert(444, atIndex: 3) -// -// let node = list.node(atIndex: 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 testRemoveAtIndexOnListWithOneElement() { -// let list = LinkedList() -// list.append(123) -// -// let value = list.remove(atIndex: 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(atIndex: 2) -// let next = list.node(atIndex: 3) -// let nodeCount = list.count -// -// list.insert(444, atIndex: 3) -// -// let value = list.remove(atIndex: 3) -// XCTAssertEqual(value, 444) -// -// let node = list.node(atIndex: 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 testInsertMiddle() { + var array = [0, 2, 3] + var list = buildList(withNumbers: array) + + XCTAssertEqual(list.count, 3) + XCTAssertEqual(list.capacity, 6) + XCTAssertTrue(list.equal(toArray: array)) + + let newElement = 1 + list.insert(element: newElement, atIndex: 1) + array.insert(newElement, at: 1) + + XCTAssertEqual(list.count, 4) + XCTAssertEqual(list.capacity, 10) + XCTAssertEqual(list[1], newElement) + XCTAssertTrue(list.equal(toArray: array)) + } + + func testSubscriptGet() { + let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + let list = buildList(withNumbers: array) + for index in 0...9 { + XCTAssertEqual(list[index], index) + } + XCTAssertTrue(list.equal(toArray: array)) + } + + func testSubscriptSet() { + var array = [Int](0..<10) + var list = buildList(withNumbers: array) + + list[1] = 100 + list[5] = 500 + list[8] = 800 + array[1] = 100 + array[5] = 500 + array[8] = 800 + + XCTAssertTrue(list.equal(toArray: array)) + } + + func testRemoveFirst() { + var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + var list = buildList(withNumbers: array) + + XCTAssertEqual(list.count, 10) + XCTAssertEqual(list.capacity, 15) + XCTAssertEqual(list.first, 1) + XCTAssertTrue(list.equal(toArray: array)) + + list.remove(atIndex: 0) + array.remove(at: 0) + + XCTAssertEqual(list.count, 9) + XCTAssertEqual(list.capacity, 15) + XCTAssertEqual(list.first, 2) + XCTAssertTrue(list.equal(toArray: array)) + } + + + func testRemoveMiddle() { + var array = [0, 1, 2, 3] + var list = buildList(withNumbers: array) + + XCTAssertEqual(list.count, 4) + XCTAssertEqual(list.capacity, 10) + XCTAssertEqual(list.first, 0) + XCTAssertTrue(list.equal(toArray: array)) + + list.remove(atIndex: 2) + array.remove(at: 2) + + XCTAssertEqual(list.count, 3) + XCTAssertEqual(list.capacity, 6) + XCTAssertEqual(list.first, 0) + XCTAssertTrue(list.equal(toArray: array)) + } + + func testRemoveLast() { + var array = [0, 1, 2, 3] + var list = buildList(withNumbers: array) + + XCTAssertEqual(list.count, 4) + XCTAssertEqual(list.capacity, 10) + XCTAssertEqual(list.first, 0) + XCTAssertTrue(list.equal(toArray: array)) + + list.remove(atIndex: 3) + array.remove(at: 3) + + XCTAssertEqual(list.count, 3) + XCTAssertEqual(list.capacity, 6) + XCTAssertEqual(list.first, 0) + XCTAssertTrue(list.equal(toArray: array)) + } } diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 2cea625d1..194c0ae79 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1543,10 +1543,10 @@ location = "group:Info.plist"> + location = "group:RootishArrayStackTests.swift"> + location = "group:RootishArrayStack.swift"> From 3b5a508c8d16bbbfbff3ea5b1028b286464d22d5 Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Tue, 20 Dec 2016 20:46:30 -0500 Subject: [PATCH 0291/1275] Added Rootish Array Stack to Readme --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index 4c812b0f3..d4637f7c0 100644 --- a/README.markdown +++ b/README.markdown @@ -130,6 +130,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Bit Set](Bit Set/). A fixed-size sequence of *n* bits. - [Fixed Size Array](Fixed Size Array/). When you know beforehand how large your data will be, it might be more efficient to use an old-fashioned array with a fixed size. - [Ordered Array](Ordered Array/). An array that is always sorted. +- [Rootish Array Stack](Rootish Array Stack/). A space and time efficient variation on Swift arrays. ### Queues @@ -205,6 +206,7 @@ The following books are available for free online: - [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) Other algorithm repositories: From 0ffeb21dc6ec1e2a2146a43800b3c058c403a435 Mon Sep 17 00:00:00 2001 From: Stefan Cimander Date: Wed, 21 Dec 2016 18:20:18 +0100 Subject: [PATCH 0292/1275] Fix typo in ReadMe --- Trie/ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 172ff4750..7caa927a7 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -36,7 +36,7 @@ func contains(word: String) -> Bool { // 3 while currentIndex < characters.count, - let child = currentNode.children[character[currentIndex]] { + let child = currentNode.children[characters[currentIndex]] { currentNode = child currentIndex += 1 From 22675cf8d18407a6618909a0d3bb916dbe69762f Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:03:18 +0100 Subject: [PATCH 0293/1275] Add new images; --- AVL Tree/Images/Rotation.jpg | Bin 35153 -> 0 bytes AVL Tree/Images/RotationStep0.jpg | Bin 0 -> 22802 bytes AVL Tree/Images/RotationStep1.jpg | Bin 0 -> 18406 bytes AVL Tree/Images/RotationStep2.jpg | Bin 0 -> 18836 bytes AVL Tree/Images/RotationStep3.jpg | Bin 0 -> 18108 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 AVL Tree/Images/Rotation.jpg create mode 100644 AVL Tree/Images/RotationStep0.jpg create mode 100644 AVL Tree/Images/RotationStep1.jpg create mode 100644 AVL Tree/Images/RotationStep2.jpg create mode 100644 AVL Tree/Images/RotationStep3.jpg diff --git a/AVL Tree/Images/Rotation.jpg b/AVL Tree/Images/Rotation.jpg deleted file mode 100644 index 94a55df4e3268d5e9f8ed5b63a443beb9d6dda6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35153 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

Fbwd9 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 literal 0 HcmV?d00001 diff --git a/AVL Tree/Images/RotationStep1.jpg b/AVL Tree/Images/RotationStep1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbfcc04d60e0e87a37ae6d730d4141103e91bcab GIT binary patch literal 18406 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 literal 0 HcmV?d00001 diff --git a/AVL Tree/Images/RotationStep2.jpg b/AVL Tree/Images/RotationStep2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df194a73889e33fca6d9d4ccfbb50eb97022864e GIT binary patch literal 18836 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 literal 0 HcmV?d00001 diff --git a/AVL Tree/Images/RotationStep3.jpg b/AVL Tree/Images/RotationStep3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae67f4d746250063a37830f3ffafcbc1e00378a9 GIT binary patch literal 18108 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 literal 0 HcmV?d00001 From 5cc12cd45f6a386788d9cb98065953c448130e19 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:08:24 +0100 Subject: [PATCH 0294/1275] Update images; --- AVL Tree/Images/RotationStep0.jpg | Bin 22802 -> 9159 bytes AVL Tree/Images/RotationStep1.jpg | Bin 18406 -> 8046 bytes AVL Tree/Images/RotationStep2.jpg | Bin 18836 -> 8277 bytes AVL Tree/Images/RotationStep3.jpg | Bin 18108 -> 7430 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/AVL Tree/Images/RotationStep0.jpg b/AVL Tree/Images/RotationStep0.jpg index 156b18062e84cd5bd05a5557c80404ee6aa9636f..99b69d3e0f58e0faf7d98ecd0a0daf30e2e48640 100644 GIT binary patch delta 8428 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 WpZCcByi4ZzU1G{1urQsc&HWdo$nTl} literal 22802 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 diff --git a/AVL Tree/Images/RotationStep1.jpg b/AVL Tree/Images/RotationStep1.jpg index dbfcc04d60e0e87a37ae6d730d4141103e91bcab..670fa0832039799d8b90d8e530a1de409bef4871 100644 GIT binary patch delta 7288 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 j3+vDQGPS26(E>v?f53Z6M~H?`*?Jbu literal 18406 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 diff --git a/AVL Tree/Images/RotationStep2.jpg b/AVL Tree/Images/RotationStep2.jpg index df194a73889e33fca6d9d4ccfbb50eb97022864e..9d1ab5b8e6e65d0b7fac22c72226242d6e7e2a29 100644 GIT binary patch delta 7538 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 literal 18836 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 diff --git a/AVL Tree/Images/RotationStep3.jpg b/AVL Tree/Images/RotationStep3.jpg index ae67f4d746250063a37830f3ffafcbc1e00378a9..50cedf0c39651abfa38991c499ba5ba136e09c8b 100644 GIT binary patch delta 6740 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 From 2f8f348816ee0b9ef8bf52a23cc60883a7486e79 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:13:05 +0100 Subject: [PATCH 0295/1275] Update readme; --- AVL Tree/README.markdown | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index bcbbbabbc..9deea5649 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -45,20 +45,21 @@ If after an insertion or deletion the balance factor becomes greater than 1, the ## Rotations Each tree node keeps track of its current balance factor in a variable. After inserting a new node, we need to update the balance factor of its parent node. If that balance factor becomes greater than 1, we "rotate" part of that tree to restore the balance. -Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation : -![Rotation](Images/Rotation.jpg) +Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: +![Rotation0](Images/RotationStep0.jpg) -Let's dig into rotation algorithm in detail using the terminology: +For the rotation we're using the terminology: * *Root* - the parent not of the subtrees that will be rotated; * *Pivot* - the node that will become parent (basically will be on the *Root*'s position) after rotation; * *RotationSubtree* - subtree of the *Pivot* upon the side of rotation * *OppositeSubtree* - subtree of the *Pivot* opposite the side of rotation +![Rotation1](Images/RotationStep1.jpg) ![Rotation2](Images/RotationStep2.jpg) ![Rotation3](Images/RotationStep3.jpg) + The steps of rotation on the example image could be described by following: -* Select the *Pivot* as `D` and hence the *Root* as `F`; -* Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; -* Assign the *Root* as a new *RotationSubtree* for the *Pivot*; -* Check the final result +1. Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; +2. Assign the *Root* as a new *RotationSubtree* for the *Pivot*; +3. Check the final result In pseudocode the algorithm above could be written as follows: ``` From 341c504c3508ef0ffd3dd111c06e4eb128106d46 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:14:46 +0100 Subject: [PATCH 0296/1275] Update readme; --- 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 9deea5649..25073f260 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -45,7 +45,7 @@ If after an insertion or deletion the balance factor becomes greater than 1, the ## Rotations Each tree node keeps track of its current balance factor in a variable. After inserting a new node, we need to update the balance factor of its parent node. If that balance factor becomes greater than 1, we "rotate" part of that tree to restore the balance. -Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: +Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: ![Rotation0](Images/RotationStep0.jpg) For the rotation we're using the terminology: From 047de8fdfe7221aaca2d0ad3a39be58ed5e11f25 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:20:47 +0100 Subject: [PATCH 0297/1275] Update readme; --- AVL Tree/Images/RotationStep0.jpg | Bin 9159 -> 22246 bytes AVL Tree/Images/RotationStep1.jpg | Bin 8046 -> 18235 bytes AVL Tree/Images/RotationStep2.jpg | Bin 8277 -> 18777 bytes AVL Tree/Images/RotationStep3.jpg | Bin 7430 -> 18265 bytes AVL Tree/README.markdown | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/AVL Tree/Images/RotationStep0.jpg b/AVL Tree/Images/RotationStep0.jpg index 99b69d3e0f58e0faf7d98ecd0a0daf30e2e48640..f61f8804ad0b12f66f87c45105315436f5ed30a9 100644 GIT binary patch literal 22246 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 CWqJ4j delta 8410 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 W6SwN}G7+K#nPb82RbGfv3o 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 UUi+Wt$^Sf4K8UF|)9;v2$>8 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 diff --git a/AVL Tree/Images/RotationStep2.jpg b/AVL Tree/Images/RotationStep2.jpg index 9d1ab5b8e6e65d0b7fac22c72226242d6e7e2a29..64c0af8622988f3bfbc4967344012eaba5379a12 100644 GIT binary patch literal 18777 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 X%fCkL#lDgaX&ejdN;jaq{QsK(NVo;U delta 7547 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 ZrTz0g{|0}NexITek-JSBdjT@0{|kD3fj|HN diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 25073f260..9254ffedf 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -56,7 +56,7 @@ For the rotation we're using the terminology: ![Rotation1](Images/RotationStep1.jpg) ![Rotation2](Images/RotationStep2.jpg) ![Rotation3](Images/RotationStep3.jpg) -The steps of rotation on the example image could be described by following: +The steps of rotation on the example image could be described by following: 1. Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; 2. Assign the *Root* as a new *RotationSubtree* for the *Pivot*; 3. Check the final result From 3f30747694400904d889588aec00133dcfef45b0 Mon Sep 17 00:00:00 2001 From: Anton Domashnev Date: Wed, 21 Dec 2016 23:25:58 +0100 Subject: [PATCH 0298/1275] Update readme; --- AVL Tree/Images/RotationStep1.jpg | Bin 18235 -> 13059 bytes AVL Tree/Images/RotationStep2.jpg | Bin 18777 -> 13357 bytes AVL Tree/Images/RotationStep3.jpg | Bin 18265 -> 12998 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/AVL Tree/Images/RotationStep1.jpg b/AVL Tree/Images/RotationStep1.jpg index 70e314df7cbe8336ae8e8d59533eca8639752f7e..953d35929abff2d5c63ad168710748dffbd4079c 100644 GIT binary patch delta 12153 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 literal 18235 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 G7XA;SX(ZDC literal 18777 zcmbTd2S5|u)-D{RHv`gZlqy}3qO^#LfQTqckro9JFajbV2q8gwM^QjQ2py$GdNq+Q zBGOyvL68_$=s6Vud^}QKepxnvB@_kl{B3S zs9{+T=X|?Gz63w|0^sLh5@EW|%p?Oi#?Qpe&veuU05Pt~%Jh%+kDoE#n2s^Cu(Gjp zaB^`o4yfk?9Ajc;KE}e#%KF!3n8FzQ0WAEiCr+I;W)rw|pIydJQ1ivBd=A-5)$Kyo z!vwi=u1_O4xr9YT#l+JF$Lt|5OOGjr{cTexv zzHcL=W8)K(Q`6Wb-15(r)n9At8^qtcd;6pV@}I-M&R}kH+@D8v8#Q z$6t-}pY4col7F1x*fAEyi<6C&?VtPp^G zHR=dJxb7RShv-EmitCi)PS+=g^mc~$q!(0Zga#qt^1;jT9vO1y%^tXA{$K}Wl@fl@ zxxj=@Tr5@4t!IH?iR4)muO*i*{fenHFsXX<(=kVV0beklUo$U%P9h@(F9|%YFw`3) zc?1w(T*?;AO+81e0577DJVrcgn8wp%a7l9iov}7=qXPP=T4X1hDeKz>mkxa~L>+IL zvvBlsoN$bZrs<1Vl=~4N(hK1skS)Fj>i8i&$J+kKx%%n5*ILfWs(|_tWQ_x=;ONp3V9Sl7@(5fL+c_hETSz(r zi0`!`xye=?Auxnz^Y8sDP`1w*9G$x9ptsiZhDEbCSRNJI+NMq%0TvgI0AxkeRPf?E zFyV$J`=Up8UwWGd>XELI;$&svOADdo73z~7)#0&pHx|AtHJWKLzGw2?Prd|VH%=FX zbNvS$oB|>%4u%J;1*T5>%yb+9xbbKaa;yWUX+i=g@aSwL4l1Q}!#AL~v3}kmwCSg4 z3ZdtUpMGz12IdM~3_gRXn`p*CVizQ|!P4s@6Cge#*;%s8=2C>$#ClL6R(@q1`Cfe- zJv*7<<ffBJ`4qG9|Z9|m6pW;Nn<4EDWDaK}Ui*bGz81qzW;T^ocuW~^GmYfTJ` zWDH+gh&?+^jCNOja@EpfeF0#^>WLB9Mr*Cja}8A*xQ7(0YflAG9*h;+O4u7>dlbC; z+xve5*uzzZQOQX&K4295myoJ#ggJQgCtQ`PMQcQORR(oofN1RvwBd+G-4P%T#J>&W z4!=KpilPyZS`c8H1KEhmqQw@d^9f76+chW34>5$(<1ffO_P zq&VBHj$OVud31gwFN!%uai zW*w*2bEUGB@b1GC*zvrkXR+4fg4ZU2Pou=f@FujWuO2kee`Xb2zd^|$3A6}&5DfH% zD^Xp?al-+QCtkgCGDx$~`hG$pG+4$i3%B~5BSrL-X~ta+v+=j#p$q)Mv6l$3v8XmX zT;kU{{5gxpjP31>r7k~X7LErQccnfF@e9_TT?Ck;en6%ZmwJjRHo>D7M}UY3`p`38 zbTGp=@WL*HRMvK88GhrJE>=AO5OEw^4BP$oO|GsnuqFw0XfX>25YE+L{3aYea(4_Z zwcg_U1dJSk5tlk1uOr z1#lUa!Oy)4(ZhRV?6kL90}2y-g`ZCMf`Y48F~**Gz(FO%L)47!Qme$y3#9Z;;Jyo@ z1}(dWg`+$#(mAU3g7+NB@kfB%*8@RyyDOjmSY0NxlDfy1$+0CcW?F@Tl42)FdSlgW zFKyBSu|$KL*})PEAC*-O=4Uz zSP9!OM2`_iO~Y6Kg71fr0#Pw$+j+48lXJ`Z><32+0f!9>J`VTaRmZwA{ko9wAtn>S zn}65YkA~^=(*+5D|Fl!L8Iuuvnc+Es9Y`R;UDY>o8JMg^1Kz&;4IN+7?T6aryQU|K zQVnQ+EXN+99&vyg8n;Qll=npvpt5@eAiei&WqIJ}ZR%x$lp_ z*fS2Z{9C;6h?~sDE@r6JL{bYa9>G+O(>V z;Y>4qz=tyd2ufUH1$ZRTGnw#z?0&CMROk%nRjY`9O?g6}(EHVkSEg7u4YdWlbda#L zJ_1;Ayf#%i?_QhB_cL8ol~bxZYwwKu(1#swk=2yz)@}L4`!q3%8$|=&<-oqxh;z2+ z!di7%fr1C>Rqj8UpleJPkK>n^I{&=vl{syG{ER(2pdh{b5^5FjXYe_l ze!@aGf*tb+Z+In0nuAz^%-^uq0IJ6?D-{l@-*cPnOF7)M!uY*^*k}LC8y-LT>lam! z);2iR2^oD&H`11J>l6>m+nx+UpBk;Kyo0D4{rV#8D{4qDEh6D`-m$;wz@w4>I~5>X z(YcrxF``h&F+BV<_1tL5ILwZKavp_w7vG)Xoz#UEGpt-dMdgXv_k+XhjT5(c!d;$l z_CPmwV!?a{QbfoXJ;iQNY!LAg78tjswr{9IVt!ktroMbPKOK1BEP7_pV6q=kx6o^e zuo$yyheYc|g*?Qlz20y@SIbnqB!`-&`eo5=+#h(omo0v;&XH!~;qICL#%|SaOMV%W zwD1YBHL!?EfJm^?Q3N}j!rNTc)+VLZIjUjX#OwyIcc38j^PXBJH~Ik&Heg-FBKv|a zc1hAy>%B~!BRX>{gj`W_=LwHBIWb&)@+Wuz&=V6#tA(oujnfc_Aj>xba zY0`E?b!b2^T+>`K?pn*4ljTY$Q%rm&`szc^edRihO2K%6v4iGhr4LiE(`5f*a0*%_ zI88?n7*$bhzw(Ni1xmXL(_24uZat$blJ*e*-{$z$@T5h|3+y?|6XZT zmaS4jjmWK9iWZp!j)912QwH=M!_I1#L`<5F2MQ*%uVk<`WkIB{B~RbH$n?8Z_oAy>qJ6 zDn~Z70^gL^Mae3i#h=Xi^eHkEy+?0*mvh%#BglWRmEnKH7;>uE)YlT^b~l~{9U4}( zdX+iOT*o>O>Fn?XEcShj{|S?#)>8bN#*O`b4{}^re9D zd_n+%S<8xN-RM-4`4w6F`tg0oxK)9IIP^GACF|(b*ry+@-Y7W`6L(^d0QHT%zSE6e zM*v2=*S)|VoYL<=jE#e7l#r1fIx5=eTE$4%d21<$iEmnG2eLOOKQ~Vc$j&-ymI-`@ zy2m8Kx9T(xyV4E{5XK;Wxa;7y6VsG3fi;k+{{H$~ z-1#2+2QOZ`L>M{U3q-B-_abZB<_&0X(Hf4_3uF&moDn}ZxU;=wArdD0aT-!pl<4Nq zMNV6`8rkOjoG_1@H#hje74h@haNcYIrpPLaEf2s+tD@dcNQ@0R40&Kav! zkTS}Taoo$`{F0$0lln;ODPYamR*bEt^3vG^uel=tWYz0N;p?frZ>I}BY5$cAsGvl- zyJ0hwOVlULl=##LX|BbO`H>~Jo@HHnXzew{1Ie^)3tLf#%orK4M z(4AC}c!m-z2xpcqpQ5vSa-`zUPON1ejHf`L<@rT6+~cp8@)FLIi2|?T-?D2%(F+8M z?0U^(A?1KvurP{ctAIX(pYMOJ{j&uLqECR?i^;kac5>^INkg&1$7SDS-NT^BKq(Jt z=YhGML|?T%$HX@Pq_Vz>MZ8>$_W20zCxU6s;ED-7m+WG%n`;w%ayl8qs{CKdj;VUK z+8o>C61)ezMphxk%@9GPc``5IAvkxTv$PAuAIL(N^sZ$|r(e2Zb4#2UrwLQR!n0qt`f2mUV1nsA<@;8gwyd zg^KbIDp}+7@?Yw2jg`;6Tc=M}tc(8X>frU*sM}!Rds;Ohwkq-nz-loJsDTJl)rsP$ zW80QMhY`t??#fAF={o{Lr*RnL4<&xcTutgRS}XlDsFvzRp7U5zQ$z0~J5zz( zrE@L0AJt2%oS>@4>n+%ciHk;?kr77mWOj-MjE|P3l|2VuIv&?x7t$87Y&-7bo^fD1 zt`6wMYD-;PUukX2mSoShQ#P{c2xlLv`$uHN{wuZ%GJUxh!3FdCNFPFc%2`3iQZJX? zm_(l>#N-W%#K0_75EWTA@y>Mvmc5qOusXZPjV4)#INV5x=}}TO0fc8)C|+ExZ6hF4 zVLE)lksadLBE5#UBM;=F`E&KN&CS3bpBtWgmjbq4*0i9;g?=9a@In+Nsy?k?aWru5 zTIe7zxxX`dg>aClWiC8(cSQcR1U3Ghvs{D|lVNd(1@uXt>hO7H0O;l|NRBictqd&# z0}?Z`2`Z%hh(Yr)ZHuUC!Vw^4kBkNKl4CsdT^rw+Z3iUV-iY{yyPELq2#~5D|F-Td zJn{dC2icFt{@$OSuJE?A84Zxq`Q}RDQDt*L4vmGZ?mmSWy%qE;{i;s zAz6pI-Gf*a5;1unJe_z45rg1(sDF~!MzSz!#fjEjwpya-ck7TcRL}l=WcSG_tk^s> z^ftFiz#^#Va2}H%>|y!Zo+z~?9`;^V)5>3_`vj1b^Ys=vYpLxlv2_uXysxnZVGV9I znb5c(ZIY4i?WZ9HH~aZ;c^#s*1|nQP0!*QMZBo1FV8R2)32idkeF7F{Kv%(B-M*K7 zHxyM9N$bBac<;#vcAeuteF1p39%_+ zTifMMx7L$cxtDqDlY6&J0Ct9efv0qJVo(f~eW`Uvl-%)KO8@%k$OOvE#u zOQmv^<)v8}J1f1i)(JX~)r9V@4uSEtL?-Qb?=VZZ$qod=n%@Fl4mst-3v?3FU75c2 zRNY79`w_r~=b_JIlOUmfp=TsW`ESFvOy%Tf8xuZS%N~l8ed_oblMT|184Mdt9*0PE zF|4P3K&xRb?z=yff`JO0PMNEEuUMykaO#?^#E+cdm-K09^i|=MYvh9Cd)WL(-X@e4 z-eX?3soJjC+q~7t-mLS280Ew?DL9jqF`UucgPk19OO%8PJ-LA;6O+{@0#dcPW8hv@9{948| z?r0y1L68W-btts*HpzI{=*&j7R?vbFY9A6O@I1UCLPHQT_;LEm;&0y1QKX4Q=}TQq zKgDS*Rgr!F3KpGTkR%JVg9WG(A7Mu1*G1Et*yFW6q{hQ%`CLv8v+XB4dsVI3Os`5^ zKBltUNnu`Q;9N|UBLGWpIrT1Ck$qwK!2CmSZO2f`VQ8~g{b!w1M*#J-bC1rP?g9qu zIQAY!ngE_7I|dUWyhay-nJvksgjmNqqDX9gFty)eQ;Fr(d6se|+4O*W)@D=ermT$X zu$S0<0SO@2Qa_F^;fQWSwl&vK6w=Sz+No|9UkLkw^+Ir!rnCPu7n5o`>F;_~D| zD$8j3fLnUb9f_)ak8k*SSpGP0M>lZd;D5&7OS zm|BYL4qBW0E&$aCB;74E(E}Z8x;|Hdv+q|x?`AXm=F#xV&C@jxv)cYeOFuH zAK6#gsl_2VuteP8lnP0Th<-;)Tn0tDu#c;q@3J!jjTYI+<~t8bRe+H2KeGmEVLU(3sA2ND-gilAg;?iEeFvkIRULFKfb?QSU*rM%RF@N?7?w2jX%FF zINbRp?Gh3)#C|mX_l}kNgO>L=o777ylA$I2+?6ByFH-cqLvb=ae$pQeM}L_TwklJz z=G{{q=dPVJ_B??VV>S-nSSTWNO0_|Gl!XLYZEl4F)&N_qa0H_Lf~%1t*=^Yud+Z4C zYYeU!e9(pM8j&s;>7ZM3n>+3Q3CL0Z%0Jy`x8@9hDN=470ot!39w4V?dK~OJcd+bT zLE<;6s~ogxIrZpl1boD?@a^=j2g{fHZ<0;`VXn>K7YhU%ie{05OemP*zDe)$AmLvAh{3U!AuU>w%_ zv|J+zYA7v=E@!pu$N{=dK*jD$Axy@umCa5qcxCJa@w^;7!0`+}e(fce{8oI=FkQY+ zOz~MG1__m{s@V5yKu-Ga)w24fKyi>66%vf7(Sm+!TtIoS8@IGjC-{vu~A5A^?M}4QjrSxOEd!S!ny69c6XY+k(j-k`? zG#x*Pu)*bW`e-h=m6ipUp0)5@s#MJ*W}qH-i*gF;c?s8iWc5)@j&%Bp)Dqr0mY(q- zn2sgTUlfvWo7E8}W4&E#s%xUv@c2bz$y+8TqOV-JRc~_#PzC_-a4ndgO!`_}K-y7+X%DL}>iX3&{|keWk4R4x;$6}sC`D)A-TW9n14Xapgn;Ctiyh&b{0&X=cyANFoN zVcX*_+Z2a=3#~H<>b<+$J7*+F_z}N|q|JUg#8WGW7HHvxpH z6#W}eOy&1wQYjfsSSB6PP;KWZ7s#C^4P#U#LV^%cH&MeyUb8=_>?*-)UfTTIj_|=t z&Z>HQ{_u=BwR`VeBpPlXER@g z4SMyiV&4#9qa@#!IehGd=ThT6Yh4~qQ9kRtf}58l@w@tRRo^!TirrhmSLvdNcH<*} zD=2AR7ZMBRW&jf&j+5^Gk~+4BQ3`iw5j;$9pZC(6eFhhyTPuAV{tyPj+lXjqRCVMv zQs|PK;98GvupsO_*&VlOaS>}WmKkE3S>_q!&e9Nc_NshC4&PaGp8K!dZ=8$Zph?l* zYBQI?2hqTsHg7lLsr(TY9V;r3W*zyp-lG<@)o#KVCfo zoW1=%8#eJr`ZC2GKA5XOPG6b>FWY^oPZ?Zh?@VtRGmsDdF5_6RQL<^$_A)X@-^MJB zJNn)gADQNh3XSoZbLeB#M}$~BKf$*XDFNdq#nla-xNG|CrPEcnriPc)T1Tg=&r@*o zHo+cAztakpe%jScE`vG{Sjf`k7L;hZtnmdXQCGb_0XO_S5pW(i7ga};ijHXwE;`MC z1LEuHd3S(ID)!>YqltgBERY!Uh4y>SdVNZ-etu~A+Mqi5 z0->=J!HhmZc3bR?WKNdt2(ih1<*}MGBKmmA{$}&`%1vRzK84R`8jb^vtuE~Socw{P z2jj(-z|$U!87N|8H=iN3A>q_$z*kKlZNqE+E7Mbs%H`)Q{mN1ic!e1?cc-PA) z!iPKN1bo!w)4Fhw`pAf5--(UKAk}u6@R7$?X{@wdG)HOs&ha_OW@D)X(JoGb@~pMI zMUH{wWx*@M zP7SAo;)e^XQw>Q!@9_cH*PI1!U1a^c4i81NYZmDtw(5@nT!+g)(FBi#Hpiuzuc`B< zqf}#r;C0jc+L-hwxz*od-%qYt!oAn^BIy0##%I-e(3A{1FD?H;>YY(_r>&Hk9zEwI zouFqtR^N`77GsV5ALku&uW3`YFbfZdr+ymb9e@kbM~UQ75+m}7h_+;?C6~Amqtt06 zM7>C$VPf0-)YE+??HuIC6Z2}vav8AXbNT9ITV3VKPwa!=U2SROuA;z@ix$U9vs!GP zOSH6vXewXYG<}HB2Qv^fJdzPF4$?lr&Q+`9*~;JNl| zhdP;ZBVH4qX6pO@ycR9Iqj`a@sLZx{U@-CVSE=^sZGLGh4;Fmr#?GPa`JqQJJe_5n z`X_jY1Rh6tBeBS3yDkl&QzvU`Y?}>qX=>$ldaeZ+xc1vg%cCg)_uPAC#O(bu)D!}X zAiZE<0$aTVySwD(su`nFf6tHJ#a?GLD<>+;=FUf2je1{x;-jJNa^7u=+vo9VIe$p? zWIF@<8(gT}PF=K;aO(URT=F{2YFJIZxb%Cnqj_Al_DRI^(jvCmPQv%_myo83?=L;N0#~*!i3XVT)$ALr~1e@wc zV!c%NY=3W~*p&|!JR-qsledtg66N+9C)2PS+8IiB3Jb%(ed}c53qF~`p~ZCj+IZb( z#Pvw~VfBK~wJpYS=e}&pSIptb7Ies<&^|1`kP_G?=P8sGQF}4en;4uDbsqz7_ zs@gRP+%n?zdis0+ROBh1^N$k%Bv2}%euuG$Ok-F3JK@@6?iiwNl>|kx<526wqYzS& zoft(u=dtv&WOL~U+aG;7PL*V6{V88feX+ny*QW-NN7?arDG%3Q1&3I27Fn^96;$H3 zmxl|}pP3^*%wBO&$+33-rtxNgwc<*V``rBPeax4gX%EsLB4t^=m4pAq$UObW`gb3_wI7_CzMujr zvkGW+_N3Nr+$~5@aqIsp`8HBzm}?C65)sttJB7mOR4;nLPz*V4dx~@K_SB=yvTkHD z3R*cqfGR!1buSr&cA9KaTWJV^(6$YSKD`V-a$w$1Fu<=x7`a>S@JD3+f zhUCY%9RW0!kW@jL#lAv^KTpd)j-_5P4Xf`SXj3YW)(kd~J^*!qbtV{$D9b$`d@)p?;UQ>Tix;%bs{Y~5C!}we!g*aO7 zh)5{ZnewZpna0P6)Q^V#yYp!~0^l^dK`|J1m~0S{8}}bd^MmgO zQ(9=O*{I@+=4e0&tI(fK5LFPls1YBFB!n6hd%G+y9|QtkAa4@2(|@+SIzGKq z(v)tM;d%#fsJQ6S4rZeNz;M=SL@e-l&o5jZQlrLQ|KZ;BZaV3;)9m*Jtx4T;=LY=F zt*oTaO=Y-3r~Z{~rLv4-kX#y5w~z$io)grwM2$q;SQ`YuX2nAe!ESbm|Bex}#@=|v zJNNtJ)&KwkV|HSv8c1|vhzwQ$7ZQh>)}s~D`S7OO`-86<@y-`!es1F%4Q{eXGXSo{ zcZ_vig?I!=ir;I%)EU}|857^zxgk9C=*bnUtqY7JNp8}* z#DysK)JpcQ)Hw8+F{%|fcE8nP@HjMv&Ft}G8D~X@m=U^FtyhNa%RZSex1XLU^|D6T zd;kQb^Z%w!)b99Hs;bG4X)w^v7vkn}FQf06h&^--1~4%o+KV7X`q)C<4;0~k zomC8oGeDk*?ADMl7$W<2;{8bWT#nJY4jIKyg|F6)Y(?fbzc-c52wsZ0;E{EDCW&l8 z0S5c@cV~blF^>$*sJ3LJkAr8uv$dwyfQMh~MZGH1`?CNG>8A3 zD@qWv|1h7Jakb}S-v*r-(Qa*Yf_k64UJ4&T8xp|DaG~IS$HuH*W;MjBH(D!W6LS{d z8lD!7swTyW#p#=}9CJ*VTY9ACz51YBly+=)U8P;X$w;oPR)jMxQd6H^GS zoY{Cb(c!IfbF4xltRibQwMF0gNwUz^|_$p1?6*&gVlGPvrujC*R8jLfo3Q0}cJ%Eq~mn3a@p* zl7zK*_BALEHRKJpsu`&`Ia1f;R^QN&>>4BbM$WG%@=<~EqVfj@MVtA>MQJ}m=weU@ zXqo{MzJwW&6_-APJH^$S)zt#lgjt_UZa;Td*0oSgvM^VTE_x=P^DbU{^DcMyb6~Gk zA{sWg(8qkX(@)Xo)Mx_U+3#_Zinqb zmWegB=Bj!1(pZwu^khOSCa@5Wt1en-Qj(VBQW+-|6Kws#oU*CC2(3jI{Mw< z?P6yK=k+zF^K}Ws?|1wmg<9eN35)B$=sqfo7_!oQb(t54U^STd(lZF?5mZL@*}0mq zD%)TtVSDV$wbu-iNf=j;rAUvSVM?RxzyW#?am>l271Sm4MYbAcn+IG~`GSgQ* zumeIq4WtS}aHvjR4bm&}-BPL$`8i>yTL*sT^IZdDFVv%uoYnV|j*ed*^O^E^uj+ku zimcn_ZNAj_S*c^g!C~U_{tP2+zWg=G-9suU#L<#6vkKq0m2NFqmsS|oFwn(G1hjq{ zV`M3-oL7Hlh}|iQ>ujk>vTpcocGC7T{^esYi*Vi$wg^74`Q9=U-v(_ynSoVTjo zahrV&39%VVK3~sSUBX=_LhXITKliX zlX-V$Nk%aqu~@huZg3m1+qbm9Mb__ZxcK{2in+G;wUyUHKPJz_pB;1TrOkscL3bxR z7{t5|#*L524({*7#!dSYExtHhtt}Ct2Em2VEj8nr;H~zub(4$x{*e4TOhk67U}Y_1 z{JZ2O1}>@d`3O)XV7Jn^b(Z1^pGTjdC833aJs2rdO+z`(Tf&M^_1f31yc?GzGp$j% zT%YXLWG_$q>1x9i0sh|HzKU^SIMjt$7fmvTB0;@FzD?L3rCf#(LDAY_=Wf*R%Eta^ zX{k#)?Y67%AX!(Rsd@U2hujNDCb(9yCzY&>+QL)x$P$YNm>S8JYJyMf{X&VQ<$+_s zI*HRKK)T;(s{<7O#!$EOeVZ;N(zgPf9%p0hd~!?K6gIr(D)m(8v0IQYzEUuAayp^Z zf>_#(VY6hceqAClhinHiu`1OyMCoDgLQbuu5KdHu`J&rwQib;Z~lA#3T(htD-+JDw@ z>w{gsWTnPP7`PP1fGfFStmT_}??CNAxa>_wHF^J;0CC$gd(ai_LlLvTV;uhLcfh0n zM&_dS(Q>t~&{B=`AAzc^lDHj$ExPR{TYhzN_kovZJB>C6tU4nu!5x#0{0#@*D@yFG zAG;)a*RpXB+h(=g_{Ay)Qitr!Mn*3PS7aSnW_kK7W^g`eXsv0he`x^?br0lLonTP# z%KCVSnk{Eoq?@TbLtrQ(g`p%1-IT%UpyiVEGMGmVf&SXJydSs2;q`kS`b;lycGuVy zcDcZzLwEMN_sX4Y^WFKyZn=^U>={b{9DR#{8tT%y&QUmmNgkthzKJfPb>k-)e2Zii zo3T?P^^UHgPU|g^j`K4}ultuRmKh$VcT0Zp!sv|&Beh`Ho!dyd;a;W6%~+dpA2Ymn z$vWOI^vV42rC-=^qe;|v3|97z)eQS`RSturcR6e_imDRkUPZNPOQaiio$+oPH8}r( zeYI&!khpTxS`PBOIP_M z+>$dqDlAs@c+dIx`t^x}5r=-&PnPA~0F%aCo7!f30>a#g8OBP6P_$te>dB6TY%3jy z$0yAF3~H|(=w?p7ZlGjuZZ;=c20iybrD^4NuC1n7^}8h?)aJjTf*^i47RlL$z(Ih) zLCd9IS}%tZMV1~G(;5q>D-!v~z2z>mRTiFWzQcU0#>4D-l57f5t<>ifDvS&w)-L_R zix4p84=7}pv0SlgZ09MkACn&w zz{f8EXsiVoy$XiUFG8}y_-oB+m3w%|;lLB zNx}gskPIn@-6IzVPlV{Cir4-z8+EeMs;YLx&Rh)dGaUH-AFAy-eB-3W2|ICUJ*t154ul`Bv;m$8>CQH*$x$BQGcH;yTf56KT9JOjO+xf% zTj;yV_;Nh1LEBW#(~5q6v){`8Cshq?pHi@tg)>rS+;TX zHI(*@w5$7@5)We z(yl1~aJ^I(Zzrr;8rJ&a@a{!P(MKY7gN-f04& z6B&yE-V3z?cse|b6?{9N6;@&UZEF41i4WQ{!xuraa4dw`z>+w)7(hbulq3xH&I`3Q z5_Ka{3g=UJgDl+C%D&B+d>&fx2ul47_0wdKHA1YmR*1cwpgLqbkQe4hNYcbQ1jh_` zgzCRaOjLQJpwg-mO_xZth)SCeq>H(^<6V{@*~sI5jO=Gtj}fxRWBeBflNTNlePi`a zp*ZLj2-!?)e+%Oi`EC6E4V3bR=CeHDh~B^C?<#FjP0^oB=`kDz5x|?!ub8D=G$Zkb zB77N3GLW&nHf}Q%daECz|I8nG?%Uk^-S_(_cLvL{2+GB=%w%&FAPHc^ zqX!ITgvu{eDzYBf4xBDDuNgDafI{7a%D;N=8OVj;(#weP%LG z3s)Hk^;2*?0?%JgJyM z?rzSnVsp*hV5n&%>DmaKV_}|po19wSx4e)*myNfB5W}b{lD|L5PxM-a3tNIMUc5~V zJ#8NjetvH7$;jYI_V?Yy0}_Fpx8OzACR`ot2yqLWS%{;bOtflsH?ivRE9VK!Vui!Q#OMBb!9hz`Yhm|aI(8~lS9yI)OV<}eQgn8|b4|(X^tSn- z!ENBH4Cs)-+12o7htm={hu=jD?wcu@&AA z6KMB``il?n44ZMaJ-xbEUU=-X$}x_`$rY*|oDp=f3=^x~xs}dYg;LIM9`Jkh`#!-N z%pV(5cjw3c(QNqT3v@QafzRn{yo|OHlOq76%uzik z?9MVhmEsa?z#ulp1V}+}9?4X(%IQr#jf6V+ItcGt%Xa2j@PKIW+Y9 z$slfDgK7g$Cp$!7=_ZnJ8z{D+qubcXC?c)oIS-T?);D{~6ZdJgb#|A$UYyW~^)9{* z%#C?>@M6ok?{>o28|p3I$#eGVu_C{oaAleBV~ono z;!XCBYH}oj}K_i-hB|XuV`C;krFg^>s+T^Ta71t8!fHVw&`>A0LYf8&ixtlrjOp_6a~zKKT^IVqLc- zwnNI>*Jm%D6+tliM_9x(~>(7C{AU}g{NPd|ywhc2gL9ZBXRXdRbn zM%3wFhIwJ6LVm_6aFH06WFa?H4(l1b8J_NZ`TD!?-K`SuQrZJ6-i}^PFZwr7ol8Bj zzXMwuLs#@%UqZwiakV(BbYoBG_w&}TCz(rizxnaOM{9E`F84=RUY&Q1iTQGd9N=)| zZyp2rS10{10X^>*otbNFR zQQDmtgo}-ab1}+aTK2FpGH@ z&=KH~uTXI2k`>-P&kHU}d=R4ZYMJ*K?^%Up^)|zb4(SV`mZ}vGUVM|Q{GB|)I+L!@ zHbdwBNJQMqUc!VQ0o;Hb>w1InfuMxLpVph=j3j7azFZ?#%fsUH6~{{zMPJED3ad8m zcbV?xR}($(APRJFabd=E(HEan!pQCt39T0i<={vII|QzhR|~Jb$9ro;KVa82_oh+r zIfJ#R({ABFQ6sbn`vA9g1*9LD12NGUepQ+A zIuQSqlUG*yo8_~!4$eJ80|KerEoX11Jg=IPnsUFuhIBDr192nT!3NM}Uf)Icg^q>z zmMAPLfiAS!k{O|G(Vr&1iVygRz&VCKxhR%PG0*5B-45seVJ6xQBHXl+2yVSf7V{$1 zF69>Lq~kCNS=-r*$;!W{@XdAN6&RxC=SDe6tNTUWVWIr(Op9Wo1FrDzo~jscAlA{c z4mZDSPxz64T8eiTEnU~}DwT4T+wnimK|Q750zkagBYy0sxW zmU4-^Jlrro4_Jei3}$Y}a8j8IU~1%``@*mD$WJ>Ku8%&>6HS>P8PSdreTfL+Oq;8=fG-5F3PikL8KMQ}{XK*}n z12x4>`q4)FM3>l1BhOs)A=uC*jov}Y;N33^yrsDtyGuVR0t_FSz9@|LeRDRr;3ZKhRTLIBa&hN|&2t=W zywoS^DpLOQ4(8)tGW;ohWTKFvc^-sPQqfRfLmkn555fy`G36id_{h0Bq%JSDQa^Fc z;o{RXS?`zA>_CM!fBrC_3@}84bY^m2@UNUi-=5Hu?-^P-ml+qZnQaTgs}l1ePgLHo zfiJH88`jhR7qG-A{x)OoKkw~C3d3A!Z+xfZdm{|IK0sR@dw2F11b_3=rg)77{&vGO zk3HsF7OQa=n}HPA5H#>!j6fX{-R7GI$AW5CGq4MZR3Q()l1*_IIXSc}VXnVuQs+#q zX6X#xJ=v#j`P7vAiJ6RK^`GfR*<=-B>rxP2fY5uL+)fC!OLZ91zN03%Ca#-2^d^II z>7{DJ0iT)pg~fN)_77~$g`CX*AiXtAbvbZm*`C%6bHiETC!^ z+%6Vj3))?2%JiE(6<2WK`lr>;x}?txRnnl`hYv`frDeA{`;k;2LiXA<&VMesL7yho z%s9m*D(teXOJ?g<;ah{$pBiP)GIgKP%&nuvrkK6ZYHIcB`g% zW1@g9?PHtUNBS3VEp7LOzi1=*HO@i@q0!l5(xGBea@kJ|0L^-Tf+a%UPd=wEhIA3L z_VI~s(9^WFfCYk;(qNYcH|#R4ycP{iGSV8;9yr^pe5jBugnm&t$iH^Kt$GB9Ns2HQ zF=-t^v|siBAE&Ajc1e{#ri_5WqgIpJx(3RgS#Rvb*{Tgn^Adja-pQa}dIG5D#iEIX zo!B}Jj^L2qj$D!2#2cept-+OQYTiSpf_xVv&KD$$Fx}$6RF(n&a53NoJa;!;8ciro zP{oY}3|P-QTC_SwoiH&F$WO5^y887&fNMo*1Si`|i3pQ`6N)E)bD)5KQFA;{(a3tc z_DcUna8D=@&v^DEf=Q_B(dq@ER}*H%3C7>d1rw^0zs|B5i?J^cPDkRTD=BKhGuIhb z4TmAnPbY@7AiPx5;P1D)9MsCFSplP8&GaTRIrs-9&W82}I(|J6c*-bnmMk)jynnD< zHY;v<7nvxoxW!wCgEh{-6SZ(Fdx?B&R#2$MN z2s|mo3;?1LZj3U$>=I(jj^G1|0&!<;5Fa#W-x{koH129V%*}sloV&e!Q_uhv{+Uh4 zCiDT#w#kt7e99RWhpBg#cj=t6r*9=W4{cEKv=$%ml3Q@?;?7o~Yx}l=@3JM>X{^x2 zMNOc+))Y1SqZ9R7e!n5--Y?OCjgLJWhoj3LJv-40wY{C8jH($#WZ!eoTflM(rBZG# zS9=|ITCFlKNvl!B?nF(uuP>Lu=(T=H&mZkp-w`#CPTzPV6(Sl#@q!O!xp~6XiS;@E zWBcYVeqo%r^aJpyi@DFXZk*d}RJ-q0WYp_G!?}xsMR#NhU9yxG4t~E1tuukXx*iwb z9yD#M{ZPM4e&e%c^94=q`|CHAcdGywGT)6juC_+(YW^2q;BM-a+%+$KJ_2`BGuqwE zv<2>_cFDY_67l-ot>yB+j{oBS%ejL2^YSp@85`O9O;I(|SezDda_IQjmpPAd|RVm{dfDL**nhv*_7+`=#sRozOs`4ri0ab z90qrt9+%cue~5q3f9U?r*AJggKXkr%mQR#kcS2lfC-+H}O=pfi+p%L_Smips^a(T7 z=A~DrPMAJ%W~chK^LOn1Uk2z0|7VCf{&fL&32?(mCI7Mhrg-lC8Tswo_jB7BzBJ6X zGX3c3;}>VCG);`3_voIFM!xyQER88`6|t&auKd#44DKhw_6Y#9M#I0eOSjx_pEYmh z$Log-i&^(~<=1bt3C@)G&oIqcUODI8`io+}U;let?=|z^ z<68bt3;0i+7Y6n^L;k3KI1e1YZ7F{oerUc-g?pp~Z*tK+`Q5o^FXwENx_ZVn;_szM zKf4ccQ*XYE-#Yzm;>Z2|eb2vT{7}^GoqFK!y`7KWmit~V`Lz7UgY6epuj{8N6hA#H zy6o}s8GGHI>i-cn{^u9+pJ9LYpV!~Dzp4Lcm|XPX{@+4iJ_~EG$ZrLXSUg(-+G}$j z*q!VLCZV~H@2Z?sn;>;H$Ap*3b9zee;!LkkKZB;I+TAR-z54E0N#rH<3}6xhmMeAo X%fCkL#lDgaX&ejdN;jaq{QsK(NVo;U diff --git a/AVL Tree/Images/RotationStep3.jpg b/AVL Tree/Images/RotationStep3.jpg index b2045111352b8ba18af53a3841e6368217beae04..921c0c4bac40c5ce1c0367fa2206b3eb3e0e27b1 100644 GIT binary patch delta 12042 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 Date: Wed, 21 Dec 2016 23:27:41 +0100 Subject: [PATCH 0299/1275] Update README.markdown --- AVL Tree/README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 9254ffedf..eaa4aa3c3 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -57,6 +57,7 @@ For the rotation we're using the terminology: ![Rotation1](Images/RotationStep1.jpg) ![Rotation2](Images/RotationStep2.jpg) ![Rotation3](Images/RotationStep3.jpg) The steps of rotation on the example image could be described by following: + 1. Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; 2. Assign the *Root* as a new *RotationSubtree* for the *Pivot*; 3. Check the final result From 39ac2ec3c36cf0cdf239d2b9b279258bd0f96dbb Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 21 Dec 2016 23:30:49 +0100 Subject: [PATCH 0300/1275] Update README.markdown --- AVL Tree/README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index eaa4aa3c3..8358fde9c 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -62,6 +62,7 @@ The steps of rotation on the example image could be described by following: 2. Assign the *Root* as a new *RotationSubtree* for the *Pivot*; 3. Check the final result + In pseudocode the algorithm above could be written as follows: ``` Root.OS = Pivot.RS From 9ecd211c61cfd4baab2665b10dc7c79547f5ec4b Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 21 Dec 2016 23:31:44 +0100 Subject: [PATCH 0301/1275] Update README.markdown --- AVL Tree/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 8358fde9c..86b631ae8 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -45,7 +45,8 @@ If after an insertion or deletion the balance factor becomes greater than 1, the ## Rotations Each tree node keeps track of its current balance factor in a variable. After inserting a new node, we need to update the balance factor of its parent node. If that balance factor becomes greater than 1, we "rotate" part of that tree to restore the balance. -Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: +Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: + ![Rotation0](Images/RotationStep0.jpg) For the rotation we're using the terminology: From bd645f33bc3640586c992e6b2c54728b4e50bccb Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 21 Dec 2016 23:33:22 +0100 Subject: [PATCH 0302/1275] Update README.markdown --- AVL Tree/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 86b631ae8..355204587 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -45,8 +45,6 @@ If after an insertion or deletion the balance factor becomes greater than 1, the ## Rotations Each tree node keeps track of its current balance factor in a variable. After inserting a new node, we need to update the balance factor of its parent node. If that balance factor becomes greater than 1, we "rotate" part of that tree to restore the balance. -Example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: - ![Rotation0](Images/RotationStep0.jpg) For the rotation we're using the terminology: @@ -55,9 +53,11 @@ For the rotation we're using the terminology: * *RotationSubtree* - subtree of the *Pivot* upon the side of rotation * *OppositeSubtree* - subtree of the *Pivot* opposite the side of rotation +Let take an example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: + ![Rotation1](Images/RotationStep1.jpg) ![Rotation2](Images/RotationStep2.jpg) ![Rotation3](Images/RotationStep3.jpg) -The steps of rotation on the example image could be described by following: +The steps of rotation could be described by following: 1. Assign the *RotationSubtree* as a new *OppositeSubtree* for the *Root*; 2. Assign the *Root* as a new *RotationSubtree* for the *Pivot*; From b64df56ea624b77b126cbc64d42ab7d687f05e1e Mon Sep 17 00:00:00 2001 From: BenEmdon Date: Thu, 22 Dec 2016 00:35:37 -0500 Subject: [PATCH 0303/1275] Fixed comment spacing in playground --- .../Contents.swift | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Rootish Array Stack/RootishArrayStack.playground/Contents.swift b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift index 401c773d6..68ec0a53e 100644 --- a/Rootish Array Stack/RootishArrayStack.playground/Contents.swift +++ b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift @@ -144,22 +144,22 @@ extension RootishArrayStack: CustomStringConvertible { } var list = RootishArrayStack() -list.isEmpty // true -list.first // nil -list.last // nil -list.count // 0 -list.capacity // 0 +list.isEmpty // true +list.first // nil +list.last // nil +list.count // 0 +list.capacity // 0 list.memoryDescription // { // } list.append(element: "Hello") -list.isEmpty // false -list.first // "Hello" -list.last // "hello" -list.count // 1 -list.capacity // 1 +list.isEmpty // false +list.first // "Hello" +list.last // "hello" +list.count // 1 +list.capacity // 1 list.memoryDescription // { @@ -167,15 +167,15 @@ list.memoryDescription // } list.append(element: "World") -list.isEmpty // false -list.first // "Hello" -list.last // "World" -list.count // 2 -list.capacity // 3 +list.isEmpty // false +list.first // "Hello" +list.last // "World" +list.count // 2 +list.capacity // 3 -list[0] // "Hello" -list[1] // "World" -//list[2] // crash! +list[0] // "Hello" +list[1] // "World" +//list[2] // crash! list.memoryDescription @@ -186,15 +186,15 @@ list.memoryDescription list.insert(element: "Swift", atIndex: 1) -list.isEmpty // false -list.first // "Hello" -list.last // "World" -list.count // 3 -list.capacity // 6 +list.isEmpty // false +list.first // "Hello" +list.last // "World" +list.count // 3 +list.capacity // 6 -list[0] // "Hello" -list[1] // "Swift" -list[2] // "World" +list[0] // "Hello" +list[1] // "Swift" +list[2] // "World" list.memoryDescription // { @@ -203,17 +203,17 @@ list.memoryDescription // [nil, nil, nil] // } -list.remove(atIndex: 2) // "World" -list.isEmpty // false -list.first // "Hello" -list.last // "Swift" -list.count // 2 -list.capacity // 3 +list.remove(atIndex: 2) // "World" +list.isEmpty // false +list.first // "Hello" +list.last // "Swift" +list.count // 2 +list.capacity // 3 -list[0] // "Hello" -list[1] // "Swift" -//list[2] // crash! +list[0] // "Hello" +list[1] // "Swift" +//list[2] // crash! list[0] = list[1] list[1] = "is awesome" -list // ["Swift", "is awesome"] +list // ["Swift", "is awesome"] From 3dd067453818046186792746479bdd4986c3ef7b Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:13:39 -0700 Subject: [PATCH 0304/1275] Update palindrome swift file contents --- Palindromes/Palindromes.swift | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/Palindromes/Palindromes.swift b/Palindromes/Palindromes.swift index 889ff357e..2760137ca 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -1,17 +1,26 @@ -import Cocoa +import Foundation -public func palindromeCheck(text: String?) -> Bool { - if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() - let length: Int = mutableText.characters.count +func isPalindrome(_ str: String) -> Bool { + let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) + let length = strippedString.characters.count - if length == 1 || length == 0 { - return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.index(mutableText.endIndex, offsetBy: -1)] { - let range = Range(mutableText.index(mutableText.startIndex, offsetBy: 1).. 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) } - } - - return false + 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) } From fe93184c3899f0ee6aebc23c453ce14fbddf4db8 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:13:57 -0700 Subject: [PATCH 0305/1275] Update palindrome playground --- .../Palindromes.playground/Contents.swift | 81 ++++++++++++------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index bb666ee9a..e8562a367 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -1,34 +1,61 @@ -import Cocoa +//: Playground - noun: a place where people can play -public func palindromeCheck(text: String?) -> Bool { - if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces).lowercased() - let length: Int = mutableText.characters.count +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 || length == 0 { - return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.index(mutableText.endIndex, offsetBy: -1)] { - let range = Range(mutableText.index(mutableText.startIndex, offsetBy: 1).. 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) } - } - - return false + return false } -// Test to check that non-palindromes are handled correctly: -palindromeCheck(text: "owls") - -// Test to check that palindromes are accurately found (regardless of case and whitespace: -palindromeCheck(text: "lol") -palindromeCheck(text: "race car") -palindromeCheck(text: "Race fast Safe car") - -// Test to check that palindromes are found regardless of case: -palindromeCheck(text: "HelloLLEH") +/** + 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) +} -palindromeCheck(text: "moom") +//true +isPalindrome("A man, a plan, a canal, Panama!") +isPalindrome("abbcbba") +isPalindrome("racecar") +isPalindrome("Madam, I'm Adam") +isPalindrome("Madam in Eden, I'm Adam") +isPalindrome("Never odd or even") +isPalindrome("5885") +isPalindrome("5 8 8 5") +isPalindrome("58 85") +isPalindrome("৯৯") +isPalindrome("In girum imus nocte et consumimur igni") -// Test that nil and empty Strings return false: -palindromeCheck(text: "") -palindromeCheck(text: nil) +// false +isPalindrome("\\\\") +isPalindrome("desserts") +isPalindrome("😀😀") +isPalindrome("") +isPalindrome("a") +isPalindrome("power") From 33048487610b59b9c7e09cafb1f33573bda5e252 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:15:07 -0700 Subject: [PATCH 0306/1275] Update the read for palindromes --- Palindromes/README.markdown | 101 ++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 12f868251..fe31cf297 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -1,64 +1,99 @@ # Palindromes -A palindrome is a word or phrase that is spelled the exact same when read forwards or backwards. -For this example puzzle, palindromes will not take case into account, meaning that uppercase and -lowercase text will be treated the same. In addition, spaces will not be considered, allowing -for multi-word phrases to constitute palindromes too. +A palindrome is a word or phrase that is spelled the exact same when reading it forwards or backward. Palindromes are allowed to be lowercase or uppercase, contain spaces, punctuation, and word dividers. Algorithms that check for palindromes are a common programming interview question. ## Example -The word "radar" is spelled the exact same both forwards and backwards, and as a result is a palindrome. -The phrase "race car" is another common palindrome that is spelled the same forwards and backwards. +The word racecar is a valid palindrome, as it is a word spelled the same when backgrounds and forwards. The examples below shows valid cases of the palindrome `racecar`. +`raceCar` +`r a c e c a r` +`r?a?c?e?c?a?r?` +`RACEcar` ## Algorithm -To check for palindromes, the first and last characters of a String must be compared for equality. -When the first and last characters are the same, they are removed from the String, resulting in a -substring starting with the second character and ending at the second to last character. +To check for palindromes, a strings character are compared starting from the beginning and end and moving inward moving to toward the middle of the string and keep the same distance apart in the comparison index. -In this implementation of a palindrome checker, recursion is used to check each substring of the -original String. +In this implementation of a palindrome algorithm, recursion is used to check each of the characters on the left-hand side and right-hand side moving inward. ## The code Here is a recursive implementation of this in Swift: ```swift -func palindromeCheck (text: String?) -> Bool { - if let text = text { - let mutableText = text.trimmingCharacters(in: NSCharacterSet.whitespaces()).lowercased() - let length: Int = mutableText.characters.count - - guard length >= 1 else { - return false - } - - if length == 1 { - return true - } else if mutableText[mutableText.startIndex] == mutableText[mutableText.index(mutableText.endIndex, offsetBy: -1)] { - let range = Range(mutableText.index(mutableText.startIndex, offsetBy: 1).. 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) +} +``` + +This algorithm has a two-step process. +1. The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. + +```swift +let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) ``` +The length of the string is then checked to make sure that the string after being stripped of non-word characters is still in a valid length. It is then passed into the next step after being lowercased. -This code can be tested in a playground using the following: +2. The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. +```swift +if left >= right { +return true +} +``` +If the check doesn't pass it continues to get the characters at the specified indexes and compare each. If they are not the same the method returns false and exits. +```swift +let lhs = str[str.index(str.startIndex, offsetBy: left)] +let rhs = str[str.index(str.startIndex, offsetBy: right)] +if lhs != rhs { +return false +} +``` +If they are the same the method calls itself again and updates the indexes accordingly to continue to check the rest of the string. ```swift -palindromeCheck(text: "Race car") +return palindrome(str, left: left + 1, right: right - 1) ``` -Since the phrase "Race car" is a palindrome, this will return true. +Step 1: +` race?C ar -> raceCar -> racecar`` + +Step 2: +| | +racecar -> r == r + | | +racecar -> a == a + | | +racecar -> c == c + | +racecar -> left index == right index -> return true ## Additional Resources [Palindrome Wikipedia](https://en.wikipedia.org/wiki/Palindrome) -*Written by [Stephen Rutstein](https://github.com/srutstein21)* +*Written by [Joshua Alvarado](https://github.com/https://github.com/lostatseajoshua)* From 0ffeb1fdd0d4568270b4bef42fef73e89fb108d9 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:28:44 -0700 Subject: [PATCH 0307/1275] Update README formatting --- Palindromes/README.markdown | 48 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index fe31cf297..48420f323 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -7,6 +7,7 @@ Algorithms that check for palindromes are a common programming interview questio ## Example The word racecar is a valid palindrome, as it is a word spelled the same when backgrounds and forwards. The examples below shows valid cases of the palindrome `racecar`. + `raceCar` `r a c e c a r` `r?a?c?e?c?a?r?` @@ -14,9 +15,7 @@ The word racecar is a valid palindrome, as it is a word spelled the same when ba ## Algorithm -To check for palindromes, a strings character are compared starting from the beginning and end and moving inward moving to toward the middle of the string and keep the same distance apart in the comparison index. - -In this implementation of a palindrome algorithm, recursion is used to check each of the characters on the left-hand side and right-hand side moving inward. +To check for palindromes, a string's characters are compared starting from the beginning and end then moving inward toward the middle of the string while maintaining the same distance apart. In this implementation of a palindrome algorithm, recursion is used to check each of the characters on the left-hand side and right-hand side moving inward. ## The code @@ -24,32 +23,33 @@ 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 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 + 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 -} + if left >= right { + return true + } -let lhs = str[str.index(str.startIndex, offsetBy: left)] -let rhs = str[str.index(str.startIndex, offsetBy: right)] + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] -if lhs != rhs { -return false -} + if lhs != rhs { + return false + } -return palindrome(str, left: left + 1, right: right - 1) + return palindrome(str, left: left + 1, right: right - 1) } ``` -This algorithm has a two-step process. +This algorithm has a two-step process. + 1. The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. ```swift @@ -61,7 +61,7 @@ The length of the string is then checked to make sure that the string after bein 2. The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. ```swift if left >= right { -return true + return true } ``` If the check doesn't pass it continues to get the characters at the specified indexes and compare each. If they are not the same the method returns false and exits. @@ -70,7 +70,7 @@ let lhs = str[str.index(str.startIndex, offsetBy: left)] let rhs = str[str.index(str.startIndex, offsetBy: right)] if lhs != rhs { -return false + return false } ``` If they are the same the method calls itself again and updates the indexes accordingly to continue to check the rest of the string. @@ -82,14 +82,18 @@ Step 1: ` race?C ar -> raceCar -> racecar`` Step 2: +``` | | racecar -> r == r + | | racecar -> a == a + | | racecar -> c == c + | -racecar -> left index == right index -> return true +racecar -> left index == right index -> return true``` ## Additional Resources From e4c2889bc3c8b6ba0f9fa47be0b86bb1f5c663d3 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:30:15 -0700 Subject: [PATCH 0308/1275] Fix code snippet from running to the bottom of the page --- Palindromes/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 48420f323..53a48225a 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -93,7 +93,8 @@ racecar -> a == a racecar -> c == c | -racecar -> left index == right index -> return true``` +racecar -> left index == right index -> return true +``` ## Additional Resources From 8c0117dbe7fa5dace9de1492280110f0d6353ea4 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:34:57 -0700 Subject: [PATCH 0309/1275] Fix spacing on list of palindrome examples --- Palindromes/README.markdown | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 53a48225a..85bdfc992 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -8,10 +8,12 @@ Algorithms that check for palindromes are a common programming interview questio The word racecar is a valid palindrome, as it is a word spelled the same when backgrounds and forwards. The examples below shows valid cases of the palindrome `racecar`. -`raceCar` -`r a c e c a r` -`r?a?c?e?c?a?r?` -`RACEcar` +``` +raceCar +r a c e c a r +r?a?c?e?c?a?r? +RACEcar +``` ## Algorithm From 13de04998d7f940c5c98bedb947ccee52fa0fe9d Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:35:38 -0700 Subject: [PATCH 0310/1275] Improved formatting in code and markdown --- Palindromes/README.markdown | 47 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 85bdfc992..ede0af39d 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -25,34 +25,34 @@ 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 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 +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 - } +if left >= right { +return true +} - let lhs = str[str.index(str.startIndex, offsetBy: left)] - let rhs = str[str.index(str.startIndex, offsetBy: right)] +let lhs = str[str.index(str.startIndex, offsetBy: left)] +let rhs = str[str.index(str.startIndex, offsetBy: right)] - if lhs != rhs { - return false - } +if lhs != rhs { +return false +} - return palindrome(str, left: left + 1, right: right - 1) +return palindrome(str, left: left + 1, right: right - 1) } ``` This algorithm has a two-step process. -1. The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. +1 - The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. ```swift let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) @@ -60,10 +60,10 @@ let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .reg The length of the string is then checked to make sure that the string after being stripped of non-word characters is still in a valid length. It is then passed into the next step after being lowercased. -2. The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. +2 - The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. ```swift if left >= right { - return true +return true } ``` If the check doesn't pass it continues to get the characters at the specified indexes and compare each. If they are not the same the method returns false and exits. @@ -72,7 +72,7 @@ let lhs = str[str.index(str.startIndex, offsetBy: left)] let rhs = str[str.index(str.startIndex, offsetBy: right)] if lhs != rhs { - return false +return false } ``` If they are the same the method calls itself again and updates the indexes accordingly to continue to check the rest of the string. @@ -81,20 +81,21 @@ return palindrome(str, left: left + 1, right: right - 1) ``` Step 1: -` race?C ar -> raceCar -> racecar`` + +`race?C ar -> raceCar -> racecar` Step 2: ``` | | racecar -> r == r - | | +| | racecar -> a == a - | | +| | racecar -> c == c - | +| racecar -> left index == right index -> return true ``` From 6a15d37a61310e7fd05c944f6be947605508b8f1 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:37:31 -0700 Subject: [PATCH 0311/1275] Revert "Improved formatting in code and markdown" This reverts commit 13de04998d7f940c5c98bedb947ccee52fa0fe9d. --- Palindromes/README.markdown | 47 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index ede0af39d..85bdfc992 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -25,34 +25,34 @@ 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 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 + 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 -} + if left >= right { + return true + } -let lhs = str[str.index(str.startIndex, offsetBy: left)] -let rhs = str[str.index(str.startIndex, offsetBy: right)] + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] -if lhs != rhs { -return false -} + if lhs != rhs { + return false + } -return palindrome(str, left: left + 1, right: right - 1) + return palindrome(str, left: left + 1, right: right - 1) } ``` This algorithm has a two-step process. -1 - The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. +1. The first step is to pass the string to validate as a palindrome into the `isPalindrome` method. This method first removes occurrences of non-word pattern matches `\W` [Regex reference](http://regexr.com). It is written with two \\ to escape the \ in the String literal. ```swift let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) @@ -60,10 +60,10 @@ let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .reg The length of the string is then checked to make sure that the string after being stripped of non-word characters is still in a valid length. It is then passed into the next step after being lowercased. -2 - The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. +2. The second step is to pass the string in a recursive method. This method takes a string, a left index, and a right index. The method checks the characters of the string using the indexes to compare each character on both sides. The method checks if the left is greater or equal to the right if so the entire string has been run through without returning false so the string is equal on both sides thus returning true. ```swift if left >= right { -return true + return true } ``` If the check doesn't pass it continues to get the characters at the specified indexes and compare each. If they are not the same the method returns false and exits. @@ -72,7 +72,7 @@ let lhs = str[str.index(str.startIndex, offsetBy: left)] let rhs = str[str.index(str.startIndex, offsetBy: right)] if lhs != rhs { -return false + return false } ``` If they are the same the method calls itself again and updates the indexes accordingly to continue to check the rest of the string. @@ -81,21 +81,20 @@ return palindrome(str, left: left + 1, right: right - 1) ``` Step 1: - -`race?C ar -> raceCar -> racecar` +` race?C ar -> raceCar -> racecar`` Step 2: ``` | | racecar -> r == r -| | + | | racecar -> a == a -| | + | | racecar -> c == c -| + | racecar -> left index == right index -> return true ``` From f8888192086c2a542fc9550441a1cb41b7b51e90 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:37:59 -0700 Subject: [PATCH 0312/1275] Remove extra character --- Palindromes/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 85bdfc992..bb52678e0 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -81,7 +81,7 @@ return palindrome(str, left: left + 1, right: right - 1) ``` Step 1: -` race?C ar -> raceCar -> racecar`` +`race?C ar -> raceCar -> racecar` Step 2: ``` From 3da3a75413cf64aca60fc98e4987e9a804c12e48 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 11:39:18 -0700 Subject: [PATCH 0313/1275] Improved spacing on code snippet --- Palindromes/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index bb52678e0..18518adbe 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -31,7 +31,8 @@ func isPalindrome(_ str: String) -> Bool { if length > 1 { return palindrome(strippedString.lowercased(), left: 0, right: length - 1) } - return false + + return false } private func palindrome(_ str: String, left: Int, right: Int) -> Bool { From 9d4f6ea1204d2a6aa475cdbb2f6e412771b6b83b Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Thu, 22 Dec 2016 16:48:58 -0700 Subject: [PATCH 0314/1275] Add tests for Travis CI --- .travis.yml | 1 + .../Tests/Tests.xcodeproj/project.pbxproj | 413 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + Palindromes/Tests/Tests/AppDelegate.swift | 46 ++ .../AppIcon.appiconset/Contents.json | 68 +++ .../Tests/Base.lproj/LaunchScreen.storyboard | 27 ++ Palindromes/Tests/Tests/Info.plist | 45 ++ Palindromes/Tests/Tests/Palindromes.swift | 26 ++ Palindromes/Tests/TestsTests/Info.plist | 22 + .../Tests/TestsTests/PalindromeTests.swift | 70 +++ 10 files changed, 725 insertions(+) create mode 100644 Palindromes/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Palindromes/Tests/Tests/AppDelegate.swift create mode 100644 Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard create mode 100644 Palindromes/Tests/Tests/Info.plist create mode 100644 Palindromes/Tests/Tests/Palindromes.swift create mode 100644 Palindromes/Tests/TestsTests/Info.plist create mode 100644 Palindromes/Tests/TestsTests/PalindromeTests.swift diff --git a/.travis.yml b/.travis.yml index 17655c21e..f7231cdfe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,3 +40,4 @@ script: - 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/Tests/Tests.xcodeproj -scheme Tests diff --git a/Palindromes/Tests/Tests.xcodeproj/project.pbxproj b/Palindromes/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..63b68d316 --- /dev/null +++ b/Palindromes/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,413 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 94D8AF0F1E0C9AB4007D8806 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */; }; + 94D8AF161E0C9AB4007D8806 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */; }; + 94D8AF191E0C9AB4007D8806 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */; }; + 94D8AF2F1E0C9AE9007D8806 /* Palindromes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */; }; + 94D8AF331E0C9BB2007D8806 /* PalindromeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 94D8AF201E0C9AB4007D8806 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 94D8AF031E0C9AB4007D8806 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 94D8AF0A1E0C9AB4007D8806; + remoteInfo = Tests; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 94D8AF0B1E0C9AB4007D8806 /* Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tests.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 94D8AF181E0C9AB4007D8806 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 94D8AF1A1E0C9AB4007D8806 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 94D8AF251E0C9AB4007D8806 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindromes.swift; sourceTree = ""; }; + 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PalindromeTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 94D8AF081E0C9AB4007D8806 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 94D8AF1C1E0C9AB4007D8806 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 94D8AF021E0C9AB4007D8806 = { + isa = PBXGroup; + children = ( + 94D8AF0D1E0C9AB4007D8806 /* Tests */, + 94D8AF221E0C9AB4007D8806 /* TestsTests */, + 94D8AF0C1E0C9AB4007D8806 /* Products */, + ); + sourceTree = ""; + }; + 94D8AF0C1E0C9AB4007D8806 /* Products */ = { + isa = PBXGroup; + children = ( + 94D8AF0B1E0C9AB4007D8806 /* Tests.app */, + 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 94D8AF0D1E0C9AB4007D8806 /* Tests */ = { + isa = PBXGroup; + children = ( + 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */, + 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */, + 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */, + 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */, + 94D8AF1A1E0C9AB4007D8806 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; + 94D8AF221E0C9AB4007D8806 /* TestsTests */ = { + isa = PBXGroup; + children = ( + 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */, + 94D8AF251E0C9AB4007D8806 /* Info.plist */, + ); + path = TestsTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 94D8AF0A1E0C9AB4007D8806 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 94D8AF281E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 94D8AF071E0C9AB4007D8806 /* Sources */, + 94D8AF081E0C9AB4007D8806 /* Frameworks */, + 94D8AF091E0C9AB4007D8806 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 94D8AF0B1E0C9AB4007D8806 /* Tests.app */; + productType = "com.apple.product-type.application"; + }; + 94D8AF1E1E0C9AB4007D8806 /* TestsTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 94D8AF2B1E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "TestsTests" */; + buildPhases = ( + 94D8AF1B1E0C9AB4007D8806 /* Sources */, + 94D8AF1C1E0C9AB4007D8806 /* Frameworks */, + 94D8AF1D1E0C9AB4007D8806 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 94D8AF211E0C9AB4007D8806 /* PBXTargetDependency */, + ); + name = TestsTests; + productName = TestsTests; + productReference = 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 94D8AF031E0C9AB4007D8806 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = "Joshua Alvarado"; + TargetAttributes = { + 94D8AF0A1E0C9AB4007D8806 = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + 94D8AF1E1E0C9AB4007D8806 = { + CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 0820; + ProvisioningStyle = Automatic; + TestTargetID = 94D8AF0A1E0C9AB4007D8806; + }; + }; + }; + buildConfigurationList = 94D8AF061E0C9AB4007D8806 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 94D8AF021E0C9AB4007D8806; + productRefGroup = 94D8AF0C1E0C9AB4007D8806 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 94D8AF0A1E0C9AB4007D8806 /* Tests */, + 94D8AF1E1E0C9AB4007D8806 /* TestsTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 94D8AF091E0C9AB4007D8806 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 94D8AF191E0C9AB4007D8806 /* LaunchScreen.storyboard in Resources */, + 94D8AF161E0C9AB4007D8806 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 94D8AF1D1E0C9AB4007D8806 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 94D8AF071E0C9AB4007D8806 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 94D8AF2F1E0C9AE9007D8806 /* Palindromes.swift in Sources */, + 94D8AF0F1E0C9AB4007D8806 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 94D8AF1B1E0C9AB4007D8806 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 94D8AF331E0C9BB2007D8806 /* PalindromeTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 94D8AF211E0C9AB4007D8806 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 94D8AF0A1E0C9AB4007D8806 /* Tests */; + targetProxy = 94D8AF201E0C9AB4007D8806 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 94D8AF181E0C9AB4007D8806 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 94D8AF261E0C9AB4007D8806 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 94D8AF271E0C9AB4007D8806 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 94D8AF291E0C9AB4007D8806 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 94D8AF2A1E0C9AB4007D8806 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 94D8AF2C1E0C9AB4007D8806 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = TestsTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.TestsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Tests.app/Tests"; + }; + name = Debug; + }; + 94D8AF2D1E0C9AB4007D8806 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = TestsTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.TestsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Tests.app/Tests"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 94D8AF061E0C9AB4007D8806 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 94D8AF261E0C9AB4007D8806 /* Debug */, + 94D8AF271E0C9AB4007D8806 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 94D8AF281E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 94D8AF291E0C9AB4007D8806 /* Debug */, + 94D8AF2A1E0C9AB4007D8806 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 94D8AF2B1E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "TestsTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 94D8AF2C1E0C9AB4007D8806 /* Debug */, + 94D8AF2D1E0C9AB4007D8806 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 94D8AF031E0C9AB4007D8806 /* Project object */; +} diff --git a/Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Palindromes/Tests/Tests/AppDelegate.swift b/Palindromes/Tests/Tests/AppDelegate.swift new file mode 100644 index 000000000..481c72c62 --- /dev/null +++ b/Palindromes/Tests/Tests/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// Tests +// +// Created by Joshua Alvarado on 12/22/16. +// Copyright © 2016 Joshua Alvarado. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json b/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..36d2c80d8 --- /dev/null +++ b/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard b/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..fdf3f97d1 --- /dev/null +++ b/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Palindromes/Tests/Tests/Info.plist b/Palindromes/Tests/Tests/Info.plist new file mode 100644 index 000000000..f197d509b --- /dev/null +++ b/Palindromes/Tests/Tests/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Palindromes/Tests/Tests/Palindromes.swift b/Palindromes/Tests/Tests/Palindromes.swift new file mode 100644 index 000000000..2760137ca --- /dev/null +++ b/Palindromes/Tests/Tests/Palindromes.swift @@ -0,0 +1,26 @@ +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/Tests/TestsTests/Info.plist b/Palindromes/Tests/TestsTests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Palindromes/Tests/TestsTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Palindromes/Tests/TestsTests/PalindromeTests.swift b/Palindromes/Tests/TestsTests/PalindromeTests.swift new file mode 100644 index 000000000..27d8f88b0 --- /dev/null +++ b/Palindromes/Tests/TestsTests/PalindromeTests.swift @@ -0,0 +1,70 @@ +// +// PalindromeTests.swift +// Tests +// +// Created by Joshua Alvarado on 12/22/16. +// Copyright © 2016 Joshua Alvarado. All rights reserved. +// + +import XCTest +@testable import Tests + +class PalindromeTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + 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() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + let _ = isPalindrome("abbcbba") + let _ = isPalindrome("asdkfaksjdfasjkdfhaslkjdfakjsdfhakljsdhflkjasdfhkasdjhfklajsdfhkljasdf") + let _ = isPalindrome("abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa") + } + } + + func testPalindromeWord() { + XCTAssertTrue(isPalindrome("abbcbba")) + XCTAssertTrue(isPalindrome("racecar")) + } + + func testPalindromeSentence() { + XCTAssertTrue(isPalindrome("A man, a plan, a canal, Panama!")) + XCTAssertTrue(isPalindrome("Madam, I'm Adam")) + XCTAssertTrue(isPalindrome("Madam in Eden, I'm Adam")) + XCTAssertTrue(isPalindrome("In girum imus nocte et consumimur igni")) + XCTAssertTrue(isPalindrome("Never odd or even")) + } + + func testPalindromeNumber() { + XCTAssertTrue(isPalindrome("5885")) + XCTAssertTrue(isPalindrome("5 8 8 5")) + XCTAssertTrue(isPalindrome("58 85")) + } + + func testSpecialCharacters() { + XCTAssertTrue(isPalindrome("৯৯")) + } + + func testNonPalindromes() { + XCTAssertFalse(isPalindrome("\\\\")) + XCTAssertFalse(isPalindrome("desserts")) + XCTAssertFalse(isPalindrome("😀😀")) + XCTAssertFalse(isPalindrome("")) + XCTAssertFalse(isPalindrome("a")) + XCTAssertFalse(isPalindrome("power")) + } +} From 4d4b63d47ca048f58d1c0ddb30bc87648f45956c Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Fri, 23 Dec 2016 10:36:05 -0700 Subject: [PATCH 0315/1275] Update test project to run palindrome tests --- .travis.yml | 2 +- .../{Tests/Tests => Test}/Palindromes.swift | 0 .../Test/Test.xcodeproj/project.pbxproj | 273 ++++++++++++ .../contents.xcworkspacedata | 2 +- .../TestsTests => Test/Test}/Info.plist | 0 .../Test/Test.swift} | 9 +- .../Tests/Tests.xcodeproj/project.pbxproj | 413 ------------------ Palindromes/Tests/Tests/AppDelegate.swift | 46 -- .../AppIcon.appiconset/Contents.json | 68 --- .../Tests/Base.lproj/LaunchScreen.storyboard | 27 -- Palindromes/Tests/Tests/Info.plist | 45 -- 11 files changed, 279 insertions(+), 606 deletions(-) rename Palindromes/{Tests/Tests => Test}/Palindromes.swift (100%) create mode 100644 Palindromes/Test/Test.xcodeproj/project.pbxproj rename Palindromes/{Tests/Tests.xcodeproj => Test/Test.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (72%) rename Palindromes/{Tests/TestsTests => Test/Test}/Info.plist (100%) rename Palindromes/{Tests/TestsTests/PalindromeTests.swift => Test/Test/Test.swift} (96%) delete mode 100644 Palindromes/Tests/Tests.xcodeproj/project.pbxproj delete mode 100644 Palindromes/Tests/Tests/AppDelegate.swift delete mode 100644 Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard delete mode 100644 Palindromes/Tests/Tests/Info.plist diff --git a/.travis.yml b/.travis.yml index f7231cdfe..dc681ccd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,4 +40,4 @@ script: - 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/Tests/Tests.xcodeproj -scheme Tests +- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test diff --git a/Palindromes/Tests/Tests/Palindromes.swift b/Palindromes/Test/Palindromes.swift similarity index 100% rename from Palindromes/Tests/Tests/Palindromes.swift rename to Palindromes/Test/Palindromes.swift diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj new file mode 100644 index 000000000..07aae3e63 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -0,0 +1,273 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 9437D8791E0D948A00A38FB8 /* Palindromes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindromes.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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9437D87E1E0D960A00A38FB8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9437D8651E0D945200A38FB8 = { + isa = PBXGroup; + children = ( + 9437D8791E0D948A00A38FB8 /* Palindromes.swift */, + 9437D8821E0D960A00A38FB8 /* Test */, + 9437D86F1E0D945200A38FB8 /* Products */, + ); + sourceTree = ""; + }; + 9437D86F1E0D945200A38FB8 /* Products */ = { + isa = PBXGroup; + children = ( + 9437D8811E0D960A00A38FB8 /* Test.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 9437D8821E0D960A00A38FB8 /* Test */ = { + isa = PBXGroup; + children = ( + 9437D8831E0D960A00A38FB8 /* Test.swift */, + 9437D8851E0D960A00A38FB8 /* Info.plist */, + ); + path = Test; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 9437D8801E0D960A00A38FB8 /* Test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9437D8861E0D960A00A38FB8 /* Build configuration list for PBXNativeTarget "Test" */; + buildPhases = ( + 9437D87D1E0D960A00A38FB8 /* Sources */, + 9437D87E1E0D960A00A38FB8 /* Frameworks */, + 9437D87F1E0D960A00A38FB8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Test; + productName = Test; + productReference = 9437D8811E0D960A00A38FB8 /* Test.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9437D8661E0D945200A38FB8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = "Joshua Alvarado"; + TargetAttributes = { + 9437D8801E0D960A00A38FB8 = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 9437D8691E0D945200A38FB8 /* Build configuration list for PBXProject "Test" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 9437D8651E0D945200A38FB8; + productRefGroup = 9437D86F1E0D945200A38FB8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 9437D8801E0D960A00A38FB8 /* Test */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 9437D87F1E0D960A00A38FB8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 9437D87D1E0D960A00A38FB8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9437D88B1E0D969500A38FB8 /* Palindromes.swift in Sources */, + 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 9437D8721E0D945200A38FB8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + }; + name = Debug; + }; + 9437D8731E0D945200A38FB8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + }; + name = Release; + }; + 9437D8871E0D960A00A38FB8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Test/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 9437D8881E0D960A00A38FB8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Test/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 9437D8691E0D945200A38FB8 /* Build configuration list for PBXProject "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9437D8721E0D945200A38FB8 /* Debug */, + 9437D8731E0D945200A38FB8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9437D8861E0D960A00A38FB8 /* Build configuration list for PBXNativeTarget "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9437D8871E0D960A00A38FB8 /* Debug */, + 9437D8881E0D960A00A38FB8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9437D8661E0D945200A38FB8 /* Project object */; +} diff --git a/Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 72% rename from Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 6c0ea8493..87cc241f8 100644 --- a/Palindromes/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:Test.xcodeproj"> diff --git a/Palindromes/Tests/TestsTests/Info.plist b/Palindromes/Test/Test/Info.plist similarity index 100% rename from Palindromes/Tests/TestsTests/Info.plist rename to Palindromes/Test/Test/Info.plist diff --git a/Palindromes/Tests/TestsTests/PalindromeTests.swift b/Palindromes/Test/Test/Test.swift similarity index 96% rename from Palindromes/Tests/TestsTests/PalindromeTests.swift rename to Palindromes/Test/Test/Test.swift index 27d8f88b0..e86a40cfb 100644 --- a/Palindromes/Tests/TestsTests/PalindromeTests.swift +++ b/Palindromes/Test/Test/Test.swift @@ -1,13 +1,12 @@ // // PalindromeTests.swift -// Tests +// Test // -// Created by Joshua Alvarado on 12/22/16. +// Created by Joshua Alvarado on 12/23/16. // Copyright © 2016 Joshua Alvarado. All rights reserved. // import XCTest -@testable import Tests class PalindromeTests: XCTestCase { @@ -48,13 +47,13 @@ class PalindromeTests: XCTestCase { XCTAssertTrue(isPalindrome("In girum imus nocte et consumimur igni")) XCTAssertTrue(isPalindrome("Never odd or even")) } - + func testPalindromeNumber() { XCTAssertTrue(isPalindrome("5885")) XCTAssertTrue(isPalindrome("5 8 8 5")) XCTAssertTrue(isPalindrome("58 85")) } - + func testSpecialCharacters() { XCTAssertTrue(isPalindrome("৯৯")) } diff --git a/Palindromes/Tests/Tests.xcodeproj/project.pbxproj b/Palindromes/Tests/Tests.xcodeproj/project.pbxproj deleted file mode 100644 index 63b68d316..000000000 --- a/Palindromes/Tests/Tests.xcodeproj/project.pbxproj +++ /dev/null @@ -1,413 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 94D8AF0F1E0C9AB4007D8806 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */; }; - 94D8AF161E0C9AB4007D8806 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */; }; - 94D8AF191E0C9AB4007D8806 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */; }; - 94D8AF2F1E0C9AE9007D8806 /* Palindromes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */; }; - 94D8AF331E0C9BB2007D8806 /* PalindromeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 94D8AF201E0C9AB4007D8806 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 94D8AF031E0C9AB4007D8806 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 94D8AF0A1E0C9AB4007D8806; - remoteInfo = Tests; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 94D8AF0B1E0C9AB4007D8806 /* Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tests.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 94D8AF181E0C9AB4007D8806 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 94D8AF1A1E0C9AB4007D8806 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 94D8AF251E0C9AB4007D8806 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindromes.swift; sourceTree = ""; }; - 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PalindromeTests.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 94D8AF081E0C9AB4007D8806 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 94D8AF1C1E0C9AB4007D8806 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 94D8AF021E0C9AB4007D8806 = { - isa = PBXGroup; - children = ( - 94D8AF0D1E0C9AB4007D8806 /* Tests */, - 94D8AF221E0C9AB4007D8806 /* TestsTests */, - 94D8AF0C1E0C9AB4007D8806 /* Products */, - ); - sourceTree = ""; - }; - 94D8AF0C1E0C9AB4007D8806 /* Products */ = { - isa = PBXGroup; - children = ( - 94D8AF0B1E0C9AB4007D8806 /* Tests.app */, - 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 94D8AF0D1E0C9AB4007D8806 /* Tests */ = { - isa = PBXGroup; - children = ( - 94D8AF0E1E0C9AB4007D8806 /* AppDelegate.swift */, - 94D8AF2E1E0C9AE9007D8806 /* Palindromes.swift */, - 94D8AF151E0C9AB4007D8806 /* Assets.xcassets */, - 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */, - 94D8AF1A1E0C9AB4007D8806 /* Info.plist */, - ); - path = Tests; - sourceTree = ""; - }; - 94D8AF221E0C9AB4007D8806 /* TestsTests */ = { - isa = PBXGroup; - children = ( - 94D8AF321E0C9BB2007D8806 /* PalindromeTests.swift */, - 94D8AF251E0C9AB4007D8806 /* Info.plist */, - ); - path = TestsTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 94D8AF0A1E0C9AB4007D8806 /* Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 94D8AF281E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "Tests" */; - buildPhases = ( - 94D8AF071E0C9AB4007D8806 /* Sources */, - 94D8AF081E0C9AB4007D8806 /* Frameworks */, - 94D8AF091E0C9AB4007D8806 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Tests; - productName = Tests; - productReference = 94D8AF0B1E0C9AB4007D8806 /* Tests.app */; - productType = "com.apple.product-type.application"; - }; - 94D8AF1E1E0C9AB4007D8806 /* TestsTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 94D8AF2B1E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "TestsTests" */; - buildPhases = ( - 94D8AF1B1E0C9AB4007D8806 /* Sources */, - 94D8AF1C1E0C9AB4007D8806 /* Frameworks */, - 94D8AF1D1E0C9AB4007D8806 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 94D8AF211E0C9AB4007D8806 /* PBXTargetDependency */, - ); - name = TestsTests; - productName = TestsTests; - productReference = 94D8AF1F1E0C9AB4007D8806 /* TestsTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 94D8AF031E0C9AB4007D8806 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0820; - LastUpgradeCheck = 0820; - ORGANIZATIONNAME = "Joshua Alvarado"; - TargetAttributes = { - 94D8AF0A1E0C9AB4007D8806 = { - CreatedOnToolsVersion = 8.2; - ProvisioningStyle = Automatic; - }; - 94D8AF1E1E0C9AB4007D8806 = { - CreatedOnToolsVersion = 8.2; - LastSwiftMigration = 0820; - ProvisioningStyle = Automatic; - TestTargetID = 94D8AF0A1E0C9AB4007D8806; - }; - }; - }; - buildConfigurationList = 94D8AF061E0C9AB4007D8806 /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 94D8AF021E0C9AB4007D8806; - productRefGroup = 94D8AF0C1E0C9AB4007D8806 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 94D8AF0A1E0C9AB4007D8806 /* Tests */, - 94D8AF1E1E0C9AB4007D8806 /* TestsTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 94D8AF091E0C9AB4007D8806 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 94D8AF191E0C9AB4007D8806 /* LaunchScreen.storyboard in Resources */, - 94D8AF161E0C9AB4007D8806 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 94D8AF1D1E0C9AB4007D8806 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 94D8AF071E0C9AB4007D8806 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 94D8AF2F1E0C9AE9007D8806 /* Palindromes.swift in Sources */, - 94D8AF0F1E0C9AB4007D8806 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 94D8AF1B1E0C9AB4007D8806 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 94D8AF331E0C9BB2007D8806 /* PalindromeTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 94D8AF211E0C9AB4007D8806 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 94D8AF0A1E0C9AB4007D8806 /* Tests */; - targetProxy = 94D8AF201E0C9AB4007D8806 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 94D8AF171E0C9AB4007D8806 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 94D8AF181E0C9AB4007D8806 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 94D8AF261E0C9AB4007D8806 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - 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; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 94D8AF271E0C9AB4007D8806 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - 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; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 94D8AF291E0C9AB4007D8806 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = self.edu.Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - 94D8AF2A1E0C9AB4007D8806 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = self.edu.Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - }; - name = Release; - }; - 94D8AF2C1E0C9AB4007D8806 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = TestsTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = self.edu.TestsTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Tests.app/Tests"; - }; - name = Debug; - }; - 94D8AF2D1E0C9AB4007D8806 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = TestsTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = self.edu.TestsTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Tests.app/Tests"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 94D8AF061E0C9AB4007D8806 /* Build configuration list for PBXProject "Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 94D8AF261E0C9AB4007D8806 /* Debug */, - 94D8AF271E0C9AB4007D8806 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 94D8AF281E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 94D8AF291E0C9AB4007D8806 /* Debug */, - 94D8AF2A1E0C9AB4007D8806 /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; - 94D8AF2B1E0C9AB4007D8806 /* Build configuration list for PBXNativeTarget "TestsTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 94D8AF2C1E0C9AB4007D8806 /* Debug */, - 94D8AF2D1E0C9AB4007D8806 /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; -/* End XCConfigurationList section */ - }; - rootObject = 94D8AF031E0C9AB4007D8806 /* Project object */; -} diff --git a/Palindromes/Tests/Tests/AppDelegate.swift b/Palindromes/Tests/Tests/AppDelegate.swift deleted file mode 100644 index 481c72c62..000000000 --- a/Palindromes/Tests/Tests/AppDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.swift -// Tests -// -// Created by Joshua Alvarado on 12/22/16. -// Copyright © 2016 Joshua Alvarado. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json b/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 36d2c80d8..000000000 --- a/Palindromes/Tests/Tests/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard b/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index fdf3f97d1..000000000 --- a/Palindromes/Tests/Tests/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Palindromes/Tests/Tests/Info.plist b/Palindromes/Tests/Tests/Info.plist deleted file mode 100644 index f197d509b..000000000 --- a/Palindromes/Tests/Tests/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - From 9ac2d762802de647082a7b5977bad4bf9e1db8d6 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 24 Dec 2016 03:39:44 -0800 Subject: [PATCH 0316/1275] Fixed up indentation and removed a few self references. --- .../BoyerMoore.playground/Contents.swift | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 362a298f9..9bbc7ec19 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -1,66 +1,66 @@ //: Playground - noun: a place where people can play extension String { - func indexOf(pattern: String) -> 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.count) - - // 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() { - skipTable[c] = patternLength - i - 1 - } - - // This points at the last character in the pattern. - let p = pattern.index(before: pattern.endIndex) - let lastChar = pattern[p] - - // The pattern is scanned right-to-left, so skip ahead in the string by - // the length of the pattern. (Minus 1 because startIndex already points - // at the first character in the source string.) - var i = self.index(startIndex, offsetBy: patternLength - 1) + func indexOf(pattern: String) -> 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 + assert(patternLength > 0) + assert(patternLength <= characters.count) + + // 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() { + skipTable[c] = patternLength - i - 1 + } + + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { - // This is a helper function that steps backwards through both strings - // until we find a character that doesn’t match, or until we’ve reached - // the beginning of the pattern. - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = index(before: j) - q = index(before: q) - if self[j] != pattern[q] { return nil } - } - return j - } + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } - // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { - let c = self[i] - - // Does the current character match the last character from the pattern? - if c == lastChar { - - // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } - - // If no match, we can only safely skip one character ahead. - i = index(after: i) - } else { - // The characters are not equal, so skip ahead. The amount to skip is - // determined by the skip table. If the character is not present in the - // pattern, we can skip ahead by the full pattern length. However, if - // the character *is* present in the pattern, there may be a match up - // ahead and we can't skip as far. - i = self.index(i, offsetBy: skipTable[c] ?? patternLength) - } - } - return nil + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = index(i, offsetBy: skipTable[c] ?? patternLength) + } } + return nil + } } // A few simple tests From 7a0417e86553dbe67495deba9f16f2ccdf14b3ea Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:18:55 -0300 Subject: [PATCH 0317/1275] Added some tests. There are a failing test in the original code. --- Boyer-Moore/Tests/BoyerMooreTests.swift | 67 +++++ Boyer-Moore/Tests/Info.plist | 24 ++ .../Tests/Tests.xcodeproj/project.pbxproj | 269 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 90 ++++++ 5 files changed, 457 insertions(+) create mode 100755 Boyer-Moore/Tests/BoyerMooreTests.swift create mode 100644 Boyer-Moore/Tests/Info.plist create mode 100644 Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Boyer-Moore/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/Boyer-Moore/Tests/BoyerMooreTests.swift b/Boyer-Moore/Tests/BoyerMooreTests.swift new file mode 100755 index 000000000..6536d1800 --- /dev/null +++ b/Boyer-Moore/Tests/BoyerMooreTests.swift @@ -0,0 +1,67 @@ +import Foundation +import XCTest + +class BoyerMooreTest: XCTestCase { + override func setUp() { + super.setUp() + } + + func assert(pattern: String, doesNotExistsIn string: String) { + let index = string.indexOf(pattern: pattern) + XCTAssertNil(index) + } + + func assert(pattern: String, existsIn string: String) { + let index = string.indexOf(pattern: pattern) + XCTAssertNotNil(index) + + let startIndex = index! + let endIndex = string.index(index!, offsetBy: pattern.characters.count) + let match = string.substring(with: startIndex.. + + + + 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/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj b/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ff4f401a1 --- /dev/null +++ b/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */; }; + 9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoyerMooreTests.swift; sourceTree = SOURCE_ROOT; }; + 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoyerMoore.swift; path = ../../BoyerMoore.swift; sourceTree = ""; }; +/* 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 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */, + 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + path = TestsTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0800; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* Tests */, + ); + }; +/* 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 = ( + 9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */, + 7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.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_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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"; + }; + 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_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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"; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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_VERSION = 3.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Boyer-Moore/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Boyer-Moore/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Boyer-Moore/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2be65b442aafa1c96456322c50039dca8184a1e0 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:19:58 -0300 Subject: [PATCH 0318/1275] Fix failing test. --- Boyer-Moore/BoyerMoore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift index 4d7660ec3..d8ff4e6d2 100644 --- a/Boyer-Moore/BoyerMoore.swift +++ b/Boyer-Moore/BoyerMoore.swift @@ -61,7 +61,7 @@ extension String { // pattern, we can skip ahead by the full pattern length. However, if // the character *is* present in the pattern, there may be a match up // ahead and we can't skip as far. - i = self.index(i, offsetBy: skipTable[c] ?? patternLength) + i = index(i, offsetBy: skipTable[c] ?? patternLength, limitedBy: endIndex) ?? endIndex } } return nil From 4ca7ab9fc784afc018f6dde770fc54afc952664a Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:22:59 -0300 Subject: [PATCH 0319/1275] Add Boyer-Moore-Horspool algorithm and tests. --- Boyer-Moore/BoyerMoore.swift | 14 +++++++++++--- Boyer-Moore/Tests/BoyerMooreHorspoolTests.swift | 14 ++++++++++++++ Boyer-Moore/Tests/BoyerMooreTests.swift | 14 ++++++++++++-- Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj | 4 ++++ 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 Boyer-Moore/Tests/BoyerMooreHorspoolTests.swift diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift index d8ff4e6d2..24842b59e 100644 --- a/Boyer-Moore/BoyerMoore.swift +++ b/Boyer-Moore/BoyerMoore.swift @@ -6,7 +6,7 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func indexOf(pattern: String) -> String.Index? { + func indexOf(pattern: String, useHorspoolImprovement: Bool = false) -> 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 @@ -53,8 +53,16 @@ extension String { // There is a possible match. Do a brute-force search backwards. if let k = backwards() { return k } - // If no match, we can only safely skip one character ahead. - i = index(after: i) + if !useHorspoolImprovement { + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } + else { + // Ensure to jump at least one character (this is needed because the first + // character is in the skipTable, and `skipTable[lastChar] = 0`) + let jumpOffset = max(skipTable[c] ?? patternLength, 1) + i = index(i, offsetBy: jumpOffset, limitedBy: endIndex) ?? endIndex + } } else { // The characters are not equal, so skip ahead. The amount to skip is // determined by the skip table. If the character is not present in the diff --git a/Boyer-Moore/Tests/BoyerMooreHorspoolTests.swift b/Boyer-Moore/Tests/BoyerMooreHorspoolTests.swift new file mode 100644 index 000000000..3924494c7 --- /dev/null +++ b/Boyer-Moore/Tests/BoyerMooreHorspoolTests.swift @@ -0,0 +1,14 @@ +// +// BoyerMooreHorspoolTests.swift +// Tests +// +// Created by Matias Mazzei on 12/24/16. +// Copyright © 2016 Swift Algorithm Club. All rights reserved. +// + +class BoyerMooreHorspoolTests: BoyerMooreTest { + override func setUp() { + super.setUp() + useHorspoolImprovement = false + } +} diff --git a/Boyer-Moore/Tests/BoyerMooreTests.swift b/Boyer-Moore/Tests/BoyerMooreTests.swift index 6536d1800..8a2cbdc77 100755 --- a/Boyer-Moore/Tests/BoyerMooreTests.swift +++ b/Boyer-Moore/Tests/BoyerMooreTests.swift @@ -1,18 +1,28 @@ +// +// BoyerMooreHorspoolTests.swift +// Tests +// +// Created by Matias Mazzei on 12/24/16. +// Copyright © 2016 Swift Algorithm Club. All rights reserved. +// + import Foundation import XCTest class BoyerMooreTest: XCTestCase { + var useHorspoolImprovement = false + override func setUp() { super.setUp() } func assert(pattern: String, doesNotExistsIn string: String) { - let index = string.indexOf(pattern: pattern) + let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement) XCTAssertNil(index) } func assert(pattern: String, existsIn string: String) { - let index = string.indexOf(pattern: pattern) + let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement) XCTAssertNotNil(index) let startIndex = index! diff --git a/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj b/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj index ff4f401a1..f263d846a 100644 --- a/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj +++ b/Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */; }; 9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */; }; + 9AED56801E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -16,6 +17,7 @@ 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoyerMooreTests.swift; sourceTree = SOURCE_ROOT; }; 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoyerMoore.swift; path = ../../BoyerMoore.swift; sourceTree = ""; }; + 9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoyerMooreHorspoolTests.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -51,6 +53,7 @@ 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */, 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */, 7B2BBC941C779E7B0067B71D /* Info.plist */, + 9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */, ); name = Tests; path = TestsTests; @@ -125,6 +128,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9AED56801E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift in Sources */, 9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */, 7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.swift in Sources */, ); From 36fba8ac3f4da6595783f5ebd4e72d19d1621c21 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:25:27 -0300 Subject: [PATCH 0320/1275] Add tests to .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 17655c21e..38099490e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ script: - 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/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 From c3cad8c13314eda236ca3d98650c5a79c89861e8 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:30:32 -0300 Subject: [PATCH 0321/1275] Updated README: updated algorithms and credits. --- Boyer-Moore/README.markdown | 92 ++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index 576f6d17b..08347e3e7 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -87,7 +87,7 @@ extension String { // pattern, we can skip ahead by the full pattern length. However, if // the character *is* present in the pattern, there may be a match up // ahead and we can't skip as far. - i = self.index(i, offsetBy: skipTable[c] ?? patternLength) + i = index(i, offsetBy: skipTable[c] ?? patternLength, limitedBy: endIndex) ?? endIndex } } return nil @@ -158,40 +158,66 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm: ```swift extension String { func indexOf(pattern: String) -> String.Index? { - let patternLength = pattern.characters.count - assert(patternLength > 0) - assert(patternLength <= self.characters.count) + // 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 + assert(patternLength > 0) + assert(patternLength <= self.characters.count) - var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { - skipTable[c] = patternLength - i - 1 - } + // 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() { + skipTable[c] = patternLength - i - 1 + } - let p = pattern.index(before: pattern.endIndex) - let lastChar = pattern[p] - var i = self.index(startIndex, offsetBy: patternLength - 1) - - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = index(before: j) - q = index(before: q) - if self[j] != pattern[q] { return nil } - } - return j - } + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] - while i < self.endIndex { - let c = self[i] - if c == lastChar { - if let k = backwards() { return k } - i = index(after: i) - } else { - i = index(i, offsetBy: skipTable[c] ?? patternLength) - } - } - return nil + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = self.index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> String.Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < self.endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + // Ensure to jump at least one character (this is needed because the first + // character is in the skipTable, and `skipTable[lastChar] = 0`) + let jumpOffset = max(skipTable[c] ?? patternLength, 1) + i = index(i, offsetBy: jumpOffset, limitedBy: endIndex) ?? endIndex + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = index(i, offsetBy: skipTable[c] ?? patternLength, limitedBy: endIndex) ?? endIndex + } + } + return nil } } ``` @@ -200,4 +226,4 @@ In practice, the Horspool version of the algorithm tends to perform a little bet Credits: This code is based on the paper: [R. N. Horspool (1980). "Practical fast searching in strings". Software - Practice & Experience 10 (6): 501–506.](http://www.cin.br/~paguso/courses/if767/bib/Horspool_1980.pdf) -_Written for Swift Algorithm Club by Matthijs Hollemans, updated by Andreas Neusüß_ +_Written for Swift Algorithm Club by Matthijs Hollemans, updated by Andreas Neusüß_, [Matías Mazzei](https://github.com/mmazzei). From 78e78a4b9e81b57698d95e68d8abbd86c218ef95 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sat, 24 Dec 2016 14:42:54 -0300 Subject: [PATCH 0322/1275] Fix swiftlint warnings. --- Boyer-Moore/Tests/BoyerMooreTests.swift | 20 +++++++++---------- .../Tests/Tests.xcodeproj/project.pbxproj | 17 ++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Boyer-Moore/Tests/BoyerMooreTests.swift b/Boyer-Moore/Tests/BoyerMooreTests.swift index 8a2cbdc77..f1638afcd 100755 --- a/Boyer-Moore/Tests/BoyerMooreTests.swift +++ b/Boyer-Moore/Tests/BoyerMooreTests.swift @@ -30,48 +30,48 @@ class BoyerMooreTest: XCTestCase { let match = string.substring(with: startIndex.. Date: Sat, 24 Dec 2016 14:47:56 -0300 Subject: [PATCH 0323/1275] Xcode option 'Uncheck Autocreate schemes' unchecked. --- .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Boyer-Moore/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + From cf45ebd0dd84a842a1d032f7545e70c76b2cbb79 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sun, 25 Dec 2016 15:08:31 -0300 Subject: [PATCH 0324/1275] Update as requested in code review. --- .../BoyerMoore.playground/Contents.swift | 143 ++++++++++-------- Boyer-Moore/BoyerMoore.swift | 35 ++--- Boyer-Moore/README.markdown | 28 ++-- Boyer-Moore/Tests/BoyerMooreTests.swift | 22 ++- 4 files changed, 135 insertions(+), 93 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index 9bbc7ec19..f1ae5018e 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -1,72 +1,91 @@ //: Playground - noun: a place where people can play +/* + Boyer-Moore string search + + This code is based on the article "Faster String Searches" by Costas Menico + from Dr Dobb's magazine, July 1989. + http://www.drdobbs.com/database/faster-string-searches/184408171 +*/ extension String { - func indexOf(pattern: String) -> 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 - assert(patternLength > 0) - assert(patternLength <= characters.count) - - // 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() { - skipTable[c] = patternLength - i - 1 - } - - // This points at the last character in the pattern. - let p = pattern.index(before: pattern.endIndex) - let lastChar = pattern[p] - - // The pattern is scanned right-to-left, so skip ahead in the string by - // the length of the pattern. (Minus 1 because startIndex already points - // at the first character in the source string.) - var i = index(startIndex, offsetBy: patternLength - 1) - - // This is a helper function that steps backwards through both strings - // until we find a character that doesn’t match, or until we’ve reached - // the beginning of the pattern. - func backwards() -> String.Index? { - var q = p - var j = i - while q > pattern.startIndex { - j = index(before: j) - q = index(before: q) - if self[j] != pattern[q] { return nil } - } - return j - } - - // The main loop. Keep going until the end of the string is reached. - while i < endIndex { - let c = self[i] - - // Does the current character match the last character from the pattern? - if c == lastChar { - - // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } - - // If no match, we can only safely skip one character ahead. - i = index(after: i) - } else { - // The characters are not equal, so skip ahead. The amount to skip is - // determined by the skip table. If the character is not present in the - // pattern, we can skip ahead by the full pattern length. However, if - // the character *is* present in the pattern, there may be a match up - // ahead and we can't skip as far. - i = index(i, offsetBy: skipTable[c] ?? patternLength) - } + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + // There are no possible match in an empty string + guard !isEmpty else { return nil } + + // 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 } + + // 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() { + skipTable[c] = patternLength - i - 1 + } + + // This points at the last character in the pattern. + let p = pattern.index(before: pattern.endIndex) + let lastChar = pattern[p] + + // The pattern is scanned right-to-left, so skip ahead in the string by + // the length of the pattern. (Minus 1 because startIndex already points + // at the first character in the source string.) + var i = index(startIndex, offsetBy: patternLength - 1) + + // This is a helper function that steps backwards through both strings + // until we find a character that doesn’t match, or until we’ve reached + // the beginning of the pattern. + func backwards() -> Index? { + var q = p + var j = i + while q > pattern.startIndex { + j = index(before: j) + q = index(before: q) + if self[j] != pattern[q] { return nil } + } + return j + } + + // The main loop. Keep going until the end of the string is reached. + while i < endIndex { + let c = self[i] + + // Does the current character match the last character from the pattern? + if c == lastChar { + + // There is a possible match. Do a brute-force search backwards. + if let k = backwards() { return k } + + if !usingHorspoolImprovement { + // If no match, we can only safely skip one character ahead. + i = index(after: i) + } else { + // Ensure to jump at least one character (this is needed because the first + // character is in the skipTable, and `skipTable[lastChar] = 0`) + let jumpOffset = max(skipTable[c] ?? patternLength, 1) + i = index(i, offsetBy: jumpOffset, limitedBy: endIndex) ?? endIndex + } + } else { + // The characters are not equal, so skip ahead. The amount to skip is + // determined by the skip table. If the character is not present in the + // pattern, we can skip ahead by the full pattern length. However, if + // the character *is* present in the pattern, there may be a match up + // ahead and we can't skip as far. + i = index(i, offsetBy: skipTable[c] ?? patternLength, limitedBy: endIndex) ?? endIndex + } + } + return nil } - return nil - } } // A few simple tests -let s = "Hello, World" -s.indexOf(pattern: "World") // 7 +let str = "Hello, World" +str.index(of: "World") // 7 let animals = "🐶🐔🐷🐮🐱" -animals.indexOf(pattern: "🐮") // 6 +animals.index(of: "🐮") // 6 + +let lorem = "Lorem ipsum dolor sit amet" +lorem.index(of: "sit", usingHorspoolImprovement: true) // 18 diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift index 24842b59e..2f6bf1392 100644 --- a/Boyer-Moore/BoyerMoore.swift +++ b/Boyer-Moore/BoyerMoore.swift @@ -6,33 +6,35 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func indexOf(pattern: String, useHorspoolImprovement: Bool = false) -> String.Index? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + // There are no possible match in an empty string + guard !isEmpty else { return nil } + // 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.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() { skipTable[c] = patternLength - i - 1 } - + // This points at the last character in the pattern. let p = pattern.index(before: pattern.endIndex) let lastChar = pattern[p] - + // The pattern is scanned right-to-left, so skip ahead in the string by // the length of the pattern. (Minus 1 because startIndex already points // at the first character in the source string.) - var i = self.index(startIndex, offsetBy: patternLength - 1) - + var i = index(startIndex, offsetBy: patternLength - 1) + // This is a helper function that steps backwards through both strings // until we find a character that doesn’t match, or until we’ve reached // the beginning of the pattern. - func backwards() -> String.Index? { + func backwards() -> Index? { var q = p var j = i while q > pattern.startIndex { @@ -42,22 +44,21 @@ extension String { } return j } - + // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { + while i < endIndex { let c = self[i] - + // Does the current character match the last character from the pattern? if c == lastChar { - + // There is a possible match. Do a brute-force search backwards. if let k = backwards() { return k } - - if !useHorspoolImprovement { + + if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. i = index(after: i) - } - else { + } else { // Ensure to jump at least one character (this is needed because the first // character is in the skipTable, and `skipTable[lastChar] = 0`) let jumpOffset = max(skipTable[c] ?? patternLength, 1) diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index 08347e3e7..2cb42b0bd 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -32,12 +32,14 @@ Here's how you could write it in Swift: ```swift extension String { - func indexOf(pattern: String) -> String.Index? { + func index(of pattern: String) -> Index? { + // There are no possible match in an empty string + guard !isEmpty else { return nil } + // 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.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. @@ -53,12 +55,12 @@ extension String { // The pattern is scanned right-to-left, so skip ahead in the string by // the length of the pattern. (Minus 1 because startIndex already points // at the first character in the source string.) - var i = self.index(startIndex, offsetBy: patternLength - 1) + var i = index(startIndex, offsetBy: patternLength - 1) // This is a helper function that steps backwards through both strings // until we find a character that doesn’t match, or until we’ve reached // the beginning of the pattern. - func backwards() -> String.Index? { + func backwards() -> Index? { var q = p var j = i while q > pattern.startIndex { @@ -70,7 +72,7 @@ extension String { } // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { + while i < endIndex { let c = self[i] // Does the current character match the last character from the pattern? @@ -157,12 +159,14 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm: ```swift extension String { - func indexOf(pattern: String) -> String.Index? { + func index(of pattern: String) -> Index? { + // There are no possible match in an empty string + guard !isEmpty else { return nil } + // 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 - assert(patternLength > 0) - assert(patternLength <= self.characters.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. @@ -178,12 +182,12 @@ extension String { // The pattern is scanned right-to-left, so skip ahead in the string by // the length of the pattern. (Minus 1 because startIndex already points // at the first character in the source string.) - var i = self.index(startIndex, offsetBy: patternLength - 1) + var i = index(startIndex, offsetBy: patternLength - 1) // This is a helper function that steps backwards through both strings // until we find a character that doesn’t match, or until we’ve reached // the beginning of the pattern. - func backwards() -> String.Index? { + func backwards() -> Index? { var q = p var j = i while q > pattern.startIndex { @@ -195,7 +199,7 @@ extension String { } // The main loop. Keep going until the end of the string is reached. - while i < self.endIndex { + while i < endIndex { let c = self[i] // Does the current character match the last character from the pattern? diff --git a/Boyer-Moore/Tests/BoyerMooreTests.swift b/Boyer-Moore/Tests/BoyerMooreTests.swift index f1638afcd..9efe60874 100755 --- a/Boyer-Moore/Tests/BoyerMooreTests.swift +++ b/Boyer-Moore/Tests/BoyerMooreTests.swift @@ -17,12 +17,12 @@ class BoyerMooreTest: XCTestCase { } func assert(pattern: String, doesNotExistsIn string: String) { - let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement) + let index = string.index(of: pattern, usingHorspoolImprovement: useHorspoolImprovement) XCTAssertNil(index) } func assert(pattern: String, existsIn string: String) { - let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement) + let index = string.index(of: pattern, usingHorspoolImprovement: useHorspoolImprovement) XCTAssertNotNil(index) let startIndex = index! @@ -31,6 +31,24 @@ class BoyerMooreTest: XCTestCase { XCTAssertEqual(match, pattern) } + func testSearchPatternInEmptyString() { + let string = "" + let pattern = "ABCDEF" + assert(pattern: pattern, doesNotExistsIn: string) + } + + func testSearchEmptyPatternString() { + let string = "ABCDEF" + let pattern = "" + assert(pattern: pattern, doesNotExistsIn: string) + } + + func testSearchPatternLongerThanString() { + let string = "ABC" + let pattern = "ABCDEF" + assert(pattern: pattern, doesNotExistsIn: string) + } + func testSearchTheSameString() { let string = "ABCDEF" let pattern = "ABCDEF" From 960bca13c0207014040b96ba22e586b688279be9 Mon Sep 17 00:00:00 2001 From: mmazzei Date: Sun, 25 Dec 2016 17:58:00 -0300 Subject: [PATCH 0325/1275] Removed redundant validation. --- Boyer-Moore/BoyerMoore.playground/Contents.swift | 3 --- Boyer-Moore/BoyerMoore.swift | 3 --- Boyer-Moore/README.markdown | 6 ------ 3 files changed, 12 deletions(-) diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift index f1ae5018e..f553e1a00 100644 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ b/Boyer-Moore/BoyerMoore.playground/Contents.swift @@ -9,9 +9,6 @@ */ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { - // There are no possible match in an empty string - guard !isEmpty else { return nil } - // 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 diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift index 2f6bf1392..af8aea9d9 100644 --- a/Boyer-Moore/BoyerMoore.swift +++ b/Boyer-Moore/BoyerMoore.swift @@ -7,9 +7,6 @@ */ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { - // There are no possible match in an empty string - guard !isEmpty else { return nil } - // 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 diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index 2cb42b0bd..e821b812e 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -33,9 +33,6 @@ Here's how you could write it in Swift: ```swift extension String { func index(of pattern: String) -> Index? { - // There are no possible match in an empty string - guard !isEmpty else { return nil } - // 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 @@ -160,9 +157,6 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm: ```swift extension String { func index(of pattern: String) -> Index? { - // There are no possible match in an empty string - guard !isEmpty else { return nil } - // 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 From f618414c65e8b45f7f11010ad988e733cea23395 Mon Sep 17 00:00:00 2001 From: Joshua Alvarado Date: Mon, 26 Dec 2016 11:31:54 -0700 Subject: [PATCH 0326/1275] Add shared scheme to test Project for tests --- .../xcshareddata/xcschemes/Test.xcscheme | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme diff --git a/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme new file mode 100644 index 000000000..9a1b39e69 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d8b96a480aeaefd3ead13c409c6957071ecfc931 Mon Sep 17 00:00:00 2001 From: Nagasawa Hiroki Date: Wed, 28 Dec 2016 08:34:51 +0900 Subject: [PATCH 0327/1275] Fix Access Control position in AVLTree --- AVL Tree/AVLTree.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AVL Tree/AVLTree.swift b/AVL Tree/AVLTree.swift index b4b97f0d6..cfcf114c0 100644 --- a/AVL Tree/AVLTree.swift +++ b/AVL Tree/AVLTree.swift @@ -29,7 +29,7 @@ public class TreeNode { internal var leftChild: Node? internal var rightChild: Node? fileprivate var height: Int - weak fileprivate var parent: Node? + fileprivate weak var parent: Node? public init(key: Key, payload: Payload?, leftChild: Node?, rightChild: Node?, parent: Node?, height: Int) { self.key = key From 03f176083b22b1ba2c40e0fb0f21af8d0451424b Mon Sep 17 00:00:00 2001 From: Nagasawa Hiroki Date: Wed, 28 Dec 2016 10:16:36 +0900 Subject: [PATCH 0328/1275] Make each steps clear --- Red-Black Tree/README.markdown | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index d4e86a095..05993f016 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -49,16 +49,17 @@ n n n n n b We create a new node with the value to be inserted into the tree. The color of this new node is always red. We perform a standard BST insert with this node. Now the three might not be a valid RBT anymore. -We now go through several insertion steps in order to make the tree valid again. We call the just inserted node n. -1. We check if n is the rootNode, if so we paint it black and we are done. If not we go to step 2. +We now go through several insertion steps in order to make the tree valid again. We call the just inserted node n. + +**Step 1**: We check if n is the rootNode, if so we paint it black and we are done. If not we go to Step 2. We now know that n at least has a parent as it is not the rootNode. -2. We check if the parent of n is black if so we are done. If not we go to step 3. +**Step 2**: We check if the parent of n is black if so we are done. If not we go to Step 3. We now know the parent is also not the root node as the parent is red. Thus n also has a grandparent and thus also an uncle as every node has two children. This uncle may however be a nullLeaf -3. We check if n's uncle is red. If not we go to 4. If n's uncle is indeed red we recolor uncle and parent to black and n's grandparent to red. We now go back to step 1 performing the same logic on n's grandparent. +**Step 3**: We check if n's uncle is red. If not we go to Step 4. If n's uncle is indeed red we recolor uncle and parent to black and n's grandparent to red. We now go back to step 1 performing the same logic on n's grandparent. From here there are four cases: - **The left left case.** n's parent is the left child of its parent and n is the left child of its parent. @@ -66,14 +67,14 @@ From here there are four cases: - **The right right case** n's parent is the right child of its parent and n is the right child of its parent. - **The right left case** n's parent is the right child of its parent and n is the left child of its parent. -4. Step 4 checks if either the **left right** case or the **right left** case applies to the current situation. - - If we find the **left right case**, we left rotate n's parent and go to step 5 while setting n to n's parent. (This transforms the **left right** case into the **left left** case) - - If we find the **right left case**, we right rotate n's parent and go to step 5 while setting n to n's parent. (This transforms the **right left** case into the **right right** case) - - If we find neither of these two we proceed to step 5. +**Step 4**: checks if either the **left right** case or the **right left** case applies to the current situation. + - If we find the **left right case**, we left rotate n's parent and go to Step 5 while setting n to n's parent. (This transforms the **left right** case into the **left left** case) + - If we find the **right left case**, we right rotate n's parent and go to Step 5 while setting n to n's parent. (This transforms the **right left** case into the **right right** case) + - If we find neither of these two we proceed to Step 5. n's parent is now red, while n's grandparent is black. -5. We swap the colors of n's parent and grandparent. +**Step 5**: We swap the colors of n's parent and grandparent. - We either right rotate n's grandparent in case of the **left left** case - Or we left rotate n's grandparent in case of the **right right** case From f8857406b07e0012c96d862e297669a04aba195a Mon Sep 17 00:00:00 2001 From: Mohamed Emad Hegab Date: Wed, 28 Dec 2016 10:55:57 +0100 Subject: [PATCH 0329/1275] swift 3 update --- Select Minimum Maximum/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Select Minimum Maximum/README.markdown b/Select Minimum Maximum/README.markdown index 5e006f50e..a67f4ec8e 100644 --- a/Select Minimum Maximum/README.markdown +++ b/Select Minimum Maximum/README.markdown @@ -89,7 +89,7 @@ The result is a minimum of `3` and a maximum of `9`. Here is a simple implementation in Swift: ```swift -func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? { +func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { guard !array.isEmpty else { return nil } From 411cbd208df10cb6a9bd9516bba3bae66173d7a6 Mon Sep 17 00:00:00 2001 From: mattthousand Date: Wed, 28 Dec 2016 13:33:29 -0500 Subject: [PATCH 0330/1275] Convert to swift 3.0 syntax. --- Heap Sort/HeapSort.playground/Contents.swift | 21 +++++++++++++++++++ Heap Sort/HeapSort.swift | 6 +++--- .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Heap/Heap.swift | 18 ++++++++-------- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 Heap Sort/HeapSort.playground/Contents.swift diff --git a/Heap Sort/HeapSort.playground/Contents.swift b/Heap Sort/HeapSort.playground/Contents.swift new file mode 100644 index 000000000..5dbe2e14f --- /dev/null +++ b/Heap Sort/HeapSort.playground/Contents.swift @@ -0,0 +1,21 @@ +//: Playground - noun: a place where people can play + +extension Heap { + public mutating func sort() -> [T] { + for i in (elements.count - 1).stride(through: 1, by: -1) { + swap(&elements[0], &elements[i]) + shiftDown(index: 0, heapSize: i) + } + return elements + } +} + +/* + Sorts an array using a heap. + Heapsort can be performed in-place, but it is not a stable sort. + */ +public func heapsort(a: [T], _ sort: (T, T) -> Bool) -> [T] { + let reverseOrder = { i1, i2 in sort(i2, i1) } + var h = Heap(array: a, sort: reverseOrder) + return h.sort() +} diff --git a/Heap Sort/HeapSort.swift b/Heap Sort/HeapSort.swift index ec5b4a478..3fbaab14d 100644 --- a/Heap Sort/HeapSort.swift +++ b/Heap Sort/HeapSort.swift @@ -1,8 +1,8 @@ extension Heap { public mutating func sort() -> [T] { - for i in (elements.count - 1).stride(through: 1, by: -1) { + for i in stride(from: (elements.count - 1), through: 1, by: -1) { swap(&elements[0], &elements[i]) - shiftDown(index: 0, heapSize: i) + shiftDown(0, heapSize: i) } return elements } @@ -12,7 +12,7 @@ extension Heap { Sorts an array using a heap. Heapsort can be performed in-place, but it is not a stable sort. */ -public func heapsort(a: [T], _ sort: (T, T) -> Bool) -> [T] { +public func heapsort(_ a: [T], _ sort: @escaping (T, T) -> Bool) -> [T] { let reverseOrder = { i1, i2 in sort(i2, i1) } var h = Heap(array: a, sort: reverseOrder) return h.sort() diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj index 454222c49..f7f101cd6 100644 --- a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -224,6 +230,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; }; name = Debug; }; @@ -235,6 +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_VERSION = 3.0; }; name = Release; }; diff --git a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..dfcf6de42 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 @@ { fileprivate mutating func buildHeap(fromArray array: [T]) { elements = array for i in stride(from: (elements.count/2 - 1), through: 0, by: -1) { - shiftDown(index: i, heapSize: elements.count) + shiftDown(i, heapSize: elements.count) } } @@ -98,7 +98,7 @@ public struct Heap { */ public mutating func insert(_ value: T) { elements.append(value) - shiftUp(index: elements.count - 1) + shiftUp(elements.count - 1) } public mutating func insert(_ sequence: S) where S.Iterator.Element == T { @@ -116,7 +116,7 @@ public struct Heap { assert(isOrderedBefore(value, elements[i])) elements[i] = value - shiftUp(index: i) + shiftUp(i) } /** @@ -142,14 +142,14 @@ public struct Heap { * 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. */ - public mutating func removeAt(index: Int) -> T? { + public mutating func removeAt(_ index: Int) -> T? { guard index < elements.count else { return nil } let size = elements.count - 1 if index != size { swap(&elements[index], &elements[size]) - shiftDown(index: index, heapSize: size) - shiftUp(index: index) + shiftDown(index, heapSize: size) + shiftUp(index) } return elements.removeLast() } @@ -158,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) { + mutating func shiftUp(_ index: Int) { var childIndex = index let child = elements[childIndex] var parentIndex = self.parentIndex(ofIndex: childIndex) @@ -173,14 +173,14 @@ public struct Heap { } mutating func shiftDown() { - shiftDown(index: 0, heapSize: elements.count) + shiftDown(0, heapSize: elements.count) } /** * 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) { + mutating func shiftDown(_ index: Int, heapSize: Int) { var parentIndex = index while true { From 75d866a0b9df43a2803bcad6f25f3151f51b73c2 Mon Sep 17 00:00:00 2001 From: mattthousand Date: Wed, 28 Dec 2016 13:35:51 -0500 Subject: [PATCH 0331/1275] Update README. --- Heap Sort/README.markdown | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Heap Sort/README.markdown b/Heap Sort/README.markdown index 3d8b0f394..5f047f82b 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -48,13 +48,13 @@ Here's how you can implement heap sort in Swift: ```swift extension Heap { - public mutating func sort() -> [T] { - for i in (elements.count - 1).stride(through: 1, by: -1) { - swap(&elements[0], &elements[i]) - shiftDown(index: 0, heapSize: i) - } + public mutating func sort() -> [T] { + for i in stride(from: (elements.count - 1), through: 1, by: -1) { + swap(&elements[0], &elements[i]) + shiftDown(0, heapSize: i) + } return elements - } + } } ``` @@ -70,10 +70,10 @@ Because we need a max-heap to sort from low-to-high, you need to give `Heap` the We can write a handy helper function for that: ```swift -public func heapsort(a: [T], _ sort: (T, T) -> Bool) -> [T] { - let reverseOrder = { i1, i2 in sort(i2, i1) } - var h = Heap(array: a, sort: reverseOrder) - return h.sort() +public func heapsort(_ a: [T], _ sort: @escaping (T, T) -> Bool) -> [T] { + let reverseOrder = { i1, i2 in sort(i2, i1) } + var h = Heap(array: a, sort: reverseOrder) + return h.sort() } ``` From bb5cbe6e839501edbc6a75d9c99748511b369040 Mon Sep 17 00:00:00 2001 From: mattthousand Date: Wed, 28 Dec 2016 13:39:53 -0500 Subject: [PATCH 0332/1275] Uncomment .travis.yml. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b5faffa6..79eb3e051 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ script: # - 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 ./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 From 6a15e73d72369d44d1b5b118c1e2f45f04b504b7 Mon Sep 17 00:00:00 2001 From: mattthousand Date: Wed, 28 Dec 2016 13:41:50 -0500 Subject: [PATCH 0333/1275] Remove playground. --- Heap Sort/HeapSort.playground/Contents.swift | 21 -------------------- 1 file changed, 21 deletions(-) delete mode 100644 Heap Sort/HeapSort.playground/Contents.swift diff --git a/Heap Sort/HeapSort.playground/Contents.swift b/Heap Sort/HeapSort.playground/Contents.swift deleted file mode 100644 index 5dbe2e14f..000000000 --- a/Heap Sort/HeapSort.playground/Contents.swift +++ /dev/null @@ -1,21 +0,0 @@ -//: Playground - noun: a place where people can play - -extension Heap { - public mutating func sort() -> [T] { - for i in (elements.count - 1).stride(through: 1, by: -1) { - swap(&elements[0], &elements[i]) - shiftDown(index: 0, heapSize: i) - } - return elements - } -} - -/* - Sorts an array using a heap. - Heapsort can be performed in-place, but it is not a stable sort. - */ -public func heapsort(a: [T], _ sort: (T, T) -> Bool) -> [T] { - let reverseOrder = { i1, i2 in sort(i2, i1) } - var h = Heap(array: a, sort: reverseOrder) - return h.sort() -} From 356844c7d61630b4aa09eb9e3d3d785593cf86e2 Mon Sep 17 00:00:00 2001 From: cruisediary Date: Thu, 29 Dec 2016 18:18:14 +0900 Subject: [PATCH 0334/1275] Updating to Swift3 (enum lowercase) - playground - README.md - some.swift file --- .../Contents.swift | 2 +- .../Sources/BinarySearchTree.swift | 54 ++++++------- .../Solution 2/BinarySearchTree.swift | 54 ++++++------- .../CountingSort.playground/Contents.swift | 6 +- Counting Sort/CountingSort.swift | 4 +- Linked List/README.markdown | 4 +- .../ShuntingYard.playground/Contents.swift | 78 +++++++++---------- Shunting Yard/ShuntingYard.swift | 62 +++++++-------- 8 files changed, 132 insertions(+), 132 deletions(-) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift index 12fbba81d..8df69fb6a 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift @@ -1,7 +1,7 @@ //: Playground - noun: a place where people can play // Each time you insert something, you get back a completely new tree. -var tree = BinarySearchTree.Leaf(7) +var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) tree = tree.insert(newValue: 5) tree = tree.insert(newValue: 10) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift index b692efdc4..5128bb348 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -4,25 +4,25 @@ The tree is immutable. Any insertions or deletions will create a new tree. */ public enum BinarySearchTree { - case Empty - case Leaf(T) - indirect case Node(BinarySearchTree, T, BinarySearchTree) + case empty + case leaf(T) + indirect case node(BinarySearchTree, T, BinarySearchTree) /* How many nodes are in this subtree. Performance: O(n). */ public var count: Int { switch self { - case .Empty: return 0 - case .Leaf: return 1 - case let .Node(left, _, right): return left.count + 1 + right.count + case .empty: return 0 + case .leaf: return 1 + case let .node(left, _, right): return left.count + 1 + right.count } } /* 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 let .Node(left, _, right): return 1 + max(left.height, right.height) + case .empty: return 0 + case .leaf: return 1 + case let .node(left, _, right): return 1 + max(left.height, right.height) } } @@ -32,21 +32,21 @@ public enum BinarySearchTree { */ public func insert(newValue: T) -> BinarySearchTree { switch self { - case .Empty: - return .Leaf(newValue) + case .empty: + return .leaf(newValue) - case .Leaf(let value): + case .leaf(let value): if newValue < value { - return .Node(.Leaf(newValue), value, .Empty) + return .node(.leaf(newValue), value, .empty) } else { - return .Node(.Empty, value, .Leaf(newValue)) + return .node(.empty, value, .leaf(newValue)) } - case .Node(let left, let value, let right): + case .node(let left, let value, let right): if newValue < value { - return .Node(left.insert(newValue: newValue), value, right) + return .node(left.insert(newValue: newValue), value, right) } else { - return .Node(left, value, right.insert(newValue: newValue)) + return .node(left, value, right.insert(newValue: newValue)) } } } @@ -57,11 +57,11 @@ public enum BinarySearchTree { */ public func search(x: T) -> BinarySearchTree? { switch self { - case .Empty: + case .empty: return nil - case .Leaf(let y): + case .leaf(let y): return (x == y) ? self : nil - case let .Node(left, y, right): + case let .node(left, y, right): if x < y { return left.search(x: x) } else if y < x { @@ -82,11 +82,11 @@ public enum BinarySearchTree { public func minimum() -> BinarySearchTree { var node = self var prev = node - while case let .Node(next, _, _) = node { + while case let .node(next, _, _) = node { prev = node node = next } - if case .Leaf = node { + if case .leaf = node { return node } return prev @@ -98,11 +98,11 @@ public enum BinarySearchTree { public func maximum() -> BinarySearchTree { var node = self var prev = node - while case let .Node(_, _, next) = node { + while case let .node(_, _, next) = node { prev = node node = next } - if case .Leaf = node { + if case .leaf = node { return node } return prev @@ -112,9 +112,9 @@ public enum BinarySearchTree { extension BinarySearchTree: CustomDebugStringConvertible { public var debugDescription: String { switch self { - case .Empty: return "." - case .Leaf(let value): return "\(value)" - case .Node(let left, let value, let right): + case .empty: return "." + case .leaf(let value): return "\(value)" + case .node(let left, let value, let right): return "(\(left.debugDescription) <- \(value) -> \(right.debugDescription))" } } diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.swift b/Binary Search Tree/Solution 2/BinarySearchTree.swift index ce2868bbf..272b86368 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.swift @@ -4,25 +4,25 @@ The tree is immutable. Any insertions or deletions will create a new tree. */ public enum BinarySearchTree { - case Empty - case Leaf(T) - indirect case Node(BinarySearchTree, T, BinarySearchTree) + case empty + case leaf(T) + indirect case node(BinarySearchTree, T, BinarySearchTree) /* How many nodes are in this subtree. Performance: O(n). */ public var count: Int { switch self { - case .Empty: return 0 - case .Leaf: return 1 - case let .Node(left, _, right): return left.count + 1 + right.count + case .empty: return 0 + case .leaf: return 1 + case let .node(left, _, right): return left.count + 1 + right.count } } /* 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 let .Node(left, _, right): return 1 + max(left.height, right.height) + case .empty: return 0 + case .leaf: return 1 + case let .node(left, _, right): return 1 + max(left.height, right.height) } } @@ -32,21 +32,21 @@ public enum BinarySearchTree { */ public func insert(newValue: T) -> BinarySearchTree { switch self { - case .Empty: - return .Leaf(newValue) + case .empty: + return .leaf(newValue) - case .Leaf(let value): + case .leaf(let value): if newValue < value { - return .Node(.Leaf(newValue), value, .Empty) + return .node(.leaf(newValue), value, .empty) } else { - return .Node(.Empty, value, .Leaf(newValue)) + return .node(.empty, value, .leaf(newValue)) } - case .Node(let left, let value, let right): + case .node(let left, let value, let right): if newValue < value { - return .Node(left.insert(newValue), value, right) + return .node(left.insert(newValue), value, right) } else { - return .Node(left, value, right.insert(newValue)) + return .node(left, value, right.insert(newValue)) } } } @@ -57,11 +57,11 @@ public enum BinarySearchTree { */ public func search(x: T) -> BinarySearchTree? { switch self { - case .Empty: + case .empty: return nil - case .Leaf(let y): + case .leaf(let y): return (x == y) ? self : nil - case let .Node(left, y, right): + case let .node(left, y, right): if x < y { return left.search(x) } else if y < x { @@ -82,11 +82,11 @@ public enum BinarySearchTree { public func minimum() -> BinarySearchTree { var node = self var prev = node - while case let .Node(next, _, _) = node { + while case let .node(next, _, _) = node { prev = node node = next } - if case .Leaf = node { + if case .leaf = node { return node } return prev @@ -98,11 +98,11 @@ public enum BinarySearchTree { public func maximum() -> BinarySearchTree { var node = self var prev = node - while case let .Node(_, _, next) = node { + while case let .node(_, _, next) = node { prev = node node = next } - if case .Leaf = node { + if case .leaf = node { return node } return prev @@ -112,9 +112,9 @@ public enum BinarySearchTree { extension BinarySearchTree: CustomDebugStringConvertible { public var debugDescription: String { switch self { - case .Empty: return "." - case .Leaf(let value): return "\(value)" - case .Node(let left, let value, let right): + case .empty: return "." + case .leaf(let value): return "\(value)" + case .node(let left, let value, let right): return "(\(left.debugDescription) <- \(value) -> \(right.debugDescription))" } } diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index 2d85347ef..1d84f8132 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -1,12 +1,12 @@ //: Playground - noun: a place where people can play enum CountingSortError: Error { - case ArrayEmpty + case arrayEmpty } func countingSort(array: [Int]) throws -> [Int] { guard array.count > 0 else { - throw CountingSortError.ArrayEmpty + throw CountingSortError.arrayEmpty } // Step 1 @@ -38,4 +38,4 @@ func countingSort(array: [Int]) throws -> [Int] { } -try countingSort(array: [10, 9, 8, 7, 1, 2, 7, 3]) \ No newline at end of file +try countingSort(array: [10, 9, 8, 7, 1, 2, 7, 3]) diff --git a/Counting Sort/CountingSort.swift b/Counting Sort/CountingSort.swift index ec8c5adcb..d37bb2eff 100644 --- a/Counting Sort/CountingSort.swift +++ b/Counting Sort/CountingSort.swift @@ -7,12 +7,12 @@ // enum CountingSortError: ErrorType { - case ArrayEmpty + case arrayEmpty } func countingSort(array: [Int]) throws -> [Int] { guard array.count > 0 else { - throw CountingSortError.ArrayEmpty + throw CountingSortError.arrayEmpty } // Step 1 diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 7b2ec0c0d..1884aeb23 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -526,8 +526,8 @@ It is possible to implement a linked list with value semantics using an enum. Th ```swift enum ListNode { - indirect case Node(T, next: ListNode) - case End + indirect case node(T, next: ListNode) + case end } ``` diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index 04fed7739..707e2a0a3 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -1,51 +1,51 @@ //: Playground - noun: a place where people can play internal enum OperatorAssociativity { - case LeftAssociative - case RightAssociative + case leftAssociative + case rightAssociative } public enum OperatorType: CustomStringConvertible { - case Add - case Subtract - case Divide - case Multiply - case Percent - case Exponent + case add + case subtract + case divide + case multiply + case percent + case exponent public var description: String { switch self { - case Add: + case add: return "+" - case Subtract: + case subtract: return "-" - case Divide: + case divide: return "/" - case Multiply: + case multiply: return "*" - case Percent: + case percent: return "%" - case Exponent: + case exponent: return "^" } } } public enum TokenType: CustomStringConvertible { - case OpenBracket - case CloseBracket + case openBracket + case closeBracket case Operator(OperatorToken) - case Operand(Double) + case operand(Double) public var description: String { switch self { - case OpenBracket: + case openBracket: return "(" - case CloseBracket: + case closeBracket: return ")" case Operator(let operatorToken): return operatorToken.description - case Operand(let value): + case operand(let value): return "\(value)" } } @@ -60,21 +60,21 @@ public struct OperatorToken: CustomStringConvertible { var precedence: Int { switch operatorType { - case .Add, .Subtract: + case .add, .subtract: return 0 - case .Divide, .Multiply, .Percent: + case .divide, .multiply, .percent: return 5 - case .Exponent: + case .exponent: return 10 } } var associativity: OperatorAssociativity { switch operatorType { - case .Add, .Subtract, .Divide, .Multiply, .Percent: - return .LeftAssociative - case .Exponent: - return .RightAssociative + case .add, .subtract, .divide, .multiply, .percent: + return .leftAssociative + case .exponent: + return .rightAssociative } } @@ -99,7 +99,7 @@ public struct Token: CustomStringConvertible { } init(operand: Double) { - tokenType = .Operand(operand) + tokenType = .operand(operand) } init(operatorType: OperatorType) { @@ -108,7 +108,7 @@ public struct Token: CustomStringConvertible { var isOpenBracket: Bool { switch tokenType { - case .OpenBracket: + case .openBracket: return true default: return false @@ -175,14 +175,14 @@ public func reversePolishNotation(expression: [Token]) -> String { for token in expression { switch token.tokenType { - case .Operand(_): + case .operand(_): reversePolishNotation.append(token) - case .OpenBracket: + case .openBracket: tokenStack.push(token) - case .CloseBracket: - while tokenStack.count > 0, let tempToken = tokenStack.pop() where !tempToken.isOpenBracket { + case .closeBracket: + while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { reversePolishNotation.append(tempToken) } @@ -217,19 +217,19 @@ public func reversePolishNotation(expression: [Token]) -> String { let expr = InfixExpressionBuilder() .addOperand(3) - .addOperator(.Add) + .addOperator(.add) .addOperand(4) - .addOperator(.Multiply) + .addOperator(.multiply) .addOperand(2) - .addOperator(.Divide) + .addOperator(.divide) .addOpenBracket() .addOperand(1) - .addOperator(.Subtract) + .addOperator(.subtract) .addOperand(5) .addCloseBracket() - .addOperator(.Exponent) + .addOperator(.exponent) .addOperand(2) - .addOperator(.Exponent) + .addOperator(.exponent) .addOperand(3) .build() diff --git a/Shunting Yard/ShuntingYard.swift b/Shunting Yard/ShuntingYard.swift index 5159c9172..9d31d5a58 100644 --- a/Shunting Yard/ShuntingYard.swift +++ b/Shunting Yard/ShuntingYard.swift @@ -7,51 +7,51 @@ // internal enum OperatorAssociativity { - case LeftAssociative - case RightAssociative + case leftAssociative + case rightAssociative } public enum OperatorType: CustomStringConvertible { - case Add - case Subtract - case Divide - case Multiply - case Percent - case Exponent + case add + case subtract + case divide + case multiply + case percent + case exponent public var description: String { switch self { - case Add: + case add: return "+" - case Subtract: + case subtract: return "-" - case Divide: + case divide: return "/" - case Multiply: + case multiply: return "*" - case Percent: + case percent: return "%" - case Exponent: + case exponent: return "^" } } } public enum TokenType: CustomStringConvertible { - case OpenBracket - case CloseBracket + case openBracket + case closeBracket case Operator(OperatorToken) - case Operand(Double) + case operand(Double) public var description: String { switch self { - case OpenBracket: + case openBracket: return "(" - case CloseBracket: + case closeBracket: return ")" case Operator(let operatorToken): return operatorToken.description - case Operand(let value): + case operand(let value): return "\(value)" } } @@ -66,20 +66,20 @@ public struct OperatorToken: CustomStringConvertible { var precedence: Int { switch operatorType { - case .Add, .Subtract: + case .add, .subtract: return 0 - case .Divide, .Multiply, .Percent: + case .divide, .multiply, .percent: return 5 - case .Exponent: + case .exponent: return 10 } } var associativity: OperatorAssociativity { switch operatorType { - case .Add, .Subtract, .Divide, .Multiply, .Percent: + case .add, .subtract, .divide, .multiply, .percent: return .LeftAssociative - case .Exponent: + case .exponent: return .RightAssociative } } @@ -105,7 +105,7 @@ public struct Token: CustomStringConvertible { } init(operand: Double) { - tokenType = .Operand(operand) + tokenType = .operand(operand) } init(operatorType: OperatorType) { @@ -114,7 +114,7 @@ public struct Token: CustomStringConvertible { var isOpenBracket: Bool { switch tokenType { - case .OpenBracket: + case .openBracket: return true default: return false @@ -181,14 +181,14 @@ public func reversePolishNotation(expression: [Token]) -> String { for token in expression { switch token.tokenType { - case .Operand(_): + case .operand(_): reversePolishNotation.append(token) - case .OpenBracket: + case .openBracket: tokenStack.push(token) - case .CloseBracket: - while tokenStack.count > 0, let tempToken = tokenStack.pop() where !tempToken.isOpenBracket { + case .closeBracket: + while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { reversePolishNotation.append(tempToken) } From e1517dc458375a589a4cfd49a3f7c0c16caaffd6 Mon Sep 17 00:00:00 2001 From: zaccone Date: Thu, 29 Dec 2016 14:34:48 -0500 Subject: [PATCH 0335/1275] Corrected a spelling error and removed the "get" syntax for a property. --- Trie/Trie/Trie/Trie.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index ad4e9f2e7..8f3b46123 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -16,9 +16,7 @@ class TrieNode { var children: [T: TrieNode] = [:] var isTerminating = false var isLeaf: Bool { - get { - return children.count == 0 - } + return children.count == 0 } /// Initializes a node. @@ -62,7 +60,7 @@ class Trie { fileprivate let root: Node fileprivate var wordCount: Int - /// Creats an empty trie. + /// Creates an empty trie. init() { root = Node() wordCount = 0 From 5021bc79cd44f1d8ae8f32780984759d2cc57b5a Mon Sep 17 00:00:00 2001 From: zaccone Date: Thu, 29 Dec 2016 16:48:29 -0500 Subject: [PATCH 0336/1275] Added NSCoding conformance. --- ...6ABF2F62-9363-4450-8DE1-D20F57026950.plist | 22 ++++++ .../Info.plist | 33 ++++++++ Trie/Trie/Trie/Trie.swift | 25 ++++++- Trie/Trie/TrieTests/TrieTests.swift | 75 +++++++++++-------- 4 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist create mode 100644 Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/Info.plist diff --git a/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist new file mode 100644 index 000000000..01ff985c8 --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist @@ -0,0 +1,22 @@ + + + + + classNames + + TrieTests + + testInsertPerformance() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 3.0053 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/Info.plist b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/Info.plist new file mode 100644 index 000000000..3c07f3d6a --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/Info.plist @@ -0,0 +1,33 @@ + + + + + runDestinationsByUUID + + 6ABF2F62-9363-4450-8DE1-D20F57026950 + + localComputer + + busSpeedInMHz + 100 + cpuCount + 1 + cpuKind + Intel Core i7 + cpuSpeedInMHz + 3300 + logicalCPUCoresPerPackage + 4 + modelCode + MacBookPro13,2 + physicalCPUCoresPerPackage + 2 + platformIdentifier + com.apple.platform.macosx + + targetArchitecture + x86_64 + + + + diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index 8f3b46123..ec3b1c5cc 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -43,7 +43,7 @@ class TrieNode { /// A trie data structure containing words. Each node is a single /// character of a word. -class Trie { +class Trie: NSObject, NSCoding { typealias Node = TrieNode /// The number of words in the trie public var count: Int { @@ -61,10 +61,31 @@ class Trie { fileprivate var wordCount: Int /// Creates an empty trie. - init() { + override init() { root = Node() wordCount = 0 } + + // 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) + } + } + + /// 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 diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 236908ece..7ef02553f 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -12,20 +12,20 @@ import XCTest 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() } - - /// Don't need to do anything here because the wordArrayu and trie should + + /// 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. @@ -36,7 +36,7 @@ class TrieTests: XCTestCase { 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) @@ -48,24 +48,23 @@ class TrieTests: XCTestCase { 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 trie.count == 0 else { return } - let numberOfWordsToInsert = wordArray!.count - for i in 0.. Date: Thu, 29 Dec 2016 17:28:41 -0500 Subject: [PATCH 0337/1275] Added a ReadMe file. --- Trie/Trie/Trie.xcodeproj/project.pbxproj | 4 +++ Trie/Trie/Trie/ReadMe.md | 33 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Trie/Trie/Trie/ReadMe.md diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 8d3611b6d..055885ee1 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ EB798E2A1DFEF81400F0628D /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E281DFEF81400F0628D /* Trie.swift */; }; EB798E2C1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; EB798E2D1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; + EB8369AD1E15C5710003A7F8 /* ReadMe.md in Sources */ = {isa = PBXBuildFile; fileRef = EB8369AC1E15C5710003A7F8 /* ReadMe.md */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -51,6 +52,7 @@ EB798E1C1DFEF79900F0628D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; EB798E281DFEF81400F0628D /* Trie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = ""; }; EB798E2B1DFEF90B00F0628D /* dictionary.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.txt; sourceTree = ""; }; + EB8369AC1E15C5710003A7F8 /* ReadMe.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -101,6 +103,7 @@ EB798DFC1DFEF79900F0628D /* Trie */ = { isa = PBXGroup; children = ( + EB8369AC1E15C5710003A7F8 /* ReadMe.md */, EB798DFD1DFEF79900F0628D /* AppDelegate.swift */, EB798DFF1DFEF79900F0628D /* ViewController.swift */, EB798E011DFEF79900F0628D /* Assets.xcassets */, @@ -267,6 +270,7 @@ files = ( EB798E291DFEF81400F0628D /* Trie.swift in Sources */, EB798E001DFEF79900F0628D /* ViewController.swift in Sources */, + EB8369AD1E15C5710003A7F8 /* ReadMe.md in Sources */, EB798DFE1DFEF79900F0628D /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Trie/Trie/Trie/ReadMe.md b/Trie/Trie/Trie/ReadMe.md new file mode 100644 index 000000000..934585a3f --- /dev/null +++ b/Trie/Trie/Trie/ReadMe.md @@ -0,0 +1,33 @@ +# Changes + +- Corrected a spelling error in a comment. + +- Got rid of the `get` syntax for a read only property as the coding guidelines suggest. + +- Changed several tests so that they are more Swift-like. That is, they now feel like they are using the features of the language better. + +- Fixed a problem in the test method `testRemovePerformance`. The `measure` method runs the block of code 10 times. Previously, all words would get removed after the first run and the next 9 runs were very fast because there was nothing to do! That is corrected now. + +- Made the `Trie` class a subclass of `NSObject` and had it conform to `NSCoding`. Added a test to verify that this works. + +--- + +I wasn't able to figure out how to recursively archive the trie. Instead, I tried Kelvin's suggestion to use the `words` property to create an array of words in the trie, then archiving the array. + +There are a couple of nice aspects to this approach. + +- The `TrieNode` class can remain generic since it doesn't need to conform to `NSCoding`. + +- It doesn't require much new code. + +There are several downsides though. + +- The size of the archived words is three times the size of the original file of words! Did I do this right? The tests pass, so it seems correct. I question whether archiving is worth the effort if the resulting archive is so much larger than the original file. + +- I would expect that archiving the trie would result in a file that was smaller than the original since a trie doesn't repeat leading character sequences when they are the same. + +- This requires that the trie get reconstructed when it is unarchived. + +- My gut tells me that it would be faster to archive and unarchive the trie itself, but I don't have any hard data to support this. + +I would like to see code that recursively archives the trie so we can compare the performance. From 02ff5694e848fa5f39ab717b2c418e0fbf014190 Mon Sep 17 00:00:00 2001 From: Yohannes Wijaya Date: Fri, 30 Dec 2016 09:33:55 +0700 Subject: [PATCH 0338/1275] Added a new algorithms book under "Learn More" --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 5c769688a..6766e7025 100644 --- a/README.markdown +++ b/README.markdown @@ -198,6 +198,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 The following books are available for free online: From 89fb804a5f006f2bcbe9c55f784a277852484581 Mon Sep 17 00:00:00 2001 From: gonini Date: Mon, 2 Jan 2017 23:24:24 +0900 Subject: [PATCH 0339/1275] Updating to Swift3 I upgraded to swift 3 because it did not run as a grammar problem. --- .../Contents.swift | 24 +++++++++---------- .../timeline.xctimeline | 6 ----- .../Sources/Graph.swift | 8 +++---- .../Sources/Node.swift | 2 +- Shortest Path (Unweighted)/ShortestPath.swift | 2 +- 5 files changed, 18 insertions(+), 24 deletions(-) delete mode 100644 Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/timeline.xctimeline diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift index cfc582c49..2380ebb69 100644 --- a/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift @@ -2,15 +2,15 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { let shortestPathGraph = graph.duplicate() var queue = Queue() - let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(source.label) - queue.enqueue(sourceInShortestPathsGraph) + let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(label: source.label) + queue.enqueue(element: sourceInShortestPathsGraph) sourceInShortestPathsGraph.distance = 0 while let current = queue.dequeue() { for edge in current.neighbors { let neighborNode = edge.neighbor if !neighborNode.hasDistance { - queue.enqueue(neighborNode) + queue.enqueue(element: neighborNode) neighborNode.distance = current.distance! + 1 } } @@ -23,14 +23,14 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { let graph = Graph() -let nodeA = graph.addNode("a") -let nodeB = graph.addNode("b") -let nodeC = graph.addNode("c") -let nodeD = graph.addNode("d") -let nodeE = graph.addNode("e") -let nodeF = graph.addNode("f") -let nodeG = graph.addNode("g") -let nodeH = graph.addNode("h") +let nodeA = graph.addNode(label: "a") +let nodeB = graph.addNode(label: "b") +let nodeC = graph.addNode(label: "c") +let nodeD = graph.addNode(label: "d") +let nodeE = graph.addNode(label: "e") +let nodeF = graph.addNode(label: "f") +let nodeG = graph.addNode(label: "g") +let nodeH = graph.addNode(label: "h") graph.addEdge(nodeA, neighbor: nodeB) graph.addEdge(nodeA, neighbor: nodeC) @@ -40,5 +40,5 @@ graph.addEdge(nodeC, neighbor: nodeF) graph.addEdge(nodeC, neighbor: nodeG) graph.addEdge(nodeE, neighbor: nodeH) -let shortestPathGraph = breadthFirstSearchShortestPath(graph, source: nodeA) +let shortestPathGraph = breadthFirstSearchShortestPath(graph: graph, source: nodeA) print(shortestPathGraph.nodes) diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/timeline.xctimeline b/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift index 8cfb2a09c..8c3281aa8 100644 --- a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift @@ -11,7 +11,7 @@ public class Graph: CustomStringConvertible, Equatable { return node } - public func addEdge(source: Node, neighbor: Node) { + public func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } @@ -35,13 +35,13 @@ public class Graph: CustomStringConvertible, Equatable { let duplicated = Graph() for node in nodes { - duplicated.addNode(node.label) + duplicated.addNode(label: node.label) } for node in nodes { for edge in node.neighbors { - let source = duplicated.findNodeWithLabel(node.label) - let neighbour = duplicated.findNodeWithLabel(edge.neighbor.label) + let source = duplicated.findNodeWithLabel(label: node.label) + let neighbour = duplicated.findNodeWithLabel(label: edge.neighbor.label) duplicated.addEdge(source, neighbor: neighbour) } } diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift index 37a3b3fdf..ebdb6f4e3 100644 --- a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift @@ -23,7 +23,7 @@ public class Node: CustomStringConvertible, Equatable { } public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + neighbors.remove(at: neighbors.index { $0 === edge }!) } } diff --git a/Shortest Path (Unweighted)/ShortestPath.swift b/Shortest Path (Unweighted)/ShortestPath.swift index 13ed0c080..6aa082a96 100644 --- a/Shortest Path (Unweighted)/ShortestPath.swift +++ b/Shortest Path (Unweighted)/ShortestPath.swift @@ -10,7 +10,7 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { for edge in current.neighbors { let neighborNode = edge.neighbor if !neighborNode.hasDistance { - queue.enqueue(neighborNode) + queue.enqueue(element: neighborNode) neighborNode.distance = current.distance! + 1 } } From 998fc13118dc7d7cefb7f088d3a70719ec5ea5d1 Mon Sep 17 00:00:00 2001 From: Mohamed Emad Hegab Date: Mon, 2 Jan 2017 15:44:58 +0100 Subject: [PATCH 0340/1275] Fix for swift 3 on playground and rest of the classes --- Select Minimum Maximum/Maximum.swift | 23 ++--- Select Minimum Maximum/Minimum.swift | 23 ++--- .../MinimumMaximumPairs.swift | 63 ++++++------ Select Minimum Maximum/README.markdown | 7 +- .../Contents.swift | 99 ++++++++++--------- .../timeline.xctimeline | 6 -- 6 files changed, 112 insertions(+), 109 deletions(-) delete mode 100644 Select Minimum Maximum/SelectMinimumMaximum.playground/timeline.xctimeline diff --git a/Select Minimum Maximum/Maximum.swift b/Select Minimum Maximum/Maximum.swift index 8c78ba478..991a0544e 100644 --- a/Select Minimum Maximum/Maximum.swift +++ b/Select Minimum Maximum/Maximum.swift @@ -1,15 +1,16 @@ /* - Finds the maximum value in an array in O(n) time. -*/ + Finds the maximum value in an array in O(n) time. + */ -func maximum(var array: [T]) -> T? { - guard !array.isEmpty else { - return nil - } +func maximum(_ array: [T]) -> T? { + var array = array + guard !array.isEmpty else { + return nil + } - var maximum = array.removeFirst() - for element in array { - maximum = element > maximum ? element : maximum - } - return maximum + var maximum = array.removeFirst() + for element in array { + maximum = element > maximum ? element : maximum + } + return maximum } diff --git a/Select Minimum Maximum/Minimum.swift b/Select Minimum Maximum/Minimum.swift index 9b08deb4f..90dfbd54b 100644 --- a/Select Minimum Maximum/Minimum.swift +++ b/Select Minimum Maximum/Minimum.swift @@ -1,15 +1,16 @@ /* - Finds the minimum value in an array in O(n) time. -*/ + Finds the minimum value in an array in O(n) time. + */ -func minimum(var array: [T]) -> T? { - guard !array.isEmpty else { - return nil - } +func minimum(_ array: [T]) -> T? { + var array = array + guard !array.isEmpty else { + return nil + } - var minimum = array.removeFirst() - for element in array { - minimum = element < minimum ? element : minimum - } - return minimum + var minimum = array.removeFirst() + for element in array { + minimum = element < minimum ? element : minimum + } + return minimum } diff --git a/Select Minimum Maximum/MinimumMaximumPairs.swift b/Select Minimum Maximum/MinimumMaximumPairs.swift index 5798e1f32..b7deb570a 100644 --- a/Select Minimum Maximum/MinimumMaximumPairs.swift +++ b/Select Minimum Maximum/MinimumMaximumPairs.swift @@ -1,39 +1,40 @@ /* - Finds the maximum and minimum value in an array in O(n) time. -*/ + Finds the maximum and minimum value in an array in O(n) time. + */ -func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? { - guard !array.isEmpty else { - return nil - } +func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { + var array = array + guard !array.isEmpty else { + return nil + } - var minimum = array.first! - var maximum = array.first! + var minimum = array.first! + var maximum = array.first! - let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } + let hasOddNumberOfItems = array.count % 2 != 0 + if hasOddNumberOfItems { + array.removeFirst() + } - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) + while !array.isEmpty { + let pair = (array.removeFirst(), array.removeFirst()) - if pair.0 > pair.1 { - if pair.0 > maximum { - maximum = pair.0 - } - if pair.1 < minimum { - minimum = pair.1 - } - } else { - if pair.1 > maximum { - maximum = pair.1 - } - if pair.0 < minimum { - minimum = pair.0 - } + if pair.0 > pair.1 { + if pair.0 > maximum { + maximum = pair.0 + } + if pair.1 < minimum { + minimum = pair.1 + } + } else { + if pair.1 > maximum { + maximum = pair.1 + } + if pair.0 < minimum { + minimum = pair.0 + } + } } - } - - return (minimum, maximum) + + return (minimum, maximum) } diff --git a/Select Minimum Maximum/README.markdown b/Select Minimum Maximum/README.markdown index a67f4ec8e..09ca97039 100644 --- a/Select Minimum Maximum/README.markdown +++ b/Select Minimum Maximum/README.markdown @@ -23,7 +23,8 @@ Repeat this process until the all elements in the list have been processed. Here is a simple implementation in Swift: ```swift -func minimum(var array: [T]) -> T? { +func minimum(_ array: [T]) -> T? { + var array = array guard !array.isEmpty else { return nil } @@ -35,7 +36,8 @@ func minimum(var array: [T]) -> T? { return minimum } -func maximum(var array: [T]) -> T? { +func maximum(_ array: [T]) -> T? { + var array = array guard !array.isEmpty else { return nil } @@ -90,6 +92,7 @@ Here is a simple implementation in Swift: ```swift func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { + var array = array guard !array.isEmpty else { return nil } diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift index ef92ac1e6..6076b5246 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift @@ -1,64 +1,67 @@ // Compare each item to find minimum -func minimum(var array: [T]) -> T? { - guard !array.isEmpty else { - return nil - } +func minimum(_ array: [T]) -> T? { + var array = array + guard !array.isEmpty else { + return nil + } - var minimum = array.removeFirst() - for element in array { - minimum = element < minimum ? element : minimum - } - return minimum + var minimum = array.removeFirst() + for element in array { + minimum = element < minimum ? element : minimum + } + return minimum } // Compare each item to find maximum -func maximum(var array: [T]) -> T? { - guard !array.isEmpty else { - return nil - } +func maximum(_ array: [T]) -> T? { + var array = array + guard !array.isEmpty else { + return nil + } - var maximum = array.removeFirst() - for element in array { - maximum = element > maximum ? element : maximum - } - return maximum + var maximum = array.removeFirst() + for element in array { + maximum = element > maximum ? element : maximum + } + return maximum } // Compare in pairs to find minimum and maximum -func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? { - guard !array.isEmpty else { - return nil - } +func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { + var array = array + guard !array.isEmpty else { + return nil + } - var minimum = array.first! - var maximum = array.first! + var minimum = array.first! + var maximum = array.first! - let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } + let hasOddNumberOfItems = array.count % 2 != 0 + if hasOddNumberOfItems { + array.removeFirst() + } - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) + while !array.isEmpty { + let pair = (array.removeFirst(), array.removeFirst()) - if pair.0 > pair.1 { - if pair.0 > maximum { - maximum = pair.0 - } - if pair.1 < minimum { - minimum = pair.1 - } - } else { - if pair.1 > maximum { - maximum = pair.1 - } - if pair.0 < minimum { - minimum = pair.0 - } + if pair.0 > pair.1 { + if pair.0 > maximum { + maximum = pair.0 + } + if pair.1 < minimum { + minimum = pair.1 + } + } else { + if pair.1 > maximum { + maximum = pair.1 + } + if pair.0 < minimum { + minimum = pair.0 + } + } } - } - return (minimum, maximum) + return (minimum, maximum) } // Test of minimum and maximum functions @@ -72,5 +75,5 @@ result.minimum result.maximum // Built-in Swift functions -array.minElement() -array.maxElement() +array.min() +array.max() diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/timeline.xctimeline b/Select Minimum Maximum/SelectMinimumMaximum.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From dfc27f868b20b5ad6408238f7d97489ff518cd49 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 2 Jan 2017 07:52:15 -0800 Subject: [PATCH 0341/1275] Fixed indentation of the code. --- .../Contents.swift | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift index 6076b5246..182060805 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift @@ -1,67 +1,67 @@ // Compare each item to find minimum func minimum(_ array: [T]) -> T? { - var array = array - guard !array.isEmpty else { - return nil - } - - var minimum = array.removeFirst() - for element in array { - minimum = element < minimum ? element : minimum - } - return minimum + var array = array + guard !array.isEmpty else { + return nil + } + + var minimum = array.removeFirst() + for element in array { + minimum = element < minimum ? element : minimum + } + return minimum } // Compare each item to find maximum func maximum(_ array: [T]) -> T? { - var array = array - guard !array.isEmpty else { - return nil - } - - var maximum = array.removeFirst() - for element in array { - maximum = element > maximum ? element : maximum - } - return maximum + var array = array + guard !array.isEmpty else { + return nil + } + + var maximum = array.removeFirst() + for element in array { + maximum = element > maximum ? element : maximum + } + return maximum } // Compare in pairs to find minimum and maximum func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { - var array = array - guard !array.isEmpty else { - return nil + var array = array + guard !array.isEmpty else { + return nil + } + + var minimum = array.first! + var maximum = array.first! + + let hasOddNumberOfItems = array.count % 2 != 0 + if hasOddNumberOfItems { + array.removeFirst() + } + + while !array.isEmpty { + let pair = (array.removeFirst(), array.removeFirst()) + + if pair.0 > pair.1 { + if pair.0 > maximum { + maximum = pair.0 + } + if pair.1 < minimum { + minimum = pair.1 + } + } else { + if pair.1 > maximum { + maximum = pair.1 + } + if pair.0 < minimum { + minimum = pair.0 + } } - - var minimum = array.first! - var maximum = array.first! - - let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } - - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) - - if pair.0 > pair.1 { - if pair.0 > maximum { - maximum = pair.0 - } - if pair.1 < minimum { - minimum = pair.1 - } - } else { - if pair.1 > maximum { - maximum = pair.1 - } - if pair.0 < minimum { - minimum = pair.0 - } - } - } - - return (minimum, maximum) + } + + return (minimum, maximum) } // Test of minimum and maximum functions From 728d749d535359788d701296ce338b681fa18b1d Mon Sep 17 00:00:00 2001 From: Zhang Date: Tue, 3 Jan 2017 08:54:29 +0900 Subject: [PATCH 0342/1275] Update README. Convert to swift 3.0 syntax. --- Shortest Path (Unweighted)/README.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Shortest Path (Unweighted)/README.markdown b/Shortest Path (Unweighted)/README.markdown index 0107964ae..a16519260 100644 --- a/Shortest Path (Unweighted)/README.markdown +++ b/Shortest Path (Unweighted)/README.markdown @@ -23,7 +23,7 @@ The root of the tree is the node you started the breadth-first search from. To f Let's put breadth-first search into practice and calculate the shortest path from `A` to all the other nodes. We start with the source node `A` and add it to a queue with a distance of `0`. ```swift -queue.enqueue(A) +queue.enqueue(element: A) A.distance = 0 ``` @@ -31,9 +31,9 @@ The queue is now `[ A ]`. We dequeue `A` and enqueue its two immediate neighbor ```swift queue.dequeue() // A -queue.enqueue(B) +queue.enqueue(element: B) B.distance = A.distance + 1 // result: 1 -queue.enqueue(C) +queue.enqueue(element: C) C.distance = A.distance + 1 // result: 1 ``` @@ -41,9 +41,9 @@ The queue is now `[ B, C ]`. Dequeue `B` and enqueue `B`'s neighbor nodes `D` an ```swift queue.dequeue() // B -queue.enqueue(D) +queue.enqueue(element: D) D.distance = B.distance + 1 // result: 2 -queue.enqueue(E) +queue.enqueue(element: E) E.distance = B.distance + 1 // result: 2 ``` @@ -51,9 +51,9 @@ The queue is now `[ C, D, E ]`. Dequeue `C` and enqueue `C`'s neighbor nodes `F` ```swift queue.dequeue() // C -queue.enqueue(F) +queue.enqueue(element: F) F.distance = C.distance + 1 // result: 2 -queue.enqueue(G) +queue.enqueue(element: G) G.distance = C.distance + 1 // result: 2 ``` @@ -66,15 +66,15 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { let shortestPathGraph = graph.duplicate() var queue = Queue() - let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(source.label) - queue.enqueue(sourceInShortestPathsGraph) + let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(label: source.label) + queue.enqueue(element: sourceInShortestPathsGraph) sourceInShortestPathsGraph.distance = 0 while let current = queue.dequeue() { for edge in current.neighbors { let neighborNode = edge.neighbor if !neighborNode.hasDistance { - queue.enqueue(neighborNode) + queue.enqueue(element: neighborNode) neighborNode.distance = current.distance! + 1 } } @@ -87,7 +87,7 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { Put this code in a playground and test it like so: ```swift -let shortestPathGraph = breadthFirstSearchShortestPath(graph, source: nodeA) +let shortestPathGraph = breadthFirstSearchShortestPath(graph: graph, source: nodeA) print(shortestPathGraph.nodes) ``` From b2688ad3cb3a9705aa73aa8fe54773192acd90a2 Mon Sep 17 00:00:00 2001 From: Zhang Date: Tue, 3 Jan 2017 09:26:34 +0900 Subject: [PATCH 0343/1275] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b5faffa6..f6c64488d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ script: # - 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 ./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 From 6aab6200651772d8f6f7c1e7cf641f2242a784fe Mon Sep 17 00:00:00 2001 From: gonini Date: Tue, 3 Jan 2017 09:40:13 +0900 Subject: [PATCH 0344/1275] Updated with XCTest Swift3 syntax for shortest path --- Shortest Path (Unweighted)/Tests/Graph.swift | 159 +++++++++--------- .../Tests/ShortestPathTests.swift | 72 ++++---- 2 files changed, 116 insertions(+), 115 deletions(-) diff --git a/Shortest Path (Unweighted)/Tests/Graph.swift b/Shortest Path (Unweighted)/Tests/Graph.swift index ed71cab7c..0d2a735c2 100644 --- a/Shortest Path (Unweighted)/Tests/Graph.swift +++ b/Shortest Path (Unweighted)/Tests/Graph.swift @@ -1,106 +1,107 @@ // MARK: - Edge public class Edge: Equatable { - public var neighbor: Node - - public init(neighbor: Node) { - self.neighbor = neighbor - } + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } } public func == (lhs: Edge, rhs: Edge) -> Bool { - return lhs.neighbor == rhs.neighbor + return lhs.neighbor == rhs.neighbor } + // MARK: - Node public class Node: CustomStringConvertible, Equatable { - public var neighbors: [Edge] - - public private(set) var label: String - public var distance: Int? - public var visited: Bool - - public init(label: String) { - self.label = label - neighbors = [] - visited = false - } - - public var description: String { - if let distance = distance { - return "Node(label: \(label), distance: \(distance))" + public var neighbors: [Edge] + + public private(set) var label: String + public var distance: Int? + public var visited: Bool + + public init(label: String) { + self.label = label + neighbors = [] + visited = false + } + + public var description: String { + if let distance = distance { + return "Node(label: \(label), distance: \(distance))" + } + return "Node(label: \(label), distance: infinity)" + } + + public var hasDistance: Bool { + return distance != nil + } + + public func remove(edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } - return "Node(label: \(label), distance: infinity)" - } - - public var hasDistance: Bool { - return distance != nil - } - - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) - } } public func == (lhs: Node, rhs: Node) -> Bool { - return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors } // MARK: - Graph public class Graph: CustomStringConvertible, Equatable { - public private(set) var nodes: [Node] - - public init() { - self.nodes = [] - } - - public func addNode(label: String) -> Node { - let node = Node(label: label) - nodes.append(node) - return node - } - - public func addEdge(source: Node, neighbor: Node) { - let edge = Edge(neighbor: neighbor) - source.neighbors.append(edge) - } - - public var description: String { - var description = "" - - for node in nodes { - if !node.neighbors.isEmpty { - description += "[node: \(node.label) edges: \(node.neighbors.map { $0.neighbor.label})]" - } + public private(set) var nodes: [Node] + + public init() { + self.nodes = [] } - return description - } - - public func findNodeWithLabel(label: String) -> Node { - return nodes.filter { $0.label == label }.first! - } - - public func duplicate() -> Graph { - let duplicated = Graph() - - for node in nodes { - duplicated.addNode(node.label) + + public func addNode(label: String) -> Node { + let node = Node(label: label) + nodes.append(node) + return node } - - for node in nodes { - for edge in node.neighbors { - let source = duplicated.findNodeWithLabel(node.label) - let neighbour = duplicated.findNodeWithLabel(edge.neighbor.label) - duplicated.addEdge(source, neighbor: neighbour) - } + + public func addEdge(_ source: Node, neighbor: Node) { + let edge = Edge(neighbor: neighbor) + source.neighbors.append(edge) + } + + public var description: String { + var description = "" + + for node in nodes { + if !node.neighbors.isEmpty { + description += "[node: \(node.label) edges: \(node.neighbors.map { $0.neighbor.label})]" + } + } + return description + } + + public func findNodeWithLabel(label: String) -> Node { + return nodes.filter { $0.label == label }.first! + } + + public func duplicate() -> Graph { + let duplicated = Graph() + + for node in nodes { + duplicated.addNode(label: node.label) + } + + for node in nodes { + for edge in node.neighbors { + let source = duplicated.findNodeWithLabel(label: node.label) + let neighbour = duplicated.findNodeWithLabel(label: edge.neighbor.label) + duplicated.addEdge(source, neighbor: neighbour) + } + } + + return duplicated } - - return duplicated - } } public func == (lhs: Graph, rhs: Graph) -> Bool { - return lhs.nodes == rhs.nodes + return lhs.nodes == rhs.nodes } diff --git a/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift b/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift index 003f3cf20..71b9f88ab 100644 --- a/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift +++ b/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift @@ -4,14 +4,14 @@ class ShortestPathTests: XCTestCase { func testShortestPathWhenGivenTree() { let tree = Graph() - let nodeA = tree.addNode("a") - let nodeB = tree.addNode("b") - let nodeC = tree.addNode("c") - let nodeD = tree.addNode("d") - let nodeE = tree.addNode("e") - let nodeF = tree.addNode("f") - let nodeG = tree.addNode("g") - let nodeH = tree.addNode("h") + let nodeA = tree.addNode(label: "a") + let nodeB = tree.addNode(label: "b") + let nodeC = tree.addNode(label: "c") + let nodeD = tree.addNode(label: "d") + let nodeE = tree.addNode(label: "e") + let nodeF = tree.addNode(label: "f") + let nodeG = tree.addNode(label: "g") + let nodeH = tree.addNode(label: "h") tree.addEdge(nodeA, neighbor: nodeB) tree.addEdge(nodeA, neighbor: nodeC) tree.addEdge(nodeB, neighbor: nodeD) @@ -20,30 +20,30 @@ class ShortestPathTests: XCTestCase { tree.addEdge(nodeC, neighbor: nodeG) tree.addEdge(nodeE, neighbor: nodeH) - let shortestPaths = breadthFirstSearchShortestPath(tree, source: nodeA) + let shortestPaths = breadthFirstSearchShortestPath(graph: tree, source: nodeA) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeA.label).distance, 0) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeB.label).distance, 1) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeC.label).distance, 1) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeD.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeE.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeF.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeG.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeH.label).distance, 3) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeA.label).distance, 0) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeB.label).distance, 1) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeC.label).distance, 1) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeD.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeE.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeF.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeG.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeH.label).distance, 3) } func testShortestPathWhenGivenGraph() { let graph = Graph() - let nodeA = graph.addNode("a") - let nodeB = graph.addNode("b") - let nodeC = graph.addNode("c") - let nodeD = graph.addNode("d") - let nodeE = graph.addNode("e") - let nodeF = graph.addNode("f") - let nodeG = graph.addNode("g") - let nodeH = graph.addNode("h") - let nodeI = graph.addNode("i") + let nodeA = graph.addNode(label:"a") + let nodeB = graph.addNode(label:"b") + let nodeC = graph.addNode(label:"c") + let nodeD = graph.addNode(label:"d") + let nodeE = graph.addNode(label:"e") + let nodeF = graph.addNode(label:"f") + let nodeG = graph.addNode(label:"g") + let nodeH = graph.addNode(label:"h") + let nodeI = graph.addNode(label:"i") graph.addEdge(nodeA, neighbor: nodeB) graph.addEdge(nodeA, neighbor: nodeH) @@ -74,16 +74,16 @@ class ShortestPathTests: XCTestCase { graph.addEdge(nodeI, neighbor: nodeG) graph.addEdge(nodeI, neighbor: nodeH) - let shortestPaths = breadthFirstSearchShortestPath(graph, source: nodeA) + let shortestPaths = breadthFirstSearchShortestPath(graph: graph, source: nodeA) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeA.label).distance, 0) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeB.label).distance, 1) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeC.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeD.label).distance, 3) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeE.label).distance, 4) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeF.label).distance, 3) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeG.label).distance, 2) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeH.label).distance, 1) - XCTAssertEqual(shortestPaths.findNodeWithLabel(nodeI.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeA.label).distance, 0) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeB.label).distance, 1) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeC.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeD.label).distance, 3) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeE.label).distance, 4) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeF.label).distance, 3) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeG.label).distance, 2) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeH.label).distance, 1) + XCTAssertEqual(shortestPaths.findNodeWithLabel(label: nodeI.label).distance, 2) } } From 6eed97951a180899d8887c739bdb493e554e99da Mon Sep 17 00:00:00 2001 From: gonini Date: Tue, 3 Jan 2017 09:51:16 +0900 Subject: [PATCH 0345/1275] Updated with XCTest Swift3 syntax for shortest path XCTest Success --- Shortest Path (Unweighted)/ShortestPath.swift | 4 +-- Shortest Path (Unweighted)/Tests/Graph.swift | 34 +++++++++---------- Shortest Path (Unweighted)/Tests/Queue.swift | 2 +- .../Tests/Tests.xcodeproj/project.pbxproj | 3 ++ 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Shortest Path (Unweighted)/ShortestPath.swift b/Shortest Path (Unweighted)/ShortestPath.swift index 6aa082a96..555ad893b 100644 --- a/Shortest Path (Unweighted)/ShortestPath.swift +++ b/Shortest Path (Unweighted)/ShortestPath.swift @@ -2,8 +2,8 @@ func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { let shortestPathGraph = graph.duplicate() var queue = Queue() - let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(source.label) - queue.enqueue(sourceInShortestPathsGraph) + let sourceInShortestPathsGraph = shortestPathGraph.findNodeWithLabel(label: source.label) + queue.enqueue(element: sourceInShortestPathsGraph) sourceInShortestPathsGraph.distance = 0 while let current = queue.dequeue() { diff --git a/Shortest Path (Unweighted)/Tests/Graph.swift b/Shortest Path (Unweighted)/Tests/Graph.swift index 0d2a735c2..8322ba0a9 100644 --- a/Shortest Path (Unweighted)/Tests/Graph.swift +++ b/Shortest Path (Unweighted)/Tests/Graph.swift @@ -1,7 +1,7 @@ // MARK: - Edge -public class Edge: Equatable { - public var neighbor: Node +open class Edge: Equatable { + open var neighbor: Node public init(neighbor: Node) { self.neighbor = neighbor @@ -15,12 +15,12 @@ public func == (lhs: Edge, rhs: Edge) -> Bool { // MARK: - Node -public class Node: CustomStringConvertible, Equatable { - public var neighbors: [Edge] +open class Node: CustomStringConvertible, Equatable { + open var neighbors: [Edge] - public private(set) var label: String - public var distance: Int? - public var visited: Bool + open fileprivate(set) var label: String + open var distance: Int? + open var visited: Bool public init(label: String) { self.label = label @@ -28,18 +28,18 @@ public class Node: CustomStringConvertible, Equatable { visited = false } - public var description: String { + open var description: String { if let distance = distance { return "Node(label: \(label), distance: \(distance))" } return "Node(label: \(label), distance: infinity)" } - public var hasDistance: Bool { + open var hasDistance: Bool { return distance != nil } - public func remove(edge: Edge) { + open func remove(_ edge: Edge) { neighbors.remove(at: neighbors.index { $0 === edge }!) } } @@ -50,25 +50,25 @@ public func == (lhs: Node, rhs: Node) -> Bool { // MARK: - Graph -public class Graph: CustomStringConvertible, Equatable { - public private(set) var nodes: [Node] +open class Graph: CustomStringConvertible, Equatable { + open fileprivate(set) var nodes: [Node] public init() { self.nodes = [] } - public func addNode(label: String) -> Node { + open func addNode(label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - public func addEdge(_ source: Node, neighbor: Node) { + open func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } - public var description: String { + open var description: String { var description = "" for node in nodes { @@ -79,11 +79,11 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + open func findNodeWithLabel(label: String) -> Node { return nodes.filter { $0.label == label }.first! } - public func duplicate() -> Graph { + open func duplicate() -> Graph { let duplicated = Graph() for node in nodes { diff --git a/Shortest Path (Unweighted)/Tests/Queue.swift b/Shortest Path (Unweighted)/Tests/Queue.swift index bf462bbdd..0d8752466 100644 --- a/Shortest Path (Unweighted)/Tests/Queue.swift +++ b/Shortest Path (Unweighted)/Tests/Queue.swift @@ -1,5 +1,5 @@ public struct Queue { - private var array: [T] + fileprivate var array: [T] public init() { array = [] diff --git a/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj index 35aeffa54..f1744fcf1 100644 --- a/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj +++ b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -94,6 +94,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -230,6 +231,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -242,6 +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 = 3.0; }; name = Release; }; From 914441ec8285ae1e8354c22f692a81ae9bb70de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Tue, 3 Jan 2017 14:40:59 +0100 Subject: [PATCH 0346/1275] converts Huffman Coding to Swift 3 syntax --- .../Huffman.playground/Contents.swift | 10 +- .../Huffman.playground/Sources/Heap.swift | 34 +- .../Huffman.playground/Sources/Huffman.swift | 30 +- .../Sources/NSData+Bits.swift | 8 +- .../Sources/PriorityQueue.swift | 8 +- .../Huffman.playground/timeline.xctimeline | 10 + Huffman Coding/Huffman.swift | 294 +++++++++--------- Huffman Coding/NSData+Bits.swift | 76 ++--- Huffman Coding/README.markdown | 52 ++-- 9 files changed, 265 insertions(+), 257 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index b67f93a6a..017c5baf2 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -3,21 +3,21 @@ import Foundation let s1 = "so much words wow many compression" -if let originalData = s1.dataUsingEncoding(NSUTF8StringEncoding) { - print(originalData.length) +if let originalData = s1.data(using: String.Encoding.utf8) { + print(originalData.count) let huffman1 = Huffman() - let compressedData = huffman1.compressData(originalData) + let compressedData = huffman1.compressData(data: originalData as NSData) print(compressedData.length) let frequencyTable = huffman1.frequencyTable() //print(frequencyTable) let huffman2 = Huffman() - let decompressedData = huffman2.decompressData(compressedData, frequencyTable: frequencyTable) + let decompressedData = huffman2.decompressData(data: compressedData, frequencyTable: frequencyTable) print(decompressedData.length) - let s2 = String(data: decompressedData, encoding: NSUTF8StringEncoding)! + let s2 = String(data: decompressedData as Data, encoding: String.Encoding.utf8)! print(s2) assert(s1 == s2) } diff --git a/Huffman Coding/Huffman.playground/Sources/Heap.swift b/Huffman Coding/Huffman.playground/Sources/Heap.swift index 64bd90cd8..5ace98a17 100644 --- a/Huffman Coding/Huffman.playground/Sources/Heap.swift +++ b/Huffman Coding/Huffman.playground/Sources/Heap.swift @@ -8,14 +8,14 @@ public struct Heap { var elements = [T]() /** Determines whether this is a max-heap (>) or min-heap (<). */ - private var isOrderedBefore: (T, T) -> Bool + fileprivate var isOrderedBefore: (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. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort } @@ -24,9 +24,9 @@ public struct Heap { * the elements are inserted into the heap in the order determined by the * sort function. */ - public init(array: [T], sort: (T, T) -> Bool) { + public init(array: [T], sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort - buildHeap(array) + buildHeap(array: array) } /* @@ -45,7 +45,7 @@ public struct Heap { */ private mutating func buildHeap(array: [T]) { elements = array - for i in (elements.count/2 - 1).stride(through: 0, by: -1) { + for i in stride(from: elements.count/2 - 1, to: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) } } @@ -96,12 +96,12 @@ public struct Heap { * 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). */ - public mutating func insert(value: T) { + public mutating func insert(_ value: T) { elements.append(value) shiftUp(index: elements.count - 1) } - public mutating func insert(sequence: S) { + public mutating func insert(sequence: S) where S.Iterator.Element == T { for value in sequence { insert(value) } @@ -154,15 +154,15 @@ 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 index: Int) { + mutating func shiftUp(index: Int) { var childIndex = index let child = elements[childIndex] - var parentIndex = indexOfParent(childIndex) + var parentIndex = indexOfParent(i: childIndex) while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { elements[childIndex] = elements[parentIndex] childIndex = parentIndex - parentIndex = indexOfParent(childIndex) + parentIndex = indexOfParent(i: childIndex) } elements[childIndex] = child @@ -176,11 +176,11 @@ public struct Heap { * 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 index: Int, heapSize: Int) { + mutating func shiftDown(index: Int, heapSize: Int) { var parentIndex = index while true { - let leftChildIndex = indexOfLeftChild(parentIndex) + let leftChildIndex = indexOfLeftChild(i: parentIndex) let rightChildIndex = leftChildIndex + 1 // Figure out which comes first if we order them by the sort function: @@ -208,16 +208,16 @@ extension Heap where T: Equatable { /** * Searches the heap for the given element. Performance: O(n). */ - public func indexOf(element: T) -> Int? { - return indexOf(element, 0) + public func index(of element: T) -> Int? { + return index(of: element, 0) } - private func indexOf(element: T, _ i: Int) -> Int? { + private 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 = indexOf(element, indexOfLeftChild(i)) { return j } - if let j = indexOf(element, indexOfRightChild(i)) { return j } + if let j = index(of: element, indexOfLeftChild(i: i)) { return j } + if let j = index(of: element, indexOfRightChild(i: i)) { return j } return nil } } diff --git a/Huffman Coding/Huffman.playground/Sources/Huffman.swift b/Huffman Coding/Huffman.playground/Sources/Huffman.swift index d50b90d82..79b24b09a 100644 --- a/Huffman Coding/Huffman.playground/Sources/Huffman.swift +++ b/Huffman Coding/Huffman.playground/Sources/Huffman.swift @@ -29,7 +29,7 @@ public class Huffman { /* The tree structure. The first 256 entries are for the leaf nodes (not all of those may be used, depending on the input). We add additional nodes as we build the tree. */ - var tree = [Node](count: 256, repeatedValue: Node()) + var tree = [Node](repeating: Node(), count: 256) /* This is the last node we add to the tree. */ var root: NodeIndex = -1 @@ -50,10 +50,10 @@ extension Huffman { occurs. These counts are stored in the first 256 nodes in the tree, i.e. the leaf nodes. The frequency table used by decompression is derived from this. */ - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0..(sort: { $0.count < $1.count }) for node in tree where node.count > 0 { @@ -123,13 +123,13 @@ extension Huffman { extension Huffman { /* Compresses the contents of an NSData object. */ public func compressData(data: NSData) -> NSData { - countByteFrequency(data) + countByteFrequency(inData: data) buildTree() let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0.. NSData { - restoreTree(frequencyTable) + restoreTree(fromTable: frequencyTable) let reader = BitReader(data: data) let outData = NSMutableData() @@ -167,7 +167,7 @@ extension Huffman { var i = 0 while i < byteCount { var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) + outData.append(&b, length: 1) i += 1 } return outData @@ -177,7 +177,7 @@ extension Huffman { next bit and use that to determine whether to step to the left or right. When we get to the leaf node, we simply return its index, which is equal to the original byte value. */ - private func findLeafNode(reader reader: BitReader, nodeIndex: Int) -> UInt8 { + private func findLeafNode(reader: BitReader, nodeIndex: Int) -> UInt8 { var h = nodeIndex while tree[h].right != -1 { if reader.readBit() { diff --git a/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift index 0aa821f72..3e5163521 100644 --- a/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift +++ b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift @@ -8,7 +8,7 @@ public class BitWriter { public func writeBit(bit: Bool) { if outCount == 8 { - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) outCount = 0 } outByte = (outByte << 1) | (bit ? 1 : 0) @@ -21,7 +21,7 @@ public class BitWriter { let diff = UInt8(8 - outCount) outByte <<= diff } - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) } } } @@ -33,12 +33,12 @@ public class BitReader { var inCount = 8 public init(data: NSData) { - ptr = UnsafePointer(data.bytes) + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) } public func readBit() -> Bool { if inCount == 8 { - inByte = ptr.memory // load the next byte + inByte = ptr.pointee // load the next byte inCount = 0 ptr = ptr.successor() } diff --git a/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift b/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift index 757a6c539..4cc9d15ed 100644 --- a/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift +++ b/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift @@ -11,13 +11,13 @@ queue (largest element first) or a min-priority queue (smallest element first). */ public struct PriorityQueue { - private var heap: Heap + fileprivate var heap: Heap /* To create a max-priority queue, supply a > sort function. For a min-priority queue, use <. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { heap = Heap(sort: sort) } @@ -33,7 +33,7 @@ public struct PriorityQueue { return heap.peek() } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { heap.insert(element) } @@ -53,6 +53,6 @@ public struct PriorityQueue { extension PriorityQueue where T: Equatable { public func indexOf(element: T) -> Int? { - return heap.indexOf(element) + return heap.index(of: element) } } diff --git a/Huffman Coding/Huffman.playground/timeline.xctimeline b/Huffman Coding/Huffman.playground/timeline.xctimeline index bf468afec..2b2555bb1 100644 --- a/Huffman Coding/Huffman.playground/timeline.xctimeline +++ b/Huffman Coding/Huffman.playground/timeline.xctimeline @@ -2,5 +2,15 @@ + + + + diff --git a/Huffman Coding/Huffman.swift b/Huffman Coding/Huffman.swift index d50b90d82..7e2961a2f 100644 --- a/Huffman Coding/Huffman.swift +++ b/Huffman Coding/Huffman.swift @@ -1,191 +1,191 @@ import Foundation /* - Basic implementation of Huffman encoding. It encodes bytes that occur often - with a smaller number of bits than bytes that occur less frequently. - - Based on Al Stevens' C Programming column from Dr.Dobb's Magazine, February - 1991 and October 1992. - - Note: This code is not optimized for speed but explanation. -*/ + Basic implementation of Huffman encoding. It encodes bytes that occur often + with a smaller number of bits than bytes that occur less frequently. + + Based on Al Stevens' C Programming column from Dr.Dobb's Magazine, February + 1991 and October 1992. + + Note: This code is not optimized for speed but explanation. + */ public class Huffman { - /* Tree nodes don't use pointers to refer to each other, but simple integer + /* Tree nodes don't use pointers to refer to each other, but simple integer indices. That allows us to use structs for the nodes. */ - typealias NodeIndex = Int - - /* A node in the compression tree. Leaf nodes represent the actual bytes that + typealias NodeIndex = Int + + /* A node in the compression tree. Leaf nodes represent the actual bytes that are present in the input data. The count of an intermediary node is the sum of the counts of all nodes below it. The root node's count is the number of bytes in the original, uncompressed input data. */ - struct Node { - var count = 0 - var index: NodeIndex = -1 - var parent: NodeIndex = -1 - var left: NodeIndex = -1 - var right: NodeIndex = -1 - } - - /* The tree structure. The first 256 entries are for the leaf nodes (not all + struct Node { + var count = 0 + var index: NodeIndex = -1 + var parent: NodeIndex = -1 + var left: NodeIndex = -1 + var right: NodeIndex = -1 + } + + /* The tree structure. The first 256 entries are for the leaf nodes (not all of those may be used, depending on the input). We add additional nodes as we build the tree. */ - var tree = [Node](count: 256, repeatedValue: Node()) - - /* This is the last node we add to the tree. */ - var root: NodeIndex = -1 - - /* The frequency table describes how often a byte occurs in the input data. + var tree = [Node](repeating: Node(), count: 256) + + /* This is the last node we add to the tree. */ + var root: NodeIndex = -1 + + /* The frequency table describes how often a byte occurs in the input data. You need it to decompress the Huffman-encoded data. The frequency table should be serialized along with the compressed data. */ - public struct Freq { - var byte: UInt8 = 0 - var count = 0 - } - - public init() { } + public struct Freq { + var byte: UInt8 = 0 + var count = 0 + } + + public init() { } } extension Huffman { - /* To compress a block of data, first we need to count how often each byte + /* To compress a block of data, first we need to count how often each byte occurs. These counts are stored in the first 256 nodes in the tree, i.e. the leaf nodes. The frequency table used by decompression is derived from this. */ - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) - for _ in 0.. [Freq] { - var a = [Freq]() - for i in 0..<256 where tree[i].count > 0 { - a.append(Freq(byte: UInt8(i), count: tree[i].count)) + public func frequencyTable() -> [Freq] { + var a = [Freq]() + for i in 0..<256 where tree[i].count > 0 { + a.append(Freq(byte: UInt8(i), count: tree[i].count)) + } + return a } - return a - } } extension Huffman { - /* Builds a Huffman tree from a frequency table. */ - private func buildTree() { - // Create a min-priority queue and enqueue all used nodes. - var queue = PriorityQueue(sort: { $0.count < $1.count }) - for node in tree where node.count > 0 { - queue.enqueue(node) + /* Builds a Huffman tree from a frequency table. */ + fileprivate func buildTree() { + // Create a min-priority queue and enqueue all used nodes. + var queue = PriorityQueue(sort: { $0.count < $1.count }) + for node in tree where node.count > 0 { + queue.enqueue(node) + } + + while queue.count > 1 { + // Find the two nodes with the smallest frequencies that do not have + // a parent node yet. + let node1 = queue.dequeue()! + let node2 = queue.dequeue()! + + // Create a new intermediate node. + var parentNode = Node() + parentNode.count = node1.count + node2.count + parentNode.left = node1.index + parentNode.right = node2.index + parentNode.index = tree.count + tree.append(parentNode) + + // Link the two nodes into their new parent node. + tree[node1.index].parent = parentNode.index + tree[node2.index].parent = parentNode.index + + // Put the intermediate node back into the queue. + queue.enqueue(parentNode) + } + + // The final remaining node in the queue becomes the root of the tree. + let rootNode = queue.dequeue()! + root = rootNode.index } - - while queue.count > 1 { - // Find the two nodes with the smallest frequencies that do not have - // a parent node yet. - let node1 = queue.dequeue()! - let node2 = queue.dequeue()! - - // Create a new intermediate node. - var parentNode = Node() - parentNode.count = node1.count + node2.count - parentNode.left = node1.index - parentNode.right = node2.index - parentNode.index = tree.count - tree.append(parentNode) - - // Link the two nodes into their new parent node. - tree[node1.index].parent = parentNode.index - tree[node2.index].parent = parentNode.index - - // Put the intermediate node back into the queue. - queue.enqueue(parentNode) - } - - // The final remaining node in the queue becomes the root of the tree. - let rootNode = queue.dequeue()! - root = rootNode.index - } } extension Huffman { - /* Compresses the contents of an NSData object. */ - public func compressData(data: NSData) -> NSData { - countByteFrequency(data) - buildTree() - - let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) - for _ in 0.. NSData { + countByteFrequency(inData: data) + buildTree() + + let writer = BitWriter() + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + for _ in 0.. NSData { - restoreTree(frequencyTable) - - let reader = BitReader(data: data) - let outData = NSMutableData() - let byteCount = tree[root].count - - var i = 0 - while i < byteCount { - var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) - i += 1 + /* Takes a Huffman-compressed NSData object and outputs the uncompressed data. */ + public func decompressData(data: NSData, frequencyTable: [Freq]) -> NSData { + restoreTree(fromTable: frequencyTable) + + let reader = BitReader(data: data) + let outData = NSMutableData() + let byteCount = tree[root].count + + var i = 0 + while i < byteCount { + var b = findLeafNode(reader: reader, nodeIndex: root) + outData.append(&b, length: 1) + i += 1 + } + return outData } - return outData - } - - /* Walks the tree from the root down to the leaf node. At every node, read the + + /* Walks the tree from the root down to the leaf node. At every node, read the next bit and use that to determine whether to step to the left or right. When we get to the leaf node, we simply return its index, which is equal to the original byte value. */ - private func findLeafNode(reader reader: BitReader, nodeIndex: Int) -> UInt8 { - var h = nodeIndex - while tree[h].right != -1 { - if reader.readBit() { - h = tree[h].left - } else { - h = tree[h].right - } + private func findLeafNode(reader: BitReader, nodeIndex: Int) -> UInt8 { + var h = nodeIndex + while tree[h].right != -1 { + if reader.readBit() { + h = tree[h].left + } else { + h = tree[h].right + } + } + return UInt8(h) } - return UInt8(h) - } } diff --git a/Huffman Coding/NSData+Bits.swift b/Huffman Coding/NSData+Bits.swift index 0aa821f72..4ae3c5c6d 100644 --- a/Huffman Coding/NSData+Bits.swift +++ b/Huffman Coding/NSData+Bits.swift @@ -2,49 +2,49 @@ import Foundation /* Helper class for writing bits to an NSData object. */ public class BitWriter { - public var data = NSMutableData() - var outByte: UInt8 = 0 - var outCount = 0 - - public func writeBit(bit: Bool) { - if outCount == 8 { - data.appendBytes(&outByte, length: 1) - outCount = 0 + public var data = NSMutableData() + var outByte: UInt8 = 0 + var outCount = 0 + + public func writeBit(bit: Bool) { + if outCount == 8 { + data.append(&outByte, length: 1) + outCount = 0 + } + outByte = (outByte << 1) | (bit ? 1 : 0) + outCount += 1 } - outByte = (outByte << 1) | (bit ? 1 : 0) - outCount += 1 - } - - public func flush() { - if outCount > 0 { - if outCount < 8 { - let diff = UInt8(8 - outCount) - outByte <<= diff - } - data.appendBytes(&outByte, length: 1) + + public func flush() { + if outCount > 0 { + if outCount < 8 { + let diff = UInt8(8 - outCount) + outByte <<= diff + } + data.append(&outByte, length: 1) + } } - } } /* Helper class for reading bits from an NSData object. */ public class BitReader { - var ptr: UnsafePointer - var inByte: UInt8 = 0 - var inCount = 8 - - public init(data: NSData) { - ptr = UnsafePointer(data.bytes) - } - - public func readBit() -> Bool { - if inCount == 8 { - inByte = ptr.memory // load the next byte - inCount = 0 - ptr = ptr.successor() + var ptr: UnsafePointer + var inByte: UInt8 = 0 + var inCount = 8 + + public init(data: NSData) { + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + } + + public func readBit() -> Bool { + if inCount == 8 { + inByte = ptr.pointee // load the next byte + inCount = 0 + ptr = ptr.successor() + } + let bit = inByte & 0x80 // read the next bit + inByte <<= 1 + inCount += 1 + return bit == 0 ? false : true } - let bit = inByte & 0x80 // read the next bit - inByte <<= 1 - inCount += 1 - return bit == 0 ? false : true - } } diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 528ba3a1d..6b2c0d245 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -70,10 +70,10 @@ public class BitWriter { public var data = NSMutableData() var outByte: UInt8 = 0 var outCount = 0 - + public func writeBit(bit: Bool) { if outCount == 8 { - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) outCount = 0 } outByte = (outByte << 1) | (bit ? 1 : 0) @@ -86,7 +86,7 @@ public class BitWriter { let diff = UInt8(8 - outCount) outByte <<= diff } - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) } } } @@ -103,14 +103,14 @@ public class BitReader { var ptr: UnsafePointer var inByte: UInt8 = 0 var inCount = 8 - + public init(data: NSData) { - ptr = UnsafePointer(data.bytes) + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) } - + public func readBit() -> Bool { if inCount == 8 { - inByte = ptr.memory // load the next byte + inByte = ptr.pointee // load the next byte inCount = 0 ptr = ptr.successor() } @@ -145,8 +145,8 @@ class Huffman { var left: NodeIndex = -1 var right: NodeIndex = -1 } - - var tree = [Node](count: 256, repeatedValue: Node()) + + var tree = [Node](repeating: Node(), count: 256) var root: NodeIndex = -1 } @@ -159,10 +159,10 @@ Note that `tree` currently has room for 256 entries. These are for the leaf node We use the following method to count how often each byte occurs in the input data: ```swift - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0..(sort: { $0.count < $1.count }) for node in tree where node.count > 0 { queue.enqueue(node) // 1 @@ -252,7 +252,7 @@ Here is how it works step-by-step: 4. Link the two nodes into their new parent node. Now this new intermediate node has become part of the tree. -5. Put the new intermediate node back into the queue. At this point we're done with `node1` and `node2`, but the `parentNode` stills need to be connected to other nodes in the tree. +5. Put the new intermediate node back into the queue. At this point we're done with `node1` and `node2`, but the `parentNode` still need to be connected to other nodes in the tree. 6. Repeat steps 2-5 until there is only one node left in the queue. This becomes the root node of the tree, and we're done. @@ -269,20 +269,18 @@ The animation shows what the process looks like: Now that we know how to build the compression tree from the frequency table, we can use it to compress the contents of an `NSData` object. Here is the code: ```swift - func compressData(data: NSData) -> NSData { - countByteFrequency(data) + public func compressData(data: NSData) -> NSData { + countByteFrequency(inData: data) buildTree() - - let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) + let writer = BitWriter() + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0.. NSData { - restoreTree(frequencyTable) + restoreTree(fromTable: frequencyTable) let reader = BitReader(data: data) let outData = NSMutableData() @@ -364,7 +362,7 @@ Here is the code for `decompressData()`, which takes an `NSData` object with Huf var i = 0 while i < byteCount { var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) + outData.append(&b, length: 1) i += 1 } return outData From 1e9ebe41a2a74c3a7dc4c01a2176ae14e5f63864 Mon Sep 17 00:00:00 2001 From: zaccone Date: Tue, 3 Jan 2017 18:21:23 -0500 Subject: [PATCH 0347/1275] Added super.init() to the initializer. --- Trie/Trie/Trie.xcodeproj/project.pbxproj | 2 -- Trie/Trie/Trie/Trie.swift | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 055885ee1..90c5734cc 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ EB798E2A1DFEF81400F0628D /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB798E281DFEF81400F0628D /* Trie.swift */; }; EB798E2C1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; EB798E2D1DFEF90B00F0628D /* dictionary.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB798E2B1DFEF90B00F0628D /* dictionary.txt */; }; - EB8369AD1E15C5710003A7F8 /* ReadMe.md in Sources */ = {isa = PBXBuildFile; fileRef = EB8369AC1E15C5710003A7F8 /* ReadMe.md */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -270,7 +269,6 @@ files = ( EB798E291DFEF81400F0628D /* Trie.swift in Sources */, EB798E001DFEF79900F0628D /* ViewController.swift in Sources */, - EB8369AD1E15C5710003A7F8 /* ReadMe.md in Sources */, EB798DFE1DFEF79900F0628D /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index ec3b1c5cc..bf1c7d9c2 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -64,6 +64,7 @@ class Trie: NSObject, NSCoding { override init() { root = Node() wordCount = 0 + super.init() } // MARK: NSCoding From b48107ff77ecd007656177914a9bb2860d0f1737 Mon Sep 17 00:00:00 2001 From: zaccone Date: Tue, 3 Jan 2017 18:32:52 -0500 Subject: [PATCH 0348/1275] Added a check for wordArray not nil to the guard statement in insertWordsIntoTrie. --- Trie/Trie/TrieTests/TrieTests.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 7ef02553f..f8e934f0d 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -51,10 +51,8 @@ class TrieTests: XCTestCase { /// Inserts words into a trie. If the trie is non-empty, don't do anything. func insertWordsIntoTrie() { - guard trie.count == 0 else { - return - } - for word in self.wordArray! { + guard let wordArray = wordArray, trie.count == 0 else { return } + for word in wordArray { trie.insert(word: word) } } From 947d4f8052bccdb6f8a104ab1d36892d8152d92e Mon Sep 17 00:00:00 2001 From: gonini Date: Wed, 4 Jan 2017 09:46:09 +0900 Subject: [PATCH 0349/1275] Update Minimum Spanning Tree (Unweighted Graph) to Swift 3 --- .../Contents.swift | 2 +- .../timeline.xctimeline | 6 ------ .../MinimumSpanningTree.playground/Sources/Graph.swift | 6 +++--- .../MinimumSpanningTree.playground/Sources/Node.swift | 4 ++-- .../MinimumSpanningTree.playground/Sources/Queue.swift | 2 +- .../MinimumSpanningTree.swift | 2 +- Minimum Spanning Tree (Unweighted)/Tests/Graph.swift | 10 +++++----- Minimum Spanning Tree (Unweighted)/Tests/Queue.swift | 2 +- .../Tests/Tests.xcodeproj/project.pbxproj | 3 +++ 9 files changed, 17 insertions(+), 20 deletions(-) delete mode 100644 Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/timeline.xctimeline 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 088da1d11..86fe27df8 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,4 +1,4 @@ -func breadthFirstSearchMinimumSpanningTree(graph: Graph, source: Node) -> Graph { +func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { let minimumSpanningTree = graph.duplicate() var queue = Queue() diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/timeline.xctimeline b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift index 8cfb2a09c..8f02baf92 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift @@ -5,13 +5,13 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(label: String) -> Node { + public func addNode(_ label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { + public func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } @@ -27,7 +27,7 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + public func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift index 37a3b3fdf..0aedb6ef9 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift @@ -22,8 +22,8 @@ public class Node: CustomStringConvertible, Equatable { return distance != nil } - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + public func remove(_ edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } } diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift index bf462bbdd..3d98f801c 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift @@ -13,7 +13,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift index 92d370878..645a41999 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift @@ -1,4 +1,4 @@ -func breadthFirstSearchMinimumSpanningTree(graph: Graph, source: Node) -> Graph { +func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { let minimumSpanningTree = graph.duplicate() var queue = Queue() diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift index ed71cab7c..2d4161245 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift +++ b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift @@ -38,8 +38,8 @@ public class Node: CustomStringConvertible, Equatable { return distance != nil } - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + public func remove(_ edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } } @@ -56,13 +56,13 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(label: String) -> Node { + public func addNode(_ label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { + public func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } @@ -78,7 +78,7 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + public func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift b/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift index bf462bbdd..3d98f801c 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift +++ b/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift @@ -13,7 +13,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj index 659c7e9f2..a066b7a71 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -94,6 +94,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -230,6 +231,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -242,6 +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 = 3.0; }; name = Release; }; From fc208c61f96838af6266980bd058f7141b3cac24 Mon Sep 17 00:00:00 2001 From: GongUi Date: Wed, 4 Jan 2017 09:48:04 +0900 Subject: [PATCH 0350/1275] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4e2918431..4fbf215de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: # - xcodebuild test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./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 ./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.xcodeproj -scheme Tests From 017351f6bb67368ff273d73cba89e1ee42aa45f2 Mon Sep 17 00:00:00 2001 From: gonini Date: Thu, 5 Jan 2017 08:10:11 +0900 Subject: [PATCH 0351/1275] Warning correction for unused return function --- .../MinimumSpanningTree.playground/Sources/Graph.swift | 2 +- Minimum Spanning Tree (Unweighted)/Tests/Graph.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift index 8f02baf92..e2bb82677 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift @@ -35,7 +35,7 @@ public class Graph: CustomStringConvertible, Equatable { let duplicated = Graph() for node in nodes { - duplicated.addNode(node.label) + _ = duplicated.addNode(node.label) } for node in nodes { diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift index 2d4161245..c8cb77ac8 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift +++ b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift @@ -86,7 +86,7 @@ public class Graph: CustomStringConvertible, Equatable { let duplicated = Graph() for node in nodes { - duplicated.addNode(node.label) + _ = duplicated.addNode(node.label) } for node in nodes { From 58058cf6e9f6813ffbde7cf89ebefba07950d18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Thu, 5 Jan 2017 08:02:06 +0100 Subject: [PATCH 0352/1275] aligning with style guidelines --- Huffman Coding/Huffman.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index 017c5baf2..2d59908e9 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -3,7 +3,7 @@ import Foundation let s1 = "so much words wow many compression" -if let originalData = s1.data(using: String.Encoding.utf8) { +if let originalData = s1.data(using: .utf8) { print(originalData.count) let huffman1 = Huffman() @@ -17,7 +17,7 @@ if let originalData = s1.data(using: String.Encoding.utf8) { let decompressedData = huffman2.decompressData(data: compressedData, frequencyTable: frequencyTable) print(decompressedData.length) - let s2 = String(data: decompressedData as Data, encoding: String.Encoding.utf8)! + let s2 = String(data: decompressedData as Data, encoding: .utf8)! print(s2) assert(s1 == s2) } From 07dc70e66a3a3e42a3cec94a2cfa6b884f1af739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Thu, 5 Jan 2017 12:42:42 +0100 Subject: [PATCH 0353/1275] Migrates App-Pairs Shortest Paths to Swift3 syntax --- .travis.yml | 2 +- .../APSP/APSP.xcodeproj/project.pbxproj | 13 +++++++++- .../xcshareddata/xcschemes/APSP.xcscheme | 2 +- .../xcshareddata/xcschemes/APSPTests.xcscheme | 2 +- All-Pairs Shortest Paths/APSP/APSP/APSP.swift | 2 +- .../APSP/APSP/FloydWarshall.swift | 26 +++++++++---------- .../APSP/APSP/Helpers.swift | 11 ++++---- .../APSP/APSPTests/APSPTests.swift | 6 ++--- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4fbf215de..2417b4b6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: script: -# - xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests +- 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 diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index e7e95bbb7..b2d93ea35 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -187,14 +187,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 493D8DDF1CDD2A1C0089795A = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0820; }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0820; }; }; }; @@ -305,8 +307,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -350,8 +354,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -370,6 +376,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -381,6 +388,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 = 3.0; }; name = Debug; }; @@ -392,6 +400,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 = 3.0; }; name = Release; }; @@ -411,6 +420,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -432,6 +442,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; 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 475997aa9..e313c4b88 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 @@ ) -> P + static func apply(_ graph: AbstractGraph) -> P } diff --git a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift index 806c8677c..b1a870f2a 100644 --- a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift +++ b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift @@ -17,7 +17,7 @@ private typealias StepResult = (distances: Distances, predecessors: Predecessors - note: In all complexity bounds, `V` is the number of vertices in the graph, and `E` is the number of edges. */ -public struct FloydWarshall: APSPAlgorithm { +public struct FloydWarshall: APSPAlgorithm where T: Hashable { public typealias Q = T public typealias P = FloydWarshallResult @@ -29,7 +29,7 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^3)` time, `Θ(V^2)` space - returns a `FloydWarshallResult` struct which can be queried for shortest paths and their total weights */ - public static func apply(graph: AbstractGraph) -> FloydWarshallResult { + public static func apply(_ graph: AbstractGraph) -> FloydWarshallResult { var previousDistance = constructInitialDistanceMatrix(graph) var previousPredecessor = constructInitialPredecessorMatrix(previousDistance) @@ -59,12 +59,12 @@ public struct FloydWarshall: APSPAlgorithm { - returns: a tuple containing the next distance matrix with weights of currently known shortest paths and the corresponding predecessor matrix */ - static private func nextStep(intermediateIdx: Int, previousDistances: Distances, + static fileprivate func nextStep(_ intermediateIdx: Int, previousDistances: Distances, previousPredecessors: Predecessors, graph: AbstractGraph) -> StepResult { let vertexCount = graph.vertices.count - var nextDistances = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: Double.infinity)) - var nextPredecessors = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: nil)) + var nextDistances = Array(repeating: Array(repeating: Double.infinity, count: vertexCount), count: vertexCount) + var nextPredecessors = Array(repeating: Array(repeating: nil, count: vertexCount), count: vertexCount) for fromIdx in 0 ..< vertexCount { for toIndex in 0 ..< vertexCount { @@ -97,12 +97,12 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^2)` time/space - returns: weighted adjacency matrix in form ready for processing with Floyd-Warshall */ - static private func constructInitialDistanceMatrix(graph: AbstractGraph) -> Distances { + static fileprivate func constructInitialDistanceMatrix(_ graph: AbstractGraph) -> Distances { let vertices = graph.vertices let vertexCount = graph.vertices.count - var distances = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: Double.infinity)) + var distances = Array(repeating: Array(repeating: Double.infinity, count: vertexCount), count: vertexCount) for row in vertices { for col in vertices { @@ -125,10 +125,10 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^2)` time/space */ - static private func constructInitialPredecessorMatrix(distances: Distances) -> Predecessors { + static fileprivate func constructInitialPredecessorMatrix(_ distances: Distances) -> Predecessors { let vertexCount = distances.count - var predecessors = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: nil)) + var predecessors = Array(repeating: Array(repeating: nil, count: vertexCount), count: vertexCount) for fromIdx in 0 ..< vertexCount { for toIdx in 0 ..< vertexCount { @@ -151,10 +151,10 @@ public struct FloydWarshall: APSPAlgorithm { It conforms to the `APSPResult` procotol which provides methods to retrieve distances and paths between given pairs of start and end nodes. */ -public struct FloydWarshallResult: APSPResult { +public struct FloydWarshallResult: APSPResult where T: Hashable { - private var weights: Distances - private var predecessors: Predecessors + fileprivate var weights: Distances + fileprivate var predecessors: Predecessors /** - returns: the total weight of the path from a starting vertex to a destination. @@ -190,7 +190,7 @@ public struct FloydWarshallResult: APSPResult { - returns: the list of predecessors discovered so far */ - private func recursePathFrom(fromVertex from: Vertex, toVertex to: Vertex, path: [Vertex], + fileprivate func recursePathFrom(fromVertex from: Vertex, toVertex to: Vertex, path: [Vertex], inGraph graph: AbstractGraph) -> [Vertex]? { if from.index == to.index { diff --git a/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift index 644454491..3812b3f58 100644 --- a/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift +++ b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift @@ -7,10 +7,11 @@ import Foundation + /** Print a matrix, optionally specifying only the cells to display with the triplet (i, j, k) -> matrix[i][j], matrix[i][k], matrix[k][j] */ -func printMatrix(matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { +func printMatrix(_ matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { if i >= 0 { print(" k: \(k); i: \(i); j: \(j)\n") @@ -31,12 +32,12 @@ func printMatrix(matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { } grid.append(row) } - print((grid as NSArray).componentsJoinedByString("\n")) + print((grid as NSArray).componentsJoined(by: "\n")) print(" =======================") } -func printIntMatrix(matrix: [[Int?]]) { +func printIntMatrix(_ matrix: [[Int?]]) { var grid = [String]() @@ -46,14 +47,14 @@ func printIntMatrix(matrix: [[Int?]]) { for y in 0.. { +struct TestCase where T: Hashable { var from: Vertex var to: Vertex @@ -71,7 +71,7 @@ class APSPTests: XCTestCase { for testCase: TestCase in cases { if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), - computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { + let computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { XCTAssert(computedDistance == testCase.expectedDistance, "expected distance \(testCase.expectedDistance) but got \(computedDistance)") XCTAssert(computedPath == testCase.expectedPath, "expected path \(testCase.expectedPath) but got \(computedPath)") } @@ -111,7 +111,7 @@ class APSPTests: XCTestCase { for testCase: TestCase in cases { if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), - computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { + let computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { XCTAssert(computedDistance == testCase.expectedDistance, "expected distance \(testCase.expectedDistance) but got \(computedDistance)") XCTAssert(computedPath == testCase.expectedPath, "expected path \(testCase.expectedPath) but got \(computedPath)") } From 797a2e9e2bf70911222cac674e05841b80679310 Mon Sep 17 00:00:00 2001 From: iamsimranjot Date: Fri, 6 Jan 2017 02:56:13 +0530 Subject: [PATCH 0354/1275] Updated Merge Sort (Recursive) to Generic. --- .../MergeSort.playground/Contents.swift | 6 +- Merge Sort/MergeSort.swift | 72 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index ac166131e..e76570481 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -1,6 +1,6 @@ /* Top-down recursive version */ -func mergeSort(_ array: [Int]) -> [Int] { +func mergeSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } let middleIndex = array.count / 2 let leftArray = mergeSort(Array(array[0.. [Int] { return merge(leftPile: leftArray, rightPile: rightArray) } -func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [T], rightPile: [T]) -> [T] { var leftIndex = 0 var rightIndex = 0 - var orderedPile = [Int]() + var orderedPile = [T]() while leftIndex < leftPile.count && rightIndex < rightPile.count { if leftPile[leftIndex] < rightPile[rightIndex] { diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index 20316663f..bb89ea4d4 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -6,45 +6,45 @@ // // -func mergeSort(_ array: [Int]) -> [Int] { - guard array.count > 1 else { return array } - let middleIndex = array.count / 2 - let leftArray = mergeSort(Array(array[0..(_ array: [T]) -> [T] { + guard array.count > 1 else { return array } + let middleIndex = array.count / 2 + let leftArray = mergeSort(Array(array[0.. [Int] { - var leftIndex = 0 - var rightIndex = 0 - var orderedPile = [Int]() - - while leftIndex < leftPile.count && rightIndex < rightPile.count { - if leftPile[leftIndex] < rightPile[rightIndex] { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - } else if leftPile[leftIndex] > rightPile[rightIndex] { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } else { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 +func merge(leftPile: [T], rightPile: [T]) -> [T] { + var leftIndex = 0 + var rightIndex = 0 + var orderedPile = [T]() + + while leftIndex < leftPile.count && rightIndex < rightPile.count { + if leftPile[leftIndex] < rightPile[rightIndex] { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + } else if leftPile[leftIndex] > rightPile[rightIndex] { + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } else { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } } - } - - while leftIndex < leftPile.count { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - } - - while rightIndex < rightPile.count { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } - - return orderedPile + + while leftIndex < leftPile.count { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + } + + while rightIndex < rightPile.count { + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } + + return orderedPile } /* From e7b54f7bbb1c48be56f0f85ff433f889e1ddd880 Mon Sep 17 00:00:00 2001 From: iamsimranjot Date: Fri, 6 Jan 2017 02:58:50 +0530 Subject: [PATCH 0355/1275] Extra Example Added. --- Merge Sort/MergeSort.playground/Contents.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index e76570481..2952fc299 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -43,6 +43,8 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { let array = [2, 1, 5, 4, 9] let sortedArray = mergeSort(array) +let array2 = ["Tom", "Harry", "Ron", "Chandler", "Monica"] +let sortedArray2 = mergeSort(array2) From 369bff5d3ed3634c140b73c348dbe000ca7df4da Mon Sep 17 00:00:00 2001 From: iamsimranjot Date: Sun, 8 Jan 2017 03:47:54 +0530 Subject: [PATCH 0356/1275] Code Re-Indented With 2 Space Indentation. --- Merge Sort/MergeSort.swift | 70 +++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index bb89ea4d4..a7677b0bb 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -7,44 +7,44 @@ // func mergeSort(_ array: [T]) -> [T] { - guard array.count > 1 else { return array } - let middleIndex = array.count / 2 - let leftArray = mergeSort(Array(array[0.. 1 else { return array } + let middleIndex = array.count / 2 + let leftArray = mergeSort(Array(array[0..(leftPile: [T], rightPile: [T]) -> [T] { - var leftIndex = 0 - var rightIndex = 0 - var orderedPile = [T]() - - while leftIndex < leftPile.count && rightIndex < rightPile.count { - if leftPile[leftIndex] < rightPile[rightIndex] { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - } else if leftPile[leftIndex] > rightPile[rightIndex] { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } else { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } - } - - while leftIndex < leftPile.count { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - } - - while rightIndex < rightPile.count { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } - - return orderedPile + var leftIndex = 0 + var rightIndex = 0 + var orderedPile = [T]() + + while leftIndex < leftPile.count && rightIndex < rightPile.count { + if leftPile[leftIndex] < rightPile[rightIndex] { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + } else if leftPile[leftIndex] > rightPile[rightIndex] { + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } else { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } + } + + while leftIndex < leftPile.count { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + } + + while rightIndex < rightPile.count { + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } + + return orderedPile } /* From f9412936fc0656eebf5f7ad1a79a241a5e05c572 Mon Sep 17 00:00:00 2001 From: iamsimranjot Date: Sun, 8 Jan 2017 03:57:16 +0530 Subject: [PATCH 0357/1275] Code Re Indented with 2 Space Indentation (Part 2) --- Merge Sort/MergeSort.swift | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index a7677b0bb..4332fc44b 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -20,28 +20,28 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { var orderedPile = [T]() while leftIndex < leftPile.count && rightIndex < rightPile.count { - if leftPile[leftIndex] < rightPile[rightIndex] { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - } else if leftPile[leftIndex] > rightPile[rightIndex] { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } else { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 - } + if leftPile[leftIndex] < rightPile[rightIndex] { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + } else if leftPile[leftIndex] > rightPile[rightIndex] { + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } else { + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 + } } while leftIndex < leftPile.count { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 + orderedPile.append(leftPile[leftIndex]) + leftIndex += 1 } while rightIndex < rightPile.count { - orderedPile.append(rightPile[rightIndex]) - rightIndex += 1 + orderedPile.append(rightPile[rightIndex]) + rightIndex += 1 } return orderedPile From 0e819963fe321021486aa8247776cb20d65d58cf Mon Sep 17 00:00:00 2001 From: Tai Heng Date: Sun, 8 Jan 2017 15:52:39 -0500 Subject: [PATCH 0358/1275] Updated K-Means Tests.xcodeproj to latest settings. Updated K-Means code to Swift3 syntax and changes to API. --- .travis.yml | 2 +- K-Means/KMeans.swift | 18 ++++----- K-Means/Tests/KMeansTests.swift | 2 +- K-Means/Tests/Tests.xcodeproj/project.pbxproj | 40 ++++++++++++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- K-Means/Tests/Vector.swift | 12 +++--- 6 files changed, 57 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 727b247a5..b33835565 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ script: # - 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 ./K-Means/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./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 diff --git a/K-Means/KMeans.swift b/K-Means/KMeans.swift index 972fd7230..4a89a3fae 100644 --- a/K-Means/KMeans.swift +++ b/K-Means/KMeans.swift @@ -11,11 +11,11 @@ class KMeans { self.numCenters = labels.count } - private func indexOfNearestCenter(x: Vector, centers: [Vector]) -> Int { + private func indexOfNearestCenter(_ x: Vector, centers: [Vector]) -> Int { var nearestDist = DBL_MAX var minIndex = 0 - for (idx, center) in centers.enumerate() { + for (idx, center) in centers.enumerated() { let dist = x.distanceTo(center) if dist < nearestDist { minIndex = idx @@ -25,8 +25,8 @@ class KMeans { return minIndex } - func trainCenters(points: [Vector], convergeDistance: Double) { - let zeroVector = Vector([Double](count: points[0].length, repeatedValue: 0)) + func trainCenters(_ points: [Vector], convergeDistance: Double) { + let zeroVector = Vector([Double](repeating: 0, count: points[0].length)) // Randomly take k objects from the input data to make the initial centroids. var centers = reservoirSample(points, k: numCenters) @@ -34,7 +34,7 @@ class KMeans { var centerMoveDist = 0.0 repeat { // This array keeps track of which data points belong to which centroids. - var classification: [[Vector]] = .init(count: numCenters, repeatedValue: []) + var classification: [[Vector]] = .init(repeating: [], count: numCenters) // For each data point, find the centroid that it is closest to. for p in points { @@ -45,7 +45,7 @@ class KMeans { // Take the average of all the data points that belong to each centroid. // This moves the centroid to a new position. let newCenters = classification.map { assignedPoints in - assignedPoints.reduce(zeroVector, combine: +) / Double(assignedPoints.count) + assignedPoints.reduce(zeroVector, +) / Double(assignedPoints.count) } // Find out how far each centroid moved since the last iteration. If it's @@ -61,14 +61,14 @@ class KMeans { centroids = centers } - func fit(point: Vector) -> Label { + func fit(_ point: Vector) -> Label { assert(!centroids.isEmpty, "Exception: KMeans tried to fit on a non trained model.") let centroidIndex = indexOfNearestCenter(point, centers: centroids) return labels[centroidIndex] } - func fit(points: [Vector]) -> [Label] { + func fit(_ points: [Vector]) -> [Label] { assert(!centroids.isEmpty, "Exception: KMeans tried to fit on a non trained model.") return points.map(fit) @@ -76,7 +76,7 @@ class KMeans { } // Pick k random elements from samples -func reservoirSample(samples: [T], k: Int) -> [T] { +func reservoirSample(_ samples: [T], k: Int) -> [T] { var result = [T]() // Fill the result array with first k elements diff --git a/K-Means/Tests/KMeansTests.swift b/K-Means/Tests/KMeansTests.swift index 179f9d418..7e0c93004 100644 --- a/K-Means/Tests/KMeansTests.swift +++ b/K-Means/Tests/KMeansTests.swift @@ -10,7 +10,7 @@ import Foundation import XCTest class KMeansTests: XCTestCase { - func genPoints(numPoints: Int, numDimensions: Int) -> [Vector] { + func genPoints(_ numPoints: Int, numDimensions: Int) -> [Vector] { var points = [Vector]() for _ in 0.. Double { + func distanceTo(_ other: Vector) -> Double { var result = 0.0 for idx in 0.. Vector { return Vector(results) } -func += (inout left: Vector, right: Vector) { +func += (left: inout Vector, right: Vector) { left = left + right } @@ -51,18 +51,18 @@ func - (left: Vector, right: Vector) -> Vector { return Vector(results) } -func -= (inout left: Vector, right: Vector) { +func -= (left: inout Vector, right: Vector) { left = left - right } func / (left: Vector, right: Double) -> Vector { - var results = [Double](count: left.length, repeatedValue: 0) - for (idx, value) in left.data.enumerate() { + var results = [Double](repeating: 0, count: left.length) + for (idx, value) in left.data.enumerated() { results[idx] = value / right } return Vector(results) } -func /= (inout left: Vector, right: Double) { +func /= (left: inout Vector, right: Double) { left = left / right } From bf46bb528139e05d41a48bed0a54d78030b420b2 Mon Sep 17 00:00:00 2001 From: Tai Heng Date: Sun, 8 Jan 2017 16:29:16 -0500 Subject: [PATCH 0359/1275] Converted playground and combSort code to Swift 3 syntax. Changed combSort to use generic type. --- Comb Sort/Comb Sort.playground/Contents.swift | 24 +------------ .../Sources/Comb Sort.swift | 36 +++++++++++++++++++ Comb Sort/Comb Sort.swift | 6 ++-- 3 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift index 2d6155b50..d6add44f5 100644 --- a/Comb Sort/Comb Sort.playground/Contents.swift +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -4,34 +4,12 @@ import Cocoa -func combSort (input: [Int]) -> [Int] { - var copy = input - var gap = copy.count - let shrink = 1.3 - - while gap > 1 { - gap = Int(Double(gap) / shrink) - if gap < 1 { - gap = 1 - } - - var index = 0 - while index + gap < copy.count { - if copy[index] > copy[index + gap] { - swap(©[index], ©[index + gap]) - } - index += 1 - } - } - return copy -} - // Test Comb Sort with small array of ten values let array = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] combSort(array) // Test Comb Sort with large array of 1000 random values -var bigArray = [Int](count: 1000, repeatedValue: 0) +var bigArray = [Int](repeating: 0, count: 1000) var i = 0 while i < 1000 { bigArray[i] = Int(arc4random_uniform(1000) + 1) diff --git a/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift b/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift new file mode 100644 index 000000000..b6e85fa2b --- /dev/null +++ b/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift @@ -0,0 +1,36 @@ +// Comb Sort.swift +// Comb Sort +// +// Created by Stephen.Rutstein on 7/16/16. +// Copyright © 2016 Stephen.Rutstein. All rights reserved. +// + +import Foundation + +public func combSort(_ input: [T]) -> [T] { + var copy: [T] = input + var gap = copy.count + let shrink = 1.3 + + while gap > 1 { + gap = (Int)(Double(gap) / shrink) + if gap < 1 { + gap = 1 + } + + var index = 0 + while !(index + gap >= copy.count) { + if copy[index] > copy[index + gap] { + swap(©[index], ©[index + gap]) + } + index += 1 + } + } + return copy +} + +fileprivate func swap(a: inout T, b: inout T) { + let temp = a + a = b + b = temp +} diff --git a/Comb Sort/Comb Sort.swift b/Comb Sort/Comb Sort.swift index 7abba8c7f..b6e85fa2b 100644 --- a/Comb Sort/Comb Sort.swift +++ b/Comb Sort/Comb Sort.swift @@ -7,8 +7,8 @@ import Foundation -func combSort (input: [Int]) -> [Int] { - var copy: [Int] = input +public func combSort(_ input: [T]) -> [T] { + var copy: [T] = input var gap = copy.count let shrink = 1.3 @@ -29,7 +29,7 @@ func combSort (input: [Int]) -> [Int] { return copy } -func swap (inout a: Int, inout b: Int) { +fileprivate func swap(a: inout T, b: inout T) { let temp = a a = b b = temp From f1dd6b66c4eca5e01b7b363a329fa4ffa5a46d0e Mon Sep 17 00:00:00 2001 From: iamsimranjot Date: Mon, 9 Jan 2017 03:12:18 +0530 Subject: [PATCH 0360/1275] Removed Extra Spaces. --- Merge Sort/MergeSort.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index 4332fc44b..f77d1cd84 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -18,7 +18,7 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { var leftIndex = 0 var rightIndex = 0 var orderedPile = [T]() - + while leftIndex < leftPile.count && rightIndex < rightPile.count { if leftPile[leftIndex] < rightPile[rightIndex] { orderedPile.append(leftPile[leftIndex]) @@ -33,17 +33,17 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { rightIndex += 1 } } - + while leftIndex < leftPile.count { orderedPile.append(leftPile[leftIndex]) leftIndex += 1 } - + while rightIndex < rightPile.count { orderedPile.append(rightPile[rightIndex]) rightIndex += 1 } - + return orderedPile } From af8b44f97392fb8f8cb5704b0799fb0523ee8e31 Mon Sep 17 00:00:00 2001 From: zaccone Date: Mon, 9 Jan 2017 13:50:28 -0500 Subject: [PATCH 0361/1275] Changed the baseline for one of the tests. --- .../6ABF2F62-9363-4450-8DE1-D20F57026950.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist index 01ff985c8..d8e350129 100644 --- a/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist +++ b/Trie/Trie/Trie.xcodeproj/xcshareddata/xcbaselines/EB798E0A1DFEF79900F0628D.xcbaseline/6ABF2F62-9363-4450-8DE1-D20F57026950.plist @@ -11,7 +11,7 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 3.0053 + 3.407 baselineIntegrationDisplayName Local Baseline From f0e83bdea4dce34d5a495fcd7dc3b3f3dec8c178 Mon Sep 17 00:00:00 2001 From: Tai Heng Date: Mon, 9 Jan 2017 22:05:24 -0500 Subject: [PATCH 0362/1275] Added Comb Sort test. --- .travis.yml | 1 + Comb Sort/Tests/CombSortTests.swift | 28 ++ Comb Sort/Tests/Info.plist | 22 ++ .../Tests/Tests.xcodeproj/project.pbxproj | 277 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 101 +++++++ 6 files changed, 436 insertions(+) create mode 100644 Comb Sort/Tests/CombSortTests.swift create mode 100644 Comb Sort/Tests/Info.plist create mode 100644 Comb Sort/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Comb Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/.travis.yml b/.travis.yml index 727b247a5..b4691467f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ script: # - 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 ./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 diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift new file mode 100644 index 000000000..1bcc67fd0 --- /dev/null +++ b/Comb Sort/Tests/CombSortTests.swift @@ -0,0 +1,28 @@ +// +// CombSortTests.swift +// Tests +// +// Created by theng on 2017-01-09. +// Copyright © 2017 Swift Algorithm Club. All rights reserved. +// + +import XCTest + +class CombSortTests: XCTestCase { + 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 tearDown() { + super.tearDown() + } + + func testCombSort() { + let sortedSequence = combSort(sequence) + XCTAssertEqual(sortedSequence, expectedSequence) + } +} diff --git a/Comb Sort/Tests/Info.plist b/Comb Sort/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Comb Sort/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..60039196c --- /dev/null +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,277 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 056E927E1E24852900B30F52 /* CombSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056E927D1E24852900B30F52 /* CombSortTests.swift */; }; + 056E92841E248A4000B30F52 /* Comb Sort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056E92831E248A4000B30F52 /* Comb Sort.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 056E92751E2483D300B30F52 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 056E92791E2483D300B30F52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 056E927D1E24852900B30F52 /* CombSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombSortTests.swift; sourceTree = ""; }; + 056E92831E248A4000B30F52 /* Comb Sort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Comb Sort.swift"; path = "../Comb Sort.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 056E92721E2483D300B30F52 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 056E92581E24836C00B30F52 = { + isa = PBXGroup; + children = ( + 056E92761E2483D300B30F52 /* Tests */, + 056E92621E24836C00B30F52 /* Products */, + ); + sourceTree = ""; + }; + 056E92621E24836C00B30F52 /* Products */ = { + isa = PBXGroup; + children = ( + 056E92751E2483D300B30F52 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 056E92761E2483D300B30F52 /* Tests */ = { + isa = PBXGroup; + children = ( + 056E92831E248A4000B30F52 /* Comb Sort.swift */, + 056E92791E2483D300B30F52 /* Info.plist */, + 056E927D1E24852900B30F52 /* CombSortTests.swift */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 056E92741E2483D300B30F52 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 056E927A1E2483D300B30F52 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 056E92711E2483D300B30F52 /* Sources */, + 056E92721E2483D300B30F52 /* Frameworks */, + 056E92731E2483D300B30F52 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 056E92751E2483D300B30F52 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 056E92591E24836C00B30F52 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 056E92741E2483D300B30F52 = { + CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 0820; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 056E925C1E24836C00B30F52 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 056E92581E24836C00B30F52; + productRefGroup = 056E92621E24836C00B30F52 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 056E92741E2483D300B30F52 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 056E92731E2483D300B30F52 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 056E92711E2483D300B30F52 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 056E927E1E24852900B30F52 /* CombSortTests.swift in Sources */, + 056E92841E248A4000B30F52 /* Comb Sort.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 056E926C1E24836C00B30F52 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 056E926D1E24836C00B30F52 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 056E927B1E2483D300B30F52 /* 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_VERSION = 3.0; + }; + name = Debug; + }; + 056E927C1E2483D300B30F52 /* 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_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 056E925C1E24836C00B30F52 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E926C1E24836C00B30F52 /* Debug */, + 056E926D1E24836C00B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 056E927A1E2483D300B30F52 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E927B1E2483D300B30F52 /* Debug */, + 056E927C1E2483D300B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 056E92591E24836C00B30F52 /* Project object */; +} diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Comb Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Comb Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..55e697ad3 --- /dev/null +++ b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6ec92d76ccecd3f0083252d406e1fc5b3a59d57b Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 10 Jan 2017 00:12:50 -0800 Subject: [PATCH 0363/1275] Fixes compile error due to missing brace. --- Trie/Trie/Trie/Trie.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index d3c845720..0e11a9c61 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -11,15 +11,15 @@ import Foundation /// A node in the trie class TrieNode { - var value: T? - weak var parentNode: TrieNode? - var children: [T: TrieNode] = [:] - var isTerminating = false - var isLeaf: Bool { - return children.count == 0 - } + var value: T? + weak var parentNode: TrieNode? + var children: [T: TrieNode] = [:] + var isTerminating = false + var isLeaf: Bool { + return children.count == 0 } + /// Initializes a node. /// /// - Parameters: From 53b87713a7f3a8083d67053416d4bc633090e68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Wed, 11 Jan 2017 02:30:24 +0100 Subject: [PATCH 0364/1275] Migrates Ternary Search Tree to Swift 3 syntax (#352) * migrates Ternary Search Tree to Swift 3 syntax * aligning function names as suggested * adds unit tests to TernarySearchTree * adds guards as suggested --- .travis.yml | 1 + .../TST.playground/Contents.swift | 30 +- .../Sources/TernarySearchTree.swift | 48 ++-- .../TST.playground/Sources/Utils.swift | 30 ++ .../TST.playground/contents.xcplayground | 2 +- Ternary Search Tree/TernarySearchTree.swift | 54 ++-- Ternary Search Tree/Tests/Info.plist | 22 ++ .../Tests/TernarySearchTreeTests.swift | 58 ++++ .../Tests/Tests.xcodeproj/project.pbxproj | 264 ++++++++++++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 56 ++++ Ternary Search Tree/Utils.swift | 30 ++ .../contents.xcworkspacedata | 10 + 12 files changed, 529 insertions(+), 76 deletions(-) create mode 100644 Ternary Search Tree/TST.playground/Sources/Utils.swift create mode 100644 Ternary Search Tree/Tests/Info.plist create mode 100644 Ternary Search Tree/Tests/TernarySearchTreeTests.swift create mode 100644 Ternary Search Tree/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Ternary Search Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme create mode 100644 Ternary Search Tree/Utils.swift diff --git a/.travis.yml b/.travis.yml index 6812ac32a..117400d97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,3 +43,4 @@ script: - 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 diff --git a/Ternary Search Tree/TST.playground/Contents.swift b/Ternary Search Tree/TST.playground/Contents.swift index 6b1fe3eaa..bacf56aee 100644 --- a/Ternary Search Tree/TST.playground/Contents.swift +++ b/Ternary Search Tree/TST.playground/Contents.swift @@ -4,39 +4,23 @@ import Cocoa import Foundation let treeOfStrings = TernarySearchTree() -let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -//Random string generator from: -//http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710 -func randomAlphaNumericString(length: Int) -> String { - let allowedCharsCount = UInt32(allowedChars.characters.count) - var randomString = "" - - for _ in (0..() for _ in (1...testCount) { let randomNum = Int(arc4random_uniform(UInt32.max)) let randomLength = Int(arc4random_uniform(10)) - let key = randomAlphaNumericString(randomLength) + let key = Utils.shared.randomAlphaNumericString(withLength: randomLength) if key != "" { testNums.append((key, randomNum)) - treeOfInts.insert(randomNum, withKey: key) + treeOfInts.insert(data: randomNum, withKey: key) } } for aTest in testNums { - let data = treeOfInts.find(aTest.key) + let data = treeOfInts.find(key: aTest.key) if data == nil { print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)") } diff --git a/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift index 43c4453e3..fed8f9710 100644 --- a/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift +++ b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift @@ -18,11 +18,10 @@ public class TernarySearchTree { //MARK: - Insertion public func insert(data: Element, withKey key: String) -> Bool { - return insertNode(&root, withData: data, andKey: key, atIndex: 0) - + return insert(node: &root, withData: data, andKey: key, atIndex: 0) } - private func insertNode(inout aNode: TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { + private func insert(node: inout TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { //sanity check. if key.characters.count == 0 { @@ -30,30 +29,30 @@ public class TernarySearchTree { } //create a new node if necessary. - if aNode == nil { - let index = key.startIndex.advancedBy(charIndex) - aNode = TSTNode(key: key[index]) + if node == nil { + let index = key.index(key.startIndex, offsetBy: charIndex) + node = TSTNode(key: key[index]) } //if current char is less than the current node's char, go left - let index = key.startIndex.advancedBy(charIndex) - if key[index] < aNode!.key { - return insertNode(&aNode!.left, withData: data, andKey: key, atIndex: charIndex) + let index = key.index(key.startIndex, offsetBy: charIndex) + if key[index] < node!.key { + return insert(node: &node!.left, withData: data, andKey: key, atIndex: charIndex) } //if it's greater, go right. - else if key[index] > aNode!.key { - return insertNode(&aNode!.right, withData: data, andKey: key, atIndex: charIndex) + else if key[index] > node!.key { + return insert(node: &node!.right, withData: data, andKey: key, atIndex: charIndex) } //current char is equal to the current nodes, go middle else { //continue down the middle. if charIndex + 1 < key.characters.count { - return insertNode(&aNode!.middle, withData: data, andKey: key, atIndex: charIndex + 1) + return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1) } //otherwise, all done. else { - aNode!.data = data - aNode?.hasData = true + node!.data = data + node?.hasData = true return true } } @@ -64,32 +63,31 @@ public class TernarySearchTree { public func find(key: String) -> Element? { - return findNode(root, withKey: key, atIndex: 0) + return find(node: root, withKey: key, atIndex: 0) } - - private func findNode(aNode: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { + private func find(node: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { //Given key does not exist in tree. - if aNode == nil { + if node == nil { return nil } - let index = key.startIndex.advancedBy(charIndex) + let index = key.index(key.startIndex, offsetBy: charIndex) //go left - if key[index] < aNode!.key { - return findNode(aNode!.left, withKey: key, atIndex: charIndex) + if key[index] < node!.key { + return find(node: node!.left, withKey: key, atIndex: charIndex) } //go right - else if key[index] > aNode!.key { - return findNode(aNode!.right, withKey: key, atIndex: charIndex) + else if key[index] > node!.key { + return find(node: node!.right, withKey: key, atIndex: charIndex) } //go middle else { if charIndex + 1 < key.characters.count { - return findNode(aNode!.middle, withKey: key, atIndex: charIndex + 1) + return find(node: node!.middle, withKey: key, atIndex: charIndex + 1) } else { - return aNode!.data + return node!.data } } } diff --git a/Ternary Search Tree/TST.playground/Sources/Utils.swift b/Ternary Search Tree/TST.playground/Sources/Utils.swift new file mode 100644 index 000000000..cabfe1b68 --- /dev/null +++ b/Ternary Search Tree/TST.playground/Sources/Utils.swift @@ -0,0 +1,30 @@ +// +// Utils.swift +// +// +// Created by Peter Bødskov on 10/01/17. +// +// + +import Foundation + +public struct Utils { + + public static let shared = Utils() + + let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + //Random string generator from: + //http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710 + public func randomAlphaNumericString(withLength length: Int) -> String { + let allowedCharsCount = UInt32(allowedChars.characters.count) + var randomString = "" + + for _ in (0.. - + \ No newline at end of file diff --git a/Ternary Search Tree/TernarySearchTree.swift b/Ternary Search Tree/TernarySearchTree.swift index 2f143bead..c4b51519a 100644 --- a/Ternary Search Tree/TernarySearchTree.swift +++ b/Ternary Search Tree/TernarySearchTree.swift @@ -33,52 +33,52 @@ public class TernarySearchTree { - returns: Value indicating insertion success/failure. */ - public func insert(data: Element, withKey key: String) -> Bool { - return insertNode(&root, withData: data, andKey: key, atIndex: 0) + @discardableResult public func insert(data: Element, withKey key: String) -> Bool { + return insert(node: &root, withData: data, andKey: key, atIndex: 0) } /** Helper method for insertion that does the actual legwork. Insertion is performed recursively. - - parameter aNode: The current node to insert below. + - parameter node: The current node to insert below. - parameter data: The data being inserted. - parameter key: The key being used to find an insertion location for the given data - parameter charIndex: The index of the character in the key string to use to for the next node. - returns: Value indicating insertion success/failure. */ - private func insertNode(inout aNode: TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { + private func insert(node: inout TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { //sanity check. - if key.characters.count == 0 { + guard key.characters.count > 0 else { return false } //create a new node if necessary. - if aNode == nil { - let index = key.startIndex.advancedBy(charIndex) - aNode = TSTNode(key: key[index]) + if node == nil { + let index = key.index(key.startIndex, offsetBy: charIndex) + node = TSTNode(key: key[index]) } //if current char is less than the current node's char, go left - let index = key.startIndex.advancedBy(charIndex) - if key[index] < aNode!.key { - return insertNode(&aNode!.left, withData: data, andKey: key, atIndex: charIndex) + let index = key.index(key.startIndex, offsetBy: charIndex) + if key[index] < node!.key { + return insert(node: &node!.left, withData: data, andKey: key, atIndex: charIndex) } //if it's greater, go right. - else if key[index] > aNode!.key { - return insertNode(&aNode!.right, withData: data, andKey: key, atIndex: charIndex) + else if key[index] > node!.key { + return insert(node: &node!.right, withData: data, andKey: key, atIndex: charIndex) } //current char is equal to the current nodes, go middle else { //continue down the middle. if charIndex + 1 < key.characters.count { - return insertNode(&aNode!.middle, withData: data, andKey: key, atIndex: charIndex + 1) + return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1) } //otherwise, all done. else { - aNode!.data = data - aNode?.hasData = true + node!.data = data + node?.hasData = true return true } } @@ -95,40 +95,40 @@ public class TernarySearchTree { - returns: The element, if found. Otherwise, nil. */ public func find(key: String) -> Element? { - return findNode(root, withKey: key, atIndex: 0) + return find(node: root, withKey: key, atIndex: 0) } /** Helper method that performs actual legwork of find operation. Implemented recursively. - - parameter aNode: The current node being evaluated. + - parameter node: The current node being evaluated. - parameter key: The key being used for the search. - parameter charIndex: The index of the current char in the search key - returns: The element, if found. Nil otherwise. */ - private func findNode(aNode: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { + private func find(node: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { //Given key does not exist in tree. - if aNode == nil { + guard let node = node else { return nil } - let index = key.startIndex.advancedBy(charIndex) + let index = key.index(key.startIndex, offsetBy: charIndex) //go left - if key[index] < aNode!.key { - return findNode(aNode!.left, withKey: key, atIndex: charIndex) + if key[index] < node.key { + return find(node: node.left, withKey: key, atIndex: charIndex) } //go right - else if key[index] > aNode!.key { - return findNode(aNode!.right, withKey: key, atIndex: charIndex) + else if key[index] > node.key { + return find(node: node.right, withKey: key, atIndex: charIndex) } //go middle else { if charIndex + 1 < key.characters.count { - return findNode(aNode!.middle, withKey: key, atIndex: charIndex + 1) + return find(node: node.middle, withKey: key, atIndex: charIndex + 1) } else { - return aNode!.data + return node.data } } } diff --git a/Ternary Search Tree/Tests/Info.plist b/Ternary Search Tree/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Ternary Search Tree/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Ternary Search Tree/Tests/TernarySearchTreeTests.swift b/Ternary Search Tree/Tests/TernarySearchTreeTests.swift new file mode 100644 index 000000000..51e7c808c --- /dev/null +++ b/Ternary Search Tree/Tests/TernarySearchTreeTests.swift @@ -0,0 +1,58 @@ +// +// Tests.swift +// Tests +// +// Created by Peter Bødskov on 10/01/17. +// Copyright © 2017 Swift Algorithm Club. All rights reserved. +// + +import XCTest + +class TernarySearchTreeTests: XCTestCase { + + let treeOfStrings = TernarySearchTree() + let testCount = 30 + + func testCanFindStringInTree() { + var testStrings: [(key: String, data: String)] = [] + for _ in (1...testCount) { + let randomLength = Int(arc4random_uniform(10)) + let key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + let data = Utils.shared.randomAlphaNumericString(withLength: randomLength) + // print("Key: \(key) Data: \(data)") + + if key != "" && data != "" { + testStrings.append((key, data)) + treeOfStrings.insert(data: data, withKey: key) + } + } + + for aTest in testStrings { + let data = treeOfStrings.find(key: aTest.key) + + XCTAssertNotNil(data) + XCTAssertEqual(data, aTest.data) + } + } + + func testCanFindNumberInTree() { + var testNums: [(key: String, data: Int)] = [] + let treeOfInts = TernarySearchTree() + for _ in (1...testCount) { + let randomNum = Int(arc4random_uniform(UInt32.max)) + let randomLength = Int(arc4random_uniform(10)) + let key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + + if key != "" { + testNums.append((key, randomNum)) + treeOfInts.insert(data: randomNum, withKey: key) + } + } + + for aTest in testNums { + let data = treeOfInts.find(key: aTest.key) + XCTAssertNotNil(data) + XCTAssertEqual(data, aTest.data) + } + } +} diff --git a/Ternary Search Tree/Tests/Tests.xcodeproj/project.pbxproj b/Ternary Search Tree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..7afaca944 --- /dev/null +++ b/Ternary Search Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,264 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + D06C22031E24D02800622925 /* TernarySearchTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06C22021E24D02800622925 /* TernarySearchTreeTests.swift */; }; + D0957B8A1E24D92D00417988 /* TernarySearchTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0957B891E24D92D00417988 /* TernarySearchTree.swift */; }; + D0957B8C1E24D9A300417988 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0957B8B1E24D9A300417988 /* Utils.swift */; }; + D0957B8E1E24DA0100417988 /* TSTNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0957B8D1E24DA0100417988 /* TSTNode.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + D06C22021E24D02800622925 /* TernarySearchTreeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TernarySearchTreeTests.swift; sourceTree = ""; }; + D06C22041E24D02800622925 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D06C22081E24D16800622925 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D0957B891E24D92D00417988 /* TernarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TernarySearchTree.swift; path = ../TernarySearchTree.swift; sourceTree = ""; }; + D0957B8B1E24D9A300417988 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../Utils.swift; sourceTree = ""; }; + D0957B8D1E24DA0100417988 /* TSTNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TSTNode.swift; path = ../TSTNode.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D06C21FD1E24D02800622925 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D06C21B61E24CC9600622925 = { + isa = PBXGroup; + children = ( + D0957B891E24D92D00417988 /* TernarySearchTree.swift */, + D0957B8B1E24D9A300417988 /* Utils.swift */, + D06C22021E24D02800622925 /* TernarySearchTreeTests.swift */, + D0957B8D1E24DA0100417988 /* TSTNode.swift */, + D06C22041E24D02800622925 /* Info.plist */, + D06C22081E24D16800622925 /* Tests.xctest */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D06C21FF1E24D02800622925 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D06C22051E24D02800622925 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + D06C21FC1E24D02800622925 /* Sources */, + D06C21FD1E24D02800622925 /* Frameworks */, + D06C21FE1E24D02800622925 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = D06C22081E24D16800622925 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D06C21B71E24CC9600622925 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 0810; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + D06C21FF1E24D02800622925 = { + CreatedOnToolsVersion = 8.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = D06C21BA1E24CC9600622925 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D06C21B61E24CC9600622925; + productRefGroup = D06C21B61E24CC9600622925; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D06C21FF1E24D02800622925 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D06C21FE1E24D02800622925 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D06C21FC1E24D02800622925 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D06C22031E24D02800622925 /* TernarySearchTreeTests.swift in Sources */, + D0957B8E1E24DA0100417988 /* TSTNode.swift in Sources */, + D0957B8A1E24D92D00417988 /* TernarySearchTree.swift in Sources */, + D0957B8C1E24D9A300417988 /* Utils.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D06C21C31E24CC9600622925 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = 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; + }; + name = Debug; + }; + D06C21C41E24CC9600622925 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = 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; + }; + name = Release; + }; + D06C22061E24D02800622925 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + D06C22071E24D02800622925 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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 = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D06C21BA1E24CC9600622925 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D06C21C31E24CC9600622925 /* Debug */, + D06C21C41E24CC9600622925 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D06C22051E24D02800622925 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D06C22061E24D02800622925 /* Debug */, + D06C22071E24D02800622925 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D06C21B71E24CC9600622925 /* Project object */; +} diff --git a/Ternary Search Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Ternary Search Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..752b0c7fc --- /dev/null +++ b/Ternary Search Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ternary Search Tree/Utils.swift b/Ternary Search Tree/Utils.swift new file mode 100644 index 000000000..cabfe1b68 --- /dev/null +++ b/Ternary Search Tree/Utils.swift @@ -0,0 +1,30 @@ +// +// Utils.swift +// +// +// Created by Peter Bødskov on 10/01/17. +// +// + +import Foundation + +public struct Utils { + + public static let shared = Utils() + + let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + //Random string generator from: + //http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710 + public func randomAlphaNumericString(withLength length: Int) -> String { + let allowedCharsCount = UInt32(allowedChars.characters.count) + var randomString = "" + + for _ in (0.. + + + + + + From b9b491d98c50a270184204a98e982e1ccc3b07ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Wed, 11 Jan 2017 16:05:37 +0100 Subject: [PATCH 0365/1275] fixing failing test (#355) the problem was that the testdata generator could generate keys that was not unique...which caused the `find` method to return the wrong values for keys when the keys were the same. --- Ternary Search Tree/TernarySearchTree.swift | 2 +- .../Tests/TernarySearchTreeTests.swift | 25 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Ternary Search Tree/TernarySearchTree.swift b/Ternary Search Tree/TernarySearchTree.swift index c4b51519a..2e2ca2917 100644 --- a/Ternary Search Tree/TernarySearchTree.swift +++ b/Ternary Search Tree/TernarySearchTree.swift @@ -75,7 +75,7 @@ public class TernarySearchTree { if charIndex + 1 < key.characters.count { return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1) } - //otherwise, all done. + //otherwise, all done. else { node!.data = data node?.hasData = true diff --git a/Ternary Search Tree/Tests/TernarySearchTreeTests.swift b/Ternary Search Tree/Tests/TernarySearchTreeTests.swift index 51e7c808c..40739c888 100644 --- a/Ternary Search Tree/Tests/TernarySearchTreeTests.swift +++ b/Ternary Search Tree/Tests/TernarySearchTreeTests.swift @@ -10,14 +10,23 @@ import XCTest class TernarySearchTreeTests: XCTestCase { - let treeOfStrings = TernarySearchTree() + let testCount = 30 func testCanFindStringInTree() { var testStrings: [(key: String, data: String)] = [] + let treeOfStrings = TernarySearchTree() + for _ in (1...testCount) { - let randomLength = Int(arc4random_uniform(10)) - let key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + var randomLength = Int(arc4random_uniform(10)) + + var key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + + while testStrings.contains(where: { $0.key == key}) { + //That key is taken, so we generate a new one with another length + randomLength = Int(arc4random_uniform(10)) + key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + } let data = Utils.shared.randomAlphaNumericString(withLength: randomLength) // print("Key: \(key) Data: \(data)") @@ -29,7 +38,6 @@ class TernarySearchTreeTests: XCTestCase { for aTest in testStrings { let data = treeOfStrings.find(key: aTest.key) - XCTAssertNotNil(data) XCTAssertEqual(data, aTest.data) } @@ -40,8 +48,13 @@ class TernarySearchTreeTests: XCTestCase { let treeOfInts = TernarySearchTree() for _ in (1...testCount) { let randomNum = Int(arc4random_uniform(UInt32.max)) - let randomLength = Int(arc4random_uniform(10)) - let key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + var randomLength = Int(arc4random_uniform(10)) + var key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + while testNums.contains(where: { $0.key == key}) { + //That key is taken, so we generate a new one with another length + randomLength = Int(arc4random_uniform(10)) + key = Utils.shared.randomAlphaNumericString(withLength: randomLength) + } if key != "" { testNums.append((key, randomNum)) From bc73299363a92f07b95bd831942985c2daba1d4b Mon Sep 17 00:00:00 2001 From: Keita Date: Wed, 11 Jan 2017 16:58:11 -0800 Subject: [PATCH 0366/1275] Update Stack and Queue files to use top and front properties (#351) * Update Stack.swift and StackTests.swift to use top property - peek() method was replaced with top property. Update Stack.swift and StackTests.swift to use top property instead of peek() method. - Fix indentation in Stack/README.markdown. * Update Queue-Optimized.swift and QueueTests.swift to use front property - peek() method was replaced with front property. Update Queue-Optimized.swift and QueueTests.swift to use front property instead of peek() method. - Fix front property implementation of Queue-Optimized in Queue/README.markdown. * Update Queue-Simple.swift to use front property instead of peek() method --- Queue/Queue-Optimized.swift | 2 +- Queue/Queue-Simple.swift | 2 +- Queue/README.markdown | 6 +++++- Queue/Tests/QueueTests.swift | 16 ++++++++-------- Stack/README.markdown | 2 +- Stack/Stack.swift | 2 +- Stack/Tests/StackTests.swift | 16 ++++++++-------- 7 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index ad6999295..7dff91698 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -37,7 +37,7 @@ public struct Queue { return element } - public func peek() -> T? { + public var front: T? { if isEmpty { return nil } else { diff --git a/Queue/Queue-Simple.swift b/Queue/Queue-Simple.swift index 27fbdee4d..c5e8067c8 100644 --- a/Queue/Queue-Simple.swift +++ b/Queue/Queue-Simple.swift @@ -30,7 +30,7 @@ public struct Queue { } } - public func peek() -> T? { + public var front: T? { return array.first } } diff --git a/Queue/README.markdown b/Queue/README.markdown index 25d6205f8..f8259c31c 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -167,7 +167,11 @@ public struct Queue { } public var front: T? { - return array.first + if isEmpty { + return nil + } else { + return array[head] + } } } ``` diff --git a/Queue/Tests/QueueTests.swift b/Queue/Tests/QueueTests.swift index 7406f8d35..b820ac0d3 100755 --- a/Queue/Tests/QueueTests.swift +++ b/Queue/Tests/QueueTests.swift @@ -6,7 +6,7 @@ class QueueTest: XCTestCase { var queue = Queue() XCTAssertTrue(queue.isEmpty) XCTAssertEqual(queue.count, 0) - XCTAssertEqual(queue.peek(), nil) + XCTAssertEqual(queue.front, nil) XCTAssertNil(queue.dequeue()) } @@ -16,13 +16,13 @@ class QueueTest: XCTestCase { queue.enqueue(123) XCTAssertFalse(queue.isEmpty) XCTAssertEqual(queue.count, 1) - XCTAssertEqual(queue.peek(), 123) + XCTAssertEqual(queue.front, 123) let result = queue.dequeue() XCTAssertEqual(result, 123) XCTAssertTrue(queue.isEmpty) XCTAssertEqual(queue.count, 0) - XCTAssertEqual(queue.peek(), nil) + XCTAssertEqual(queue.front, nil) } func testTwoElements() { @@ -32,19 +32,19 @@ class QueueTest: XCTestCase { queue.enqueue(456) XCTAssertFalse(queue.isEmpty) XCTAssertEqual(queue.count, 2) - XCTAssertEqual(queue.peek(), 123) + XCTAssertEqual(queue.front, 123) let result1 = queue.dequeue() XCTAssertEqual(result1, 123) XCTAssertFalse(queue.isEmpty) XCTAssertEqual(queue.count, 1) - XCTAssertEqual(queue.peek(), 456) + XCTAssertEqual(queue.front, 456) let result2 = queue.dequeue() XCTAssertEqual(result2, 456) XCTAssertTrue(queue.isEmpty) XCTAssertEqual(queue.count, 0) - XCTAssertEqual(queue.peek(), nil) + XCTAssertEqual(queue.front, nil) } func testMakeEmpty() { @@ -58,12 +58,12 @@ class QueueTest: XCTestCase { queue.enqueue(789) XCTAssertEqual(queue.count, 1) - XCTAssertEqual(queue.peek(), 789) + XCTAssertEqual(queue.front, 789) let result = queue.dequeue() XCTAssertEqual(result, 789) XCTAssertTrue(queue.isEmpty) XCTAssertEqual(queue.count, 0) - XCTAssertEqual(queue.peek(), nil) + XCTAssertEqual(queue.front, nil) } } diff --git a/Stack/README.markdown b/Stack/README.markdown index a79e2c261..1a3ca2638 100644 --- a/Stack/README.markdown +++ b/Stack/README.markdown @@ -61,7 +61,7 @@ public struct Stack { } public var top: T? { - return array.last + return array.last } } ``` diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 49edaf4cb..974d5a443 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -22,7 +22,7 @@ public struct Stack { return array.popLast() } - public func peek() -> T? { + public var top: T? { return array.last } } diff --git a/Stack/Tests/StackTests.swift b/Stack/Tests/StackTests.swift index 62e26b0fa..f4df09a67 100755 --- a/Stack/Tests/StackTests.swift +++ b/Stack/Tests/StackTests.swift @@ -6,7 +6,7 @@ class StackTest: XCTestCase { var stack = Stack() XCTAssertTrue(stack.isEmpty) XCTAssertEqual(stack.count, 0) - XCTAssertEqual(stack.peek(), nil) + XCTAssertEqual(stack.top, nil) XCTAssertNil(stack.pop()) } @@ -16,13 +16,13 @@ class StackTest: XCTestCase { stack.push(123) XCTAssertFalse(stack.isEmpty) XCTAssertEqual(stack.count, 1) - XCTAssertEqual(stack.peek(), 123) + XCTAssertEqual(stack.top, 123) let result = stack.pop() XCTAssertEqual(result, 123) XCTAssertTrue(stack.isEmpty) XCTAssertEqual(stack.count, 0) - XCTAssertEqual(stack.peek(), nil) + XCTAssertEqual(stack.top, nil) XCTAssertNil(stack.pop()) } @@ -33,19 +33,19 @@ class StackTest: XCTestCase { stack.push(456) XCTAssertFalse(stack.isEmpty) XCTAssertEqual(stack.count, 2) - XCTAssertEqual(stack.peek(), 456) + XCTAssertEqual(stack.top, 456) let result1 = stack.pop() XCTAssertEqual(result1, 456) XCTAssertFalse(stack.isEmpty) XCTAssertEqual(stack.count, 1) - XCTAssertEqual(stack.peek(), 123) + XCTAssertEqual(stack.top, 123) let result2 = stack.pop() XCTAssertEqual(result2, 123) XCTAssertTrue(stack.isEmpty) XCTAssertEqual(stack.count, 0) - XCTAssertEqual(stack.peek(), nil) + XCTAssertEqual(stack.top, nil) XCTAssertNil(stack.pop()) } @@ -60,13 +60,13 @@ class StackTest: XCTestCase { stack.push(789) XCTAssertEqual(stack.count, 1) - XCTAssertEqual(stack.peek(), 789) + XCTAssertEqual(stack.top, 789) let result = stack.pop() XCTAssertEqual(result, 789) XCTAssertTrue(stack.isEmpty) XCTAssertEqual(stack.count, 0) - XCTAssertEqual(stack.peek(), nil) + XCTAssertEqual(stack.top, nil) XCTAssertNil(stack.pop()) } } From d3b2496c3b5a3eca4f80fdc8d33159ccd2fa6c2a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 12 Jan 2017 01:43:41 -0800 Subject: [PATCH 0367/1275] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 9e0ae00fa..e5c8f8dae 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. -All code is compatible with **Xcode 7.3** and **Swift 2.2**. We'll keep this updated with the latest version of Swift. +Most code is compatible with **Xcode 8.2** and **Swift 3**. We'll keep this updated with the latest version of Swift. This is a work in progress. More algorithms will be added soon. :-) From d44abb819f182abc44f86026d211ed1a132ccc88 Mon Sep 17 00:00:00 2001 From: Tai Heng Date: Tue, 10 Jan 2017 21:47:58 -0500 Subject: [PATCH 0368/1275] Updated radixSort argument to swift3 syntax. --- Radix Sort/radixSort.swift | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Radix Sort/radixSort.swift b/Radix Sort/radixSort.swift index 31a783db7..24d4155d7 100644 --- a/Radix Sort/radixSort.swift +++ b/Radix Sort/radixSort.swift @@ -5,43 +5,42 @@ */ -func radixSort(inout arr: [Int] ) { - - +// NOTE: This implementation does not handle negative numbers +func radixSort(_ array: inout [Int] ) { let radix = 10 //Here we define our radix to be 10 var done = false var index: Int var digit = 1 //Which digit are we on? - - + + while !done { //While our sorting is not completed done = true //Assume it is done for now - + var buckets: [[Int]] = [] //Our sorting subroutine is bucket sort, so let us predefine our buckets - + for _ in 1...radix { buckets.append([]) } - - - for number in arr { + + + for number in array { index = number / digit //Which bucket will we access? buckets[index % radix].append(number) if done && index > 0 { //If we arent done, continue to finish, otherwise we are done done = false } } - + var i = 0 - + for j in 0.. Date: Tue, 10 Jan 2017 21:48:55 -0500 Subject: [PATCH 0369/1275] Added playground demonstrating radixSort. --- .../RadixSort.playground/Contents.swift | 16 +++++++ .../Sources/radixSort.swift | 46 +++++++++++++++++++ .../contents.xcplayground | 4 ++ 3 files changed, 66 insertions(+) create mode 100644 Radix Sort/RadixSort.playground/Contents.swift create mode 100644 Radix Sort/RadixSort.playground/Sources/radixSort.swift create mode 100644 Radix Sort/RadixSort.playground/contents.xcplayground diff --git a/Radix Sort/RadixSort.playground/Contents.swift b/Radix Sort/RadixSort.playground/Contents.swift new file mode 100644 index 000000000..a4f7e3527 --- /dev/null +++ b/Radix Sort/RadixSort.playground/Contents.swift @@ -0,0 +1,16 @@ +//: Playground - noun: a place where people can play + +import Cocoa + +// 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 +} +radixSort(&bigArray) diff --git a/Radix Sort/RadixSort.playground/Sources/radixSort.swift b/Radix Sort/RadixSort.playground/Sources/radixSort.swift new file mode 100644 index 000000000..136ede4fd --- /dev/null +++ b/Radix Sort/RadixSort.playground/Sources/radixSort.swift @@ -0,0 +1,46 @@ +/* + + 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] ) { + let radix = 10 //Here we define our radix to be 10 + var done = false + var index: Int + var digit = 1 //Which digit are we on? + + + while !done { //While our sorting is not completed + done = true //Assume it is done for now + + var buckets: [[Int]] = [] //Our sorting subroutine is bucket sort, so let us predefine our buckets + + for _ in 1...radix { + buckets.append([]) + } + + + for number in array { + index = number / digit //Which bucket will we access? + buckets[index % radix].append(number) + if done && index > 0 { //If we arent done, continue to finish, otherwise we are done + done = false + } + } + + var i = 0 + + for j in 0.. + + + \ No newline at end of file From 021772eee7c6b8da4598fa7d0ecffb817388aa94 Mon Sep 17 00:00:00 2001 From: Tai Heng Date: Tue, 10 Jan 2017 21:49:55 -0500 Subject: [PATCH 0370/1275] Added tests for RadixSort. --- .travis.yml | 1 + .../contents.xcworkspacedata | 7 + Radix Sort/Tests/Info.plist | 22 ++ Radix Sort/Tests/RadixSortTests.swift | 18 ++ .../Tests/Tests.xcodeproj/project.pbxproj | 277 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 101 +++++++ 7 files changed, 433 insertions(+) create mode 100644 Radix Sort/RadixSort.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Radix Sort/Tests/Info.plist create mode 100644 Radix Sort/Tests/RadixSortTests.swift create mode 100644 Radix Sort/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Radix Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Radix Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/.travis.yml b/.travis.yml index 9d8c6e346..64c23eb56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ script: # - 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.xcodeproj -scheme Tests +- xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests # - xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests diff --git a/Radix Sort/RadixSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Radix Sort/RadixSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Radix Sort/RadixSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Radix Sort/Tests/Info.plist b/Radix Sort/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Radix Sort/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Radix Sort/Tests/RadixSortTests.swift b/Radix Sort/Tests/RadixSortTests.swift new file mode 100644 index 000000000..688bcdcb8 --- /dev/null +++ b/Radix Sort/Tests/RadixSortTests.swift @@ -0,0 +1,18 @@ +// +// RadixSortTests.swift +// Tests +// +// Created by theng on 2017-01-10. +// Copyright © 2017 Swift Algorithm Club. All rights reserved. +// + +import XCTest + +class RadixSortTests: XCTestCase { + 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] + radixSort(&sequence) + XCTAssertEqual(sequence, expectedSequence) + } +} diff --git a/Radix Sort/Tests/Tests.xcodeproj/project.pbxproj b/Radix Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..4b32f71b5 --- /dev/null +++ b/Radix Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,277 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 056E92AB1E25D0C700B30F52 /* RadixSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056E92AA1E25D0C700B30F52 /* RadixSortTests.swift */; }; + 056E92AF1E25D3D700B30F52 /* radixSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056E92AE1E25D3D700B30F52 /* radixSort.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 056E92A21E25D04D00B30F52 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 056E92A61E25D04D00B30F52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 056E92AA1E25D0C700B30F52 /* RadixSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadixSortTests.swift; sourceTree = ""; }; + 056E92AE1E25D3D700B30F52 /* radixSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = radixSort.swift; path = ../radixSort.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 056E929F1E25D04D00B30F52 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 056E92851E25D03300B30F52 = { + isa = PBXGroup; + children = ( + 056E92A31E25D04D00B30F52 /* Tests */, + 056E928F1E25D03300B30F52 /* Products */, + ); + sourceTree = ""; + }; + 056E928F1E25D03300B30F52 /* Products */ = { + isa = PBXGroup; + children = ( + 056E92A21E25D04D00B30F52 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 056E92A31E25D04D00B30F52 /* Tests */ = { + isa = PBXGroup; + children = ( + 056E92AE1E25D3D700B30F52 /* radixSort.swift */, + 056E92A61E25D04D00B30F52 /* Info.plist */, + 056E92AA1E25D0C700B30F52 /* RadixSortTests.swift */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 056E92A11E25D04D00B30F52 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 056E92A71E25D04D00B30F52 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 056E929E1E25D04D00B30F52 /* Sources */, + 056E929F1E25D04D00B30F52 /* Frameworks */, + 056E92A01E25D04D00B30F52 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 056E92A21E25D04D00B30F52 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 056E92861E25D03300B30F52 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 056E92A11E25D04D00B30F52 = { + CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 0820; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 056E92891E25D03300B30F52 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 056E92851E25D03300B30F52; + productRefGroup = 056E928F1E25D03300B30F52 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 056E92A11E25D04D00B30F52 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 056E92A01E25D04D00B30F52 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 056E929E1E25D04D00B30F52 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 056E92AF1E25D3D700B30F52 /* radixSort.swift in Sources */, + 056E92AB1E25D0C700B30F52 /* RadixSortTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 056E92991E25D03300B30F52 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 056E929A1E25D03300B30F52 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 056E92A81E25D04D00B30F52 /* 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_VERSION = 3.0; + }; + name = Debug; + }; + 056E92A91E25D04D00B30F52 /* 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_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 056E92891E25D03300B30F52 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E92991E25D03300B30F52 /* Debug */, + 056E929A1E25D03300B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 056E92A71E25D04D00B30F52 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E92A81E25D04D00B30F52 /* Debug */, + 056E92A91E25D04D00B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 056E92861E25D03300B30F52 /* Project object */; +} diff --git a/Radix Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Radix Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Radix Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Radix Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Radix Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..b3f6d696a --- /dev/null +++ b/Radix Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 548f11791666bb2df3cae77183efda861171a0d0 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 12 Jan 2017 20:17:41 -0800 Subject: [PATCH 0371/1275] Code restructuring - Moved source files Matrix.swift, MatrixSize.swift & Number.swift to the Sources foler in the PLayground - Restrucutred the code into extensions to make it more organized and readable - Deleted all the objects from the playground and moved them to the Sources folder --- .../MatrixSize.swift | 26 -- .../Contents.swift | 297 +----------------- .../Sources}/Matrix.swift | 183 +++++------ .../Sources/MatrixSize.swift | 33 ++ .../Sources}/Number.swift | 15 +- 5 files changed, 136 insertions(+), 418 deletions(-) delete mode 100644 Strassen Matrix Multiplication/MatrixSize.swift rename Strassen Matrix Multiplication/{ => StrassensMatrixMultiplication.playground/Sources}/Matrix.swift (72%) create mode 100644 Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift rename Strassen Matrix Multiplication/{ => StrassensMatrixMultiplication.playground/Sources}/Number.swift (71%) diff --git a/Strassen Matrix Multiplication/MatrixSize.swift b/Strassen Matrix Multiplication/MatrixSize.swift deleted file mode 100644 index f1eada931..000000000 --- a/Strassen Matrix Multiplication/MatrixSize.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// MatrixSize.swift -// -// -// Created by Richard Ash on 10/28/16. -// -// - -import Foundation - -struct MatrixSize: Equatable { - let rows: Int - let columns: Int - - func forEach(_ body: (Int, Int) throws -> Void) rethrows { - for row in 0.. Bool { - return lhs.columns == rhs.columns && lhs.rows == rhs.rows -} diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift index d4b4d8330..50af60a6f 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -1,302 +1,7 @@ //: Playground - noun: a place where people can play // Reference - http://mathworld.wolfram.com/StrassenFormulas.html - -import UIKit - -enum RowOrColumn { - case row, column -} - -protocol Number: Multipliable, Addable { - static var zero: Self { get } -} - -protocol Addable { - static func +(lhs: Self, rhs: Self) -> Self - static func -(lhs: Self, rhs: Self) -> Self -} - -protocol Multipliable { - static func *(lhs: Self, rhs: Self) -> Self -} - -extension Int: Number { - static var zero: Int { - return 0 - } -} - -extension Double: Number { - static var zero: Double { - return 0.0 - } -} - -extension Float: Number { - static var zero: Float { - return 0.0 - } -} - - -extension Array where Element: Number { - func dot(_ b: Array) -> Element { - let a = self - assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") - let c = a.indices.map{ a[$0] * b[$0] } - return c.reduce(Element.zero, { $0 + $1 }) - } -} - -struct MatrixSize: Equatable { - let rows: Int - let columns: Int - - func forEach(_ body: (Int, Int) throws -> Void) rethrows { - for row in 0.. Bool { - return lhs.columns == rhs.columns && lhs.rows == rhs.rows -} - - -struct Matrix { - - // MARK: - Variables - - let rows: Int, columns: Int - var grid: [T] - - var isSquare: Bool { - return rows == columns - } - - var size: MatrixSize { - return MatrixSize(rows: rows, columns: columns) - } - - // MARK: - Init - - init(rows: Int, columns: Int, initialValue: T = T.zero) { - self.rows = rows - self.columns = columns - self.grid = Array(repeating: initialValue, count: rows * columns) - } - - init(size: Int, initialValue: T = T.zero) { - self.rows = size - self.columns = size - self.grid = Array(repeating: initialValue, count: rows * columns) - } - - // MARK: - Subscript - - subscript(row: Int, column: Int) -> T { - get { - assert(indexIsValid(row: row, column: column), "Index out of range") - return grid[(row * columns) + column] - } - set { - assert(indexIsValid(row: row, column: column), "Index out of range") - grid[(row * columns) + column] = newValue - } - } - - subscript(type: RowOrColumn, value: Int) -> [T] { - get { - switch type { - case .row: - assert(indexIsValid(row: value, column: 0), "Index out of range") - return Array(grid[(value * columns)..<(value * columns) + columns]) - case .column: - assert(indexIsValid(row: 0, column: value), "Index out of range") - var columns: [T] = [] - for row in 0.. Bool { - return row >= 0 && row < rows && column >= 0 && column < columns - } - - private func strassenR(by B: Matrix) -> Matrix { - let A = self - assert(A.isSquare && B.isSquare, "This function requires square matricies!") - guard A.rows > 1 && B.rows > 1 else { return A * B } - - let n = A.rows - let nBy2 = n / 2 - - var a11 = Matrix(size: nBy2) - var a12 = Matrix(size: nBy2) - var a21 = Matrix(size: nBy2) - var a22 = Matrix(size: nBy2) - var b11 = Matrix(size: nBy2) - var b12 = Matrix(size: nBy2) - var b21 = Matrix(size: nBy2) - var b22 = Matrix(size: nBy2) - - for i in 0.. Int { - return Int(pow(2, ceil(log2(Double(n))))) - } - - // MARK: - Functions - - func strassenMatrixMultiply(by B: Matrix) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - - let n = max(A.rows, A.columns, B.rows, B.columns) - let m = nextPowerOfTwo(of: n) - - var APrep = Matrix(size: m) - var BPrep = Matrix(size: m) - - A.size.forEach { (i, j) in - APrep[i,j] = A[i,j] - } - - B.size.forEach { (i, j) in - BPrep[i,j] = B[i,j] - } - - let CPrep = APrep.strassenR(by: BPrep) - var C = Matrix(rows: A.rows, columns: B.columns) - - for i in 0..) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - - var C = Matrix(rows: A.rows, columns: B.columns) - - for i in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term multiply matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0.. { +public struct Matrix { // MARK: - Variables @@ -29,20 +29,22 @@ struct Matrix { // MARK: - Init - init(rows: Int, columns: Int, initialValue: T = T.zero) { + public init(rows: Int, columns: Int, initialValue: T = T.zero) { self.rows = rows self.columns = columns self.grid = Array(repeating: initialValue, count: rows * columns) } - init(size: Int, initialValue: T = T.zero) { + public init(size: Int, initialValue: T = T.zero) { self.rows = size self.columns = size self.grid = Array(repeating: initialValue, count: rows * columns) } - - // MARK: - Subscript - +} + +// MARK: - Public Functions + +public extension Matrix { subscript(row: Int, column: Int) -> T { get { assert(indexIsValid(row: row, column: column), "Index out of range") @@ -88,13 +90,59 @@ struct Matrix { } } - // MARK: - Private Functions + func strassenMatrixMultiply(by B: Matrix) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + let n = max(A.rows, A.columns, B.rows, B.columns) + let m = nextPowerOfTwo(of: n) + + var APrep = Matrix(size: m) + var BPrep = Matrix(size: m) + + A.size.forEach { (i, j) in + APrep[i,j] = A[i,j] + } + + B.size.forEach { (i, j) in + BPrep[i,j] = B[i,j] + } + + let CPrep = APrep.strassenR(by: BPrep) + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0.. Bool { + func matrixMultiply(by B: Matrix) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0.. Bool { return row >= 0 && row < rows && column >= 0 && column < columns } - private func strassenR(by B: Matrix) -> Matrix { + func strassenR(by B: Matrix) -> Matrix { let A = self assert(A.isSquare && B.isSquare, "This function requires square matricies!") guard A.rows > 1 && B.rows > 1 else { return A * B } @@ -150,97 +198,56 @@ struct Matrix { return C } - private func nextPowerOfTwo(of n: Int) -> Int { + func nextPowerOfTwo(of n: Int) -> Int { return Int(pow(2, ceil(log2(Double(n))))) } - - // MARK: - Functions - - func strassenMatrixMultiply(by B: Matrix) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - - let n = max(A.rows, A.columns, B.rows, B.columns) - let m = nextPowerOfTwo(of: n) - - var APrep = Matrix(size: m) - var BPrep = Matrix(size: m) - - A.size.forEach { (i, j) in - APrep[i,j] = A[i,j] - } - - B.size.forEach { (i, j) in - BPrep[i,j] = B[i,j] - } - - let CPrep = APrep.strassenR(by: BPrep) - var C = Matrix(rows: A.rows, columns: B.columns) - - for i in 0..) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - - var C = Matrix(rows: A.rows, columns: B.columns) - - for i in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term multiply matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { - assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") - let rows = lhs.rows - let columns = lhs.columns - - var newMatrix = Matrix(rows: rows, columns: columns) - for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { + assert(lhs.size == rhs.size, "To term-by-term multiply matricies they need to be the same size!") + let rows = lhs.rows + let columns = lhs.columns + + var newMatrix = Matrix(rows: rows, columns: columns) + for row in 0.. Void) rethrows { + for row in 0.. Bool { + return lhs.columns == rhs.columns && lhs.rows == rhs.rows + } +} diff --git a/Strassen Matrix Multiplication/Number.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift similarity index 71% rename from Strassen Matrix Multiplication/Number.swift rename to Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift index 34c6d5308..9f4c7f4ab 100644 --- a/Strassen Matrix Multiplication/Number.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift @@ -8,40 +8,39 @@ import Foundation -protocol Number: Multipliable, Addable { +public protocol Number: Multipliable, Addable { static var zero: Self { get } } -protocol Addable { +public protocol Addable { static func +(lhs: Self, rhs: Self) -> Self static func -(lhs: Self, rhs: Self) -> Self } -protocol Multipliable { +public protocol Multipliable { static func *(lhs: Self, rhs: Self) -> Self } extension Int: Number { - static var zero: Int { + public static var zero: Int { return 0 } } extension Double: Number { - static var zero: Double { + public static var zero: Double { return 0.0 } } extension Float: Number { - static var zero: Float { + public static var zero: Float { return 0.0 } } - extension Array where Element: Number { - func dot(_ b: Array) -> Element { + public func dot(_ b: Array) -> Element { let a = self assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") let c = a.indices.map{ a[$0] * b[$0] } From c260a3438c5e7103654d3b576b528065089c6972 Mon Sep 17 00:00:00 2001 From: pbodsk Date: Fri, 13 Jan 2017 13:31:37 +0100 Subject: [PATCH 0372/1275] migrates Single-Source Shortest Paths to Swift 3 syntax --- .travis.yml | 2 +- .../SSSP.playground/Contents.swift | 2 +- .../SSSP.xcodeproj/project.pbxproj | 13 +++++++++++- .../xcshareddata/xcschemes/SSSP.xcscheme | 2 +- .../xcshareddata/xcschemes/SSSPTests.xcscheme | 2 +- .../SSSP/BellmanFord.swift | 20 +++++++++---------- .../SSSP/SSSP.swift | 2 +- .../SSSPTests/SSSPTests.swift | 20 +++++++++---------- 8 files changed, 37 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9d8c6e346..765f07786 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ script: - 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 ./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 diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift b/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift index ece36a663..652b558b1 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift +++ b/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift @@ -25,4 +25,4 @@ graph.addDirectedEdge(z, to: x, withWeight: 7) let result = BellmanFord.apply(graph, source: s)! -let path = result.path(z, inGraph: graph) +let path = result.path(to: z, inGraph: graph) diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj index 55893acfd..0dd67f69c 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj @@ -184,14 +184,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 49BFA2921CDF86E100522D66 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0810; }; 49BFA29C1CDF86E100522D66 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0810; }; }; }; @@ -301,8 +303,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -349,8 +353,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -370,6 +376,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -392,6 +399,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -411,6 +419,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.SSSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -422,6 +431,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.SSSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -433,6 +443,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.SSSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSP.xcscheme b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSP.xcscheme index 9d28c18c4..469159bd8 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSP.xcscheme +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSP.xcscheme @@ -1,6 +1,6 @@ { +public struct BellmanFord where T: Hashable { public typealias Q = T } @@ -30,12 +30,12 @@ extension BellmanFord: SSSPAlgorithm { - returns a `BellmanFordResult` struct which can be queried for shortest paths and their total weights, or `nil` if a negative weight cycle exists */ - public static func apply(graph: AbstractGraph, source: Vertex) -> BellmanFordResult? { + public static func apply(_ graph: AbstractGraph, source: Vertex) -> BellmanFordResult? { let vertices = graph.vertices let edges = graph.edges - var predecessors = Array(count: vertices.count, repeatedValue: nil) - var weights = Array(count: vertices.count, repeatedValue: Double.infinity) + var predecessors = Array(repeating: nil, count: vertices.count) + var weights = Array(repeating: Double.infinity, count: vertices.count) predecessors[source.index] = source.index weights[source.index] = 0 @@ -78,10 +78,10 @@ extension BellmanFord: SSSPAlgorithm { It conforms to the `SSSPResult` procotol which provides methods to retrieve distances and paths between given pairs of start and end nodes. */ -public struct BellmanFordResult { +public struct BellmanFordResult where T: Hashable { - private var predecessors: [Int?] - private var weights: [Double] + fileprivate var predecessors: [Int?] + fileprivate var weights: [Double] } @@ -112,7 +112,7 @@ extension BellmanFordResult: SSSPResult { return nil } - guard let path = recursePath(to, inGraph: graph, path: [to]) else { + guard let path = recursePath(to: to, inGraph: graph, path: [to]) else { return nil } @@ -126,7 +126,7 @@ extension BellmanFordResult: SSSPResult { - returns: the list of predecessors discovered so far, or `nil` if the next vertex has no predecessor */ - private func recursePath(to: Vertex, inGraph graph: AbstractGraph, path: [Vertex]) -> [Vertex]? { + fileprivate func recursePath(to: Vertex, inGraph graph: AbstractGraph, path: [Vertex]) -> [Vertex]? { guard let predecessorIdx = predecessors[to.index] else { return nil } @@ -136,7 +136,7 @@ extension BellmanFordResult: SSSPResult { return [ to ] } - guard let buildPath = recursePath(predecessor, inGraph: graph, path: path) else { + guard let buildPath = recursePath(to: predecessor, inGraph: graph, path: path) else { return nil } diff --git a/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift index 8e3afc40a..3066f6516 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift +++ b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift @@ -18,7 +18,7 @@ protocol SSSPAlgorithm { associatedtype Q: Equatable, Hashable associatedtype P: SSSPResult - static func apply(graph: AbstractGraph, source: Vertex) -> P? + static func apply(_ graph: AbstractGraph, source: Vertex) -> P? } diff --git a/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift b/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift index 1bb862b74..04584dfeb 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift +++ b/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift @@ -40,11 +40,11 @@ class SSSPTests: XCTestCase { let result = BellmanFord.apply(graph, source: s)! let expectedPath = ["s", "y", "x", "t", "z"] - let computedPath = result.path(z, inGraph: graph)! + let computedPath = result.path(to: z, inGraph: graph)! XCTAssertEqual(expectedPath, computedPath, "expected path of \(expectedPath) but got \(computedPath)") let expectedWeight = -2.0 - let computedWeight = result.distance(z) + let computedWeight = result.distance(to: z) XCTAssertEqual(expectedWeight, computedWeight, "expected weight of \(expectedWeight) but got \(computedWeight)") } @@ -71,11 +71,11 @@ class SSSPTests: XCTestCase { let result = BellmanFord.apply(graph, source: a)! let expectedPath = ["a", "b", "c", "e", "d"] - let computedPath = result.path(d, inGraph: graph)! + let computedPath = result.path(to: d, inGraph: graph)! XCTAssertEqual(expectedPath, computedPath, "expected path of \(expectedPath) but got \(computedPath)") let expectedWeight = 7.0 - let computedWeight = result.distance(d) + let computedWeight = result.distance(to: d) XCTAssertEqual(expectedWeight, computedWeight, "expected weight of \(expectedWeight) but got \(computedWeight)") } @@ -104,12 +104,12 @@ class SSSPTests: XCTestCase { let result = BellmanFord.apply(graph, source: a)! - XCTAssertNil(result.path(b, inGraph: graph), "a path should not be defined from a ~> b") - XCTAssertNil(result.distance(b), "a path should not be defined from a ~> b") - XCTAssertNotNil(result.path(s, inGraph: graph), "a path should be defined from a ~> s") - XCTAssertNotNil(result.distance(s), "a path should be defined from a ~> s") - XCTAssertNotNil(result.path(t, inGraph: graph), "a path should be defined from a ~> t") - XCTAssertNotNil(result.distance(t), "a path should be defined from a ~> t") + XCTAssertNil(result.path(to: b, inGraph: graph), "a path should not be defined from a ~> b") + XCTAssertNil(result.distance(to: b), "a path should not be defined from a ~> b") + XCTAssertNotNil(result.path(to: s, inGraph: graph), "a path should be defined from a ~> s") + XCTAssertNotNil(result.distance(to: s), "a path should be defined from a ~> s") + XCTAssertNotNil(result.path(to: t, inGraph: graph), "a path should be defined from a ~> t") + XCTAssertNotNil(result.distance(to: t), "a path should be defined from a ~> t") } func testNegativeWeightCycle() { From 2e5a4a60471ba9d215bfe52975bd563524908637 Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Sat, 14 Jan 2017 12:50:59 +0000 Subject: [PATCH 0373/1275] Update README.md --- DiningPhilosophers/README.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 06302cf2a..5f5d5383d 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -1,13 +1,35 @@ # SwiftDiningPhilosophers Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using GCD and Semaphore in Swift) -Written by Jacopo Mangiavacchi +Written for Swift Algorithm Club by Jacopo Mangiavacchi -# from https://en.wikipedia.org/wiki/Dining_philosophers_problem +# Introduction In computer science, the dining philosophers problem is an example problem often used in concurrent algorithm design to illustrate synchronization issues and techniques for resolving them. It was originally formulated in 1965 by Edsger Dijkstra as a student exam exercise, presented in terms of computers competing for access to tape drive peripherals. Soon after, Tony Hoare gave the problem its present formulation. This Swift implementation is based on the Chandy/Misra solution and it use GCD Dispatch and Semaphone on Swift cross platform + +# Problem statement + +Five silent philosophers sit at a round table with bowls of spaghetti. Forks are placed between each pair of adjacent philosophers. + +Each philosopher must alternately think and eat. However, a philosopher can only eat spaghetti when they have both left and right forks. Each fork can be held by only one philosopher and so a philosopher can use the fork only if it is not being used by another philosopher. After an individual philosopher finishes eating, they need to put down both forks so that the forks become available to others. A philosopher can take the fork on their right or the one on their left as they become available, but cannot start eating before getting both forks. + +Eating is not limited by the remaining amounts of spaghetti or stomach space; an infinite supply and an infinite demand are assumed. + +The problem is how to design a discipline of behavior (a concurrent algorithm) such that no philosopher will starve; i.e., each can forever continue to alternate between eating and thinking, assuming that no philosopher can know when others may want to eat or think. + +This is an illustration of an dinining table: + +![Dining Philosophers table](https://upload.wikimedia.org/wikipedia/commons/7/7b/An_illustration_of_the_dining_philosophers_problem.png) + + + +# See also + +Dining Philosophers on Wikipedia https://en.wikipedia.org/wiki/Dining_philosophers_problem + +Written for Swift Algorithm Club by Jacopo Mangiavacchi From 13d1827d697b030de86dcb042a2068b9f26f3f52 Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Sat, 14 Jan 2017 13:00:23 +0000 Subject: [PATCH 0374/1275] Update README.md --- DiningPhilosophers/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 5f5d5383d..22687d2fd 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -27,6 +27,27 @@ This is an illustration of an dinining table: ![Dining Philosophers table](https://upload.wikimedia.org/wikipedia/commons/7/7b/An_illustration_of_the_dining_philosophers_problem.png) +# Solution +There are different solutions for this classic algorithm and this Swift implementation is based on the on the Chandy/Misra solution that more generally allows for arbitrary agents to contend for an arbitrary number of resources in a completely distributed scenario with no needs for a central authority to control the locking and serialization of resources. + +However, it is very important to note here that this solution violates the requirement that "the philosophers do not speak to each other" (due to the request messages). + + +# Description +For every pair of philosophers contending for a resource, create a fork and give it to the philosopher with the lower ID (n for agent Pn). Each fork can either be dirty or clean. Initially, all forks are dirty. +When a philosopher wants to use a set of resources (i.e. eat), said philosopher must obtain the forks from their contending neighbors. For all such forks the philosopher does not have, they send a request message. +When a philosopher with a fork receives a request message, they keep the fork if it is clean, but give it up when it is dirty. If the philosopher sends the fork over, they clean the fork before doing so. +After a philosopher is done eating, all their forks become dirty. If another philosopher had previously requested one of the forks, the philosopher that has just finished eating cleans the fork and sends it. +This solution also allows for a large degree of concurrency, and will solve an arbitrarily large problem. + +It also solves the starvation problem. The clean / dirty labels act as a way of giving preference to the most "starved" processes, and a disadvantage to processes that have just "eaten". One could compare their solution to one where philosophers are not allowed to eat twice in a row without letting others use the forks in between. Chandy and Misra's solution is more flexible than that, but has an element tending in that direction. + +In their analysis they derive a system of preference levels from the distribution of the forks and their clean/dirty states. They show that this system may describe an acyclic graph, and if so, the operations in their protocol cannot turn that graph into a cyclic one. This guarantees that deadlock cannot occur. However, if the system is initialized to a perfectly symmetric state, like all philosophers holding their left side forks, then the graph is cyclic at the outset, and their solution cannot prevent a deadlock. Initializing the system so that philosophers with lower IDs have dirty forks ensures the graph is initially acyclic. + + +# Swift implementation + + # See also From 4daf0d07dedf6f638a494a535b69d63e17bdf53c Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Sat, 14 Jan 2017 13:01:02 +0000 Subject: [PATCH 0375/1275] Update README.md --- DiningPhilosophers/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 22687d2fd..3ac5b1343 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -1,4 +1,4 @@ -# SwiftDiningPhilosophers +# Dining Philosophers Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using GCD and Semaphore in Swift) Written for Swift Algorithm Club by Jacopo Mangiavacchi From 5b3f3c4570b17be37d4f19344e3755523a9bcd21 Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Sat, 14 Jan 2017 13:08:16 +0000 Subject: [PATCH 0376/1275] Update main.swift --- DiningPhilosophers/Sources/main.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiningPhilosophers/Sources/main.swift b/DiningPhilosophers/Sources/main.swift index dfde40773..deff344b9 100755 --- a/DiningPhilosophers/Sources/main.swift +++ b/DiningPhilosophers/Sources/main.swift @@ -12,7 +12,7 @@ import Dispatch let numberOfPhilosophers = 4 -class ForkPair { +struct ForkPair { static let forksSemaphore:[DispatchSemaphore] = Array(repeating: DispatchSemaphore(value: 1), count: numberOfPhilosophers) let leftFork: DispatchSemaphore @@ -44,7 +44,7 @@ class ForkPair { } -class Philosophers { +struct Philosophers { let forkPair: ForkPair let philosopherIndex: Int From dca7bf14870e3007247344415b9d00e7d5cd8471 Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Sat, 14 Jan 2017 13:23:28 +0000 Subject: [PATCH 0377/1275] Update README.md --- DiningPhilosophers/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 3ac5b1343..29b5916e9 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -47,7 +47,13 @@ In their analysis they derive a system of preference levels from the distributio # Swift implementation +This Swift 3.0 implementation of the Chandy/Misra solution is based on GCD and Semaphore tecnique and it could 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. + +The ForkPair DispatchSemaphore static array is used for waking the neighbour Philosophers any time a fork pair is put down on the table. + +A background DispatchQueue is then used to let any Philosopher run asyncrounosly on the background and a global DispatchSemaphore is simply used in order to keep the main thread on wait forever and let the Philosophers contienue forever in their alternate think and eat cycle. # See also From 671aa3b26f8ec5ea16c2bfdbc567c1f7a2f5819a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 14 Jan 2017 14:57:45 -0800 Subject: [PATCH 0378/1275] Update README.markdown Added Dining Philosophers link. --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index e5c8f8dae..ad5f910b4 100644 --- a/README.markdown +++ b/README.markdown @@ -190,6 +190,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Fizz Buzz](Fizz Buzz/) - [Monty Hall Problem](Monty Hall Problem/) - [Finding Palindromes](Palindromes/) +- [Dining Philosophers](DiningPhilosophers/) ## Learn more! From 71d8a43149fe3b125ce21b4ae3f0ec8eeb50220c Mon Sep 17 00:00:00 2001 From: vincentngo Date: Sun, 15 Jan 2017 11:23:42 -0500 Subject: [PATCH 0379/1275] Update Target to Swift 3.0 --- .../SSSP.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj index 0dd67f69c..fb425a73e 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj @@ -334,6 +334,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -377,6 +378,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From cf0d1b539b2bf628a76e37b33332bab02c9bcc1a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 16 Jan 2017 10:59:20 -0800 Subject: [PATCH 0380/1275] Modified Z-Algorithm to conform to our style guide. --- Z-Algorithm/ZAlgorithm.swift | 116 +++++++------- .../ZetaAlgorithm.playground/Contents.swift | 150 +++++++++--------- Z-Algorithm/ZetaAlgorithm.swift | 56 +++---- 3 files changed, 161 insertions(+), 161 deletions(-) diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift index c9d7de876..9bef69687 100644 --- a/Z-Algorithm/ZAlgorithm.swift +++ b/Z-Algorithm/ZAlgorithm.swift @@ -1,66 +1,66 @@ /* Z-Algorithm for pattern/string pre-processing - - The code is based on the book: - "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" - by Dan Gusfield - Cambridge University Press, 1997 -*/ + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 + */ import Foundation func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var zeta: [Int] = [Int](repeating: 0, count: patternLength) - - var left: Int = 0 - var right: Int = 0 - var k_1: Int = 0 - var betaLength: Int = 0 - var textIndex: Int = 0 - var patternIndex: Int = 0 - - for k in 1 ..< patternLength { - if k > right { - patternIndex = 0 - - while k + patternIndex < patternLength && - pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - - if zeta[k] > 0 { - left = k - right = k + zeta[k] - 1 - } - } else { - k_1 = k - left + 1 - betaLength = right - k + 1 - - if zeta[k_1 - 1] < betaLength { - zeta[k] = zeta[k_1 - 1] - } else if zeta[k_1 - 1] >= betaLength { - textIndex = betaLength - patternIndex = right + 1 - - while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - k - left = k - right = patternIndex - 1 - } + + let pattern = Array(ptrn.characters) + let patternLength = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta = [Int](repeating: 0, count: patternLength) + + var left = 0 + var right = 0 + var k_1 = 0 + var betaLength = 0 + var textIndex = 0 + var patternIndex = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } } - return zeta + } + return zeta } diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift index c9d942149..395122af0 100644 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -2,88 +2,88 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) - let patternLength: Int = pattern.count - - guard patternLength > 0 else { - return nil - } - - var zeta: [Int] = [Int](repeating: 0, count: patternLength) - - var left: Int = 0 - var right: Int = 0 - var k_1: Int = 0 - var betaLength: Int = 0 - var textIndex: Int = 0 - var patternIndex: Int = 0 - - for k in 1 ..< patternLength { - if k > right { - patternIndex = 0 - - while k + patternIndex < patternLength && - pattern[k + patternIndex] == pattern[patternIndex] { - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - - if zeta[k] > 0 { - left = k - right = k + zeta[k] - 1 - } - } else { - k_1 = k - left + 1 - betaLength = right - k + 1 - - if zeta[k_1 - 1] < betaLength { - zeta[k] = zeta[k_1 - 1] - } else if zeta[k_1 - 1] >= betaLength { - textIndex = betaLength - patternIndex = right + 1 - - while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { - textIndex = textIndex + 1 - patternIndex = patternIndex + 1 - } - - zeta[k] = patternIndex - k - left = k - right = patternIndex - 1 - } + + let pattern = Array(ptrn.characters) + let patternLength = pattern.count + + guard patternLength > 0 else { + return nil + } + + var zeta = [Int](repeating: 0, count: patternLength) + + var left = 0 + var right = 0 + var k_1 = 0 + var betaLength = 0 + var textIndex = 0 + var patternIndex = 0 + + for k in 1 ..< patternLength { + if k > right { + patternIndex = 0 + + while k + patternIndex < patternLength && + pattern[k + patternIndex] == pattern[patternIndex] { + patternIndex = patternIndex + 1 + } + + zeta[k] = patternIndex + + if zeta[k] > 0 { + left = k + right = k + zeta[k] - 1 + } + } else { + k_1 = k - left + 1 + betaLength = right - k + 1 + + if zeta[k_1 - 1] < betaLength { + zeta[k] = zeta[k_1 - 1] + } else if zeta[k_1 - 1] >= betaLength { + textIndex = betaLength + patternIndex = right + 1 + + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { + textIndex = textIndex + 1 + patternIndex = patternIndex + 1 } + + zeta[k] = patternIndex - k + left = k + right = patternIndex - 1 + } } - return zeta + } + return zeta } extension String { - - func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) - - guard zeta != nil else { - return nil - } - - var indexes: [Int] = [Int]() - - /* Scan the zeta array to find matched patterns */ - for i in 0 ..< zeta!.count { - if zeta![i] == patternLength { - indexes.append(i - patternLength - 1) - } - } - - guard !indexes.isEmpty else { - return nil - } - - return indexes + + func indexesOf(pattern: String) -> [Int]? { + let patternLength = pattern.characters.count + let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + + var indexes: [Int] = [] + + /* Scan the zeta array to find matched patterns */ + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) + } + } + + guard !indexes.isEmpty else { + return nil } + + return indexes + } } /* Examples */ diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift index 4d80aa665..c35703272 100644 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -1,36 +1,36 @@ /* Z-Algorithm based algorithm for pattern/string matching - - The code is based on the book: - "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" - by Dan Gusfield - Cambridge University Press, 1997 -*/ + + The code is based on the book: + "Algorithms on String, Trees and Sequences: Computer Science and Computational Biology" + by Dan Gusfield + Cambridge University Press, 1997 + */ import Foundation extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength = pattern.characters.count + let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) + + guard zeta != nil else { + return nil + } + + var indexes: [Int] = [Int]() - func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count - let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) - - guard zeta != nil else { - return nil - } - - var indexes: [Int] = [Int]() - - /* Scan the zeta array to find matched patterns */ - for i in 0 ..< zeta!.count { - if zeta![i] == patternLength { - indexes.append(i - patternLength - 1) - } - } - - guard !indexes.isEmpty else { - return nil - } - - return indexes + /* Scan the zeta array to find matched patterns */ + for i in 0 ..< zeta!.count { + if zeta![i] == patternLength { + indexes.append(i - patternLength - 1) + } } + + guard !indexes.isEmpty else { + return nil + } + + return indexes + } } From e5fb825ffa5fb4604ac0dd40782c372b5a5aef20 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 16 Jan 2017 11:01:46 -0800 Subject: [PATCH 0381/1275] Update README.markdown Added Z-algorithm link. --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index ad5f910b4..2d7522b1e 100644 --- a/README.markdown +++ b/README.markdown @@ -50,6 +50,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [k-th Largest Element](Kth Largest Element/). Find the *k*-th largest element in an array, such as the median. - [Selection Sampling](Selection Sampling/). Randomly choose a bunch of items from a collection. - [Union-Find](Union-Find/). Keeps track of disjoint sets and lets you quickly merge them. +- [Z-Algorithm](Z-Algorithm/). Finds all instances of a pattern in a String, and returns the indexes of where the pattern starts within the String. ### String Search From 10abdbc8efa765f6b9700498e9a08ab8de0ffbe1 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 16 Jan 2017 11:02:39 -0800 Subject: [PATCH 0382/1275] Update README.markdown Updated the Z-algorithm link to the String Search section. --- README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 2d7522b1e..97b84057b 100644 --- a/README.markdown +++ b/README.markdown @@ -50,7 +50,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [k-th Largest Element](Kth Largest Element/). Find the *k*-th largest element in an array, such as the median. - [Selection Sampling](Selection Sampling/). Randomly choose a bunch of items from a collection. - [Union-Find](Union-Find/). Keeps track of disjoint sets and lets you quickly merge them. -- [Z-Algorithm](Z-Algorithm/). Finds all instances of a pattern in a String, and returns the indexes of where the pattern starts within the String. + ### String Search @@ -59,6 +59,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - Knuth-Morris-Pratt - Rabin-Karp - [Longest Common Subsequence](Longest Common Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. +- [Z-Algorithm](Z-Algorithm/). Finds all instances of a pattern in a String, and returns the indexes of where the pattern starts within the String. ### Sorting From ca35d57d14073ac99f6a74c5a2057f1ab7f28c60 Mon Sep 17 00:00:00 2001 From: Bo Qian Date: Wed, 18 Jan 2017 17:25:53 -0800 Subject: [PATCH 0383/1275] Simplify the insert method by removing the fileprivate method. Delete duplicated BinarySearchTree.swift, so that there is only one single file. --- .../Sources/BinarySearchTree.swift | 14 +- .../Solution 1/BinarySearchTree.swift | 377 ------------------ .../Tests/Tests.xcodeproj/project.pbxproj | 8 +- .../contents.xcworkspacedata | 3 - 4 files changed, 9 insertions(+), 393 deletions(-) delete mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.swift 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 f4960380e..5edbfc48a 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -23,7 +23,7 @@ public class BinarySearchTree { precondition(array.count > 0) self.init(value: array.first!) for v in array.dropFirst() { - insert(value: v, parent: self) + insert(value: v) } } @@ -74,23 +74,19 @@ extension BinarySearchTree { Performance: runs in O(h) time, where h is the height of the tree. */ public func insert(value: T) { - insert(value: value, parent: self) - } - - fileprivate func insert(value: T, parent: BinarySearchTree) { if value < self.value { if let left = left { - left.insert(value: value, parent: left) + left.insert(value: value) } else { left = BinarySearchTree(value: value) - left?.parent = parent + left?.parent = self } } else { if let right = right { - right.insert(value: value, parent: right) + right.insert(value: value) } else { right = BinarySearchTree(value: value) - right?.parent = parent + right?.parent = self } } } diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.swift b/Binary Search Tree/Solution 1/BinarySearchTree.swift deleted file mode 100644 index a58ac075a..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree.swift +++ /dev/null @@ -1,377 +0,0 @@ -/* - A binary search tree. - - Each node stores a value and two children. The left child contains a smaller - value; the right a larger (or equal) value. - - This tree allows duplicate elements. - - This tree does not automatically balance itself. To make sure it is balanced, - you should insert new values in randomized order, not in sorted order. -*/ -public class BinarySearchTree { - private(set) public var value: T - private(set) public var parent: BinarySearchTree? - private(set) public var left: BinarySearchTree? - private(set) public var right: BinarySearchTree? - - public init(value: T) { - self.value = value - } - - public convenience init(array: [T]) { - precondition(array.count > 0) - self.init(value: array.first!) - for v in array.dropFirst() { - insert(v, parent: self) - } - } - - public var isRoot: Bool { - return parent == nil - } - - public var isLeaf: Bool { - return left == nil && right == nil - } - - public var isLeftChild: Bool { - return parent?.left === self - } - - public var isRightChild: Bool { - return parent?.right === self - } - - public var hasLeftChild: Bool { - return left != nil - } - - public var hasRightChild: Bool { - return right != nil - } - - public var hasAnyChild: Bool { - return hasLeftChild || hasRightChild - } - - public var hasBothChildren: Bool { - return hasLeftChild && hasRightChild - } - - /* How many nodes are in this subtree. Performance: O(n). */ - public var count: Int { - return (left?.count ?? 0) + 1 + (right?.count ?? 0) - } -} - -// MARK: - Adding items - -extension BinarySearchTree { - /* - Inserts a new element into the tree. You should only insert elements - at the root, to make to sure this remains a valid binary tree! - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func insert(value: T) { - insert(value, parent: self) - } - - private func insert(value: T, parent: BinarySearchTree) { - if value < self.value { - if let left = left { - left.insert(value, parent: left) - } else { - left = BinarySearchTree(value: value) - left?.parent = parent - } - } else { - if let right = right { - right.insert(value, parent: right) - } else { - right = BinarySearchTree(value: value) - right?.parent = parent - } - } - } -} - -// MARK: - Deleting items - -extension BinarySearchTree { - /* - Deletes a node from the tree. - - Returns the node that has replaced this removed one (or nil if this was a - leaf node). That is primarily useful for when you delete the root node, in - which case the tree gets a new root. - - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func remove() -> BinarySearchTree? { - let replacement: BinarySearchTree? - - if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - } - - reconnectParentToNode(replacement) - - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - - return replacement - } - - private func removeNodeWithTwoChildren(left: BinarySearchTree, _ right: BinarySearchTree) -> BinarySearchTree { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() - - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() - - // Connect our left child with the new node. - successor.left = left - left.parent = successor - - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor - } else { - successor.right = nil - } - - // And finally, connect the successor node to our parent. - return successor - } - - private func reconnectParentToNode(node: BinarySearchTree?) { - if let parent = parent { - if isLeftChild { - parent.left = node - } else { - parent.right = node - } - } - node?.parent = parent - } -} - -// MARK: - Searching - -extension BinarySearchTree { - /* - Finds the "highest" node with the specified value. - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func search(value: T) -> BinarySearchTree? { - var node: BinarySearchTree? = self - while case let n? = node { - if value < n.value { - node = n.left - } else if value > n.value { - node = n.right - } else { - return node - } - } - return nil - } - - /* - // Recursive version of search - public func search(value: T) -> BinarySearchTree? { - if value < self.value { - return left?.search(value) - } else if value > self.value { - return right?.search(value) - } else { - return self // found it! - } - } - */ - - public func contains(value: T) -> Bool { - return search(value) != nil - } - - /* - Returns the leftmost descendent. O(h) time. - */ - public func minimum() -> BinarySearchTree { - var node = self - while case let next? = node.left { - node = next - } - return node - } - - /* - Returns the rightmost descendent. O(h) time. - */ - public func maximum() -> BinarySearchTree { - var node = self - while case let next? = node.right { - node = next - } - return node - } - - /* - Calculates the depth of this node, i.e. the distance to the root. - Takes O(h) time. - */ - public func depth() -> Int { - var node = self - var edges = 0 - while case let parent? = node.parent { - node = parent - edges += 1 - } - return edges - } - - /* - Calculates the height of this node, i.e. the distance to the lowest leaf. - Since this looks at all children of this node, performance is O(n). - */ - public func height() -> Int { - if isLeaf { - return 0 - } else { - return 1 + max(left?.height() ?? 0, right?.height() ?? 0) - } - } - - /* - Finds the node whose value precedes our value in sorted order. - */ - public func predecessor() -> BinarySearchTree? { - if let left = left { - return left.maximum() - } else { - var node = self - while case let parent? = node.parent { - if parent.value < value { return parent } - node = parent - } - return nil - } - } - - /* - Finds the node whose value succeeds our value in sorted order. - */ - public func successor() -> BinarySearchTree? { - if let right = right { - return right.minimum() - } else { - var node = self - while case let parent? = node.parent { - if parent.value > value { return parent } - node = parent - } - return nil - } - } -} - -// MARK: - Traversal - -extension BinarySearchTree { - public func traverseInOrder(@noescape process: T -> Void) { - left?.traverseInOrder(process) - process(value) - right?.traverseInOrder(process) - } - - public func traversePreOrder(@noescape process: T -> Void) { - process(value) - left?.traversePreOrder(process) - right?.traversePreOrder(process) - } - - public func traversePostOrder(@noescape process: T -> Void) { - left?.traversePostOrder(process) - right?.traversePostOrder(process) - process(value) - } - - /* - Performs an in-order traversal and collects the results in an array. - */ - public func map(@noescape formula: T -> T) -> [T] { - var a = [T]() - if let left = left { a += left.map(formula) } - a.append(formula(value)) - if let right = right { a += right.map(formula) } - return a - } -} - -/* - Is this binary tree a valid binary search tree? -*/ -extension BinarySearchTree { - public func isBST(minValue 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 - return leftBST && rightBST - } -} - -// MARK: - Debugging - -extension BinarySearchTree: CustomStringConvertible { - public var description: String { - var s = "" - if let left = left { - s += "(\(left.description)) <- " - } - s += "\(value)" - if let right = right { - s += " -> (\(right.description))" - } - return s - } -} - -extension BinarySearchTree: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" - } - if let left = left { - s += ", left = [" + left.debugDescription + "]" - } - if let right = right { - s += ", right = [" + right.debugDescription + "]" - } - return s - } - - public func toArray() -> [T] { - return map { $0 } - } -} 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 c1d6c8029..7ecfe593f 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -7,15 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 7B80C3D81C77A313003CECC7 /* BinarySearchTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3D71C77A313003CECC7 /* BinarySearchTree.swift */; }; 7B80C3DA1C77A323003CECC7 /* BinarySearchTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3D91C77A323003CECC7 /* BinarySearchTreeTests.swift */; }; + 9E5A58B91E304C3100DAB3BB /* BinarySearchTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; - 7B80C3D71C77A313003CECC7 /* BinarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchTree.swift; path = ../BinarySearchTree.swift; sourceTree = SOURCE_ROOT; }; 7B80C3D91C77A323003CECC7 /* BinarySearchTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeTests.swift; sourceTree = SOURCE_ROOT; }; + 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchTree.swift; path = ../BinarySearchTree.playground/Sources/BinarySearchTree.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -48,7 +48,7 @@ 7B2BBC831C779D720067B71D /* Tests */ = { isa = PBXGroup; children = ( - 7B80C3D71C77A313003CECC7 /* BinarySearchTree.swift */, + 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */, 7B80C3D91C77A323003CECC7 /* BinarySearchTreeTests.swift */, 7B2BBC941C779E7B0067B71D /* Info.plist */, ); @@ -125,7 +125,7 @@ buildActionMask = 2147483647; files = ( 7B80C3DA1C77A323003CECC7 /* BinarySearchTreeTests.swift in Sources */, - 7B80C3D81C77A313003CECC7 /* BinarySearchTree.swift in Sources */, + 9E5A58B91E304C3100DAB3BB /* BinarySearchTree.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4231528aa..b2ffce836 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -310,9 +310,6 @@ - - From 942e3b1738d95645e4dc49c483d84e9e094b1ea5 Mon Sep 17 00:00:00 2001 From: Bo Qian Date: Thu, 19 Jan 2017 18:33:43 -0800 Subject: [PATCH 0384/1275] Simplified the remove(). I feel the new implementation is more elegant and conceptually more straightforward. --- .../Sources/BinarySearchTree.swift | 97 +++++++------------ 1 file changed, 34 insertions(+), 63 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 5edbfc48a..31ae99a2f 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -106,58 +106,30 @@ extension BinarySearchTree { */ @discardableResult public func remove() -> BinarySearchTree? { let replacement: BinarySearchTree? - + + // Replacement for current node can be either biggest one on the left or + // smallest one on the right, whichever is not nil if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - } + replacement = left.maximum() } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right + replacement = right.minimum() } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil + replacement = nil; } - - reconnectParentTo(node: replacement) - + + replacement?.remove(); + + // Place the replacement on current node's position + replacement?.right = right; + replacement?.left = left; + reconnectParentTo(node:replacement); + // The current node is no longer part of the tree, so clean it up. parent = nil left = nil right = nil - - return replacement - } - - private func removeNodeWithTwoChildren(_ left: BinarySearchTree, _ right: BinarySearchTree) -> BinarySearchTree { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() - - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() - - // Connect our left child with the new node. - successor.left = left - left.parent = successor - - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor - } else { - successor.right = nil - } - - // And finally, connect the successor node to our parent. - return successor + + return replacement; } private func reconnectParentTo(node: BinarySearchTree?) { @@ -350,24 +322,23 @@ extension BinarySearchTree: CustomStringConvertible { } return s } -} - -extension BinarySearchTree: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" - } - if let left = left { - s += ", left = [" + left.debugDescription + "]" - } - if let right = right { - s += ", right = [" + right.debugDescription + "]" - } - return s - } + + public func toArray() -> [T] { + return map { $0 } + } - public func toArray() -> [T] { - return map { $0 } - } } + +//extension BinarySearchTree: CustomDebugStringConvertible { +// public var debugDescription: String { +// var s = "" +// if let left = left { +// s += "(\(left.description)) <- " +// } +// s += "\(value)" +// if let right = right { +// s += " -> (\(right.description))" +// } +// return s +// } +//} From c3ea705cb7623f9d6a9df3babcfcb01c61abcf4e Mon Sep 17 00:00:00 2001 From: Ray Wenderlich Date: Wed, 25 Jan 2017 11:46:55 -0500 Subject: [PATCH 0385/1275] Added license clarification. --- How to Contribute.markdown | 2 +- README.markdown | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/How to Contribute.markdown b/How to Contribute.markdown index 9e83b5ed6..258357e8b 100644 --- a/How to Contribute.markdown +++ b/How to Contribute.markdown @@ -21,7 +21,7 @@ To keep this a high quality repo, please follow this process when submitting you 1. Create a pull request to "claim" an algorithm or data structure. Just so multiple people don't work on the same thing. 2. Use this [style guide](https://github.com/raywenderlich/swift-style-guide) for writing code (more or less). 3. Write an explanation of how the algorithm works. Include **plenty of examples** for readers to follow along. Pictures are good. Take a look at [the explanation of quicksort](Quicksort/) to get an idea. -4. Include your name in the explanation, something like *Written by Your Name* at the end of the document. If you wrote it, you deserve the credit and fame. +4. Include your name in the explanation, something like *Written by Your Name* at the end of the document. 5. Add a playground and/or unit tests. 6. Run [SwiftLint](https://github.com/realm/SwiftLint) - [Install](https://github.com/realm/SwiftLint#installation) diff --git a/README.markdown b/README.markdown index c6d2e0149..b33a8f8ae 100644 --- a/README.markdown +++ b/README.markdown @@ -233,4 +233,6 @@ The Swift Algorithm Club is a collaborative effort from the [most algorithmic me All content is licensed under the terms of the MIT open source license. +By posting here, or by submitting any pull request through this forum, you agree that all content you submit or create, both code and text, is subject to this license. Razeware, LLC, and others will have all the rights described in the license regarding this content. The precise terms of this license may be found [here](https://github.com/raywenderlich/swift-algorithm-club/blob/master/LICENSE.txt). + [![Build Status](https://travis-ci.org/raywenderlich/swift-algorithm-club.svg?branch=master)](https://travis-ci.org/raywenderlich/swift-algorithm-club) From 40f667cfbb57e51ed5f639c9bfff5bdcc45fa867 Mon Sep 17 00:00:00 2001 From: Ray Wenderlich Date: Wed, 25 Jan 2017 11:47:48 -0500 Subject: [PATCH 0386/1275] Added Vincent as maintainer. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index b33a8f8ae..e2d99e2bc 100644 --- a/README.markdown +++ b/README.markdown @@ -225,7 +225,7 @@ Other algorithm repositories: The Swift Algorithm Club was originally created by [Matthijs Hollemans](https://github.com/hollance). -It is now maintained by [Chris Pilcher](https://github.com/chris-pilcher) and [Kelvin Lau](https://github.com/kelvinlauKL). +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](How to Contribute.markdown)? :] From 1504e605537c2c2b881c8bdbdadac8eabc209bfd Mon Sep 17 00:00:00 2001 From: Jaap Date: Sat, 28 Jan 2017 01:10:46 +0100 Subject: [PATCH 0387/1275] migrated to swift 3 --- Run-Length Encoding/README.markdown | 121 ++++---- .../RLE.playground/Contents.swift | 162 ++++++----- .../RLE.playground/Sources/RLE.swift | 68 +++++ Run-Length Encoding/RLE.swift | 70 ----- Run-Length Encoding/Tests/Info.plist | 24 -- Run-Length Encoding/Tests/RLETests.swift | 110 -------- .../Tests/Tests.xcodeproj/project.pbxproj | 261 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Tests.xcscheme | 90 ------ 9 files changed, 228 insertions(+), 685 deletions(-) create mode 100644 Run-Length Encoding/RLE.playground/Sources/RLE.swift delete mode 100644 Run-Length Encoding/RLE.swift delete mode 100644 Run-Length Encoding/Tests/Info.plist delete mode 100644 Run-Length Encoding/Tests/RLETests.swift delete mode 100644 Run-Length Encoding/Tests/Tests.xcodeproj/project.pbxproj delete mode 100644 Run-Length Encoding/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 Run-Length Encoding/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/Run-Length Encoding/README.markdown b/Run-Length Encoding/README.markdown index 8371b1227..f7d196161 100644 --- a/Run-Length Encoding/README.markdown +++ b/Run-Length Encoding/README.markdown @@ -3,14 +3,14 @@ RLE is probably the simplest way to do compression. Let's say you have data that looks like this: aaaaabbbcdeeeeeeef... - + then RLE encodes it as follows: 5a3b1c1d7e1f... Instead of repeating bytes, you first write how often that byte occurs and then the byte's actual value. So `5a` means `aaaaa`. If the data has a lot of "byte runs", that is lots of repeating bytes, then RLE can save quite a bit of space. It works quite well on images. -There are many different ways you can implement RLE. Here's an extension of `NSData` that does a version of RLE inspired by the old [PCX image file format](https://en.wikipedia.org/wiki/PCX). +There are many different ways you can implement RLE. Here's an extension of `Data` that does a version of RLE inspired by the old [PCX image file format](https://en.wikipedia.org/wiki/PCX). The rules are these: @@ -20,44 +20,42 @@ The rules are these: - A single byte in the range 192 - 255 is represented by two bytes: first the byte 192 (meaning a run of 1 byte), followed by the actual value. -Here is the compression code. It returns a new `NSData` object containing the run-length encoded bytes: +Here is the compression code. It returns a new `Data` object containing the run-length encoded bytes: ```swift -extension NSData { - public func compressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length - - while ptr < end { // 1 - var count = 0 - var byte = ptr.memory - var next = byte - - while next == byte && ptr < end && count < 64 { // 2 - ptr = ptr.advancedBy(1) - next = ptr.memory - count += 1 - } - - if count > 1 || byte >= 192 { // 3 - var size = 191 + UInt8(count) - data.appendBytes(&size, length: 1) - data.appendBytes(&byte, length: 1) - } else { // 4 - data.appendBytes(&byte, length: 1) +extension Data { + public func compressRLE() -> Data { + var data = Data() + self.withUnsafeBytes { (uPtr: UnsafePointer) in + var ptr = uPtr + let end = ptr + count + while ptr < end { //1 + var count = 0 + var byte = ptr.pointee + var next = byte + + while next == byte && ptr < end && count < 64 { //2 + ptr = ptr.advanced(by: 1) + next = ptr.pointee + count += 1 + } + + if count > 1 || byte >= 192 { // 3 + var size = 191 + UInt8(count) + data.append(&size, count: 1) + data.append(&byte, count: 1) + } else { // 4 + data.append(&byte, count: 1) + } + } } - } + return data } - return data - } -} ``` How it works: -1. We use an `UnsafePointer` to step through the bytes of the original `NSData` object. +1. We use an `UnsafePointer` to step through the bytes of the original `Data` object. 2. At this point we've read the current byte value into the `byte` variable. If the next byte is the same, then we keep reading until we find a byte value that is different, or we reach the end of the data. We also stop if the run is 64 bytes because that's the maximum we can encode. @@ -69,11 +67,11 @@ You can test it like this in a playground: ```swift let originalString = "aaaaabbbcdeeeeeeef" -let utf8 = originalString.dataUsingEncoding(NSUTF8StringEncoding)! +let utf8 = originalString.data(using: String.Encoding.utf8)! let compressed = utf8.compressRLE() ``` -The compressed `NSData` object should be ``. Let's decode that by hand to see what has happened: +The compressed `Data` object should be ``. Let's decode that by hand to see what has happened: c4 This is 196 in decimal. It means the next byte appears 5 times. 61 The data byte "a". @@ -90,34 +88,38 @@ So that's 9 bytes encoded versus 18 original. That's a savings of 50%. Of course Here is the decompression code: ```swift - public func decompressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length - - while ptr < end { - var byte = ptr.memory // 1 - ptr = ptr.advancedBy(1) - - if byte < 192 { // 2 - data.appendBytes(&byte, length: 1) - - } else if ptr < end { // 3 - var value = ptr.memory - ptr = ptr.advancedBy(1) - - for _ in 0 ..< byte - 191 { - data.appendBytes(&value, length: 1) - } +public func decompressRLE() -> Data { + var data = Data() + self.withUnsafeBytes { (uPtr: UnsafePointer) in + var ptr = uPtr + let end = ptr + count + + while ptr < end { + // Read the next byte. This is either a single value less than 192, + // or the start of a byte run. + var byte = ptr.pointee // 1 + ptr = ptr.advanced(by: 1) + + if byte < 192 { // 2 + data.append(&byte, count: 1) + } else if ptr < end { // 3 + // Read the actual data value. + var value = ptr.pointee + ptr = ptr.advanced(by: 1) + + // And write it out repeatedly. + for _ in 0 ..< byte - 191 { + data.append(&value, count: 1) + } + } + } } - } + return data } - return data - } + ``` -1. Again this uses an `UnsafePointer` to read the `NSData`. Here we read the next byte; this is either a single value less than 192, or the start of a byte run. +1. Again this uses an `UnsafePointer` to read the `Data`. Here we read the next byte; this is either a single value less than 192, or the start of a byte run. 2. If it's a single value, then it's just a matter of copying it to the output. @@ -134,6 +136,7 @@ And now `originalString == restoredString` must be true! Footnote: The original PCX implementation is slightly different. There, a byte value of 192 (0xC0) means that the following byte will be repeated 0 times. This also limits the maximum run size to 63 bytes. Because it makes no sense to store bytes that don't occur, in my implementation 192 means the next byte appears once, and the maximum run length is 64 bytes. -This was probably a trade-off when they designed the PCX format way back when. If you look at it in binary, the upper two bits indicate whether a byte is compressed. (If both bits are set then the byte value is 192 or more.) To get the run length you can simply do `byte & 0x3F`, giving you a value in the range 0 to 63. +This was probably a trade-off when they designed the PCX format way back when. If you look at it in binary, the upper two bits indicate whether a byte is compressed. (If both bits are set then the byte value is 192 or more.) To get the run length you can simply do `byte & 0x3F`, giving you a value in the range 0 to 63. *Written for Swift Algorithm Club by Matthijs Hollemans* +*Migrated to Swift3 by Jaap Wijnen* diff --git a/Run-Length Encoding/RLE.playground/Contents.swift b/Run-Length Encoding/RLE.playground/Contents.swift index 41dcae3b1..62b4ef437 100644 --- a/Run-Length Encoding/RLE.playground/Contents.swift +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -2,81 +2,115 @@ import Foundation -extension NSData { - /* - Compresses the NSData using run-length encoding. - */ - public func compressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length +let originalString = "aaaaabbbcdeeeeeeef" +let utf8 = originalString.data(using: String.Encoding.utf8)! +let compressed = utf8.compressRLE() - while ptr < end { - var count = 0 - var byte = ptr.memory - var next = byte +let decompressed = compressed.decompressRLE() +let restoredString = String(data: decompressed, encoding: String.Encoding.utf8) +originalString == restoredString - // Is the next byte the same? Keep reading until we find a different - // value, or we reach the end of the data, or the run is 64 bytes. - while next == byte && ptr < end && count < 64 { - ptr = ptr.advancedBy(1) - next = ptr.memory - count += 1 - } +func encodeAndDecode(_ bytes: [UInt8]) -> Bool { + var bytes = bytes + + var data1 = Data(bytes: &bytes, count: bytes.count) + print("data1 is \(data1.count) bytes") + + var rleData = data1.compressRLE() + print("encoded data is \(rleData.count) bytes") + + var data2 = rleData.decompressRLE() + print("data2 is \(data2.count) bytes") + + return data1 == data2 +} - if count > 1 || byte >= 192 { // byte run of up to 64 repeats - var size = 191 + UInt8(count) - data.appendBytes(&size, length: 1) - data.appendBytes(&byte, length: 1) - } else { // single byte between 0 and 192 - data.appendBytes(&byte, length: 1) - } - } - } - return data - } +func testEmpty() -> Bool { + let bytes: [UInt8] = [] + return encodeAndDecode(bytes) +} - /* - Converts a run-length encoded NSData back to the original. - */ - public func decompressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length +func testOneByteWithLowValue() -> Bool { + let bytes: [UInt8] = [0x80] + return encodeAndDecode(bytes) +} - while ptr < end { - // Read the next byte. This is either a single value less than 192, - // or the start of a byte run. - var byte = ptr.memory - ptr = ptr.advancedBy(1) +func testOneByteWithHighValue() -> Bool { + let bytes: [UInt8] = [0xD0] + return encodeAndDecode(bytes) +} - if byte < 192 { // single value - data.appendBytes(&byte, length: 1) +func testSimpleCases() -> Bool { + let bytes: [UInt8] = [ + 0x00, + 0x20, 0x20, 0x20, 0x20, 0x20, + 0x30, + 0x00, 0x00, + 0xC0, + 0xC1, + 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF + ] + return encodeAndDecode(bytes) +} - } else if ptr < end { // byte run - // Read the actual data value. - var value = ptr.memory - ptr = ptr.advancedBy(1) +func testBufferWithoutSpans() -> Bool { + // There is nothing that can be encoded in this buffer, so the encoded + // data ends up being longer. + var bytes: [UInt8] = [] + for i in 0..<1024 { + bytes.append(UInt8(i%256)) + } + return encodeAndDecode(bytes) +} - // And write it out repeatedly. - for _ in 0 ..< byte - 191 { - data.appendBytes(&value, length: 1) - } +func testBufferWithSpans(_ spanSize: Int) -> Bool { + print("span size \(spanSize)") + + let length = spanSize * 32 + var bytes: [UInt8] = Array(repeating: 0, count: length) + + for t in stride(from: 0, to: length, by: spanSize) { + for i in 0.. Bool { + let length = 1 + Int(arc4random_uniform(2048)) + var bytes: [UInt8] = [] + for _ in 0.. Bool { + var tests: [Bool] = [ + testEmpty(), + testOneByteWithLowValue(), + testOneByteWithHighValue(), + testSimpleCases(), + testBufferWithoutSpans(), + testBufferWithSpans(4), + testBufferWithSpans(63), + testBufferWithSpans(64), + testBufferWithSpans(65), + testBufferWithSpans(66), + testBufferWithSpans(80) + ] + for _ in 0..<10 { + let result = testRandomByte() + tests.append(result) + } + var result = true + for bool in tests { + result = result && bool + } + + return result +} -let originalString = "aaaaabbbcdeeeeeeef" -let utf8 = originalString.dataUsingEncoding(NSUTF8StringEncoding)! -let compressed = utf8.compressRLE() - -let decompressed = compressed.decompressRLE() -let restoredString = String(data: decompressed, encoding: NSUTF8StringEncoding) -originalString == restoredString +runTests() \ No newline at end of file diff --git a/Run-Length Encoding/RLE.playground/Sources/RLE.swift b/Run-Length Encoding/RLE.playground/Sources/RLE.swift new file mode 100644 index 000000000..5707e3d9d --- /dev/null +++ b/Run-Length Encoding/RLE.playground/Sources/RLE.swift @@ -0,0 +1,68 @@ +import Foundation + +extension Data { + /* + Compresses the NSData using run-length encoding. + */ + public func compressRLE() -> Data { + var data = Data() + self.withUnsafeBytes { (uPtr: UnsafePointer) in + var ptr = uPtr + let end = ptr + count + while ptr < end { + var count = 0 + var byte = ptr.pointee + var next = byte + + // Is the next byte the same? Keep reading until we find a different + // value, or we reach the end of the data, or the run is 64 bytes. + while next == byte && ptr < end && count < 64 { + ptr = ptr.advanced(by: 1) + next = ptr.pointee + count += 1 + } + + if count > 1 || byte >= 192 { // byte run of up to 64 repeats + var size = 191 + UInt8(count) + data.append(&size, count: 1) + data.append(&byte, count: 1) + } else { // single byte between 0 and 192 + data.append(&byte, count: 1) + } + } + } + return data + } + + /* + Converts a run-length encoded NSData back to the original. + */ + public func decompressRLE() -> Data { + var data = Data() + self.withUnsafeBytes { (uPtr: UnsafePointer) in + var ptr = uPtr + let end = ptr + count + + while ptr < end { + // Read the next byte. This is either a single value less than 192, + // or the start of a byte run. + var byte = ptr.pointee + ptr = ptr.advanced(by: 1) + + if byte < 192 { // single value + data.append(&byte, count: 1) + } else if ptr < end { // byte run + // Read the actual data value. + var value = ptr.pointee + ptr = ptr.advanced(by: 1) + + // And write it out repeatedly. + for _ in 0 ..< byte - 191 { + data.append(&value, count: 1) + } + } + } + } + return data + } +} diff --git a/Run-Length Encoding/RLE.swift b/Run-Length Encoding/RLE.swift deleted file mode 100644 index b62c59c63..000000000 --- a/Run-Length Encoding/RLE.swift +++ /dev/null @@ -1,70 +0,0 @@ -import Foundation - -extension NSData { - /* - Compresses the NSData using run-length encoding. - */ - public func compressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length - - while ptr < end { - var count = 0 - var byte = ptr.memory - var next = byte - - // Is the next byte the same? Keep reading until we find a different - // value, or we reach the end of the data, or the run is 64 bytes. - while next == byte && ptr < end && count < 64 { - ptr = ptr.advancedBy(1) - next = ptr.memory - count += 1 - } - - if count > 1 || byte >= 192 { // byte run of up to 64 repeats - var size = 191 + UInt8(count) - data.appendBytes(&size, length: 1) - data.appendBytes(&byte, length: 1) - } else { // single byte between 0 and 192 - data.appendBytes(&byte, length: 1) - } - } - } - return data - } - - /* - Converts a run-length encoded NSData back to the original. - */ - public func decompressRLE() -> NSData { - let data = NSMutableData() - if length > 0 { - var ptr = UnsafePointer(bytes) - let end = ptr + length - - while ptr < end { - // Read the next byte. This is either a single value less than 192, - // or the start of a byte run. - var byte = ptr.memory - ptr = ptr.advancedBy(1) - - if byte < 192 { // single value - data.appendBytes(&byte, length: 1) - - } else if ptr < end { // byte run - // Read the actual data value. - var value = ptr.memory - ptr = ptr.advancedBy(1) - - // And write it out repeatedly. - for _ in 0 ..< byte - 191 { - data.appendBytes(&value, length: 1) - } - } - } - } - return data - } -} diff --git a/Run-Length Encoding/Tests/Info.plist b/Run-Length Encoding/Tests/Info.plist deleted file mode 100644 index ba72822e8..000000000 --- a/Run-Length Encoding/Tests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - 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/Run-Length Encoding/Tests/RLETests.swift b/Run-Length Encoding/Tests/RLETests.swift deleted file mode 100644 index f4b2f8d7d..000000000 --- a/Run-Length Encoding/Tests/RLETests.swift +++ /dev/null @@ -1,110 +0,0 @@ -import XCTest - -class RLETests: XCTestCase { - private var showExtraOutput = false - - private func dumpData(data: NSData) { - if showExtraOutput { - var ptr = UnsafePointer(data.bytes) - for _ in 0.. - - - - diff --git a/Run-Length Encoding/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Run-Length Encoding/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme deleted file mode 100644 index 8ef8d8581..000000000 --- a/Run-Length Encoding/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 2accb9907f434968e8806afe5637eeab69d4a0a9 Mon Sep 17 00:00:00 2001 From: Jaap Date: Sat, 28 Jan 2017 01:39:29 +0100 Subject: [PATCH 0388/1275] Migrate Shunting Yard to Swift 3 --- Shunting Yard/README.markdown | 5 +- .../ShuntingYard.playground/Contents.swift | 38 +- .../Sources/Stack.swift | 32 +- Shunting Yard/ShuntingYard.swift | 364 +++++++++--------- 4 files changed, 218 insertions(+), 221 deletions(-) diff --git a/Shunting Yard/README.markdown b/Shunting Yard/README.markdown index d2e568d39..72df4d346 100644 --- a/Shunting Yard/README.markdown +++ b/Shunting Yard/README.markdown @@ -6,7 +6,7 @@ Any mathematics we write is expressed in a notation known as *infix notation*. F The operator is placed in between the operands, hence the expression is said to be in *infix* form. If you think about it, any expression that you write on a piece of paper will always be in infix form. This is what we humans understand. -Multiplication has higher precedence than addition, so when the above expression is evaluated you would first multiply **B** and **C**, and then add the result to **A**. We humans can easily understand the precedence of operators, but a machine needs to be given instructions about each operator. +Multiplication has higher precedence than addition, so when the above expression is evaluated you would first multiply **B** and **C**, and then add the result to **A**. We humans can easily understand the precedence of operators, but a machine needs to be given instructions about each operator. To change the order of evaluation, we can use parentheses: @@ -108,4 +108,5 @@ We end up with the postfix expression: [Shunting yard algorithm on Wikipedia](https://en.wikipedia.org/wiki/Shunting-yard_algorithm) -*Written for the Swift Algorithm Club by [Ali Hafizji](http://www.github.com/aliHafizji)* \ No newline at end of file +*Written for the Swift Algorithm Club by [Ali Hafizji](http://www.github.com/aliHafizji)* +*Migrated to Swift 3 by Jaap Wijnen* diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index 707e2a0a3..b341c673b 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -15,17 +15,17 @@ public enum OperatorType: CustomStringConvertible { public var description: String { switch self { - case add: + case .add: return "+" - case subtract: + case .subtract: return "-" - case divide: + case .divide: return "/" - case multiply: + case .multiply: return "*" - case percent: + case .percent: return "%" - case exponent: + case .exponent: return "^" } } @@ -39,13 +39,13 @@ public enum TokenType: CustomStringConvertible { public var description: String { switch self { - case openBracket: + case .openBracket: return "(" - case closeBracket: + case .closeBracket: return ")" - case Operator(let operatorToken): + case .Operator(let operatorToken): return operatorToken.description - case operand(let value): + case .operand(let value): return "\(value)" } } @@ -141,23 +141,23 @@ public struct Token: CustomStringConvertible { public class InfixExpressionBuilder { private var expression = [Token]() - public func addOperator(operatorType: OperatorType) -> InfixExpressionBuilder { + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { expression.append(Token(operatorType: operatorType)) return self } - public func addOperand(operand: Double) -> InfixExpressionBuilder { + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { expression.append(Token(operand: operand)) return self } public func addOpenBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .OpenBracket)) + expression.append(Token(tokenType: .openBracket)) return self } public func addCloseBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .CloseBracket)) + expression.append(Token(tokenType: .closeBracket)) return self } @@ -168,7 +168,7 @@ public class InfixExpressionBuilder { } // This returns the result of the shunting yard algorithm -public func reversePolishNotation(expression: [Token]) -> String { +public func reversePolishNotation(_ expression: [Token]) -> String { var tokenStack = Stack() var reversePolishNotation = [Token]() @@ -187,14 +187,14 @@ public func reversePolishNotation(expression: [Token]) -> String { } case .Operator(let operatorToken): - for tempToken in tokenStack.generate() { + for tempToken in tokenStack.makeIterator() { if !tempToken.isOperator { break } if let tempOperatorToken = tempToken.operatorToken { - if operatorToken.associativity == .LeftAssociative && operatorToken <= tempOperatorToken - || operatorToken.associativity == .RightAssociative && operatorToken < tempOperatorToken { + if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken + || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { reversePolishNotation.append(tokenStack.pop()!) } else { break @@ -209,7 +209,7 @@ public func reversePolishNotation(expression: [Token]) -> String { reversePolishNotation.append(tokenStack.pop()!) } - return reversePolishNotation.map({token in token.description}).joinWithSeparator(" ") + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } diff --git a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift index 0df342af5..a67bb9d64 100644 --- a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift +++ b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift @@ -1,41 +1,37 @@ import Foundation public struct Stack { - private var array = [T]() - + fileprivate var array = [T]() + public init() { - array = [] + } - + public var isEmpty: Bool { return array.isEmpty } - + public var count: Int { return array.count } - - public mutating func push(element: T) { + + public mutating func push(_ element: T) { array.append(element) } - + public mutating func pop() -> T? { - if isEmpty { - return nil - } else { - return array.removeLast() - } + return array.popLast() } - - public func peek() -> T? { + + public var top: T? { return array.last } } -extension Stack: SequenceType { - public func generate() -> AnyGenerator { +extension Stack: Sequence { + public func makeIterator() -> AnyIterator { var curr = self - return anyGenerator { + return AnyIterator { _ -> T? in return curr.pop() } diff --git a/Shunting Yard/ShuntingYard.swift b/Shunting Yard/ShuntingYard.swift index 9d31d5a58..b8f5f8e6b 100644 --- a/Shunting Yard/ShuntingYard.swift +++ b/Shunting Yard/ShuntingYard.swift @@ -7,213 +7,213 @@ // internal enum OperatorAssociativity { - case leftAssociative - case rightAssociative + case leftAssociative + case rightAssociative } public enum OperatorType: CustomStringConvertible { - case add - case subtract - case divide - case multiply - case percent - case exponent - - public var description: String { - switch self { - case add: - return "+" - case subtract: - return "-" - case divide: - return "/" - case multiply: - return "*" - case percent: - return "%" - case exponent: - return "^" - } - } + case add + case subtract + case divide + case multiply + case percent + case exponent + + public var description: String { + switch self { + case .add: + return "+" + case .subtract: + return "-" + case .divide: + return "/" + case .multiply: + return "*" + case .percent: + return "%" + case .exponent: + return "^" + } + } } public enum TokenType: CustomStringConvertible { - case openBracket - case closeBracket - case Operator(OperatorToken) - case operand(Double) - - public var description: String { - switch self { - case openBracket: - return "(" - case closeBracket: - return ")" - case Operator(let operatorToken): - return operatorToken.description - case operand(let value): - return "\(value)" - } - } + case openBracket + case closeBracket + case Operator(OperatorToken) + case operand(Double) + + public var description: String { + switch self { + case .openBracket: + return "(" + case .closeBracket: + return ")" + case .Operator(let operatorToken): + return operatorToken.description + case .operand(let value): + return "\(value)" + } + } } public struct OperatorToken: CustomStringConvertible { - let operatorType: OperatorType - - init(operatorType: OperatorType) { - self.operatorType = operatorType - } - - var precedence: Int { - switch operatorType { - case .add, .subtract: - return 0 - case .divide, .multiply, .percent: - return 5 - case .exponent: - return 10 - } - } - - var associativity: OperatorAssociativity { - switch operatorType { - case .add, .subtract, .divide, .multiply, .percent: - return .LeftAssociative - case .exponent: - return .RightAssociative - } - } - - public var description: String { - return operatorType.description - } + let operatorType: OperatorType + + init(operatorType: OperatorType) { + self.operatorType = operatorType + } + + var precedence: Int { + switch operatorType { + case .add, .subtract: + return 0 + case .divide, .multiply, .percent: + return 5 + case .exponent: + return 10 + } + } + + var associativity: OperatorAssociativity { + switch operatorType { + case .add, .subtract, .divide, .multiply, .percent: + return .leftAssociative + case .exponent: + return .rightAssociative + } + } + + public var description: String { + return operatorType.description + } } func <= (left: OperatorToken, right: OperatorToken) -> Bool { - return left.precedence <= right.precedence + return left.precedence <= right.precedence } func < (left: OperatorToken, right: OperatorToken) -> Bool { - return left.precedence < right.precedence + return left.precedence < right.precedence } public struct Token: CustomStringConvertible { - let tokenType: TokenType - - init(tokenType: TokenType) { - self.tokenType = tokenType - } - - init(operand: Double) { - tokenType = .operand(operand) - } - - init(operatorType: OperatorType) { - tokenType = .Operator(OperatorToken(operatorType: operatorType)) - } - - var isOpenBracket: Bool { - switch tokenType { - case .openBracket: - return true - default: - return false - } - } - - var isOperator: Bool { - switch tokenType { - case .Operator(_): - return true - default: - return false - } - } - - var operatorToken: OperatorToken? { - switch tokenType { - case .Operator(let operatorToken): - return operatorToken - default: - return nil - } - } - - public var description: String { - return tokenType.description - } + let tokenType: TokenType + + init(tokenType: TokenType) { + self.tokenType = tokenType + } + + init(operand: Double) { + tokenType = .operand(operand) + } + + init(operatorType: OperatorType) { + tokenType = .Operator(OperatorToken(operatorType: operatorType)) + } + + var isOpenBracket: Bool { + switch tokenType { + case .openBracket: + return true + default: + return false + } + } + + var isOperator: Bool { + switch tokenType { + case .Operator(_): + return true + default: + return false + } + } + + var operatorToken: OperatorToken? { + switch tokenType { + case .Operator(let operatorToken): + return operatorToken + default: + return nil + } + } + + public var description: String { + return tokenType.description + } } public class InfixExpressionBuilder { - private var expression = [Token]() - - public func addOperator(operatorType: OperatorType) -> InfixExpressionBuilder { - expression.append(Token(operatorType: operatorType)) - return self - } - - public func addOperand(operand: Double) -> InfixExpressionBuilder { - expression.append(Token(operand: operand)) - return self - } - - public func addOpenBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .OpenBracket)) - return self - } - - public func addCloseBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .CloseBracket)) - return self - } - - public func build() -> [Token] { - // Maybe do some validation here - return expression - } + private var expression = [Token]() + + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { + expression.append(Token(operatorType: operatorType)) + return self + } + + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { + expression.append(Token(operand: operand)) + return self + } + + public func addOpenBracket() -> InfixExpressionBuilder { + expression.append(Token(tokenType: .openBracket)) + return self + } + + public func addCloseBracket() -> InfixExpressionBuilder { + expression.append(Token(tokenType: .closeBracket)) + return self + } + + public func build() -> [Token] { + // Maybe do some validation here + return expression + } } // This returns the result of the shunting yard algorithm -public func reversePolishNotation(expression: [Token]) -> String { - - var tokenStack = Stack() - var reversePolishNotation = [Token]() - - for token in expression { - switch token.tokenType { - case .operand(_): - reversePolishNotation.append(token) - - case .openBracket: - tokenStack.push(token) - - case .closeBracket: - while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { - reversePolishNotation.append(tempToken) - } - - case .Operator(let operatorToken): - for tempToken in tokenStack.generate() { - if !tempToken.isOperator { - break - } - - if let tempOperatorToken = tempToken.operatorToken { - if operatorToken.associativity == .LeftAssociative && operatorToken <= tempOperatorToken - || operatorToken.associativity == .RightAssociative && operatorToken < tempOperatorToken { - reversePolishNotation.append(tokenStack.pop()!) - } else { - break +public func reversePolishNotation(_ expression: [Token]) -> String { + + var tokenStack = Stack() + var reversePolishNotation = [Token]() + + for token in expression { + switch token.tokenType { + case .operand(_): + reversePolishNotation.append(token) + + case .openBracket: + tokenStack.push(token) + + case .closeBracket: + while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { + reversePolishNotation.append(tempToken) + } + + case .Operator(let operatorToken): + for tempToken in tokenStack.makeIterator() { + if !tempToken.isOperator { + break + } + + if let tempOperatorToken = tempToken.operatorToken { + if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken + || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { + reversePolishNotation.append(tokenStack.pop()!) + } else { + break + } + } } - } + tokenStack.push(token) } - tokenStack.push(token) } - } - - while tokenStack.count > 0 { - reversePolishNotation.append(tokenStack.pop()!) - } - - return reversePolishNotation.map({token in token.description}).joinWithSeparator(" ") + + while tokenStack.count > 0 { + reversePolishNotation.append(tokenStack.pop()!) + } + + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } From 9d5c990ea69bd6f0fce8747630358a8391be48c5 Mon Sep 17 00:00:00 2001 From: Jaap Date: Sat, 28 Jan 2017 01:55:24 +0100 Subject: [PATCH 0389/1275] Set Cover migrated to swift 3 --- Set Cover (Unweighted)/README.markdown | 3 ++- .../SetCover.playground/Sources/RandomArrayOfSets.swift | 2 +- .../SetCover.playground/Sources/SetCover.swift | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown index fde032438..0b4ddfefe 100644 --- a/Set Cover (Unweighted)/README.markdown +++ b/Set Cover (Unweighted)/README.markdown @@ -30,4 +30,5 @@ If there is no cover within the group of sets, `cover` returns `nil`. [Set cover problem on Wikipedia](https://en.wikipedia.org/wiki/Set_cover_problem) -*Written for Swift Algorithm Club by [Michael C. Rael](https://github.com/mrael2)* \ No newline at end of file +*Written for Swift Algorithm Club by [Michael C. Rael](https://github.com/mrael2)* +*Migrated to Swift 3 by Jaap Wijnen* diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift index b64d8d70e..9454c6383 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -18,7 +18,7 @@ public func randomArrayOfSets(covering universe: Set, while true { let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) - for (setIndex, value) in universe.enumerate() { + for (setIndex, value) in universe.enumerated() { if setIndex == randomUniverseIndex { generatedSet.insert(value) break diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift index 8d40e1fda..043cf46a0 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -8,7 +8,7 @@ public extension Set { var largestSet: Set? for set in array { - let intersectionLength = remainingSet.intersect(set).count + let intersectionLength = remainingSet.intersection(set).count if intersectionLength > largestIntersectionLength { largestIntersectionLength = intersectionLength largestSet = set @@ -21,7 +21,7 @@ public extension Set { while !remainingSet.isEmpty { guard let largestSet = largestIntersectingSet() else { break } result!.append(largestSet) - remainingSet = remainingSet.subtract(largestSet) + remainingSet = remainingSet.subtracting(largestSet) } if !remainingSet.isEmpty || isEmpty { From 83dea87c62a44e8d180811e4d1b5c9da211dddeb Mon Sep 17 00:00:00 2001 From: barbara Date: Sat, 28 Jan 2017 19:29:21 +0100 Subject: [PATCH 0390/1275] Splay Tree Initial Commit --- Splay Tree/readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Splay Tree/readme.md diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md new file mode 100644 index 000000000..2282502fa --- /dev/null +++ b/Splay Tree/readme.md @@ -0,0 +1 @@ +In progress From dcd1a0a877d72a5285b56401866ea9a9a97e8017 Mon Sep 17 00:00:00 2001 From: Bo Qian Date: Sat, 28 Jan 2017 18:11:26 -0800 Subject: [PATCH 0391/1275] Updated README.markdown for the new implementation of insert and remove. Added a remove example in BinarySearchTree.playground. --- .../Images/DeleteTwoChildren.graffle | Bin 2912 -> 11233 bytes .../Images/DeleteTwoChildren.png | Bin 13760 -> 33187 bytes Binary Search Tree/README.markdown | 132 ++++-------------- .../Contents.swift | 3 +- 4 files changed, 31 insertions(+), 104 deletions(-) diff --git a/Binary Search Tree/Images/DeleteTwoChildren.graffle b/Binary Search Tree/Images/DeleteTwoChildren.graffle index a03748077e6c23fec83e473e86fd9d71ef5fe97e..a6a09877a55b170f3d9f0938099d6841e93f1af7 100644 GIT binary patch literal 11233 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 literal 2912 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 diff --git a/Binary Search Tree/Images/DeleteTwoChildren.png b/Binary Search Tree/Images/DeleteTwoChildren.png index c0a77aab1f93d9026e523e2d2439d04ef5b943a5..1d941fe3c16265e73797fa9fc8ea5b621b9d5272 100644 GIT binary patch literal 33187 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 P_@kz*tyHXV*)&wu)y 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 diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index bacb1ffe1..e8d2f58e2 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -69,21 +69,14 @@ If you traverse a binary search tree in-order, it looks at all the nodes as if t ## Deleting nodes -Removing nodes is kinda tricky. It is easy to remove a leaf node, you just disconnect it from its parent: - -![Deleting a leaf node](Images/DeleteLeaf.png) - -If the node to remove has only one child, we can link that child to the parent node. So we just pull the node out: - -![Deleting a node with one child](Images/DeleteOneChild.png) - -The gnarly part is when the node to remove has two children. To keep the tree properly sorted, we must replace this node by the smallest child that is larger than the node: +Removing nodes is also easy. After removing a node, we replace the node with either its biggest child on the left or its smallest child on the right. That way the tree is still sorted after the removal. In following example, 10 is removed and replaced with either 9 (Figure 2), or 11 (Figure 3). ![Deleting a node with two children](Images/DeleteTwoChildren.png) -This is always the leftmost descendant in the right subtree. It requires an additional search of at most **O(h)** to find this child. +Note the replacement needs to happen when the node has at least one child. If it has no child, you just disconnect it from its parent: + +![Deleting a leaf node](Images/DeleteLeaf.png) -Most of the other code involving binary search trees is fairly straightforward (if you understand recursion) but deleting nodes is a bit of a headscratcher. ## The code (solution 1) @@ -158,23 +151,19 @@ A tree node by itself is pretty useless, so here is how you would add new nodes ```swift public func insert(value: T) { - insert(value, parent: self) - } - - private func insert(value: T, parent: BinarySearchTree) { if value < self.value { if let left = left { - left.insert(value, parent: left) + left.insert(value: value) } else { left = BinarySearchTree(value: value) - left?.parent = parent + left?.parent = self } } else { if let right = right { - right.insert(value, parent: right) + right.insert(value: value) } else { right = BinarySearchTree(value: value) - right?.parent = parent + right?.parent = self } } } @@ -379,7 +368,7 @@ As an exercise for yourself, see if you can implement filter and reduce. ### Deleting nodes -You've seen that deleting nodes can be tricky. We can make the code much more readable by defining some helper functions. +We can make the code much more readable by defining some helper functions. ```swift private func reconnectParentToNode(node: BinarySearchTree?) { @@ -396,7 +385,7 @@ You've seen that deleting nodes can be tricky. We can make the code much more re Making changes to the tree involves changing a bunch of `parent` and `left` and `right` pointers. This function helps with that. It takes the parent of the current node -- that is `self` -- and connects it to another node. Usually that other node will be one of the children of `self`. -We also need a function that returns the leftmost descendent of a node: +We also need a function that returns the minimum and maximum of a node: ```swift public func minimum() -> BinarySearchTree { @@ -406,17 +395,7 @@ We also need a function that returns the leftmost descendent of a node: } return node } -``` - -To see how this works, take the following tree: - -![Example](Images/MinimumMaximum.png) - -For example, if we look at node `10`, its leftmost descendent is `7`. We get there by following all the `left` pointers until there are no more left children to look at. The leftmost descendent of the root node `6` is `1`. Therefore, `1` is the minimum value in the entire tree. - -We won't need it for deleting, but for completeness' sake, here is the opposite of `minimum()`: - -```swift + public func maximum() -> BinarySearchTree { var node = self while case let next? = node.right { @@ -424,94 +403,41 @@ We won't need it for deleting, but for completeness' sake, here is the opposite } return node } -``` -It returns the rightmost descendent of the node. We find it by following `right` pointers until we get to the end. In the above example, the rightmost descendent of node `2` is `5`. The maximum value in the entire tree is `11`, because that is the rightmost descendent of the root node `6`. +``` -Finally, we can write the code that removes a node from the tree: +The rest of the code is pretty self-explanatory: ```swift - public func remove() -> BinarySearchTree? { + @discardableResult public func remove() -> BinarySearchTree? { let replacement: BinarySearchTree? - + + // Replacement for current node can be either biggest one on the left or + // smallest one on the right, whichever is not nil if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) // 1 - } else { - replacement = left // 2 - } - } else if let right = right { // 3 - replacement = right + replacement = left.maximum() + } else if let right = right { + replacement = right.minimum() } else { - replacement = nil // 4 + replacement = nil; } - reconnectParentToNode(replacement) + replacement?.remove(); + // Place the replacement on current node's position + replacement?.right = right; + replacement?.left = left; + reconnectParentTo(node:replacement); + + // The current node is no longer part of the tree, so clean it up. parent = nil left = nil right = nil - - return replacement - } -``` - -It doesn't look so scary after all. ;-) There are four situations to handle: - -1. This node has two children. -2. This node only has a left child. The left child replaces the node. -3. This node only has a right child. The right child replaces the node. -4. This node has no children. We just disconnect it from its parent. - -First, we determine which node will replace the one we're removing and then we call `reconnectParentToNode()` to change the `left`, `right`, and `parent` pointers to make that happen. Since the current node is no longer part of the tree, we clean it up by setting its pointers to `nil`. Finally, we return the node that has replaced the removed one (or `nil` if this was a leaf node). - -The only tricky situation here is `// 1` and that logic has its own helper method: - -```swift - private func removeNodeWithTwoChildren(left: BinarySearchTree, _ right: BinarySearchTree) -> BinarySearchTree { - let successor = right.minimum() - successor.remove() - - successor.left = left - left.parent = successor - - if right !== successor { - successor.right = right - right.parent = successor - } else { - successor.right = nil - } - return successor + return replacement; } ``` -If the node to remove has two children, it must be replaced by the smallest child that is larger than this node's value. That always happens to be the leftmost descendent of the right child, i.e. `right.minimum()`. We take that node out of its original position in the tree and put it into the place of the node we're removing. - -Try it out: - -```swift -if let node2 = tree.search(2) { - print(tree) // before - node2.remove() - print(tree) // after -} -``` - -First you find the node that you want to remove with `search()` and then you call `remove()` on that object. Before the removal, the tree printed like this: - - ((1) <- 2 -> (5)) <- 6 -> ((9) <- 10) - -But after `remove()` you get: - - ((1) <- 5) <- 6 -> ((9) <- 10) - -As you can see, node `5` has taken the place of `2`. - -> **Note:** What would happen if you deleted the root node? In that case, `remove()` tells you which node has become the new root. Try it out: call `tree.remove()` and see what happens. - -Like most binary search tree operations, removing a node runs in **O(h)** time, where **h** is the height of the tree. - ### Depth and height Recall that the height of a node is the distance to its lowest leaf. We can calculate that with the following function: diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 6d73585b5..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -7,8 +7,9 @@ tree.insert(value: 10) tree.insert(value: 9) tree.insert(value: 1) +let toDelete = tree.search(value: 1) +toDelete?.remove() tree -tree.debugDescription let tree2 = BinarySearchTree(array: [7, 2, 5, 10, 9, 1]) From eb54bc8544f0d482336878e211269ea43da9a7a7 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Mon, 30 Jan 2017 11:38:32 +0100 Subject: [PATCH 0392/1275] 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 0393/1275] 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 0394/1275] 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 717794dcb7cfaba84bc5f2dbbe3f316e5b7f57f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Azevedo?= Date: Wed, 1 Feb 2017 16:05:06 +0100 Subject: [PATCH 0395/1275] Fixed the trimming of deques --- Deque/Deque-Optimized.swift | 6 ++++-- Deque/README.markdown | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Deque/Deque-Optimized.swift b/Deque/Deque-Optimized.swift index 6326b457b..f565458c7 100644 --- a/Deque/Deque-Optimized.swift +++ b/Deque/Deque-Optimized.swift @@ -7,9 +7,11 @@ public struct Deque { private var array: [T?] private var head: Int private var capacity: Int + private let originalCapacity:Int public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) + originalCapacity = self.capacity array = [T?](repeating: nil, count: capacity) head = capacity } @@ -30,7 +32,7 @@ public struct Deque { if head == 0 { capacity *= 2 let emptySpace = [T?](repeating: nil, count: capacity) - array.insertContentsOf(emptySpace, at: 0) + array.insert(contentsOf: emptySpace, at: 0) head = capacity } @@ -44,7 +46,7 @@ public struct Deque { array[head] = nil head += 1 - if capacity > 10 && head >= capacity*2 { + if capacity >= originalCapacity && head >= capacity*2 { let amountToRemove = capacity + capacity/2 array.removeFirst(amountToRemove) head -= amountToRemove diff --git a/Deque/README.markdown b/Deque/README.markdown index 5858f3e6d..d156f9d97 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -119,9 +119,11 @@ public struct Deque { private var array: [T?] private var head: Int private var capacity: Int + private let originalCapacity:Int public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) + originalCapacity = self.capacity array = [T?](repeating: nil, count: capacity) head = capacity } @@ -267,7 +269,7 @@ Those empty spots at the front only get used when you call `enqueueFront()`. But array[head] = nil head += 1 - if capacity > 10 && head >= capacity*2 { + if capacity >= originalCapacity && head >= capacity*2 { let amountToRemove = capacity + capacity/2 array.removeFirst(amountToRemove) head -= amountToRemove @@ -279,6 +281,8 @@ Those empty spots at the front only get used when you call `enqueueFront()`. But Recall that `capacity` is the original number of empty places at the front of the queue. If the `head` has advanced more to the right than twice the capacity, then it's time to trim off a bunch of these empty spots. We reduce it to about 25%. +> **Note:** he deque will keep at least its original capacity by comparing `capacity` to `originalCapacity`. + For example, this: [ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, 1, 2, 3 ] @@ -288,9 +292,9 @@ For example, this: becomes after trimming: [ x, x, x, x, x, 1, 2, 3 ] - | - head - capacity + | + head + capacity This way we can strike a balance between fast enqueuing and dequeuing at the front and keeping the memory requirements reasonable. From 096eca30aa4a686f4d0839321dd99089d63c6c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Azevedo?= Date: Wed, 1 Feb 2017 16:07:50 +0100 Subject: [PATCH 0396/1275] Typo fixed --- Deque/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Deque/README.markdown b/Deque/README.markdown index d156f9d97..67a734576 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -281,7 +281,7 @@ Those empty spots at the front only get used when you call `enqueueFront()`. But Recall that `capacity` is the original number of empty places at the front of the queue. If the `head` has advanced more to the right than twice the capacity, then it's time to trim off a bunch of these empty spots. We reduce it to about 25%. -> **Note:** he deque will keep at least its original capacity by comparing `capacity` to `originalCapacity`. +> **Note:** The deque will keep at least its original capacity by comparing `capacity` to `originalCapacity`. For example, this: From 74bbb2105111797bad57ddc795b2b44cb494bb22 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Wed, 1 Feb 2017 19:09:34 -0800 Subject: [PATCH 0397/1275] Update README.markdown Hello, My name is Parvaneh. I am taking a writing course in the field of Computer Science. For an assignment, I need to edit some relevant documents and share the result. I hope you like my revisions. --- Merge Sort/README.markdown | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index 3ff69fdd5..05b90f166 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -2,40 +2,40 @@ Goal: Sort an array from low to high (or high to low) -Invented in 1945 by John von Neumann, merge sort is a fairly efficient sorting algorithm with a best, worst, and average time complexity of **O(n log n)**. +Invented in 1945 by John von Neumann, merge-sort is an efficient algorithm with a best, worst, and average time complexity of **O(n log n)**. -The idea behind merge sort is to **divide and conquer**: to divide a big problem into smaller problems and solving many small problems instead of solving a big one. I think of merge sort as **split first** and **merge after**. +The merge-sort algorithm uses the **divide and conquer** approach which is to divide a big problem into smaller problems and solve them. I think of the merge-sort algorithm as **split first** and **merge after**. -Assume you're given an array of *n* numbers and you need to put them in the right order. The merge sort algorithm works as follows: +Assume you need to sort an array of *n* numbers in the right order. The merge-sort algorithm works as follows: -- Put the numbers in a pile. The pile is unsorted. -- Split the pile into 2. Now you have **two unsorted piles** of numbers. -- Keep splitting the resulting piles until you can't split anymore. In the end, you will have *n* piles with 1 number in each pile. -- Begin to **merge** the piles together by sequentially pairing a pile with another pile. During each merge, you put the contents in sorted order. This is fairly easy because each individual pile is already sorted. +- Put the numbers in an unsorted pile. +- Split the pile into two. Now, you have **two unsorted piles** of numbers. +- Keep splitting the resulting piles until you cannot split anymore. In the end, you will have *n* piles with one number in each pile. +- Begin to **merge** the piles together by pairing them sequentially. During each merge, put the contents in sorted order. This is fairly easy because each individual pile is already sorted. ## An example ### Splitting -Let's say the numbers to sort are `[2, 1, 5, 4, 9]`. This is your unsorted pile. The goal is to keep splitting the pile until you can't split anymore. +Assume you are given an array of *n* numbers as`[2, 1, 5, 4, 9]`. This is an unsorted pile. The goal is to keep splitting the pile until you cannot split anymore. -First, split the array into two halves: `[2, 1]` and `[5, 4, 9]`. Can you keep splitting them? Yes you can! +First, split the array into two halves: `[2, 1]` and `[5, 4, 9]`. Can you keep splitting them? Yes, you can! -Focus on the left pile. `[2, 1]` will split into `[2]` and `[1]`. Can you keep splitting them? No. Time to check the other pile. +Focus on the left pile. Split`[2, 1]` into `[2]` and `[1]`. Can you keep splitting them? No. Time to check the other pile. -`[5, 4, 9]` splits to `[5]` and `[4, 9]`. Unsurprisingly, `[5]` can't be split anymore, but `[4, 9]` splits into `[4]` and `[9]`. +Split `[5, 4, 9]` into `[5]` and `[4, 9]`. Unsurprisingly, `[5]` cannot be split anymore, but `[4, 9]` can be split into `[4]` and `[9]`. The splitting process ends with the following piles: `[2]` `[1]` `[5]` `[4]` `[9]`. Notice that each pile consists of just one element. ### Merging -Now that you've split the array, you'll **merge** the piles together **while sorting them**. Remember, the idea is to solve many small problems rather than a big one. For each merge iteration you'll only be concerned at merging one pile with another. +Now that you have split the array, you should **merge** the piles together **while sorting them**. Remember, the idea is to solve many small problems rather than a big one. For each merge iteration, you must be concerned at merging one pile with another. -Given the piles `[2]` `[1]` `[5]` `[4]` `[9]`, the first pass will result in `[1, 2]` and `[4, 5]` and `[9]`. Since `[9]` is the odd one out, you can't merge it with anything during this pass. +Given the piles `[2]` `[1]` `[5]` `[4]` `[9]`, the first pass will result in `[1, 2]` and `[4, 5]` and `[9]`. Since `[9]` is the odd one out, you cannot merge it with anything during this pass. -The next pass will merge `[1, 2]` and `[4, 5]` together. This results in `[1, 2, 4, 5]`, with the `[9]` left out again since it's the odd one out. +The next pass will merge `[1, 2]` and `[4, 5]` together. This results in `[1, 2, 4, 5]`, with the `[9]` left out again because it is the odd one out. -You're left with only two piles and `[9]` finally gets its chance to merge, resulting in the sorted array `[1, 2, 4, 5, 9]`. +You are left with only two piles and `[9]`, finally gets its chance to merge, resulting in the sorted array as `[1, 2, 4, 5, 9]`. ## Top-down implementation @@ -57,15 +57,15 @@ func mergeSort(_ array: [Int]) -> [Int] { A step-by-step explanation of how the code works: -1. If the array is empty or only contains a single element, there's no way to split it into smaller pieces. You'll just return the array. +1. If the array is empty or contains a single element, there is no way to split it into smaller pieces. You must just return the array. 2. Find the middle index. 3. Using the middle index from the previous step, recursively split the left side of the array. -4. Also recursively split the right side of the array. +4. Also, recursively split the right side of the array. -5. Finally, merge all the values together, making sure that it's always sorted. +5. Finally, merge all the values together, making sure that it is always sorted. Here's the merging algorithm: @@ -109,15 +109,15 @@ func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { } ``` -This method may look scary but it is quite straightforward: +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's empty right now, but you'll 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. -3. This while loop will compare the elements from the left and right sides, and append them to the `orderedPile` while making sure that the result stays in order. +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. -4. If control exits from the previous while loop, it means that either `leftPile` or `rightPile` has its contents completely merged into the `orderedPile`. At this point, you no longer need to do comparisons. Just append the rest of the contents of the other array until there's no more to append. +4. If control exits from the previous while-loop, it means that either the `leftPile` or the `rightPile` has its contents completely merged into the `orderedPile`. At this point, you no longer need to do comparisons. Just append the rest of the contents of the other array until there is no more to append. As an example of how `merge()` works, suppose that we have the following piles: `leftPile = [1, 7, 8]` and `rightPile = [3, 6, 9]`. Note that each of these piles is individually sorted already -- that is always true with merge sort. These are merged into one larger sorted pile in the following steps: @@ -131,13 +131,13 @@ The left index, here represented as `l`, points at the first item from the left [ 1, 7, 8 ] [ 3, 6, 9 ] [ 1 ] -->l r -Now `l` points at `7` but `r` is still at `3`. We add the smallest item to the ordered pile, so that's `3`. The situation is now: +Now `l` points at `7` but `r` is still at `3`. We add the smallest item to the ordered pile, so that is `3`. The situation is now: leftPile rightPile orderedPile [ 1, 7, 8 ] [ 3, 6, 9 ] [ 1, 3 ] l -->r -This process repeats. At each step we pick the smallest item from either `leftPile` or `rightPile` and add it to `orderedPile`: +This process repeats. At each step, we pick the smallest item from either the `leftPile` or the `rightPile` and add the item into the `orderedPile`: leftPile rightPile orderedPile [ 1, 7, 8 ] [ 3, 6, 9 ] [ 1, 3, 6 ] @@ -151,13 +151,13 @@ This process repeats. At each step we pick the smallest item from either `leftPi [ 1, 7, 8 ] [ 3, 6, 9 ] [ 1, 3, 6, 7, 8 ] -->l r -Now there are no more items in the left pile. We simply add the remaining items from the right pile, and we're done. The merged pile is `[ 1, 3, 6, 7, 8, 9 ]`. +Now, there are no more items in the left pile. We simply add the remaining items from the right pile, and we are done. The merged pile is `[ 1, 3, 6, 7, 8, 9 ]`. -Notice that this algorithm is very simple: it moves from left-to-right through the two piles and at every step picks the smallest item. This works because we guarantee that each of the piles is already sorted. +Notice that, this algorithm is very simple: it moves from left-to-right through the two piles and at every step picks the smallest item. This works because we guarantee that each of the piles is already sorted. ## Bottom-up implementation -The implementation of merge sort you've seen so far is called "top-down" because it first splits the array into smaller piles and then merges them. When sorting an array (as opposed to, say, a linked list) you can actually skip the splitting step and immediately start merging the individual array elements. This is called the "bottom-up" approach. +The implementation of the merge-sort algorithm you have seen so far is called the "top-down" approach because it first splits the array into smaller piles and then merges them. When sorting an array (as opposed to, say, a linked list) you can actually skip the splitting step and immediately start merging the individual array elements. This is called the "bottom-up" approach. Time to step up the game a little. :-) Here is a complete bottom-up implementation in Swift: @@ -212,19 +212,19 @@ func mergeSortBottomUp(_ a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { } ``` -It looks a lot more intimidating than the top-down version but notice that the main body includes the same three `while` loops from `merge()`. +It looks a lot more intimidating than the top-down version, but notice that the main body includes the same three `while` loops from `merge()`. Notable points: -1. Merge sort needs a temporary working array because you can't merge the left and right piles and at the same time overwrite their contents. But allocating a new array for each merge is wasteful. Therefore, we're using two working arrays and we'll switch between them using the value of `d`, which is either 0 or 1. The array `z[d]` is used for reading, `z[1 - d]` is used for writing. This is called *double-buffering*. +1. The Merge-sort algorithm needs a temporary working array because you cannot merge the left and right piles and at the same time overwrite their contents. Because allocating a new array for each merge is wasteful, we are using two working arrays, and we will switch between them using the value of `d`, which is either 0 or 1. The array `z[d]` is used for reading, and `z[1 - d]` is used for writing. This is called *double-buffering*. -2. Conceptually, the bottom-up version works the same way as the top-down version. First, it merges small piles of 1 element each, then it merges piles of 2 elements each, then piles of 4 elements each, and so on. The size of the pile is given by `width`. Initially, `width` is `1` but at the end of each loop iteration we multiply it by 2. So this outer loop determines the size of the piles being merged. And in each step, the subarrays to merge become larger. +2. Conceptually, the bottom-up version works the same way as the top-down version. First, it merges small piles of one element each, then it merges piles of two elements each, then piles of four elements each, and so on. The size of the pile is given by `width`. Initially, `width` is `1` but at the end of each loop iteration, we multiply it by two, so this outer loop determines the size of the piles being merged, and the subarrays to merge become larger in each step. 3. The inner loop steps through the piles and merges each pair of piles into a larger one. The result is written in the array given by `z[1 - d]`. -4. This is the same logic as in the top-down version. The main difference is that we're using double-buffering, so values are read from `z[d]` and written into `z[1 - d]`. It also uses an `isOrderedBefore` function to compare the elements rather than just `<`, so this merge sort is generic and you can use it to sort any kind of object you want. +4. This is the same logic as in the top-down version. The main difference is that we're using double-buffering, so values are read from `z[d]` and written into `z[1 - d]`. It also uses an `isOrderedBefore` function to compare the elements rather than just `<`, so this merge-sort algorithm is generic, and you can use it to sort any kind of object you want. -5. At this point, the piles of size `width` from array `z[d]` have been merged into larger piles of size `width * 2` in array `z[1 - d]`. Here we swap the active array, so that in the next step we'll read from the new piles we've just created. +5. At this point, the piles of size `width` from array `z[d]` have been merged into larger piles of size `width * 2` in array `z[1 - d]`. Here, we swap the active array, so that in the next step we'll read from the new piles we have just created. This function is generic, so you can use it to sort any type you desire, as long as you provide a proper `isOrderedBefore` closure to compare the elements. @@ -237,15 +237,15 @@ mergeSortBottomUp(array, <) // [1, 2, 4, 5, 9] ## Performance -The speed of merge sort is dependent on the size of the array it needs to sort. The larger the array, the more work it needs to do. +The speed of the merge-sort algorithm is dependent on the size of the array it needs to sort. The larger the array, the more work it needs to do. -Whether or not the initial array is sorted already doesn't affect the speed of merge sort since you'll be doing the same amount splits and comparisons regardless of the initial order of the elements. +Whether or not the initial array is sorted already doesnot affect the speed of the merge-sort algorithm since you will be doing the same amount splits and comparisons regardless of the initial order of the elements. Therefore, the time complexity for the best, worst, and average case will always be **O(n log n)**. -A disadvantage of merge sort is that it needs a temporary "working" array equal in size to the array being sorted. It is not an **in-place** sort, unlike for example [quicksort](../Quicksort/). +A disadvantage of the merge-sort algorithm is that it needs a temporary "working" array equal in size to the array being sorted. It is not an **in-place** sort, unlike for example [quicksort](../Quicksort/). -Most implementations of merge sort produce a **stable** sort. This means that array elements that have identical sort keys will stay in the same order relative to each other after sorting. This is not important for simple values such as numbers or strings, but it can be an issue when sorting more complex objects. +Most implementations of the merge-sort algorithm produce a **stable** sort. This means that array elements that have identical sort keys will stay in the same order relative to each other after sorting. This is not important for simple values such as numbers or strings, but it can be an issue when sorting more complex objects. ## See also From b99c037c861f295f63470d394a66b2dcaed40303 Mon Sep 17 00:00:00 2001 From: Keizar Date: Fri, 3 Feb 2017 13:20:07 -0800 Subject: [PATCH 0398/1275] update README.markdown --- Bubble Sort/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index ceb2a98cb..93d370827 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,14 +1,14 @@ # 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 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. ##### Runtime: -- Average: O(N^2) +- Average: O(N^2) - Worst: O(N^2) -##### Memory: +##### Memory: - O(1) ### Implementation: -The implementation will not be shown because as you can see from the average and worst runtimes this is a very inefficient algorithm but having a grasp of the concept will help in getting to know the basics of simple sorting algorithms. +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. From c22799378133820468783a1699be31d13c0f9d29 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 4 Feb 2017 18:22:06 +0800 Subject: [PATCH 0399/1275] left/right tree should reconnect to new node --- .../Sources/BinarySearchTree.swift | 8 +- .../Tests/BinarySearchTreeTests.swift | 87 ++++++++++--------- .../Tests/Tests.xcodeproj/project.pbxproj | 5 +- .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++ 4 files changed, 61 insertions(+), 47 deletions(-) create mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings 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 31ae99a2f..74399efef 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -109,10 +109,10 @@ extension BinarySearchTree { // Replacement for current node can be either biggest one on the left or // smallest one on the right, whichever is not nil - if let left = left { - replacement = left.maximum() - } else if let right = right { + if let right = right { replacement = right.minimum() + } else if let left = left { + replacement = left.maximum() } else { replacement = nil; } @@ -122,6 +122,8 @@ extension BinarySearchTree { // Place the replacement on current node's position replacement?.right = right; replacement?.left = left; + right?.parent = replacement + left?.parent = replacement reconnectParentTo(node:replacement); // The current node is no longer part of the tree, so clean it up. diff --git a/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift b/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift index 7c7fd069b..30749d8e4 100755 --- a/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift +++ b/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift @@ -17,8 +17,8 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.count, 8) XCTAssertEqual(tree.toArray(), [3, 5, 6, 8, 9, 10, 12, 16]) - XCTAssertEqual(tree.search(9)!.value, 9) - XCTAssertNil(tree.search(99)) + XCTAssertEqual(tree.search(value: 9)!.value, 9) + XCTAssertNil(tree.search(value: 99)) XCTAssertEqual(tree.minimum().value, 3) XCTAssertEqual(tree.maximum().value, 16) @@ -26,17 +26,17 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.height(), 3) XCTAssertEqual(tree.depth(), 0) - let node1 = tree.search(16) + let node1 = tree.search(value: 16) XCTAssertNotNil(node1) XCTAssertEqual(node1!.height(), 0) XCTAssertEqual(node1!.depth(), 3) - let node2 = tree.search(12) + let node2 = tree.search(value: 12) XCTAssertNotNil(node2) XCTAssertEqual(node2!.height(), 1) XCTAssertEqual(node2!.depth(), 2) - let node3 = tree.search(10) + let node3 = tree.search(value: 10) XCTAssertNotNil(node3) XCTAssertEqual(node3!.height(), 2) XCTAssertEqual(node3!.depth(), 1) @@ -45,32 +45,32 @@ class BinarySearchTreeTest: XCTestCase { func testInsert() { let tree = BinarySearchTree(value: 8) - tree.insert(5) + tree.insert(value: 5) XCTAssertEqual(tree.count, 2) XCTAssertEqual(tree.height(), 1) XCTAssertEqual(tree.depth(), 0) - let node1 = tree.search(5) + let node1 = tree.search(value: 5) XCTAssertNotNil(node1) XCTAssertEqual(node1!.height(), 0) XCTAssertEqual(node1!.depth(), 1) - tree.insert(10) + tree.insert(value: 10) XCTAssertEqual(tree.count, 3) XCTAssertEqual(tree.height(), 1) XCTAssertEqual(tree.depth(), 0) - let node2 = tree.search(10) + let node2 = tree.search(value: 10) XCTAssertNotNil(node2) XCTAssertEqual(node2!.height(), 0) XCTAssertEqual(node2!.depth(), 1) - tree.insert(3) + tree.insert(value: 3) XCTAssertEqual(tree.count, 4) XCTAssertEqual(tree.height(), 2) XCTAssertEqual(tree.depth(), 0) - let node3 = tree.search(3) + let node3 = tree.search(value: 3) XCTAssertNotNil(node3) XCTAssertEqual(node3!.height(), 0) XCTAssertEqual(node3!.depth(), 2) @@ -84,9 +84,9 @@ class BinarySearchTreeTest: XCTestCase { func testInsertDuplicates() { let tree = BinarySearchTree(array: [8, 5, 10]) - tree.insert(8) - tree.insert(5) - tree.insert(10) + tree.insert(value: 8) + tree.insert(value: 5) + tree.insert(value: 10) XCTAssertEqual(tree.count, 6) XCTAssertEqual(tree.toArray(), [5, 5, 8, 8, 10, 10]) } @@ -108,7 +108,7 @@ class BinarySearchTreeTest: XCTestCase { } func testInsertSorted() { - let tree = BinarySearchTree(array: [8, 5, 10, 3, 12, 9, 6, 16].sort(<)) + let tree = BinarySearchTree(array: [8, 5, 10, 3, 12, 9, 6, 16].sorted(by: <)) XCTAssertEqual(tree.count, 8) XCTAssertEqual(tree.toArray(), [3, 5, 6, 8, 9, 10, 12, 16]) @@ -118,7 +118,7 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.height(), 7) XCTAssertEqual(tree.depth(), 0) - let node1 = tree.search(16) + let node1 = tree.search(value: 16) XCTAssertNotNil(node1) XCTAssertEqual(node1!.height(), 0) XCTAssertEqual(node1!.depth(), 7) @@ -127,15 +127,15 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveLeaf() { let tree = BinarySearchTree(array: [8, 5, 10, 4]) - let node10 = tree.search(10)! + let node10 = tree.search(value: 10)! XCTAssertNil(node10.left) XCTAssertNil(node10.right) XCTAssertTrue(tree.right === node10) - let node5 = tree.search(5)! + let node5 = tree.search(value: 5)! XCTAssertTrue(tree.left === node5) - let node4 = tree.search(4)! + let node4 = tree.search(value: 4)! XCTAssertTrue(node5.left === node4) XCTAssertNil(node5.right) @@ -158,8 +158,8 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveOneChildLeft() { let tree = BinarySearchTree(array: [8, 5, 10, 4, 9]) - let node4 = tree.search(4)! - let node5 = tree.search(5)! + let node4 = tree.search(value: 4)! + let node5 = tree.search(value: 5)! XCTAssertTrue(node5.left === node4) XCTAssertTrue(node5 === node4.parent) @@ -171,8 +171,8 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.count, 4) XCTAssertEqual(tree.toArray(), [4, 8, 9, 10]) - let node9 = tree.search(9)! - let node10 = tree.search(10)! + let node9 = tree.search(value: 9)! + let node10 = tree.search(value: 10)! XCTAssertTrue(node10.left === node9) XCTAssertTrue(node10 === node9.parent) @@ -188,8 +188,8 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveOneChildRight() { let tree = BinarySearchTree(array: [8, 5, 10, 6, 11]) - let node6 = tree.search(6)! - let node5 = tree.search(5)! + let node6 = tree.search(value: 6)! + let node5 = tree.search(value: 5)! XCTAssertTrue(node5.right === node6) XCTAssertTrue(node5 === node6.parent) @@ -201,8 +201,8 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.count, 4) XCTAssertEqual(tree.toArray(), [6, 8, 10, 11]) - let node11 = tree.search(11)! - let node10 = tree.search(10)! + let node11 = tree.search(value: 11)! + let node10 = tree.search(value: 10)! XCTAssertTrue(node10.right === node11) XCTAssertTrue(node10 === node11.parent) @@ -218,9 +218,9 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveTwoChildrenSimple() { let tree = BinarySearchTree(array: [8, 5, 10, 4, 6, 9, 11]) - let node4 = tree.search(4)! - let node5 = tree.search(5)! - let node6 = tree.search(6)! + let node4 = tree.search(value: 4)! + let node5 = tree.search(value: 5)! + let node6 = tree.search(value: 6)! XCTAssertTrue(node5.left === node4) XCTAssertTrue(node5.right === node6) XCTAssertTrue(node5 === node4.parent) @@ -241,9 +241,9 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertEqual(tree.count, 6) XCTAssertEqual(tree.toArray(), [4, 6, 8, 9, 10, 11]) - let node9 = tree.search(9)! - let node10 = tree.search(10)! - let node11 = tree.search(11)! + let node9 = tree.search(value: 9)! + let node10 = tree.search(value: 10)! + let node11 = tree.search(value: 11)! XCTAssertTrue(node10.left === node9) XCTAssertTrue(node10.right === node11) XCTAssertTrue(node10 === node9.parent) @@ -268,11 +268,12 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveTwoChildrenComplex() { let tree = BinarySearchTree(array: [8, 5, 10, 4, 9, 20, 11, 15, 13]) - let node9 = tree.search(9)! - let node10 = tree.search(10)! - let node11 = tree.search(11)! - let node15 = tree.search(15)! - let node20 = tree.search(20)! + let node9 = tree.search(value: 9)! + let node10 = tree.search(value: 10)! + let node11 = tree.search(value: 11)! + let node13 = tree.search(value: 13)! + let node15 = tree.search(value: 15)! + let node20 = tree.search(value: 20)! XCTAssertTrue(node10.left === node9) XCTAssertTrue(node10 === node9.parent) XCTAssertTrue(node10.right === node20) @@ -290,8 +291,8 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertTrue(node11 === node9.parent) XCTAssertTrue(node11.right === node20) XCTAssertTrue(node11 === node20.parent) - XCTAssertTrue(node20.left === node15) - XCTAssertTrue(node20 === node15.parent) + XCTAssertTrue(node20.left === node13) + XCTAssertTrue(node20 === node13.parent) XCTAssertNil(node20.right) XCTAssertNil(node10.left) XCTAssertNil(node10.right) @@ -303,7 +304,7 @@ class BinarySearchTreeTest: XCTestCase { func testRemoveRoot() { let tree = BinarySearchTree(array: [8, 5, 10, 4, 9, 20, 11, 15, 13]) - let node9 = tree.search(9)! + let node9 = tree.search(value: 9)! let newRoot = tree.remove() XCTAssertTrue(newRoot === node9) @@ -319,7 +320,7 @@ class BinarySearchTreeTest: XCTestCase { func testPredecessor() { let tree = BinarySearchTree(array: [3, 1, 2, 5, 4]) - let node = tree.search(5) + let node = tree.search(value: 5) XCTAssertEqual(node!.value, 5) XCTAssertEqual(node!.predecessor()!.value, 4) @@ -331,7 +332,7 @@ class BinarySearchTreeTest: XCTestCase { func testSuccessor() { let tree = BinarySearchTree(array: [3, 1, 2, 5, 4]) - let node = tree.search(1) + let node = tree.search(value: 1) XCTAssertEqual(node!.value, 1) XCTAssertEqual(node!.successor()!.value, 2) 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 7ecfe593f..f4c3f65c7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 7B80C3D91C77A323003CECC7 /* BinarySearchTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeTests.swift; sourceTree = SOURCE_ROOT; }; - 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchTree.swift; path = ../BinarySearchTree.playground/Sources/BinarySearchTree.swift; sourceTree = ""; }; + 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchTree.swift; path = ../BinarySearchTree.playground/Sources/BinarySearchTree.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -88,6 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -220,6 +221,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; }; name = Debug; }; @@ -231,6 +233,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; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + From eef96f6431477e31598e884a72d3178c9b06e8f6 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 4 Feb 2017 17:59:53 +0800 Subject: [PATCH 0400/1275] unmark .travis.yml test for BinarySearchTree --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80ced8b6c..2b2bafd14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - 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/Tests/Tests.xcodeproj -scheme Tests -# - xcodebuild test -project ./Binary\ Search\ Tree/Solution\ 1/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 From 78da2c7b4719f55faaa69f2ae0c0324eb3423db0 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 4 Feb 2017 17:36:46 +0800 Subject: [PATCH 0401/1275] lint files --- .../Sources/BinarySearchTree.swift | 24 +++++++++---------- .../Contents.swift | 2 -- 2 files changed, 12 insertions(+), 14 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 74399efef..8a126e950 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -22,7 +22,7 @@ public class BinarySearchTree { public convenience init(array: [T]) { precondition(array.count > 0) self.init(value: array.first!) - for v in array.dropFirst() { + for v in array.dropFirst() { insert(value: v) } } @@ -106,7 +106,7 @@ extension BinarySearchTree { */ @discardableResult public func remove() -> BinarySearchTree? { let replacement: BinarySearchTree? - + // Replacement for current node can be either biggest one on the left or // smallest one on the right, whichever is not nil if let right = right { @@ -114,24 +114,24 @@ extension BinarySearchTree { } else if let left = left { replacement = left.maximum() } else { - replacement = nil; + replacement = nil } - - replacement?.remove(); + + replacement?.remove() // Place the replacement on current node's position - replacement?.right = right; - replacement?.left = left; + replacement?.right = right + replacement?.left = left right?.parent = replacement left?.parent = replacement - reconnectParentTo(node:replacement); - + reconnectParentTo(node:replacement) + // The current node is no longer part of the tree, so clean it up. parent = nil left = nil right = nil - - return replacement; + + return replacement } private func reconnectParentTo(node: BinarySearchTree?) { @@ -324,7 +324,7 @@ extension BinarySearchTree: CustomStringConvertible { } return s } - + public func toArray() -> [T] { return map { $0 } } diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift index 8df69fb6a..2b5dcc341 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift @@ -12,5 +12,3 @@ print(tree) tree.search(x: 10) tree.search(x: 1) tree.search(x: 11) - - From f47a45e967ec651b6091f1d81a352f15420fd564 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 4 Feb 2017 17:56:24 +0800 Subject: [PATCH 0402/1275] Update README.markdown --- Binary Search Tree/README.markdown | 75 ++++++++++++++++-------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index e8d2f58e2..bd2a00c9e 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -58,7 +58,7 @@ Sometimes you don't want to look at just a single node, but at all of them. There are three ways to traverse a binary tree: 1. *In-order* (or *depth-first*): first look at the left child of a node, then at the node itself, and finally at its right child. -2. *Pre-order*: first look at a node, then its left and right children. +2. *Pre-order*: first look at a node, then its left and right children. 3. *Post-order*: first look at the left and right children and process the node itself last. Once again, this happens recursively. @@ -133,7 +133,7 @@ public class BinarySearchTree { } ``` -This class describes just a single node, not the entire tree. It's a generic type, so the node can store any kind of data. It also has references to its `left` and `right` child nodes and a `parent` node. +This class describes just a single node, not the entire tree. It's a generic type, so the node can store any kind of data. It also has references to its `left` and `right` child nodes and a `parent` node. Here's how you'd use it: @@ -258,7 +258,7 @@ Here is the implementation of `search()`: I hope the logic is clear: this starts at the current node (usually the root) and compares the values. If the search value is less than the node's value, we continue searching in the left branch; if the search value is greater, we dive into the right branch. -Of course, if there are no more nodes to look at -- when `left` or `right` is nil -- then we return `nil` to indicate the search value is not in the tree. +Of course, if there are no more nodes to look at -- when `left` or `right` is nil -- then we return `nil` to indicate the search value is not in the tree. > **Note:** In Swift that's very conveniently done with optional chaining; when you write `left?.search(value)` it automatically returns nil if `left` is nil. There's no need to explicitly check for this with an `if` statement. @@ -300,21 +300,21 @@ The first three lines all return the corresponding `BinaryTreeNode` object. The Remember there are 3 different ways to look at all nodes in the tree? Here they are: ```swift - public func traverseInOrder(@noescape process: T -> Void) { - left?.traverseInOrder(process) + public func traverseInOrder(process: (T) -> Void) { + left?.traverseInOrder(process: process) process(value) - right?.traverseInOrder(process) + right?.traverseInOrder(process: process) } - - public func traversePreOrder(@noescape process: T -> Void) { + + public func traversePreOrder(process: (T) -> Void) { process(value) - left?.traversePreOrder(process) - right?.traversePreOrder(process) + left?.traversePreOrder(process: process) + right?.traversePreOrder(process: process) } - - public func traversePostOrder(@noescape process: T -> Void) { - left?.traversePostOrder(process) - right?.traversePostOrder(process) + + public func traversePostOrder(process: (T) -> Void) { + left?.traversePostOrder(process: process) + right?.traversePostOrder(process: process) process(value) } ``` @@ -339,11 +339,12 @@ This prints the following: You can also add things like `map()` and `filter()` to the tree. For example, here's an implementation of map: ```swift - public func map(@noescape formula: T -> T) -> [T] { + + public func map(formula: (T) -> T) -> [T] { var a = [T]() - if let left = left { a += left.map(formula) } + if let left = left { a += left.map(formula: formula) } a.append(formula(value)) - if let right = right { a += right.map(formula) } + if let right = right { a += right.map(formula: formula) } return a } ``` @@ -365,7 +366,7 @@ tree.toArray() // [1, 2, 5, 7, 9, 10] ``` As an exercise for yourself, see if you can implement filter and reduce. - + ### Deleting nodes We can make the code much more readable by defining some helper functions. @@ -395,7 +396,7 @@ We also need a function that returns the minimum and maximum of a node: } return node } - + public func maximum() -> BinarySearchTree { var node = self while case let next? = node.right { @@ -411,30 +412,32 @@ The rest of the code is pretty self-explanatory: ```swift @discardableResult public func remove() -> BinarySearchTree? { let replacement: BinarySearchTree? - + // Replacement for current node can be either biggest one on the left or // smallest one on the right, whichever is not nil - if let left = left { - replacement = left.maximum() - } else if let right = right { + if let right = right { replacement = right.minimum() + } else if let left = left { + replacement = left.maximum() } else { - replacement = nil; + replacement = nil } - - replacement?.remove(); + + replacement?.remove() // Place the replacement on current node's position - replacement?.right = right; - replacement?.left = left; - reconnectParentTo(node:replacement); - + replacement?.right = right + replacement?.left = left + right?.parent = replacement + left?.parent = replacement + reconnectParentTo(node:replacement) + // The current node is no longer part of the tree, so clean it up. parent = nil left = nil right = nil - - return replacement; + + return replacement } ``` @@ -574,7 +577,7 @@ if let node1 = tree.search(1) { ## The code (solution 2) -We've implemented the binary tree node as a class but you can also use an enum. +We've implemented the binary tree node as a class but you can also use an enum. The difference is reference semantics versus value semantics. Making a change to the class-based tree will update that same instance in memory. But the enum-based tree is immutable -- any insertions or deletions will give you an entirely new copy of the tree. Which one is best totally depends on what you want to use it for. @@ -588,7 +591,7 @@ public enum BinarySearchTree { } ``` -The enum has three cases: +The enum has three cases: - `Empty` to mark the end of a branch (the class-based version used `nil` references for this). - `Leaf` for a leaf node that has no children. @@ -606,7 +609,7 @@ As usual, we'll implement most functionality recursively. We'll treat each case case let .Node(left, _, right): return left.count + 1 + right.count } } - + public var height: Int { switch self { case .Empty: return 0 @@ -623,7 +626,7 @@ Inserting new nodes looks like this: switch self { case .Empty: return .Leaf(newValue) - + case .Leaf(let value): if newValue < value { return .Node(.Leaf(newValue), value, .Empty) From 257e973125884983b42193d7e67d1a6155081b4c Mon Sep 17 00:00:00 2001 From: Julio Guzman Date: Mon, 6 Feb 2017 16:32:26 -0600 Subject: [PATCH 0403/1275] Change last upgrade version --- .../Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8ef8d8581..dfcf6de42 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: Mon, 6 Feb 2017 16:32:42 -0600 Subject: [PATCH 0404/1275] Change last upgrade check --- Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj index 33be43391..a04c95170 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -89,7 +89,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { From c8ce274329483d25f8e3ddfb3917419dad7eb9b0 Mon Sep 17 00:00:00 2001 From: Julio Guzman Date: Mon, 6 Feb 2017 16:40:38 -0600 Subject: [PATCH 0405/1275] Add assignation to remove warning --- Breadth-First Search/Tests/Graph.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Breadth-First Search/Tests/Graph.swift b/Breadth-First Search/Tests/Graph.swift index ed71cab7c..09684da5b 100644 --- a/Breadth-First Search/Tests/Graph.swift +++ b/Breadth-First Search/Tests/Graph.swift @@ -86,7 +86,7 @@ public class Graph: CustomStringConvertible, Equatable { let duplicated = Graph() for node in nodes { - duplicated.addNode(node.label) + let _ = duplicated.addNode(node.label) } for node in nodes { From e0a3b634d087a3376ba2f2478effd872cbe800f1 Mon Sep 17 00:00:00 2001 From: Julio Guzman Date: Mon, 6 Feb 2017 16:51:01 -0600 Subject: [PATCH 0406/1275] Migrates Breadth First Search tests project to Swift 3 syntax --- Breadth-First Search/Tests/Graph.swift | 8 ++++---- Breadth-First Search/Tests/Queue.swift | 2 +- .../Tests/Tests.xcodeproj/project.pbxproj | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Breadth-First Search/Tests/Graph.swift b/Breadth-First Search/Tests/Graph.swift index 09684da5b..5e0837160 100644 --- a/Breadth-First Search/Tests/Graph.swift +++ b/Breadth-First Search/Tests/Graph.swift @@ -39,7 +39,7 @@ public class Node: CustomStringConvertible, Equatable { } public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + neighbors.remove(at: neighbors.index { $0 === edge }!) } } @@ -56,13 +56,13 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(label: String) -> Node { + public func addNode(_ label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { + public func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } @@ -78,7 +78,7 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + public func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } diff --git a/Breadth-First Search/Tests/Queue.swift b/Breadth-First Search/Tests/Queue.swift index bf462bbdd..3d98f801c 100644 --- a/Breadth-First Search/Tests/Queue.swift +++ b/Breadth-First Search/Tests/Queue.swift @@ -13,7 +13,7 @@ public struct Queue { return array.count } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { array.append(element) } diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj index a04c95170..f86abf86e 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -94,6 +94,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -230,6 +231,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -242,6 +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 = 3.0; }; name = Release; }; From ca8e7ff4be86d94c8f5fea31d50a74896362b0dc Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 6 Feb 2017 17:26:07 -0800 Subject: [PATCH 0407/1275] Fixed spacing. --- .../ShuntingYard.playground/Contents.swift | 174 ++++----- Shunting Yard/ShuntingYard.swift | 366 +++++++++--------- 2 files changed, 270 insertions(+), 270 deletions(-) diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index b341c673b..fa9f5745b 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -12,21 +12,21 @@ public enum OperatorType: CustomStringConvertible { case multiply case percent case exponent - + public var description: String { switch self { - case .add: - return "+" - case .subtract: - return "-" - case .divide: - return "/" - case .multiply: - return "*" - case .percent: - return "%" - case .exponent: - return "^" + case .add: + return "+" + case .subtract: + return "-" + case .divide: + return "/" + case .multiply: + return "*" + case .percent: + return "%" + case .exponent: + return "^" } } } @@ -36,48 +36,48 @@ public enum TokenType: CustomStringConvertible { case closeBracket case Operator(OperatorToken) case operand(Double) - + public var description: String { switch self { - case .openBracket: - return "(" - case .closeBracket: - return ")" - case .Operator(let operatorToken): - return operatorToken.description - case .operand(let value): - return "\(value)" + case .openBracket: + return "(" + case .closeBracket: + return ")" + case .Operator(let operatorToken): + return operatorToken.description + case .operand(let value): + return "\(value)" } } } public struct OperatorToken: CustomStringConvertible { let operatorType: OperatorType - + init(operatorType: OperatorType) { self.operatorType = operatorType } - + var precedence: Int { switch operatorType { - case .add, .subtract: - return 0 - case .divide, .multiply, .percent: - return 5 - case .exponent: - return 10 + case .add, .subtract: + return 0 + case .divide, .multiply, .percent: + return 5 + case .exponent: + return 10 } } - + var associativity: OperatorAssociativity { switch operatorType { - case .add, .subtract, .divide, .multiply, .percent: - return .leftAssociative - case .exponent: - return .rightAssociative + case .add, .subtract, .divide, .multiply, .percent: + return .leftAssociative + case .exponent: + return .rightAssociative } } - + public var description: String { return operatorType.description } @@ -93,46 +93,46 @@ func < (left: OperatorToken, right: OperatorToken) -> Bool { public struct Token: CustomStringConvertible { let tokenType: TokenType - + init(tokenType: TokenType) { self.tokenType = tokenType } - + init(operand: Double) { tokenType = .operand(operand) } - + init(operatorType: OperatorType) { tokenType = .Operator(OperatorToken(operatorType: operatorType)) } - + var isOpenBracket: Bool { switch tokenType { - case .openBracket: - return true - default: - return false + case .openBracket: + return true + default: + return false } } - + var isOperator: Bool { switch tokenType { - case .Operator(_): - return true - default: - return false + case .Operator(_): + return true + default: + return false } } - + var operatorToken: OperatorToken? { switch tokenType { - case .Operator(let operatorToken): - return operatorToken - default: - return nil + case .Operator(let operatorToken): + return operatorToken + default: + return nil } } - + public var description: String { return tokenType.description } @@ -140,27 +140,27 @@ public struct Token: CustomStringConvertible { public class InfixExpressionBuilder { private var expression = [Token]() - + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { expression.append(Token(operatorType: operatorType)) return self } - + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { expression.append(Token(operand: operand)) return self } - + public func addOpenBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .openBracket)) return self } - + public func addCloseBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .closeBracket)) return self } - + public func build() -> [Token] { // Maybe do some validation here return expression @@ -169,46 +169,46 @@ public class InfixExpressionBuilder { // This returns the result of the shunting yard algorithm public func reversePolishNotation(_ expression: [Token]) -> String { - + var tokenStack = Stack() var reversePolishNotation = [Token]() - + for token in expression { switch token.tokenType { - case .operand(_): - reversePolishNotation.append(token) - - case .openBracket: - tokenStack.push(token) - - case .closeBracket: - while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { - reversePolishNotation.append(tempToken) + case .operand(_): + reversePolishNotation.append(token) + + case .openBracket: + tokenStack.push(token) + + case .closeBracket: + while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { + reversePolishNotation.append(tempToken) + } + + case .Operator(let operatorToken): + for tempToken in tokenStack.makeIterator() { + if !tempToken.isOperator { + break } - - case .Operator(let operatorToken): - for tempToken in tokenStack.makeIterator() { - if !tempToken.isOperator { + + if let tempOperatorToken = tempToken.operatorToken { + if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken + || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { + reversePolishNotation.append(tokenStack.pop()!) + } else { break } - - if let tempOperatorToken = tempToken.operatorToken { - if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken - || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { - reversePolishNotation.append(tokenStack.pop()!) - } else { - break - } - } } - tokenStack.push(token) + } + tokenStack.push(token) } } - + while tokenStack.count > 0 { reversePolishNotation.append(tokenStack.pop()!) } - + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } diff --git a/Shunting Yard/ShuntingYard.swift b/Shunting Yard/ShuntingYard.swift index b8f5f8e6b..97a72249d 100644 --- a/Shunting Yard/ShuntingYard.swift +++ b/Shunting Yard/ShuntingYard.swift @@ -7,213 +7,213 @@ // internal enum OperatorAssociativity { - case leftAssociative - case rightAssociative + case leftAssociative + case rightAssociative } public enum OperatorType: CustomStringConvertible { - case add - case subtract - case divide - case multiply - case percent - case exponent - - public var description: String { - switch self { - case .add: - return "+" - case .subtract: - return "-" - case .divide: - return "/" - case .multiply: - return "*" - case .percent: - return "%" - case .exponent: - return "^" - } - } + case add + case subtract + case divide + case multiply + case percent + case exponent + + public var description: String { + switch self { + case .add: + return "+" + case .subtract: + return "-" + case .divide: + return "/" + case .multiply: + return "*" + case .percent: + return "%" + case .exponent: + return "^" + } + } } public enum TokenType: CustomStringConvertible { - case openBracket - case closeBracket - case Operator(OperatorToken) - case operand(Double) - - public var description: String { - switch self { - case .openBracket: - return "(" - case .closeBracket: - return ")" - case .Operator(let operatorToken): - return operatorToken.description - case .operand(let value): - return "\(value)" - } - } + case openBracket + case closeBracket + case Operator(OperatorToken) + case operand(Double) + + public var description: String { + switch self { + case .openBracket: + return "(" + case .closeBracket: + return ")" + case .Operator(let operatorToken): + return operatorToken.description + case .operand(let value): + return "\(value)" + } + } } public struct OperatorToken: CustomStringConvertible { - let operatorType: OperatorType - - init(operatorType: OperatorType) { - self.operatorType = operatorType - } - - var precedence: Int { - switch operatorType { - case .add, .subtract: - return 0 - case .divide, .multiply, .percent: - return 5 - case .exponent: - return 10 - } - } - - var associativity: OperatorAssociativity { - switch operatorType { - case .add, .subtract, .divide, .multiply, .percent: - return .leftAssociative - case .exponent: - return .rightAssociative - } - } - - public var description: String { - return operatorType.description - } + let operatorType: OperatorType + + init(operatorType: OperatorType) { + self.operatorType = operatorType + } + + var precedence: Int { + switch operatorType { + case .add, .subtract: + return 0 + case .divide, .multiply, .percent: + return 5 + case .exponent: + return 10 + } + } + + var associativity: OperatorAssociativity { + switch operatorType { + case .add, .subtract, .divide, .multiply, .percent: + return .leftAssociative + case .exponent: + return .rightAssociative + } + } + + public var description: String { + return operatorType.description + } } func <= (left: OperatorToken, right: OperatorToken) -> Bool { - return left.precedence <= right.precedence + return left.precedence <= right.precedence } func < (left: OperatorToken, right: OperatorToken) -> Bool { - return left.precedence < right.precedence + return left.precedence < right.precedence } public struct Token: CustomStringConvertible { - let tokenType: TokenType - - init(tokenType: TokenType) { - self.tokenType = tokenType - } - - init(operand: Double) { - tokenType = .operand(operand) - } - - init(operatorType: OperatorType) { - tokenType = .Operator(OperatorToken(operatorType: operatorType)) - } - - var isOpenBracket: Bool { - switch tokenType { - case .openBracket: - return true - default: - return false - } - } - - var isOperator: Bool { - switch tokenType { - case .Operator(_): - return true - default: - return false - } - } - - var operatorToken: OperatorToken? { - switch tokenType { - case .Operator(let operatorToken): - return operatorToken - default: - return nil - } - } - - public var description: String { - return tokenType.description - } + let tokenType: TokenType + + init(tokenType: TokenType) { + self.tokenType = tokenType + } + + init(operand: Double) { + tokenType = .operand(operand) + } + + init(operatorType: OperatorType) { + tokenType = .Operator(OperatorToken(operatorType: operatorType)) + } + + var isOpenBracket: Bool { + switch tokenType { + case .openBracket: + return true + default: + return false + } + } + + var isOperator: Bool { + switch tokenType { + case .Operator(_): + return true + default: + return false + } + } + + var operatorToken: OperatorToken? { + switch tokenType { + case .Operator(let operatorToken): + return operatorToken + default: + return nil + } + } + + public var description: String { + return tokenType.description + } } public class InfixExpressionBuilder { - private var expression = [Token]() - - public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { - expression.append(Token(operatorType: operatorType)) - return self - } - - public func addOperand(_ operand: Double) -> InfixExpressionBuilder { - expression.append(Token(operand: operand)) - return self - } - - public func addOpenBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .openBracket)) - return self - } - - public func addCloseBracket() -> InfixExpressionBuilder { - expression.append(Token(tokenType: .closeBracket)) - return self - } - - public func build() -> [Token] { - // Maybe do some validation here - return expression - } + private var expression = [Token]() + + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { + expression.append(Token(operatorType: operatorType)) + return self + } + + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { + expression.append(Token(operand: operand)) + return self + } + + public func addOpenBracket() -> InfixExpressionBuilder { + expression.append(Token(tokenType: .openBracket)) + return self + } + + public func addCloseBracket() -> InfixExpressionBuilder { + expression.append(Token(tokenType: .closeBracket)) + return self + } + + public func build() -> [Token] { + // Maybe do some validation here + return expression + } } // This returns the result of the shunting yard algorithm public func reversePolishNotation(_ expression: [Token]) -> String { - - var tokenStack = Stack() - var reversePolishNotation = [Token]() - - for token in expression { - switch token.tokenType { - case .operand(_): - reversePolishNotation.append(token) - - case .openBracket: - tokenStack.push(token) - - case .closeBracket: - while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { - reversePolishNotation.append(tempToken) - } - - case .Operator(let operatorToken): - for tempToken in tokenStack.makeIterator() { - if !tempToken.isOperator { - break - } - - if let tempOperatorToken = tempToken.operatorToken { - if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken - || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { - reversePolishNotation.append(tokenStack.pop()!) - } else { - break - } - } - } - tokenStack.push(token) + + var tokenStack = Stack() + var reversePolishNotation = [Token]() + + for token in expression { + switch token.tokenType { + case .operand(_): + reversePolishNotation.append(token) + + case .openBracket: + tokenStack.push(token) + + case .closeBracket: + while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { + reversePolishNotation.append(tempToken) + } + + case .Operator(let operatorToken): + for tempToken in tokenStack.makeIterator() { + if !tempToken.isOperator { + break } - } - - while tokenStack.count > 0 { - reversePolishNotation.append(tokenStack.pop()!) - } - - return reversePolishNotation.map({token in token.description}).joined(separator: " ") + + if let tempOperatorToken = tempToken.operatorToken { + if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken + || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { + reversePolishNotation.append(tokenStack.pop()!) + } else { + break + } + } + } + tokenStack.push(token) + } + } + + while tokenStack.count > 0 { + reversePolishNotation.append(tokenStack.pop()!) + } + + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } From 6eb7d9a172e3cded2c5be3e52c7193c9168def81 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 7 Feb 2017 18:43:38 +0100 Subject: [PATCH 0408/1275] old version with error --- Threaded Binary Tree/README.markdown | 49 +- .../Contents.swift} | 52 +- .../Sources/ThreadedBinaryTree.swift | 459 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + Threaded Binary Tree/ThreadedBinaryTree.swift | 459 ------------------ 6 files changed, 519 insertions(+), 511 deletions(-) rename Threaded Binary Tree/{ThreadedBinaryTreeTests.swift => ThreadedBinaryTree.playground/Contents.swift} (53%) create mode 100644 Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift create mode 100644 Threaded Binary Tree/ThreadedBinaryTree.playground/contents.xcplayground create mode 100644 Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata delete mode 100644 Threaded Binary Tree/ThreadedBinaryTree.swift diff --git a/Threaded Binary Tree/README.markdown b/Threaded Binary Tree/README.markdown index 0c533ad63..fd05113d8 100644 --- a/Threaded Binary Tree/README.markdown +++ b/Threaded Binary Tree/README.markdown @@ -158,31 +158,31 @@ outlined above. We use these predecessor/successor attributes to great effect in this new algorithm for both forward and backward traversals: ```swift -func traverseInOrderForward(visit: T -> Void) { - var n: ThreadedBinaryTree - n = minimum() - while true { - visit(n.value) - if let successor = n.successor() { - n = successor - } else { - break + public func traverseInOrderForward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = minimum() + while true { + visit(n.value) + if let successor = n.successor() { + n = successor + } else { + break + } + } } - } -} -func traverseInOrderBackward(visit: T -> Void) { - var n: ThreadedBinaryTree - n = maximum() - while true { - visit(n.value) - if let predecessor = n.predecessor() { - n = predecessor - } else { - break + public func traverseInOrderBackward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = maximum() + while true { + visit(n.value) + if let predecessor = n.predecessor() { + n = predecessor + } else { + break + } + } } - } -} ``` Again, this a method of `ThreadedBinaryTree`, so we'd call it via `node.traverseInorderForward(visitFunction)`. Note that we are able to specify @@ -221,7 +221,7 @@ continuously manage the `leftThread` and `rightThread` variables. Rather than walking through some boring code, it is best to explain this with an example (although you can read through [the implementation](ThreadedBinaryTree.swift) if you want to know the finer details). Please note that this requires -knowledge of binary search trees, so make sure you have +knowledge of binary search trees, so make sure you have [read this first](../Binary Search Tree/). > Note: we do allow duplicate nodes in this implementation of a threaded binary @@ -342,11 +342,12 @@ Many of these methods are inherent to binary search trees as well, so you can find [further documentation here](../Binary Search Tree/). -## See also +## See also [Threaded Binary Tree on Wikipedia](https://en.wikipedia.org/wiki/Threaded_binary_tree) *Written for the Swift Algorithm Club by [Jayson Tung](https://github.com/JFTung)* +*Migrated to Swift 3 by Jaap Wijnen* *Images made using www.draw.io* diff --git a/Threaded Binary Tree/ThreadedBinaryTreeTests.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift similarity index 53% rename from Threaded Binary Tree/ThreadedBinaryTreeTests.swift rename to Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift index 514c0db63..ff59f81d1 100644 --- a/Threaded Binary Tree/ThreadedBinaryTreeTests.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift @@ -1,35 +1,31 @@ -/* - TESTS - I don't have access to an Apple computer, so I can't make a Playground or any - of that fancy stuff. Here's a simple demonstration of the ThreadedBinaryTree - class. It follows the examples in the README. -*/ +//: Playground - noun: a place where people can play + // Simple little debug function to make testing output pretty -func check(tree: ThreadedBinaryTree?) { - if let tree = tree { - print("\(tree.count) Total Nodes:") - print(tree) - print("Debug Info:") - print(tree.debugDescription) - print("In-Order Traversal:") - let myArray = tree.toArray() - for node in myArray { - print(node) - } - if tree.isBST(minValue: Int.min, maxValue: Int.max) { - print("This is a VALID binary search tree.") - } else { - print("This is an INVALID binary search tree.") - } - if tree.isThreaded() { - print("This is a VALID threaded binary tree.") +func check(_ tree: ThreadedBinaryTree?) { + if let tree = tree { + print("\(tree.count) Total Nodes:") + print(tree) + print("Debug Info:") + print(tree.debugDescription) + print("In-Order Traversal:") + let myArray = tree.toArray() + for node in myArray { + print(node) + } + if tree.isBST(minValue: Int.min, maxValue: Int.max) { + print("This is a VALID binary search tree.") + } else { + print("This is an INVALID binary search tree.") + } + if tree.isThreaded() { + print("This is a VALID threaded binary tree.") + } else { + print("This is an INVALID threaded binary tree.") + } } else { - print("This is an INVALID threaded binary tree.") + print("This tree is nil.") } - } else { - print("This tree is nil.") - } } diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift new file mode 100644 index 000000000..4ae03238d --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift @@ -0,0 +1,459 @@ +/* + A Threaded Binary Tree. + Based on this club's Binary Search Tree implementation. + + Each node stores a value and two children. The left child contains a smaller + value; the right a larger (or equal) value. + + Any nodes that lack either a left or right child instead keep track of their + in-order predecessor and/or successor. + + This tree allows duplicate elements (we break ties by defaulting right). + + This tree does not automatically balance itself. To make sure it is balanced, + you should insert new values in randomized order, not in sorted order. + */ +public class ThreadedBinaryTree { + fileprivate(set) public var value: T + fileprivate(set) public var parent: ThreadedBinaryTree? + fileprivate(set) public var left: ThreadedBinaryTree? + fileprivate(set) public var right: ThreadedBinaryTree? + fileprivate(set) public var leftThread: ThreadedBinaryTree? + fileprivate(set) public var rightThread: ThreadedBinaryTree? + + public init(value: T) { + self.value = value + } + + public convenience init(array: [T]) { + precondition(array.count > 0) + self.init(value: array.first!) + for v in array.dropFirst() { + insert(v, parent: self) + } + } + + public var isRoot: Bool { + return parent == nil + } + + public var isLeaf: Bool { + return left == nil && right == nil + } + + public var isLeftChild: Bool { + return parent?.left === self + } + + public var isRightChild: Bool { + return parent?.right === self + } + + public var hasLeftChild: Bool { + return left != nil + } + + public var hasRightChild: Bool { + return right != nil + } + + public var hasAnyChild: Bool { + return hasLeftChild || hasRightChild + } + + public var hasBothChildren: Bool { + return hasLeftChild && hasRightChild + } + + /* How many nodes are in this subtree. Performance: O(n). */ + public var count: Int { + return (left?.count ?? 0) + 1 + (right?.count ?? 0) + } +} + +// MARK: - Adding items + +extension ThreadedBinaryTree { + /* + Inserts a new element into the tree. You should only insert elements + at the root, to make to sure this remains a valid binary tree! + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func insert(_ value: T) { + insert(value, parent: self) + } + + fileprivate func insert(_ value: T, parent: ThreadedBinaryTree) { + if value < self.value { + if let left = left { + left.insert(value, parent: left) + } else { + left = ThreadedBinaryTree(value: value) + left?.parent = parent + left?.rightThread = parent + left?.leftThread = leftThread + leftThread = nil + } + } else { + if let right = right { + right.insert(value, parent: right) + } else { + right = ThreadedBinaryTree(value: value) + right?.parent = parent + right?.leftThread = parent + right?.rightThread = rightThread + rightThread = nil + } + } + } +} + +// MARK: - Deleting items + +extension ThreadedBinaryTree { + /* + Deletes the "highest" node with the specified value. + + Returns the node that has replaced this removed one (or nil if this was a + leaf node). That is primarily useful for when you delete the root node, in + which case the tree gets a new root. + + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func remove(_ value: T) -> ThreadedBinaryTree? { + return search(value)?.remove() + } + + /* + Deletes "this" node from the tree. + */ + public func remove() -> ThreadedBinaryTree? { + let replacement: ThreadedBinaryTree? + + if let left = left { + if let right = right { + replacement = removeNodeWithTwoChildren(left, right) + replacement?.leftThread = leftThread + replacement?.rightThread = rightThread + left.maximum().rightThread = replacement + right.minimum().leftThread = replacement + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + left.maximum().rightThread = rightThread + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + right.minimum().leftThread = leftThread + } else { + // This node has no children. We just disconnect it from its parent. + replacement = nil + if isLeftChild { + parent?.leftThread = leftThread + } else { + parent?.rightThread = rightThread + } + } + + reconnectParentToNode(replacement) + + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil + leftThread = nil + rightThread = nil + + return replacement + } + + private func removeNodeWithTwoChildren(_ left: ThreadedBinaryTree, _ right: ThreadedBinaryTree) -> ThreadedBinaryTree { + // This node has two children. It must be replaced by the smallest + // child that is larger than this node's value, which is the leftmost + // descendent of the right child. + let successor = right.minimum() + + // If this in-order successor has a right child of its own (it cannot + // have a left child by definition), then that must take its place. + successor.remove() + + // Connect our left child with the new node. + successor.left = left + left.parent = successor + + // Connect our right child with the new node. If the right child does + // not have any left children of its own, then the in-order successor + // *is* the right child. + if right !== successor { + successor.right = right + right.parent = successor + } else { + successor.right = nil + } + + // And finally, connect the successor node to our parent. + return successor + } + + private func reconnectParentToNode(_ node: ThreadedBinaryTree?) { + if let parent = parent { + if isLeftChild { + parent.left = node + } else { + parent.right = node + } + } + node?.parent = parent + } +} + +// MARK: - Searching + +extension ThreadedBinaryTree { + /* + Finds the "highest" node with the specified value. + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func search(_ value: T) -> ThreadedBinaryTree? { + var node: ThreadedBinaryTree? = self + while case let n? = node { + if value < n.value { + node = n.left + } else if value > n.value { + node = n.right + } else { + return node + } + } + return nil + } + + /* + // Recursive version of search + // Educational but undesirable due to the overhead cost of recursion + public func search(value: T) -> ThreadedBinaryTree? { + if value < self.value { + return left?.search(value) + } else if value > self.value { + return right?.search(value) + } else { + return self + } + } + */ + + public func contains(value: T) -> Bool { + return search(value) != nil + } + + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum() -> ThreadedBinaryTree { + var node = self + while case let next? = node.left { + node = next + } + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum() -> ThreadedBinaryTree { + var node = self + while case let next? = node.right { + node = next + } + return node + } + + /* + Calculates the depth of this node, i.e. the distance to the root. + Takes O(h) time. + */ + public func depth() -> Int { + var node = self + var edges = 0 + while case let parent? = node.parent { + node = parent + edges += 1 + } + return edges + } + + /* + Calculates the height of this node, i.e. the distance to the lowest leaf. + Since this looks at all children of this node, performance is O(n). + */ + public func height() -> Int { + if isLeaf { + return 0 + } else { + return 1 + max(left?.height() ?? 0, right?.height() ?? 0) + } + } + + /* + Finds the node whose value precedes our value in sorted order. + */ + public func predecessor() -> ThreadedBinaryTree? { + if let left = left { + return left.maximum() + } else { + return leftThread + } + } + + /* + Finds the node whose value succeeds our value in sorted order. + */ + public func successor() -> ThreadedBinaryTree? { + if let right = right { + return right.minimum() + } else { + return rightThread + } + } +} + +// MARK: - Traversal + +extension ThreadedBinaryTree { + public func traverseInOrderForward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = minimum() + while true { + visit(n.value) + if let successor = n.successor() { + n = successor + } else { + break + } + } + } + + public func traverseInOrderBackward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = maximum() + while true { + visit(n.value) + if let predecessor = n.predecessor() { + n = predecessor + } else { + break + } + } + } + + public func traversePreOrder(_ visit: (T) -> Void) { + visit(value) + left?.traversePreOrder(visit) + right?.traversePreOrder(visit) + } + + public func traversePostOrder(_ visit: (T) -> Void) { + left?.traversePostOrder(visit) + right?.traversePostOrder(visit) + visit(value) + } + + /* + Performs an in-order traversal and collects the results in an array. + */ + public func map(formula: (T) -> T) -> [T] { + var a = [T]() + var n: ThreadedBinaryTree + n = minimum() + while true { + a.append(formula(n.value)) + if let successor = n.successor() { + n = successor + } else { + break + } + } + return a + } +} + +// MARK: - Verification + +extension ThreadedBinaryTree { + /* + Is this threaded binary tree a valid binary search tree? + */ + 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 + return leftBST && rightBST + } + + /* + Is this binary tree properly threaded? + Either left or leftThread (but not both) must be nil (likewise for right). + The first and last nodes in the in-order traversal are exempt from this, + as the first has leftThread = nil, and the last has rightThread = nil. + */ + public func isThreaded() -> Bool { + if left == nil && leftThread == nil { + if self !== minimum() { return false } + } + if left != nil && leftThread != nil { + return false + } + if right == nil && rightThread == nil { + if self !== maximum() { return false } + } + if right != nil && rightThread != nil { + return false + } + let leftThreaded = left?.isThreaded() ?? true + let rightThreaded = right?.isThreaded() ?? true + return leftThreaded && rightThreaded + } +} + +// MARK: - Debugging + +extension ThreadedBinaryTree: CustomStringConvertible { + public var description: String { + var s = "" + if let left = left { + s += "(\(left.description)) <- " + } + s += "\(value)" + if let right = right { + s += " -> (\(right.description))" + } + return s + } +} + +extension ThreadedBinaryTree: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "value: \(value)" + if let parent = parent { + s += ", parent: \(parent.value)" + } + if let leftThread = leftThread { + s += ", leftThread: \(leftThread.value)" + } + if let rightThread = rightThread { + s += ", rightThread: \(rightThread.value)" + } + if let left = left { + s += ", left = [" + left.debugDescription + "]" + } + if let right = right { + s += ", right = [" + right.debugDescription + "]" + } + return s + } + + public func toArray() -> [T] { + return map { $0 } + } +} diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/contents.xcplayground b/Threaded Binary Tree/ThreadedBinaryTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Threaded Binary Tree/ThreadedBinaryTree.swift b/Threaded Binary Tree/ThreadedBinaryTree.swift deleted file mode 100644 index 98a23d013..000000000 --- a/Threaded Binary Tree/ThreadedBinaryTree.swift +++ /dev/null @@ -1,459 +0,0 @@ -/* - A Threaded Binary Tree. - Based on this club's Binary Search Tree implementation. - - Each node stores a value and two children. The left child contains a smaller - value; the right a larger (or equal) value. - - Any nodes that lack either a left or right child instead keep track of their - in-order predecessor and/or successor. - - This tree allows duplicate elements (we break ties by defaulting right). - - This tree does not automatically balance itself. To make sure it is balanced, - you should insert new values in randomized order, not in sorted order. -*/ -public class ThreadedBinaryTree { - private(set) public var value: T - private(set) public var parent: ThreadedBinaryTree? - private(set) public var left: ThreadedBinaryTree? - private(set) public var right: ThreadedBinaryTree? - private(set) public var leftThread: ThreadedBinaryTree? - private(set) public var rightThread: ThreadedBinaryTree? - - public init(value: T) { - self.value = value - } - - public convenience init(array: [T]) { - precondition(array.count > 0) - self.init(value: array.first!) - for v in array.dropFirst() { - insert(v, parent: self) - } - } - - public var isRoot: Bool { - return parent == nil - } - - public var isLeaf: Bool { - return left == nil && right == nil - } - - public var isLeftChild: Bool { - return parent?.left === self - } - - public var isRightChild: Bool { - return parent?.right === self - } - - public var hasLeftChild: Bool { - return left != nil - } - - public var hasRightChild: Bool { - return right != nil - } - - public var hasAnyChild: Bool { - return hasLeftChild || hasRightChild - } - - public var hasBothChildren: Bool { - return hasLeftChild && hasRightChild - } - - /* How many nodes are in this subtree. Performance: O(n). */ - public var count: Int { - return (left?.count ?? 0) + 1 + (right?.count ?? 0) - } -} - -// MARK: - Adding items - -extension ThreadedBinaryTree { - /* - Inserts a new element into the tree. You should only insert elements - at the root, to make to sure this remains a valid binary tree! - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func insert(value: T) { - insert(value, parent: self) - } - - private func insert(value: T, parent: ThreadedBinaryTree) { - if value < self.value { - if let left = left { - left.insert(value, parent: left) - } else { - left = ThreadedBinaryTree(value: value) - left?.parent = parent - left?.rightThread = parent - left?.leftThread = leftThread - leftThread = nil - } - } else { - if let right = right { - right.insert(value, parent: right) - } else { - right = ThreadedBinaryTree(value: value) - right?.parent = parent - right?.leftThread = parent - right?.rightThread = rightThread - rightThread = nil - } - } - } -} - -// MARK: - Deleting items - -extension ThreadedBinaryTree { - /* - Deletes the "highest" node with the specified value. - - Returns the node that has replaced this removed one (or nil if this was a - leaf node). That is primarily useful for when you delete the root node, in - which case the tree gets a new root. - - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func remove(value: T) -> ThreadedBinaryTree? { - return search(value)?.remove() - } - - /* - Deletes "this" node from the tree. - */ - public func remove() -> ThreadedBinaryTree? { - let replacement: ThreadedBinaryTree? - - if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) - replacement?.leftThread = leftThread - replacement?.rightThread = rightThread - left.maximum().rightThread = replacement - right.minimum().leftThread = replacement - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - left.maximum().rightThread = rightThread - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - right.minimum().leftThread = leftThread - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - if isLeftChild { - parent?.leftThread = leftThread - } else { - parent?.rightThread = rightThread - } - } - - reconnectParentToNode(replacement) - - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - leftThread = nil - rightThread = nil - - return replacement - } - - private func removeNodeWithTwoChildren(left: ThreadedBinaryTree, _ right: ThreadedBinaryTree) -> ThreadedBinaryTree { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() - - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() - - // Connect our left child with the new node. - successor.left = left - left.parent = successor - - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor - } else { - successor.right = nil - } - - // And finally, connect the successor node to our parent. - return successor - } - - private func reconnectParentToNode(node: ThreadedBinaryTree?) { - if let parent = parent { - if isLeftChild { - parent.left = node - } else { - parent.right = node - } - } - node?.parent = parent - } -} - -// MARK: - Searching - -extension ThreadedBinaryTree { - /* - Finds the "highest" node with the specified value. - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func search(value: T) -> ThreadedBinaryTree? { - var node: ThreadedBinaryTree? = self - while case let n? = node { - if value < n.value { - node = n.left - } else if value > n.value { - node = n.right - } else { - return node - } - } - return nil - } - - /* - // Recursive version of search - // Educational but undesirable due to the overhead cost of recursion - public func search(value: T) -> ThreadedBinaryTree? { - if value < self.value { - return left?.search(value) - } else if value > self.value { - return right?.search(value) - } else { - return self - } - } - */ - - public func contains(value: T) -> Bool { - return search(value) != nil - } - - /* - Returns the leftmost descendent. O(h) time. - */ - public func minimum() -> ThreadedBinaryTree { - var node = self - while case let next? = node.left { - node = next - } - return node - } - - /* - Returns the rightmost descendent. O(h) time. - */ - public func maximum() -> ThreadedBinaryTree { - var node = self - while case let next? = node.right { - node = next - } - return node - } - - /* - Calculates the depth of this node, i.e. the distance to the root. - Takes O(h) time. - */ - public func depth() -> Int { - var node = self - var edges = 0 - while case let parent? = node.parent { - node = parent - edges += 1 - } - return edges - } - - /* - Calculates the height of this node, i.e. the distance to the lowest leaf. - Since this looks at all children of this node, performance is O(n). - */ - public func height() -> Int { - if isLeaf { - return 0 - } else { - return 1 + max(left?.height() ?? 0, right?.height() ?? 0) - } - } - - /* - Finds the node whose value precedes our value in sorted order. - */ - public func predecessor() -> ThreadedBinaryTree? { - if let left = left { - return left.maximum() - } else { - return leftThread - } - } - - /* - Finds the node whose value succeeds our value in sorted order. - */ - public func successor() -> ThreadedBinaryTree? { - if let right = right { - return right.minimum() - } else { - return rightThread - } - } -} - -// MARK: - Traversal - -extension ThreadedBinaryTree { - public func traverseInOrderForward(@noescape visit: T -> Void) { - var n: ThreadedBinaryTree - n = minimum() - while true { - visit(n.value) - if let successor = n.successor() { - n = successor - } else { - break - } - } - } - - public func traverseInOrderBackward(@noescape visit: T -> Void) { - var n: ThreadedBinaryTree - n = maximum() - while true { - visit(n.value) - if let predecessor = n.predecessor() { - n = predecessor - } else { - break - } - } - } - - public func traversePreOrder(@noescape visit: T -> Void) { - visit(value) - left?.traversePreOrder(visit) - right?.traversePreOrder(visit) - } - - public func traversePostOrder(@noescape visit: T -> Void) { - left?.traversePostOrder(visit) - right?.traversePostOrder(visit) - visit(value) - } - - /* - Performs an in-order traversal and collects the results in an array. - */ - public func map(@noescape formula: T -> T) -> [T] { - var a = [T]() - var n: ThreadedBinaryTree - n = minimum() - while true { - a.append(formula(n.value)) - if let successor = n.successor() { - n = successor - } else { - break - } - } - return a - } -} - -// MARK: - Verification - -extension ThreadedBinaryTree { - /* - Is this threaded binary tree a valid binary search tree? - */ - public func isBST(minValue 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 - return leftBST && rightBST - } - - /* - Is this binary tree properly threaded? - Either left or leftThread (but not both) must be nil (likewise for right). - The first and last nodes in the in-order traversal are exempt from this, - as the first has leftThread = nil, and the last has rightThread = nil. - */ - public func isThreaded() -> Bool { - if left == nil && leftThread == nil { - if self !== minimum() { return false } - } - if left != nil && leftThread != nil { - return false - } - if right == nil && rightThread == nil { - if self !== maximum() { return false } - } - if right != nil && rightThread != nil { - return false - } - let leftThreaded = left?.isThreaded() ?? true - let rightThreaded = right?.isThreaded() ?? true - return leftThreaded && rightThreaded - } -} - -// MARK: - Debugging - -extension ThreadedBinaryTree: CustomStringConvertible { - public var description: String { - var s = "" - if let left = left { - s += "(\(left.description)) <- " - } - s += "\(value)" - if let right = right { - s += " -> (\(right.description))" - } - return s - } -} - -extension ThreadedBinaryTree: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" - } - if let leftThread = leftThread { - s += ", leftThread: \(leftThread.value)" - } - if let rightThread = rightThread { - s += ", rightThread: \(rightThread.value)" - } - if let left = left { - s += ", left = [" + left.debugDescription + "]" - } - if let right = right { - s += ", right = [" + right.debugDescription + "]" - } - return s - } - - public func toArray() -> [T] { - return map { $0 } - } -} From 3fc54e61b6c727323e97cc026021141966aec193 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 7 Feb 2017 18:46:27 +0100 Subject: [PATCH 0409/1275] fix --- .../Sources/ThreadedBinaryTree.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift index 4ae03238d..e703d793a 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift @@ -120,7 +120,7 @@ extension ThreadedBinaryTree { Performance: runs in O(h) time, where h is the height of the tree. */ - public func remove(_ value: T) -> ThreadedBinaryTree? { + @discardableResult public func remove(_ value: T) -> ThreadedBinaryTree? { return search(value)?.remove() } From 92363b88477de2595c69924fb51c65679f9d0d85 Mon Sep 17 00:00:00 2001 From: Jaap Date: Tue, 7 Feb 2017 19:01:31 +0100 Subject: [PATCH 0410/1275] fix spaces --- .../Contents.swift | 42 +- .../Sources/ThreadedBinaryTree.swift | 752 +++++++++--------- 2 files changed, 397 insertions(+), 397 deletions(-) diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift index ff59f81d1..e4b527664 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift @@ -3,28 +3,28 @@ // Simple little debug function to make testing output pretty func check(_ tree: ThreadedBinaryTree?) { - if let tree = tree { - print("\(tree.count) Total Nodes:") - print(tree) - print("Debug Info:") - print(tree.debugDescription) - print("In-Order Traversal:") - let myArray = tree.toArray() - for node in myArray { - print(node) - } - if tree.isBST(minValue: Int.min, maxValue: Int.max) { - print("This is a VALID binary search tree.") - } else { - print("This is an INVALID binary search tree.") - } - if tree.isThreaded() { - print("This is a VALID threaded binary tree.") - } else { - print("This is an INVALID threaded binary tree.") - } + if let tree = tree { + print("\(tree.count) Total Nodes:") + print(tree) + print("Debug Info:") + print(tree.debugDescription) + print("In-Order Traversal:") + let myArray = tree.toArray() + for node in myArray { + print(node) + } + if tree.isBST(minValue: Int.min, maxValue: Int.max) { + print("This is a VALID binary search tree.") + } else { + print("This is an INVALID binary search tree.") + } + if tree.isThreaded() { + print("This is a VALID threaded binary tree.") + } else { + print("This is an INVALID threaded binary tree.") + } } else { - print("This tree is nil.") + print("This tree is nil.") } } diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift index e703d793a..a4d308e77 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift @@ -14,446 +14,446 @@ you should insert new values in randomized order, not in sorted order. */ public class ThreadedBinaryTree { - fileprivate(set) public var value: T - fileprivate(set) public var parent: ThreadedBinaryTree? - fileprivate(set) public var left: ThreadedBinaryTree? - fileprivate(set) public var right: ThreadedBinaryTree? - fileprivate(set) public var leftThread: ThreadedBinaryTree? - fileprivate(set) public var rightThread: ThreadedBinaryTree? - - public init(value: T) { - self.value = value - } - - public convenience init(array: [T]) { - precondition(array.count > 0) - self.init(value: array.first!) - for v in array.dropFirst() { - insert(v, parent: self) - } - } - - public var isRoot: Bool { - return parent == nil - } - - public var isLeaf: Bool { - return left == nil && right == nil - } - - public var isLeftChild: Bool { - return parent?.left === self - } - - public var isRightChild: Bool { - return parent?.right === self - } - - public var hasLeftChild: Bool { - return left != nil - } - - public var hasRightChild: Bool { - return right != nil - } - - public var hasAnyChild: Bool { - return hasLeftChild || hasRightChild - } - - public var hasBothChildren: Bool { - return hasLeftChild && hasRightChild - } - - /* How many nodes are in this subtree. Performance: O(n). */ - public var count: Int { - return (left?.count ?? 0) + 1 + (right?.count ?? 0) + fileprivate(set) public var value: T + fileprivate(set) public var parent: ThreadedBinaryTree? + fileprivate(set) public var left: ThreadedBinaryTree? + fileprivate(set) public var right: ThreadedBinaryTree? + fileprivate(set) public var leftThread: ThreadedBinaryTree? + fileprivate(set) public var rightThread: ThreadedBinaryTree? + + public init(value: T) { + self.value = value + } + + public convenience init(array: [T]) { + precondition(array.count > 0) + self.init(value: array.first!) + for v in array.dropFirst() { + insert(v, parent: self) } + } + + public var isRoot: Bool { + return parent == nil + } + + public var isLeaf: Bool { + return left == nil && right == nil + } + + public var isLeftChild: Bool { + return parent?.left === self + } + + public var isRightChild: Bool { + return parent?.right === self + } + + public var hasLeftChild: Bool { + return left != nil + } + + public var hasRightChild: Bool { + return right != nil + } + + public var hasAnyChild: Bool { + return hasLeftChild || hasRightChild + } + + public var hasBothChildren: Bool { + return hasLeftChild && hasRightChild + } + + /* How many nodes are in this subtree. Performance: O(n). */ + public var count: Int { + return (left?.count ?? 0) + 1 + (right?.count ?? 0) + } } // MARK: - Adding items extension ThreadedBinaryTree { - /* - Inserts a new element into the tree. You should only insert elements - at the root, to make to sure this remains a valid binary tree! - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func insert(_ value: T) { - insert(value, parent: self) - } + /* + Inserts a new element into the tree. You should only insert elements + at the root, to make to sure this remains a valid binary tree! + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func insert(_ value: T) { + insert(value, parent: self) + } - fileprivate func insert(_ value: T, parent: ThreadedBinaryTree) { - if value < self.value { - if let left = left { - left.insert(value, parent: left) - } else { - left = ThreadedBinaryTree(value: value) - left?.parent = parent - left?.rightThread = parent - left?.leftThread = leftThread - leftThread = nil - } - } else { - if let right = right { - right.insert(value, parent: right) - } else { - right = ThreadedBinaryTree(value: value) - right?.parent = parent - right?.leftThread = parent - right?.rightThread = rightThread - rightThread = nil - } - } + fileprivate func insert(_ value: T, parent: ThreadedBinaryTree) { + if value < self.value { + if let left = left { + left.insert(value, parent: left) + } else { + left = ThreadedBinaryTree(value: value) + left?.parent = parent + left?.rightThread = parent + left?.leftThread = leftThread + leftThread = nil + } + } else { + if let right = right { + right.insert(value, parent: right) + } else { + right = ThreadedBinaryTree(value: value) + right?.parent = parent + right?.leftThread = parent + right?.rightThread = rightThread + rightThread = nil + } } + } } // MARK: - Deleting items extension ThreadedBinaryTree { - /* - Deletes the "highest" node with the specified value. + /* + Deletes the "highest" node with the specified value. - Returns the node that has replaced this removed one (or nil if this was a - leaf node). That is primarily useful for when you delete the root node, in - which case the tree gets a new root. + Returns the node that has replaced this removed one (or nil if this was a + leaf node). That is primarily useful for when you delete the root node, in + which case the tree gets a new root. - Performance: runs in O(h) time, where h is the height of the tree. - */ - @discardableResult public func remove(_ value: T) -> ThreadedBinaryTree? { - return search(value)?.remove() - } + Performance: runs in O(h) time, where h is the height of the tree. + */ + @discardableResult public func remove(_ value: T) -> ThreadedBinaryTree? { + return search(value)?.remove() + } - /* - Deletes "this" node from the tree. - */ - public func remove() -> ThreadedBinaryTree? { - let replacement: ThreadedBinaryTree? + /* + Deletes "this" node from the tree. + */ + public func remove() -> ThreadedBinaryTree? { + let replacement: ThreadedBinaryTree? - if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) - replacement?.leftThread = leftThread - replacement?.rightThread = rightThread - left.maximum().rightThread = replacement - right.minimum().leftThread = replacement - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - left.maximum().rightThread = rightThread - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - right.minimum().leftThread = leftThread - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - if isLeftChild { - parent?.leftThread = leftThread - } else { - parent?.rightThread = rightThread - } - } + if let left = left { + if let right = right { + replacement = removeNodeWithTwoChildren(left, right) + replacement?.leftThread = leftThread + replacement?.rightThread = rightThread + left.maximum().rightThread = replacement + right.minimum().leftThread = replacement + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + left.maximum().rightThread = rightThread + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + right.minimum().leftThread = leftThread + } else { + // This node has no children. We just disconnect it from its parent. + replacement = nil + if isLeftChild { + parent?.leftThread = leftThread + } else { + parent?.rightThread = rightThread + } + } - reconnectParentToNode(replacement) + reconnectParentToNode(replacement) - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - leftThread = nil - rightThread = nil + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil + leftThread = nil + rightThread = nil - return replacement - } + return replacement + } - private func removeNodeWithTwoChildren(_ left: ThreadedBinaryTree, _ right: ThreadedBinaryTree) -> ThreadedBinaryTree { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() + private func removeNodeWithTwoChildren(_ left: ThreadedBinaryTree, _ right: ThreadedBinaryTree) -> ThreadedBinaryTree { + // This node has two children. It must be replaced by the smallest + // child that is larger than this node's value, which is the leftmost + // descendent of the right child. + let successor = right.minimum() - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() + // If this in-order successor has a right child of its own (it cannot + // have a left child by definition), then that must take its place. + successor.remove() - // Connect our left child with the new node. - successor.left = left - left.parent = successor + // Connect our left child with the new node. + successor.left = left + left.parent = successor - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor - } else { - successor.right = nil - } - - // And finally, connect the successor node to our parent. - return successor + // Connect our right child with the new node. If the right child does + // not have any left children of its own, then the in-order successor + // *is* the right child. + if right !== successor { + successor.right = right + right.parent = successor + } else { + successor.right = nil } + + // And finally, connect the successor node to our parent. + return successor + } - private func reconnectParentToNode(_ node: ThreadedBinaryTree?) { - if let parent = parent { - if isLeftChild { - parent.left = node - } else { - parent.right = node - } - } - node?.parent = parent - } + private func reconnectParentToNode(_ node: ThreadedBinaryTree?) { + if let parent = parent { + if isLeftChild { + parent.left = node + } else { + parent.right = node + } + } + node?.parent = parent + } } // MARK: - Searching extension ThreadedBinaryTree { - /* - Finds the "highest" node with the specified value. - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func search(_ value: T) -> ThreadedBinaryTree? { - var node: ThreadedBinaryTree? = self - while case let n? = node { - if value < n.value { - node = n.left - } else if value > n.value { - node = n.right - } else { - return node - } - } - return nil + /* + Finds the "highest" node with the specified value. + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func search(_ value: T) -> ThreadedBinaryTree? { + var node: ThreadedBinaryTree? = self + while case let n? = node { + if value < n.value { + node = n.left + } else if value > n.value { + node = n.right + } else { + return node + } } + return nil + } - /* - // Recursive version of search - // Educational but undesirable due to the overhead cost of recursion - public func search(value: T) -> ThreadedBinaryTree? { - if value < self.value { - return left?.search(value) - } else if value > self.value { - return right?.search(value) - } else { - return self - } - } - */ + /* + // Recursive version of search + // Educational but undesirable due to the overhead cost of recursion + public func search(value: T) -> ThreadedBinaryTree? { + if value < self.value { + return left?.search(value) + } else if value > self.value { + return right?.search(value) + } else { + return self + } + } + */ - public func contains(value: T) -> Bool { - return search(value) != nil - } + public func contains(value: T) -> Bool { + return search(value) != nil + } - /* - Returns the leftmost descendent. O(h) time. - */ - public func minimum() -> ThreadedBinaryTree { - var node = self - while case let next? = node.left { - node = next - } - return node - } + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum() -> ThreadedBinaryTree { + var node = self + while case let next? = node.left { + node = next + } + return node + } - /* - Returns the rightmost descendent. O(h) time. - */ - public func maximum() -> ThreadedBinaryTree { - var node = self - while case let next? = node.right { - node = next - } - return node - } + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum() -> ThreadedBinaryTree { + var node = self + while case let next? = node.right { + node = next + } + return node + } - /* - Calculates the depth of this node, i.e. the distance to the root. - Takes O(h) time. - */ - public func depth() -> Int { - var node = self - var edges = 0 - while case let parent? = node.parent { - node = parent - edges += 1 - } - return edges - } + /* + Calculates the depth of this node, i.e. the distance to the root. + Takes O(h) time. + */ + public func depth() -> Int { + var node = self + var edges = 0 + while case let parent? = node.parent { + node = parent + edges += 1 + } + return edges + } - /* - Calculates the height of this node, i.e. the distance to the lowest leaf. - Since this looks at all children of this node, performance is O(n). - */ - public func height() -> Int { - if isLeaf { - return 0 - } else { - return 1 + max(left?.height() ?? 0, right?.height() ?? 0) - } - } + /* + Calculates the height of this node, i.e. the distance to the lowest leaf. + Since this looks at all children of this node, performance is O(n). + */ + public func height() -> Int { + if isLeaf { + return 0 + } else { + return 1 + max(left?.height() ?? 0, right?.height() ?? 0) + } + } - /* - Finds the node whose value precedes our value in sorted order. - */ - public func predecessor() -> ThreadedBinaryTree? { - if let left = left { - return left.maximum() - } else { - return leftThread - } - } + /* + Finds the node whose value precedes our value in sorted order. + */ + public func predecessor() -> ThreadedBinaryTree? { + if let left = left { + return left.maximum() + } else { + return leftThread + } + } - /* - Finds the node whose value succeeds our value in sorted order. - */ - public func successor() -> ThreadedBinaryTree? { - if let right = right { - return right.minimum() - } else { - return rightThread - } - } + /* + Finds the node whose value succeeds our value in sorted order. + */ + public func successor() -> ThreadedBinaryTree? { + if let right = right { + return right.minimum() + } else { + return rightThread + } + } } // MARK: - Traversal extension ThreadedBinaryTree { - public func traverseInOrderForward(_ visit: (T) -> Void) { - var n: ThreadedBinaryTree - n = minimum() - while true { - visit(n.value) - if let successor = n.successor() { - n = successor - } else { - break - } - } - } + public func traverseInOrderForward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = minimum() + while true { + visit(n.value) + if let successor = n.successor() { + n = successor + } else { + break + } + } + } - public func traverseInOrderBackward(_ visit: (T) -> Void) { - var n: ThreadedBinaryTree - n = maximum() - while true { - visit(n.value) - if let predecessor = n.predecessor() { - n = predecessor - } else { - break - } - } - } + public func traverseInOrderBackward(_ visit: (T) -> Void) { + var n: ThreadedBinaryTree + n = maximum() + while true { + visit(n.value) + if let predecessor = n.predecessor() { + n = predecessor + } else { + break + } + } + } - public func traversePreOrder(_ visit: (T) -> Void) { - visit(value) - left?.traversePreOrder(visit) - right?.traversePreOrder(visit) - } + public func traversePreOrder(_ visit: (T) -> Void) { + visit(value) + left?.traversePreOrder(visit) + right?.traversePreOrder(visit) + } - public func traversePostOrder(_ visit: (T) -> Void) { - left?.traversePostOrder(visit) - right?.traversePostOrder(visit) - visit(value) - } + public func traversePostOrder(_ visit: (T) -> Void) { + left?.traversePostOrder(visit) + right?.traversePostOrder(visit) + visit(value) + } - /* - Performs an in-order traversal and collects the results in an array. - */ - public func map(formula: (T) -> T) -> [T] { - var a = [T]() - var n: ThreadedBinaryTree - n = minimum() - while true { - a.append(formula(n.value)) - if let successor = n.successor() { - n = successor - } else { - break - } - } - return a - } + /* + Performs an in-order traversal and collects the results in an array. + */ + public func map(formula: (T) -> T) -> [T] { + var a = [T]() + var n: ThreadedBinaryTree + n = minimum() + while true { + a.append(formula(n.value)) + if let successor = n.successor() { + n = successor + } else { + break + } + } + return a + } } // MARK: - Verification extension ThreadedBinaryTree { - /* - Is this threaded binary tree a valid binary search tree? - */ - 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 - return leftBST && rightBST - } + /* + Is this threaded binary tree a valid binary search tree? + */ + 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 + return leftBST && rightBST + } - /* - Is this binary tree properly threaded? - Either left or leftThread (but not both) must be nil (likewise for right). - The first and last nodes in the in-order traversal are exempt from this, - as the first has leftThread = nil, and the last has rightThread = nil. - */ - public func isThreaded() -> Bool { - if left == nil && leftThread == nil { - if self !== minimum() { return false } - } - if left != nil && leftThread != nil { - return false - } - if right == nil && rightThread == nil { - if self !== maximum() { return false } - } - if right != nil && rightThread != nil { - return false - } - let leftThreaded = left?.isThreaded() ?? true - let rightThreaded = right?.isThreaded() ?? true - return leftThreaded && rightThreaded - } + /* + Is this binary tree properly threaded? + Either left or leftThread (but not both) must be nil (likewise for right). + The first and last nodes in the in-order traversal are exempt from this, + as the first has leftThread = nil, and the last has rightThread = nil. + */ + public func isThreaded() -> Bool { + if left == nil && leftThread == nil { + if self !== minimum() { return false } + } + if left != nil && leftThread != nil { + return false + } + if right == nil && rightThread == nil { + if self !== maximum() { return false } + } + if right != nil && rightThread != nil { + return false + } + let leftThreaded = left?.isThreaded() ?? true + let rightThreaded = right?.isThreaded() ?? true + return leftThreaded && rightThreaded + } } // MARK: - Debugging extension ThreadedBinaryTree: CustomStringConvertible { - public var description: String { - var s = "" - if let left = left { - s += "(\(left.description)) <- " - } - s += "\(value)" - if let right = right { - s += " -> (\(right.description))" - } - return s + public var description: String { + var s = "" + if let left = left { + s += "(\(left.description)) <- " } + s += "\(value)" + if let right = right { + s += " -> (\(right.description))" + } + return s + } } extension ThreadedBinaryTree: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" - } - if let leftThread = leftThread { - s += ", leftThread: \(leftThread.value)" - } - if let rightThread = rightThread { - s += ", rightThread: \(rightThread.value)" - } - if let left = left { - s += ", left = [" + left.debugDescription + "]" - } - if let right = right { - s += ", right = [" + right.debugDescription + "]" - } - return s + public var debugDescription: String { + var s = "value: \(value)" + if let parent = parent { + s += ", parent: \(parent.value)" } - - public func toArray() -> [T] { - return map { $0 } + if let leftThread = leftThread { + s += ", leftThread: \(leftThread.value)" } + if let rightThread = rightThread { + s += ", rightThread: \(rightThread.value)" + } + if let left = left { + s += ", left = [" + left.debugDescription + "]" + } + if let right = right { + s += ", right = [" + right.debugDescription + "]" + } + return s + } + + public func toArray() -> [T] { + return map { $0 } + } } From c1c1a55904bf2f02c426ddcda33633443fe82656 Mon Sep 17 00:00:00 2001 From: vincentngo Date: Wed, 8 Feb 2017 00:29:35 -0500 Subject: [PATCH 0411/1275] fix warning --- .../Sources/ThreadedBinaryTree.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift index a4d308e77..6f438c0cf 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Sources/ThreadedBinaryTree.swift @@ -176,7 +176,7 @@ extension ThreadedBinaryTree { // If this in-order successor has a right child of its own (it cannot // have a left child by definition), then that must take its place. - successor.remove() + _ = successor.remove() // Connect our left child with the new node. successor.left = left From e149dac200ddd46d110fa94a39c539fde919adf4 Mon Sep 17 00:00:00 2001 From: Yurii Samsoniuk Date: Sat, 11 Feb 2017 16:31:04 +0100 Subject: [PATCH 0412/1275] Create big enough array for merge results --- Merge Sort/MergeSort.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index f77d1cd84..990c432fa 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -18,6 +18,9 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { var leftIndex = 0 var rightIndex = 0 var orderedPile = [T]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } while leftIndex < leftPile.count && rightIndex < rightPile.count { if leftPile[leftIndex] < rightPile[rightIndex] { From bfef1ee575456b66f1cb483750f2f6164dcea7a5 Mon Sep 17 00:00:00 2001 From: Yurii Samsoniuk Date: Sat, 11 Feb 2017 16:32:34 +0100 Subject: [PATCH 0413/1275] Also update workspace content --- Merge Sort/MergeSort.playground/Contents.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index 2952fc299..137dd19e2 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -12,6 +12,9 @@ func merge(leftPile: [T], rightPile: [T]) -> [T] { var leftIndex = 0 var rightIndex = 0 var orderedPile = [T]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } while leftIndex < leftPile.count && rightIndex < rightPile.count { if leftPile[leftIndex] < rightPile[rightIndex] { From 8f57fbb8635df485a125cad192c9685999b71b22 Mon Sep 17 00:00:00 2001 From: Yurii Samsoniuk Date: Mon, 13 Feb 2017 09:49:30 +0100 Subject: [PATCH 0414/1275] Use string interpolation for the whole description string --- Binary Tree/BinaryTree.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Tree/BinaryTree.swift b/Binary Tree/BinaryTree.swift index ad5fcfd13..61ae696c7 100644 --- a/Binary Tree/BinaryTree.swift +++ b/Binary Tree/BinaryTree.swift @@ -21,7 +21,7 @@ extension BinaryTree: CustomStringConvertible { public var description: String { switch self { case let .node(left, value, right): - return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" case .empty: return "" } From b68b3b9309ecea1d56e8c5bf40779156abfafbe1 Mon Sep 17 00:00:00 2001 From: Yurii Samsoniuk Date: Mon, 13 Feb 2017 09:50:24 +0100 Subject: [PATCH 0415/1275] Updated playground content --- Binary Tree/BinaryTree.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index b4d65ec1f..aa084e44d 100644 --- a/Binary Tree/BinaryTree.playground/Contents.swift +++ b/Binary Tree/BinaryTree.playground/Contents.swift @@ -18,7 +18,7 @@ extension BinaryTree: CustomStringConvertible { public var description: String { switch self { case let .node(left, value, right): - return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" case .empty: return "" } From 0155784b6cb0860d66f877439ebfe0acfa8ff29f Mon Sep 17 00:00:00 2001 From: Yurii Samsoniuk Date: Mon, 13 Feb 2017 09:51:23 +0100 Subject: [PATCH 0416/1275] Updated README content --- Binary Tree/README.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index 52089b8e7..896116dda 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -58,8 +58,7 @@ extension BinaryTree: CustomStringConvertible { public var description: String { switch self { case let .node(left, value, right): - return "value: \(value), left = [" + left.description + "], right = [" - + right.description + "]" + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" case .empty: return "" } From cb64ed6034f91f5a300d0f728f08a4c09cd3e8f0 Mon Sep 17 00:00:00 2001 From: abhisood Date: Mon, 13 Feb 2017 03:13:53 -0800 Subject: [PATCH 0417/1275] Trie - Support prefix matching Solves issue #378 --- Trie/Trie/Trie/Trie.swift | 54 ++++++++++++++++++++++++----- Trie/Trie/TrieTests/TrieTests.swift | 16 +++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index 0e11a9c61..cc310b9ee 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -135,7 +135,26 @@ extension Trie { } return currentNode.isTerminating } - + + + /// Attempts to walk to the last node of a word. The + /// search will fail if the word is not present. Doesn't + /// check if the node is terminating + /// + /// - Parameter word: the word in question + /// - 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().characters { + guard let childNode = currentNode.children[character] else { + return nil + } + currentNode = childNode + } + return currentNode + } + /// Attempts to walk to the terminating node of a word. The /// search will fail if the word is not present. /// @@ -143,14 +162,11 @@ extension Trie { /// - Returns: the node where the search ended, nil if the /// search failed. private func findTerminalNodeOf(word: String) -> Node? { - var currentNode = root - for character in word.lowercased().characters { - guard let childNode = currentNode.children[character] else { - return nil - } - currentNode = childNode + if let lastNode = findLastNodeOf(word: word) { + return lastNode.isTerminating ? lastNode : nil } - return currentNode.isTerminating ? currentNode : nil + return nil + } /// Deletes a word from the trie by starting with the last letter @@ -201,7 +217,7 @@ extension Trie { /// - rootNode: the root node of the subtrie /// - partialWord: the letters collected by traversing to this node /// - Returns: the words in the subtrie - func wordsInSubtrie(rootNode: Node, partialWord: String) -> [String] { + fileprivate func wordsInSubtrie(rootNode: Node, partialWord: String) -> [String] { var subtrieWords = [String]() var previousLetters = partialWord if let value = rootNode.value { @@ -216,4 +232,24 @@ extension Trie { } return subtrieWords } + + /// Returns an array of words in a subtrie of the trie that start + /// with given prefix + /// + /// - Parameters: + /// - prefix: the letters for word prefix + /// - Returns: the words in the subtrie that start with prefix + func findWordsWithPrefix(prefix: String) -> [String] { + var words = [String]() + if let lastNode = findLastNodeOf(word: prefix) { + if lastNode.isTerminating { + words.append(prefix) + } + for childNode in lastNode.children.values { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefix) + words += childWords + } + } + return words + } } diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index f8e934f0d..de41663a9 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -168,4 +168,20 @@ class TrieTests: XCTestCase { 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, []); + } } From 9c5a98dc5f64b941f38596088fd867f601a97af7 Mon Sep 17 00:00:00 2001 From: abhisood Date: Mon, 13 Feb 2017 03:58:25 -0800 Subject: [PATCH 0418/1275] Handle uppercase prefix --- Trie/Trie/Trie/Trie.swift | 7 ++++--- Trie/Trie/TrieTests/TrieTests.swift | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index cc310b9ee..4321479c3 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -241,12 +241,13 @@ extension Trie { /// - Returns: the words in the subtrie that start with prefix func findWordsWithPrefix(prefix: String) -> [String] { var words = [String]() - if let lastNode = findLastNodeOf(word: prefix) { + let prefixLowerCased = prefix.lowercased() + if let lastNode = findLastNodeOf(word: prefixLowerCased) { if lastNode.isTerminating { - words.append(prefix) + words.append(prefixLowerCased) } for childNode in lastNode.children.values { - let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefix) + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) words += childWords } } diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index de41663a9..a75c35c62 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -183,5 +183,13 @@ class TrieTests: XCTestCase { 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"]); + } } From ba3975281965852471a40f7a58514fa1d98d1578 Mon Sep 17 00:00:00 2001 From: Adrian Date: Wed, 15 Feb 2017 18:11:12 -0500 Subject: [PATCH 0419/1275] Update CountingSort.swift to Swift 3.0 syntax Updated to Swift 3.0 syntax --- Counting Sort/CountingSort.swift | 66 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/Counting Sort/CountingSort.swift b/Counting Sort/CountingSort.swift index d37bb2eff..9a1ffb373 100644 --- a/Counting Sort/CountingSort.swift +++ b/Counting Sort/CountingSort.swift @@ -6,39 +6,41 @@ // Copyright © 2016 Ali Hafizji. All rights reserved. // -enum CountingSortError: ErrorType { - case arrayEmpty +import Foundation + +enum CountingSortError: Error { + case arrayEmpty } func countingSort(array: [Int]) throws -> [Int] { - guard array.count > 0 else { - throw CountingSortError.arrayEmpty - } - - // Step 1 - // Create an array to store the count of each element - let maxElement = array.maxElement() ?? 0 - - var countArray = [Int](count: Int(maxElement + 1), repeatedValue: 0) - for element in array { - countArray[element] += 1 - } - - // Step 2 - // Set each value to be the sum of the previous two values - for index in 1 ..< countArray.count { - let sum = countArray[index] + countArray[index - 1] - countArray[index] = sum - } - - print(countArray) - - // Step 3 - // Place the element in the final array as per the number of elements before it - var sortedArray = [Int](count: array.count, repeatedValue: 0) - for element in array { - countArray[element] -= 1 - sortedArray[countArray[element]] = element - } - return sortedArray + guard array.count > 0 else { + throw CountingSortError.arrayEmpty + } + + // Step 1 + // Create an array to store the count of each element + let maxElement = array.max() ?? 0 + + var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) + for element in array { + countArray[element] += 1 + } + + // Step 2 + // Set each value to be the sum of the previous two values + for index in 1 ..< countArray.count { + let sum = countArray[index] + countArray[index - 1] + countArray[index] = sum + } + + print(countArray) + + // Step 3 + // Place the element in the final array as per the number of elements before it + var sortedArray = [Int](repeating: 0, count: array.count) + for element in array { + countArray[element] -= 1 + sortedArray[countArray[element]] = element + } + return sortedArray } From 0b93a48f4dd66111fb9033e187cb4176d51d6dc0 Mon Sep 17 00:00:00 2001 From: Timur Galimov Date: Sat, 18 Feb 2017 02:20:13 +0300 Subject: [PATCH 0420/1275] Quadtree --- QuadTree/QuadTree.playground/Contents.swift | 14 + .../Sources/QuadTree.swift | 290 ++++++++++++++++++ .../QuadTree.playground/contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + QuadTree/README.md | 158 ++++++++++ .../Tests/Tests.xcodeproj/project.pbxproj | 274 +++++++++++++++++ .../contents.xcworkspacedata | 7 + QuadTree/Tests/Tests/Info.plist | 22 ++ QuadTree/Tests/Tests/Tests.swift | 85 +++++ 9 files changed, 861 insertions(+) create mode 100644 QuadTree/QuadTree.playground/Contents.swift create mode 100644 QuadTree/QuadTree.playground/Sources/QuadTree.swift create mode 100644 QuadTree/QuadTree.playground/contents.xcplayground create mode 100644 QuadTree/QuadTree.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 QuadTree/README.md create mode 100644 QuadTree/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 QuadTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 QuadTree/Tests/Tests/Info.plist create mode 100644 QuadTree/Tests/Tests/Tests.swift diff --git a/QuadTree/QuadTree.playground/Contents.swift b/QuadTree/QuadTree.playground/Contents.swift new file mode 100644 index 000000000..41e73147f --- /dev/null +++ b/QuadTree/QuadTree.playground/Contents.swift @@ -0,0 +1,14 @@ + +import Foundation + +let tree = QuadTree(rect: Rect(origin: Point(0, 0), size: Size(xLength: 10, yLength: 10))) + +for _ in 0..<40 { + let randomX = Double(arc4random_uniform(100)) / 10 + let randomY = Double(arc4random_uniform(100)) / 10 + let point = Point(randomX, randomY) + tree.add(point: point) +} + +print(tree) +print(tree.points(inRect: Rect(origin: Point(1, 1), size: Size(xLength: 5, yLength: 5)))) diff --git a/QuadTree/QuadTree.playground/Sources/QuadTree.swift b/QuadTree/QuadTree.playground/Sources/QuadTree.swift new file mode 100644 index 000000000..beec4a7b7 --- /dev/null +++ b/QuadTree/QuadTree.playground/Sources/QuadTree.swift @@ -0,0 +1,290 @@ + +public struct Point { + let x: Double + let y: Double + + public init(_ x: Double, _ y: Double) { + self.x = x + self.y = y + } +} + +extension Point: CustomStringConvertible { + public var description: String { + return "Point(\(x), \(y))" + } +} + +public struct Size: CustomStringConvertible { + var xLength: Double + var yLength: Double + + public init(xLength: Double, yLength: Double) { + precondition(xLength >= 0, "xLength can not be negative") + precondition(yLength >= 0, "yLength can not be negative") + self.xLength = xLength + self.yLength = yLength + } + + var half: Size { + return Size(xLength: xLength / 2, yLength: yLength / 2) + } + + public var description: String { + return "Size(\(xLength), \(yLength))" + } +} + +public struct Rect { + // left top vertice + var origin: Point + var size: Size + + public init(origin: Point, size: Size) { + self.origin = origin + self.size = size + } + + var minX: Double { + return origin.x + } + + var minY: Double { + return origin.y + } + + var maxX: Double { + return origin.x + size.xLength + } + + var maxY: Double { + return origin.y + size.yLength + } + + func containts(point: Point) -> Bool { + return (minX <= point.x && point.x <= maxX) && + (minY <= point.y && point.y <= maxY) + } + + var leftTopRect: Rect { + return Rect(origin: origin, size: size.half) + } + + var leftBottomRect: Rect { + return Rect(origin: Point(origin.x, origin.y + size.half.yLength), size: size.half) + } + + var rightTopRect: Rect { + return Rect(origin: Point(origin.x + size.half.xLength, origin.y), size: size.half) + } + + var rightBottomRect: Rect { + return Rect(origin: Point(origin.x + size.half.xLength, origin.y + size.half.yLength), size: size.half) + } + + func intersects(rect: Rect) -> Bool { + + func lineSegmentsIntersect(lStart: Double, lEnd: Double, rStart: Double, rEnd: Double) -> Bool { + return max(lStart, rStart) <= min(lEnd, rEnd) + } + // to intersect, both horizontal and vertical projections need to intersect + // horizontal + if !lineSegmentsIntersect(lStart: minX, lEnd: maxX, rStart: rect.minX, rEnd: rect.maxX) { + return false + } + + // vertical + return lineSegmentsIntersect(lStart: minY, lEnd: maxY, rStart: rect.minY, rEnd: rect.maxY) + } +} + +extension Rect: CustomStringConvertible { + public var description: String { + return "Rect(\(origin), \(size))" + } +} + +protocol PointsContainter { + func add(point: Point) -> Bool + func points(inRect rect: Rect) -> [Point] +} + +class QuadTreeNode { + + enum NodeType { + case leaf + case `internal`(children: Children) + } + + struct Children: Sequence { + let leftTop: QuadTreeNode + let leftBottom: QuadTreeNode + let rightTop: QuadTreeNode + let rightBottom: QuadTreeNode + + init(parentNode: QuadTreeNode) { + leftTop = QuadTreeNode(rect: parentNode.rect.leftTopRect) + leftBottom = QuadTreeNode(rect: parentNode.rect.leftBottomRect) + rightTop = QuadTreeNode(rect: parentNode.rect.rightTopRect) + rightBottom = QuadTreeNode(rect: parentNode.rect.rightBottomRect) + } + + struct ChildrenIterator: IteratorProtocol { + private var index = 0 + private let children: Children + + init(children: Children) { + self.children = children + } + + mutating func next() -> QuadTreeNode? { + + defer { index += 1 } + + switch index { + case 0: return children.leftTop + case 1: return children.leftBottom + case 2: return children.rightTop + case 3: return children.rightBottom + default: return nil + } + } + } + + public func makeIterator() -> ChildrenIterator { + return ChildrenIterator(children: self) + } + } + + var points: [Point] = [] + let rect: Rect + var type: NodeType = .leaf + + static let maxPointCapacity = 3 + + init(rect: Rect) { + self.rect = rect + } + + var recursiveDescription: String { + return recursiveDescription(withTabCount: 0) + } + + private func recursiveDescription(withTabCount count: Int) -> String { + let indent = String(repeating: "\t", count: count) + var result = "\(indent)" + description + "\n" + switch type { + case .internal(let children): + for child in children { + result += child.recursiveDescription(withTabCount: count + 1) + } + default: + break + } + return result + } +} + +extension QuadTreeNode: PointsContainter { + + @discardableResult + func add(point: Point) -> Bool { + if !rect.containts(point: point) { + return false + } + + switch type { + case .internal(let children): + // pass the point to one of the children + for child in children { + if child.add(point: point) { + return true + } + } + + fatalError("rect.containts evaluted to true, but none of the children added the point") + case .leaf: + points.append(point) + // if the max capacity was reached, become an internal node + if points.count == QuadTreeNode.maxPointCapacity { + subdivide() + } + } + return true + } + + private func subdivide() { + switch type { + case .leaf: + type = .internal(children: Children(parentNode: self)) + case .internal: + preconditionFailure("Calling subdivide on an internal node") + } + } + + 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) { + result.append(point) + } + } + + switch type { + case .leaf: + break + case .internal(let children): + // recursively add children's points that lie in the rect + for childNode in children { + result.append(contentsOf: childNode.points(inRect: rect)) + } + } + + return result + } +} + +extension QuadTreeNode: CustomStringConvertible { + var description: String { + switch type { + case .leaf: + return "leaf \(rect) Points: \(points)" + case .internal: + return "parent \(rect) Points: \(points)" + } + } +} + +public class QuadTree: PointsContainter { + + let root: QuadTreeNode + + public init(rect: Rect) { + self.root = QuadTreeNode(rect: rect) + } + + @discardableResult + public func add(point: Point) -> Bool { + return root.add(point: point) + } + + public func points(inRect rect: Rect) -> [Point] { + return root.points(inRect: rect) + } +} + +extension QuadTree: CustomStringConvertible { + public var description: String { + return "Quad tree\n" + root.recursiveDescription + } +} diff --git a/QuadTree/QuadTree.playground/contents.xcplayground b/QuadTree/QuadTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/QuadTree/QuadTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/QuadTree/QuadTree.playground/playground.xcworkspace/contents.xcworkspacedata b/QuadTree/QuadTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/QuadTree/QuadTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/QuadTree/README.md b/QuadTree/README.md new file mode 100644 index 000000000..77ac8b8fa --- /dev/null +++ b/QuadTree/README.md @@ -0,0 +1,158 @@ +# QuadTree + +A quadtree is a [tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Tree) in which each internal (not leaf) node has four children. + +### 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. + +### 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. + +Each node in the tree represents a rectangular region and stores a limited number(`maxPointCapacity`) of points that all lie in its region. + +```swift +class QuadTreeNode { + + enum NodeType { + case leaf + case `internal`(children: Children) + } + + struct Children { + let leftTop: QuadTreeNode + let leftBottom: QuadTreeNode + let rightTop: QuadTreeNode + let rightBottom: QuadTreeNode + + ... + } + + var points: [Point] = [] + let rect: Rect + var type: NodeType = .leaf + + static let maxPointCapacity = 3 + + init(rect: Rect) { + self.rect = rect + } + + ... +} + +``` +Once the limit in a leaf node is reached, four child nodes are added to the node and they represent `topLeft`, `topRight`, `bottomLeft`, `bottomRight` quadrants of the node's rect; each of the consequent points in the rect will be passed to one of the children. Thus, new points are always added to leaf nodes. + +```swift +extension QuadTreeNode { + + @discardableResult + func add(point: Point) -> Bool { + + if !rect.containts(point: point) { + return false + } + + switch type { + case .internal(let children): + // pass the point to one of the children + for child in children { + if child.add(point: point) { + return true + } + } + return false // should never happen + case .leaf: + points.append(point) + // if the max capacity was reached, become an internal node + if points.count == QuadTreeNode.maxPointCapacity { + subdivide() + } + } + return true + } + + private func subdivide() { + switch type { + case .leaf: + type = .internal(children: Children(parentNode: self)) + case .internal: + preconditionFailure("Calling subdivide on an internal node") + } + } +} + +extension Children { + + init(parentNode: QuadTreeNode) { + leftTop = QuadTreeNode(rect: parentNode.rect.leftTopRect) + leftBottom = QuadTreeNode(rect: parentNode.rect.leftBottomRect) + rightTop = QuadTreeNode(rect: parentNode.rect.rightTopRect) + rightBottom = QuadTreeNode(rect: parentNode.rect.rightBottomRect) + } +} + +``` + +To find the points that lie in a given region we can now traverse the tree from top to bottom and collect the suitable points from nodes. + +```swift + +class QuadTree { + + ... + + let root: QuadTreeNode + + public func points(inRect rect: Rect) -> [Point] { + return root.points(inRect: rect) + } +} + +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) { + result.append(point) + } + } + + switch type { + case .leaf: + break + case .internal(children: let children): + // recursively add children's points that lie in the rect + for childNode in children { + result.append(contentsOf: childNode.points(inRect: rect)) + } + } + + return result + } +} + +``` + +Both adding a point and searching can still take up to O(n) in the worst case, since the tree isn't balanced in any way. However, on average it runs significantly faster (something comparable to O(log n)). + +### See also + +Displaying a large amount of objects in a MapView - a great use case for a Quadtree ([Thoughtbot Atricle](https://robots.thoughtbot.com/how-to-handle-large-amounts-of-data-on-maps)) + +More info on [Wiki](https://en.wikipedia.org/wiki/Quadtree) + +*Written for Swift Algorithm Club by Timur Galimov* + diff --git a/QuadTree/Tests/Tests.xcodeproj/project.pbxproj b/QuadTree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a972bf534 --- /dev/null +++ b/QuadTree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,274 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 82EF3AAE1E50E77800013ECB /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82EF3AAD1E50E77800013ECB /* Tests.swift */; }; + 82EF3AB51E50E82400013ECB /* QuadTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82EF3AB41E50E82400013ECB /* QuadTree.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 82EF3AAA1E50E77800013ECB /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 82EF3AAD1E50E77800013ECB /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; + 82EF3AAF1E50E77800013ECB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 82EF3AB41E50E82400013ECB /* QuadTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = QuadTree.swift; path = ../QuadTree.playground/Sources/QuadTree.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 82EF3AA71E50E77800013ECB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 82EF3A9F1E50E74900013ECB = { + isa = PBXGroup; + children = ( + 82EF3AB41E50E82400013ECB /* QuadTree.swift */, + 82EF3AAC1E50E77800013ECB /* Tests */, + 82EF3AAB1E50E77800013ECB /* Products */, + ); + sourceTree = ""; + }; + 82EF3AAB1E50E77800013ECB /* Products */ = { + isa = PBXGroup; + children = ( + 82EF3AAA1E50E77800013ECB /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 82EF3AAC1E50E77800013ECB /* Tests */ = { + isa = PBXGroup; + children = ( + 82EF3AAD1E50E77800013ECB /* Tests.swift */, + 82EF3AAF1E50E77800013ECB /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 82EF3AA91E50E77800013ECB /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 82EF3AB01E50E77800013ECB /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 82EF3AA61E50E77800013ECB /* Sources */, + 82EF3AA71E50E77800013ECB /* Frameworks */, + 82EF3AA81E50E77800013ECB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 82EF3AAA1E50E77800013ECB /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 82EF3AA01E50E74900013ECB /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + TargetAttributes = { + 82EF3AA91E50E77800013ECB = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 34BUG46ZSN; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 82EF3AA31E50E74900013ECB /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 82EF3A9F1E50E74900013ECB; + productRefGroup = 82EF3AAB1E50E77800013ECB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 82EF3AA91E50E77800013ECB /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 82EF3AA81E50E77800013ECB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 82EF3AA61E50E77800013ECB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 82EF3AB51E50E82400013ECB /* QuadTree.swift in Sources */, + 82EF3AAE1E50E77800013ECB /* Tests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 82EF3AA41E50E74900013ECB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 82EF3AA51E50E74900013ECB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 82EF3AB11E50E77800013ECB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 34BUG46ZSN; + 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; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 82EF3AB21E50E77800013ECB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 34BUG46ZSN; + 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; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 82EF3AA31E50E74900013ECB /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 82EF3AA41E50E74900013ECB /* Debug */, + 82EF3AA51E50E74900013ECB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 82EF3AB01E50E77800013ECB /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 82EF3AB11E50E77800013ECB /* Debug */, + 82EF3AB21E50E77800013ECB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 82EF3AA01E50E74900013ECB /* Project object */; +} diff --git a/QuadTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/QuadTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/QuadTree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/QuadTree/Tests/Tests/Info.plist b/QuadTree/Tests/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/QuadTree/Tests/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/QuadTree/Tests/Tests/Tests.swift b/QuadTree/Tests/Tests/Tests.swift new file mode 100644 index 000000000..b7bcda4e6 --- /dev/null +++ b/QuadTree/Tests/Tests/Tests.swift @@ -0,0 +1,85 @@ +// +// Tests.swift +// Tests +// +// Created by Timur Galimov on 12/02/2017. +// +// + +import XCTest + +extension Point: Equatable { + +} + +public func ==(lhs: Point, rhs: Point) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y +} + +class Tests: XCTestCase { + + func testRectContains() { + let rect = Rect(origin: Point(0, 0), size: Size(xLength: 3, yLength: 3)) + + XCTAssertTrue(rect.containts(point: Point(1, 1))) + XCTAssertTrue(rect.containts(point: Point(0, 0))) + XCTAssertTrue(rect.containts(point: Point(0, 3))) + XCTAssertTrue(rect.containts(point: Point(3, 3))) + + XCTAssertFalse(rect.containts(point: Point(-1, 1))) + XCTAssertFalse(rect.containts(point: Point(-0.1, 0.1))) + XCTAssertFalse(rect.containts(point: Point(0, 3.1))) + XCTAssertFalse(rect.containts(point: Point(-4, 1))) + } + + func testIntersects() { + let rect = Rect(origin: Point(0, 0), size: Size(xLength: 5, yLength: 5)) + let rect2 = Rect(origin: Point(1, 1), size: Size(xLength: 1, yLength: 1)) + XCTAssertTrue(rect.intersects(rect: rect2)) + + let rect3 = Rect(origin: Point(1, 0), size: Size(xLength: 1, yLength: 10)) + let rect4 = Rect(origin: Point(0, 1), size: Size(xLength: 10, yLength: 1)) + XCTAssertTrue(rect3.intersects(rect: rect4)) + + let rect5 = Rect(origin: Point(0, 0), size: Size(xLength: 4, yLength: 4)) + let rect6 = Rect(origin: Point(2, 2), size: Size(xLength: 4, yLength: 4)) + XCTAssertTrue(rect5.intersects(rect: rect6)) + + let rect7 = Rect(origin: Point(0, 0), size: Size(xLength: 4, yLength: 4)) + let rect8 = Rect(origin: Point(4, 4), size: Size(xLength: 1, yLength: 1)) + XCTAssertTrue(rect7.intersects(rect: rect8)) + + let rect9 = Rect(origin: Point(-1, -1), size: Size(xLength: 0.5, yLength: 0.5)) + let rect10 = Rect(origin: Point(0, 0), size: Size(xLength: 1, yLength: 1)) + XCTAssertFalse(rect9.intersects(rect: rect10)) + + let rect11 = Rect(origin: Point(0, 0), size: Size(xLength: 2, yLength: 1)) + let rect12 = Rect(origin: Point(3, 0), size: Size(xLength: 1, yLength: 1)) + XCTAssertFalse(rect11.intersects(rect: rect12)) + } + + func testQuadTree() { + let rect = Rect(origin: Point(0, 0), size: Size(xLength: 5, yLength: 5)) + let qt = QuadTree(rect: rect) + + XCTAssertTrue(qt.points(inRect: rect) == [Point]()) + + XCTAssertFalse(qt.add(point: Point(-0.1, 0.1))) + + XCTAssertTrue(qt.points(inRect: rect) == [Point]()) + + XCTAssertTrue(qt.add(point: Point(1, 1))) + XCTAssertTrue(qt.add(point: Point(3, 3))) + XCTAssertTrue(qt.add(point: Point(4, 4))) + XCTAssertTrue(qt.add(point: Point(0.5, 0.5))) + + XCTAssertFalse(qt.add(point: Point(5.5, 0))) + XCTAssertFalse(qt.add(point: Point(5.5, 1))) + XCTAssertFalse(qt.add(point: Point(5.5, 2))) + + XCTAssertTrue(qt.add(point: Point(1.5, 1.5))) + + let rect2 = Rect(origin: Point(0, 0), size: Size(xLength: 2, yLength: 2)) + XCTAssertTrue(qt.points(inRect: rect2) == [Point(1, 1), Point(0.5, 0.5), Point(1.5, 1.5)]) + } +} From c1952ec2f66b4ce98d82d3e948e43af4be77809d Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Sat, 18 Feb 2017 02:18:53 +0100 Subject: [PATCH 0421/1275] finalize migration tests (#381) * finalize migration tests * fix * fixes * test fixes * fix bounded priority queue --- .travis.yml | 23 ++++--- .../Sources/BoundedPriorityQueue.swift | 2 +- .../BoundedPriorityQueue.swift | 30 ++++----- .../Tests/Tests.xcodeproj/project.pbxproj | 42 +++++++++++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Counting Sort/CountingSort.swift | 66 +++++++++---------- .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Depth-First Search/Tests/Graph.swift | 38 +++++------ .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- Graph/Graph.xcodeproj/project.pbxproj | 5 +- Graph/GraphTests/GraphTests.swift | 24 +++---- Heap/Tests/HeapTests.swift | 12 ++-- Heap/Tests/Tests.xcodeproj/project.pbxproj | 2 +- .../Tests/Tests.xcodeproj/project.pbxproj | 2 +- Quicksort/Quicksort.swift | 20 +++--- Quicksort/Tests/QuicksortTests.swift | 6 +- .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Tests/MaximumTests.swift | 2 +- .../Tests/MinimumMaximumPairsTests.swift | 4 +- .../Tests/MinimumTests.swift | 2 +- Select Minimum Maximum/Tests/TestHelper.swift | 2 +- .../Tests/Tests.xcodeproj/project.pbxproj | 10 ++- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 26 files changed, 202 insertions(+), 130 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2b2bafd14..b6ff6190c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,30 +15,29 @@ script: - xcodebuild test -project ./Boyer-Moore/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 ./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 ./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 ./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 ./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 ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests -# - xcodebuild test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests +- xcodebuild test -project ./Quicksort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests -# - xcodebuild test -project ./Run-Length\ Encoding/Tests/Tests.xcodeproj -scheme Tests -# - xcodebuild test -project ./Select\ Minimum\ Maximum/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 ./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 diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift index fc399811d..b94863afc 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift @@ -9,7 +9,7 @@ public class LinkedListNode { } public class BoundedPriorityQueue { - private typealias Node = LinkedListNode + fileprivate typealias Node = LinkedListNode private(set) public var count = 0 fileprivate var head: Node? diff --git a/Bounded Priority Queue/BoundedPriorityQueue.swift b/Bounded Priority Queue/BoundedPriorityQueue.swift index fbd8d5450..d882a7698 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.swift +++ b/Bounded Priority Queue/BoundedPriorityQueue.swift @@ -1,4 +1,4 @@ -public class LinkedListNode { +open class LinkedListNode { var value: T var next: LinkedListNode? var previous: LinkedListNode? @@ -8,27 +8,27 @@ public class LinkedListNode { } } -public class BoundedPriorityQueue { - private typealias Node = LinkedListNode +open class BoundedPriorityQueue { + fileprivate typealias Node = LinkedListNode - private(set) public var count = 0 - private var head: Node? - private var tail: Node? - private var maxElements: Int + fileprivate(set) open var count = 0 + fileprivate var head: Node? + fileprivate var tail: Node? + fileprivate var maxElements: Int public init(maxElements: Int) { self.maxElements = maxElements } - public var isEmpty: Bool { + open var isEmpty: Bool { return count == 0 } - public func peek() -> T? { + open func peek() -> T? { return head?.value } - public func enqueue(value: T) { + open func enqueue(_ value: T) { if let node = insert(value, after: findInsertionPoint(value)) { // If the newly inserted node is the last one in the list, then update // the tail pointer. @@ -44,7 +44,7 @@ public class BoundedPriorityQueue { } } - private func insert(value: T, after: Node?) -> Node? { + fileprivate func insert(_ value: T, after: Node?) -> Node? { if let previous = after { // If the queue is full and we have to insert at the end of the list, @@ -78,18 +78,18 @@ public class BoundedPriorityQueue { /* Find the node after which to insert the new value. If this returns nil, the new value should be inserted at the head of the list. */ - private func findInsertionPoint(value: T) -> Node? { + fileprivate func findInsertionPoint(_ value: T) -> Node? { var node = head var prev: Node? = nil - while let current = node where value < current.value { + while let current = node, value < current.value { prev = node node = current.next } return prev } - private func removeLeastImportantElement() { + fileprivate func removeLeastImportantElement() { if let last = tail { tail = last.previous tail?.next = nil @@ -101,7 +101,7 @@ public class BoundedPriorityQueue { // this is much slower on large lists. } - public func dequeue() -> T? { + open func dequeue() -> T? { if let first = head { count -= 1 if count == 0 { diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj index 6fd5c0b46..842c51695 100644 --- a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -82,10 +82,11 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; TargetAttributes = { B80004B21C83E342001FE2D7 = { CreatedOnToolsVersion = 7.2.1; + LastSwiftMigration = 0820; }; }; }; @@ -132,12 +133,49 @@ B80004AD1C83E324001FE2D7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; B80004AE1C83E324001FE2D7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -188,6 +226,7 @@ SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -230,6 +269,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 0416248f1..8bb763edd 100644 --- a/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ [Int] { - guard array.count > 0 else { - throw CountingSortError.arrayEmpty - } - - // Step 1 - // Create an array to store the count of each element - let maxElement = array.max() ?? 0 - - var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) - for element in array { - countArray[element] += 1 - } - - // Step 2 - // Set each value to be the sum of the previous two values - for index in 1 ..< countArray.count { - let sum = countArray[index] + countArray[index - 1] - countArray[index] = sum - } - - print(countArray) - - // Step 3 - // Place the element in the final array as per the number of elements before it - var sortedArray = [Int](repeating: 0, count: array.count) - for element in array { - countArray[element] -= 1 - sortedArray[countArray[element]] = element - } - return sortedArray +func countingSort(_ array: [Int]) throws -> [Int] { + guard array.count > 0 else { + throw CountingSortError.arrayEmpty + } + + // Step 1 + // Create an array to store the count of each element + let maxElement = array.max() ?? 0 + + var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) + for element in array { + countArray[element] += 1 + } + + // Step 2 + // Set each value to be the sum of the previous two values + for index in 1 ..< countArray.count { + let sum = countArray[index] + countArray[index - 1] + countArray[index] = sum + } + + print(countArray) + + // Step 3 + // Place the element in the final array as per the number of elements before it + var sortedArray = [Int](repeating: 0, count: array.count) + for element in array { + countArray[element] -= 1 + sortedArray[countArray[element]] = element + } + return sortedArray } diff --git a/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj index 6801bb587..5cbb0d4aa 100644 --- a/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -83,11 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -145,8 +146,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -189,8 +192,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -209,6 +214,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -220,6 +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; }; name = Debug; }; @@ -231,6 +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; }; name = Release; }; diff --git a/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..dfcf6de42 100644 --- a/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Bool { // MARK: - Node -public class Node: CustomStringConvertible, Equatable { - public var neighbors: [Edge] +open class Node: CustomStringConvertible, Equatable { + open var neighbors: [Edge] - public private(set) var label: String - public var distance: Int? - public var visited: Bool + open fileprivate(set) var label: String + open var distance: Int? + open var visited: Bool public init(label: String) { self.label = label @@ -27,19 +27,19 @@ public class Node: CustomStringConvertible, Equatable { visited = false } - public var description: String { + open var description: String { if let distance = distance { return "Node(label: \(label), distance: \(distance))" } return "Node(label: \(label), distance: infinity)" } - public var hasDistance: Bool { + open var hasDistance: Bool { return distance != nil } - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf { $0 === edge }!) + open func remove(_ edge: Edge) { + neighbors.remove(at: neighbors.index { $0 === edge }!) } } @@ -49,25 +49,25 @@ public func == (lhs: Node, rhs: Node) -> Bool { // MARK: - Graph -public class Graph: CustomStringConvertible, Equatable { - public private(set) var nodes: [Node] +open class Graph: CustomStringConvertible, Equatable { + open fileprivate(set) var nodes: [Node] public init() { self.nodes = [] } - public func addNode(label: String) -> Node { + open func addNode(_ label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - public func addEdge(source: Node, neighbor: Node) { + open func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } - public var description: String { + open var description: String { var description = "" for node in nodes { @@ -78,15 +78,15 @@ public class Graph: CustomStringConvertible, Equatable { return description } - public func findNodeWithLabel(label: String) -> Node { + open func findNodeWithLabel(_ label: String) -> Node { return nodes.filter { $0.label == label }.first! } - public func duplicate() -> Graph { + open func duplicate() -> Graph { let duplicated = Graph() for node in nodes { - duplicated.addNode(node.label) + _ = duplicated.addNode(node.label) } for node in nodes { diff --git a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj index 9e2872f88..dbc44ecd4 100644 --- a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -226,6 +232,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -238,6 +245,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; }; name = Release; }; diff --git a/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index e5bd10d97..4462aede0 100644 --- a/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ .Type) { + func testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(_ graphType: AbstractGraph.Type) { let graph = graphType.init() let a = graph.createVertex(1) @@ -71,7 +71,7 @@ class GraphTests: XCTestCase { XCTAssertEqual(edgesFromA.first?.to, b) } - func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(graphType: AbstractGraph.Type) { + func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(_ graphType: AbstractGraph.Type) { let graph = graphType.init() let a = graph.createVertex(1) @@ -89,7 +89,7 @@ class GraphTests: XCTestCase { XCTAssertEqual(edgesFromB.first?.to, a) } - func testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(graphType: AbstractGraph.Type) { + func testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(_ graphType: AbstractGraph.Type) { let graph = graphType.init() let a = graph.createVertex(1) @@ -99,7 +99,7 @@ class GraphTests: XCTestCase { XCTAssertEqual(graph.edgesFrom(b).count, 0) } - func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(graphType: AbstractGraph.Type) { + func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(_ graphType: AbstractGraph.Type) { let graph = graphType.init() let verticesCount = 100 var vertices: [Vertex] = [] @@ -125,34 +125,34 @@ class GraphTests: XCTestCase { } func testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedMatrixGraph() { - testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(AdjacencyMatrixGraph) + testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(AdjacencyMatrixGraph.self) } func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedMatrixGraph() { - testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyMatrixGraph) + testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyMatrixGraph.self) } func testEdgesFromReturnsNoInNoEdgeMatrixGraph() { - testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyMatrixGraph) + testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyMatrixGraph.self) } func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedMatrixGraph() { - testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyMatrixGraph) + testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyMatrixGraph.self) } func testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedListGraph() { - testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(AdjacencyListGraph) + testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(AdjacencyListGraph.self) } func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedListGraph() { - testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyListGraph) + testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyListGraph.self) } func testEdgesFromReturnsNoInNoEdgeListGraph() { - testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyListGraph) + testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyListGraph.self) } func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedListGraph() { - testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyListGraph) + testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyListGraph.self) } } diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index c5b479f14..0e6c504f3 100644 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -197,27 +197,27 @@ class HeapTests: XCTestCase { XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) //test index out of bounds - let v = h.removeAt(index: 10) + let v = h.removeAt(10) XCTAssertEqual(v, nil) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) - let v1 = h.removeAt(index: 5) + let v1 = h.removeAt(5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 65]) - let v2 = h.removeAt(index: 4) + let v2 = h.removeAt(4) XCTAssertEqual(v2, 20) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 65, 70, 10, 50]) - let v3 = h.removeAt(index: 4) + let v3 = h.removeAt(4) XCTAssertEqual(v3, 50) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 65, 70, 10]) - let v4 = h.removeAt(index: 0) + let v4 = h.removeAt(0) XCTAssertEqual(v4, 100) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [70, 65, 10]) @@ -270,7 +270,7 @@ class HeapTests: XCTestCase { let m = (n + 1)/2 for k in 1...m { let i = Int(arc4random_uniform(UInt32(n - k + 1))) - let v = h.removeAt(index: i)! + let v = h.removeAt(i)! let j = a.index(of: v)! a.remove(at: j) diff --git a/Heap/Tests/Tests.xcodeproj/project.pbxproj b/Heap/Tests/Tests.xcodeproj/project.pbxproj index 9319e2089..22112fa60 100644 --- a/Heap/Tests/Tests.xcodeproj/project.pbxproj +++ b/Heap/Tests/Tests.xcodeproj/project.pbxproj @@ -88,7 +88,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 0820; }; }; }; diff --git a/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj index 77423c57a..0f7d84be9 100644 --- a/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -91,7 +91,7 @@ TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 0820; }; }; }; diff --git a/Quicksort/Quicksort.swift b/Quicksort/Quicksort.swift index 6448dd815..39fa27b66 100644 --- a/Quicksort/Quicksort.swift +++ b/Quicksort/Quicksort.swift @@ -3,7 +3,7 @@ import Foundation /* Easy to understand but not very efficient. */ -func quicksort(a: [T]) -> [T] { +func quicksort(_ a: [T]) -> [T] { guard a.count > 1 else { return a } let pivot = a[a.count/2] @@ -29,7 +29,7 @@ func quicksort(a: [T]) -> [T] { if the pivot value occurs more than once, its duplicates will be found in the left partition. */ -func partitionLomuto(inout a: [T], low: Int, high: Int) -> Int { +func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int { // We always use the highest item as the pivot. let pivot = a[high] @@ -56,7 +56,7 @@ func partitionLomuto(inout a: [T], low: Int, high: Int) -> Int { /* Recursive, in-place version that uses Lomuto's partioning scheme. */ -func quicksortLomuto(inout a: [T], low: Int, high: Int) { +func quicksortLomuto(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionLomuto(&a, low: low, high: high) quicksortLomuto(&a, low: low, high: p - 1) @@ -80,7 +80,7 @@ func quicksortLomuto(inout a: [T], low: Int, high: Int) { Hoare scheme is more efficient than Lomuto's partition scheme; it performs fewer swaps. */ -func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { +func partitionHoare(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[low] var i = low - 1 var j = high + 1 @@ -101,7 +101,7 @@ func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { Recursive, in-place version that uses Hoare's partioning scheme. Because of the choice of pivot, this performs badly if the array is already sorted. */ -func quicksortHoare(inout a: [T], low: Int, high: Int) { +func quicksortHoare(_ a: inout [T], low: Int, high: Int) { if low < high { let p = partitionHoare(&a, low: low, high: high) quicksortHoare(&a, low: low, high: p) @@ -112,7 +112,7 @@ func quicksortHoare(inout a: [T], low: Int, high: Int) { // MARK: - Randomized sort /* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { +public func random(min: Int, max: Int) -> Int { assert(min < max) return min + Int(arc4random_uniform(UInt32(max - min + 1))) } @@ -121,7 +121,7 @@ public func random(min min: Int, max: Int) -> Int { Uses a random pivot index. On average, this results in a well-balanced split of the input array. */ -func quicksortRandom(inout a: [T], low: Int, high: Int) { +func quicksortRandom(_ a: inout [T], low: Int, high: Int) { if low < high { // Create a random pivot index in the range [low...high]. let pivotIndex = random(min: low, max: high) @@ -142,7 +142,7 @@ func quicksortRandom(inout a: [T], low: Int, high: Int) { Swift's swap() doesn't like it if the items you're trying to swap refer to the same memory location. This little wrapper simply ignores such swaps. */ -public func swap(inout a: [T], _ i: Int, _ j: Int) { +public func swap(_ a: inout [T], _ i: Int, _ j: Int) { if i != j { swap(&a[i], &a[j]) } @@ -165,7 +165,7 @@ public func swap(inout a: [T], _ i: Int, _ j: Int) { Time complexity is O(n), space complexity is O(1). */ -func partitionDutchFlag(inout a: [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { +func partitionDutchFlag(_ a: inout [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { let pivot = a[pivotIndex] var smaller = low @@ -195,7 +195,7 @@ func partitionDutchFlag(inout a: [T], low: Int, high: Int, pivotI /* Uses Dutch national flag partitioning and a random pivot index. */ -func quicksortDutchFlag(inout a: [T], low: Int, high: Int) { +func quicksortDutchFlag(_ a: inout [T], low: Int, high: Int) { if low < high { let pivotIndex = random(min: low, max: high) let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex) diff --git a/Quicksort/Tests/QuicksortTests.swift b/Quicksort/Tests/QuicksortTests.swift index 00135b31f..c8d9a62e6 100644 --- a/Quicksort/Tests/QuicksortTests.swift +++ b/Quicksort/Tests/QuicksortTests.swift @@ -5,12 +5,12 @@ class QuicksortTests: XCTestCase { checkSortAlgorithm(quicksort) } - private typealias QuicksortFunction = (inout [Int], low: Int, high: Int) -> Void + fileprivate typealias QuicksortFunction = (inout [Int], _ low: Int, _ high: Int) -> Void - private func checkQuicksort(function: QuicksortFunction) { + fileprivate func checkQuicksort(_ function: QuicksortFunction) { checkSortAlgorithm { (a: [Int]) -> [Int] in var b = a - function(&b, low: 0, high: b.count - 1) + function(&b, 0, b.count - 1) return b } } diff --git a/Quicksort/Tests/Tests.xcodeproj/project.pbxproj b/Quicksort/Tests/Tests.xcodeproj/project.pbxproj index 8aecb59f8..2d8ee18ff 100644 --- a/Quicksort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Quicksort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,11 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -149,8 +150,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,8 +196,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -213,6 +218,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -224,6 +230,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; }; name = Debug; }; @@ -235,6 +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_VERSION = 3.0; }; name = Release; }; diff --git a/Quicksort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Quicksort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..dfcf6de42 100644 --- a/Quicksort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Quicksort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ [UInt32] { +func createRandomList(_ numberOfElements: Int) -> [UInt32] { return (1...numberOfElements).map {_ in arc4random()} } diff --git a/Select Minimum Maximum/Tests/Tests.xcodeproj/project.pbxproj b/Select Minimum Maximum/Tests/Tests.xcodeproj/project.pbxproj index e2857d2b7..fb70d6970 100644 --- a/Select Minimum Maximum/Tests/Tests.xcodeproj/project.pbxproj +++ b/Select Minimum Maximum/Tests/Tests.xcodeproj/project.pbxproj @@ -98,11 +98,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; }; }; }; @@ -165,8 +166,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -209,8 +212,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -229,6 +234,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -240,6 +246,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; }; name = Debug; }; @@ -251,6 +258,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; }; name = Release; }; diff --git a/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..dfcf6de42 100644 --- a/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 19 Feb 2017 14:58:50 +0100 Subject: [PATCH 0422/1275] Convex Hull algorithm --- .../Convex Hull.xcodeproj/project.pbxproj | 297 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + Convex Hull/Convex Hull/AppDelegate.swift | 57 ++++ .../AppIcon.appiconset/Contents.json | 93 ++++++ .../Base.lproj/LaunchScreen.storyboard | 27 ++ Convex Hull/Convex Hull/Info.plist | 47 +++ Convex Hull/Convex Hull/View.swift | 177 +++++++++++ Convex Hull/README.md | 41 +++ 8 files changed, 746 insertions(+) create mode 100644 Convex Hull/Convex Hull.xcodeproj/project.pbxproj create mode 100644 Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Convex Hull/Convex Hull/AppDelegate.swift create mode 100644 Convex Hull/Convex Hull/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Convex Hull/Convex Hull/Base.lproj/LaunchScreen.storyboard create mode 100644 Convex Hull/Convex Hull/Info.plist create mode 100644 Convex Hull/Convex Hull/View.swift create mode 100644 Convex Hull/README.md diff --git a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj new file mode 100644 index 000000000..2f236b013 --- /dev/null +++ b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj @@ -0,0 +1,297 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 8E6D68BA1E59989400161780 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6D68B91E59989400161780 /* AppDelegate.swift */; }; + 8E6D68C11E59989400161780 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8E6D68C01E59989400161780 /* Assets.xcassets */; }; + 8E6D68C41E59989400161780 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E6D68C21E59989400161780 /* LaunchScreen.storyboard */; }; + 8E6D68CC1E599CF100161780 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6D68CB1E599CF100161780 /* View.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8E6D68B61E59989400161780 /* Convex Hull.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Convex Hull.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E6D68B91E59989400161780 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 8E6D68C01E59989400161780 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8E6D68C31E59989400161780 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 8E6D68C51E59989400161780 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8E6D68CB1E599CF100161780 /* View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8E6D68B31E59989400161780 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8E6D68AD1E59989400161780 = { + isa = PBXGroup; + children = ( + 8E6D68B81E59989400161780 /* Convex Hull */, + 8E6D68B71E59989400161780 /* Products */, + ); + sourceTree = ""; + }; + 8E6D68B71E59989400161780 /* Products */ = { + isa = PBXGroup; + children = ( + 8E6D68B61E59989400161780 /* Convex Hull.app */, + ); + name = Products; + sourceTree = ""; + }; + 8E6D68B81E59989400161780 /* Convex Hull */ = { + isa = PBXGroup; + children = ( + 8E6D68B91E59989400161780 /* AppDelegate.swift */, + 8E6D68CB1E599CF100161780 /* View.swift */, + 8E6D68C01E59989400161780 /* Assets.xcassets */, + 8E6D68C21E59989400161780 /* LaunchScreen.storyboard */, + 8E6D68C51E59989400161780 /* Info.plist */, + ); + path = "Convex Hull"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8E6D68B51E59989400161780 /* Convex Hull */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8E6D68C81E59989400161780 /* Build configuration list for PBXNativeTarget "Convex Hull" */; + buildPhases = ( + 8E6D68B21E59989400161780 /* Sources */, + 8E6D68B31E59989400161780 /* Frameworks */, + 8E6D68B41E59989400161780 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Convex Hull"; + productName = "Convex Hull"; + productReference = 8E6D68B61E59989400161780 /* Convex Hull.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8E6D68AE1E59989400161780 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = Workmoose; + TargetAttributes = { + 8E6D68B51E59989400161780 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 7C4LVS3ZVC; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8E6D68B11E59989400161780 /* Build configuration list for PBXProject "Convex Hull" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8E6D68AD1E59989400161780; + productRefGroup = 8E6D68B71E59989400161780 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8E6D68B51E59989400161780 /* Convex Hull */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8E6D68B41E59989400161780 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E6D68C41E59989400161780 /* LaunchScreen.storyboard in Resources */, + 8E6D68C11E59989400161780 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8E6D68B21E59989400161780 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E6D68BA1E59989400161780 /* AppDelegate.swift in Sources */, + 8E6D68CC1E599CF100161780 /* View.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8E6D68C21E59989400161780 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 8E6D68C31E59989400161780 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 8E6D68C61E59989400161780 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8E6D68C71E59989400161780 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8E6D68C91E59989400161780 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + INFOPLIST_FILE = "Convex Hull/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 8E6D68CA1E59989400161780 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + INFOPLIST_FILE = "Convex Hull/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8E6D68B11E59989400161780 /* Build configuration list for PBXProject "Convex Hull" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8E6D68C61E59989400161780 /* Debug */, + 8E6D68C71E59989400161780 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8E6D68C81E59989400161780 /* Build configuration list for PBXNativeTarget "Convex Hull" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8E6D68C91E59989400161780 /* Debug */, + 8E6D68CA1E59989400161780 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8E6D68AE1E59989400161780 /* Project object */; +} diff --git a/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..dfcd4bc52 --- /dev/null +++ b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Convex Hull/Convex Hull/AppDelegate.swift b/Convex Hull/Convex Hull/AppDelegate.swift new file mode 100644 index 000000000..1901083a8 --- /dev/null +++ b/Convex Hull/Convex Hull/AppDelegate.swift @@ -0,0 +1,57 @@ +// +// AppDelegate.swift +// Convex Hull +// +// Created by Jaap Wijnen on 19/02/2017. +// Copyright © 2017 Workmoose. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + let screenBounds = UIScreen.main.bounds + + window = UIWindow(frame: screenBounds) + + let viewController = UIViewController() + viewController.view = View(frame: (window?.frame)!) + viewController.view.backgroundColor = .white + + window?.rootViewController = viewController + window?.makeKeyAndVisible() + + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Convex Hull/Convex Hull/Assets.xcassets/AppIcon.appiconset/Contents.json b/Convex Hull/Convex Hull/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..1d060ed28 --- /dev/null +++ b/Convex Hull/Convex Hull/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Convex Hull/Convex Hull/Base.lproj/LaunchScreen.storyboard b/Convex Hull/Convex Hull/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..fdf3f97d1 --- /dev/null +++ b/Convex Hull/Convex Hull/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Convex Hull/Convex Hull/Info.plist b/Convex Hull/Convex Hull/Info.plist new file mode 100644 index 000000000..390c5347e --- /dev/null +++ b/Convex Hull/Convex Hull/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Convex Hull/Convex Hull/View.swift b/Convex Hull/Convex Hull/View.swift new file mode 100644 index 000000000..2d7157e6f --- /dev/null +++ b/Convex Hull/Convex Hull/View.swift @@ -0,0 +1,177 @@ +// +// View.swift +// Convex Hull +// +// Created by Jaap Wijnen on 19/02/2017. +// Copyright © 2017 Workmoose. All rights reserved. +// + +import UIKit + +class View: UIView { + + let MAX_POINTS = 100 + + var points = [CGPoint]() + + var convexHull = [CGPoint]() + + override init(frame: CGRect) { + super.init(frame: frame) + + generatePoints() + quickHull(points: points) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func generatePoints() { + for _ in 0.. Bool in + return a.x < b.x + } + } + + func quickHull(points: [CGPoint]) { + var pts = points + + // Assume points has at least 2 points + // Assume list is ordered on x + + // left most point + let p1 = pts.removeFirst() + // right most point + let p2 = pts.removeLast() + + // p1 and p2 are outer most points and thus are part of the hull + convexHull.append(p1) + convexHull.append(p2) + + // points to the right of oriented line from p1 to p2 + var s1 = [CGPoint]() + + // points to the right of oriented line from p2 to p1 + var s2 = [CGPoint]() + + // p1 to p2 line + let lineVec1 = CGPoint(x: p2.x - p1.x, y: p2.y - p1.y) + + for p in pts { // per point check if point is to right or left of p1 to p2 line + let pVec1 = CGPoint(x: p.x - p1.x, y: p.y - p1.y) + let sign1 = lineVec1.x * pVec1.y - pVec1.x * lineVec1.y // cross product to check on which side of the line point p is. + + if sign1 > 0 { // right of p1 p2 line (in a normal xy coordinate system this would be < 0 but due to the weird iPhone screen coordinates this is > 0 + s1.append(p) + } else { // right of p2 p1 line + s2.append(p) + } + } + + // find new hull points + findHull(s1, p1, p2) + findHull(s2, p2, p1) + } + + func findHull(_ points: [CGPoint], _ p1: CGPoint, _ p2: CGPoint) { + // if set of points is empty there are no points to the right of this line so this line is part of the hull. + if points.isEmpty { + return + } + + var pts = points + + // calculate parameters of general line equation y = a * x + b + let a = (p1.y - p2.y) / (p1.x - p2.x) + let b = p1.y - a * p1.x + + // calculate normal line's growth factor + let a1 = -1 / a + + var maxDist: CGFloat = -1 + var maxPoint: CGPoint = pts.first! + + for p in pts { // for every point check the distance from our line + let b1 = p.y - a1 * p.x // calculate offset to line equation for given point p + let x = -(b - b1)/(a - a1) // calculate x where the two lines intersect + let y = a * x + b // calculate y value of this intersect point + + let dist = pow(x - p.x, 2) + pow(y - p.y, 2) // calculate distance squared between intersection point and point p + if dist > maxDist { // if distance is larger than current maxDist remember new point p + maxDist = dist + maxPoint = p + } + } + + convexHull.insert(maxPoint, at: convexHull.index(of: p1)! + 1) // insert point with max distance from line in the convexHull after p1 + + pts.remove(at: pts.index(of: maxPoint)!) // remove maxPoint from points array as we are going to split this array in points left and right of the line + + // points to the right of oriented line from p1 to maxPoint + var s1 = [CGPoint]() + + // points to the right of oriented line from maxPoint to p2 + var s2 = [CGPoint]() + + // p1 to maxPoint line + let lineVec1 = CGPoint(x: maxPoint.x - p1.x, y: maxPoint.y - p1.y) + // maxPoint to p2 line + let lineVec2 = CGPoint(x: p2.x - maxPoint.x, y: p2.y - maxPoint.y) + + for p in pts { + let pVec1 = CGPoint(x: p.x - p1.x, y: p.y - p1.y) // vector from p1 to p + let sign1 = lineVec1.x * pVec1.y - pVec1.x * lineVec1.y // sign to check is p is to the right or left of lineVec1 + + let pVec2 = CGPoint(x: p.x - maxPoint.x, y: p.y - maxPoint.y) // vector from p2 to p + let sign2 = lineVec2.x * pVec2.y - pVec2.x * lineVec2.y // sign to check is p is to the right or left of lineVec2 + + if sign1 > 0 { // right of p1 maxPoint line + s1.append(p) + } else if sign2 > 0 { // right of maxPoint p2 line + s2.append(p) + } + } + + // find new hull points + findHull(s1, p1, maxPoint) + findHull(s2, maxPoint, p2) + } + + override func draw(_ rect: CGRect) { + + let context = UIGraphicsGetCurrentContext() + + // Draw hull + let lineWidth:CGFloat = 2.0 + + context!.setFillColor(UIColor.black.cgColor) + context!.setLineWidth(lineWidth) + context!.setStrokeColor(UIColor.red.cgColor) + context!.setFillColor(UIColor.black.cgColor) + + let firstPoint = convexHull.first! + context!.move(to: firstPoint) + + for p in convexHull.dropFirst() { + context!.addLine(to: p) + } + context!.addLine(to: firstPoint) + + context!.strokePath() + + // Draw points + for p in points { + let radius: CGFloat = 5 + let circleRect = CGRect(x: p.x - radius, y: p.y - radius, width: 2 * radius, height: 2 * radius) + context!.fillEllipse(in: circleRect) + } + } +} diff --git a/Convex Hull/README.md b/Convex Hull/README.md new file mode 100644 index 000000000..b73f66176 --- /dev/null +++ b/Convex Hull/README.md @@ -0,0 +1,41 @@ +# Convex Hull + +There are multiple Convex Hull algorithms. This particular implementation uses the Quickhull algorithm. + +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 dimention. This implementation however covers points on a plane. It essentially calculates the lines between points which together contain all points. + +## Quickhull + +The quickhull algorithm works as follows. +The algorithm takes an input of a collection of points. These points should be ordered on their x coordinate value. We pick the two points A and B with the smallest(A) and the largest(B) x coordinate. These of course have to be part of the hull. Imagine a line from point A to point B. All points to the right of this line are grouped in an array S1. Imagine now a line from point B to point A. (this is of course the same line as before just with opposite direction) Again all points to the right of this line are grouped in an array, S2 this time. +We now define the following recursive function: + +`findHull(points: [CGPoint], p1: CGPoint, p2: CGPoint)` + +``` +findHull(S1, A, B) +findHull(S2, B, A) +``` + +What this function does is the following: +1. If `points` is empty we return as there are no points to the right of our line to add to our hull. +2. Draw a line from `p1` to `p2`. +3. Find the point in `points` that is furthest away from this line. (`maxPoint`) +4. Add `maxPoint` to the hull right after `p1`. +5. Draw a line (`line1`) from `p1` to `maxPoint`. +6. Draw a line (`line2`) from `maxPoint` to `p2`. (These lines now form a triangle) +7. All points within this triangle are of course not part of the hull and thus can be ignored. We check which points in `points` are to the right of `line1` these are grouped in an array `s1`. +8. All points that are to the right of `line2` are grouped in an array `s2`. Note that there are no points that are both to the right of `line1` and `line2` as then `maxPoint` wouldn't be the point furthest away from our initial line between `p1` and `p2`. +9. We call `findHull(_, _, _)` again on our new groups of points to find more hull points. +``` +findHull(s1, p1, maxPoint) +findHull(s2, maxPoint, p2) +``` + +This eventually leaves us with an array of points describing the convex hull. + +## See also + +[Convex Hull on Wikipedia](https://en.wikipedia.org/wiki/Convex_hull_algorithms) + +*Written for the Swift Algorithm Club by Jaap Wijnen.* From 94c9b5f2b0306e9924c01486889b69934f34575a Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 19 Feb 2017 16:46:31 +0100 Subject: [PATCH 0423/1275] initial implementation fro Splay Trees Test in progress Debug in progress Playground in progress Documentation not started --- .../SplayTree.playground/Contents.swift | 7 + .../Sources/SplayTree.swift | 509 ++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + Splay Tree/SplayTree.swift | 552 ++++++++++++++++++ Splay Tree/Tests/Info.plist | 22 + Splay Tree/Tests/SplayTreeTests.swift | 19 + Splay Tree/Tests/Tests-Bridging-Header.h | 4 + .../Tests/Tests.xcodeproj/project.pbxproj | 279 +++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Tests.xcscheme | 101 ++++ 11 files changed, 1511 insertions(+) create mode 100644 Splay Tree/SplayTree.playground/Contents.swift create mode 100644 Splay Tree/SplayTree.playground/Sources/SplayTree.swift create mode 100644 Splay Tree/SplayTree.playground/contents.xcplayground create mode 100644 Splay Tree/SplayTree.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Splay Tree/SplayTree.swift create mode 100644 Splay Tree/Tests/Info.plist create mode 100644 Splay Tree/Tests/SplayTreeTests.swift create mode 100644 Splay Tree/Tests/Tests-Bridging-Header.h create mode 100644 Splay Tree/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Splay Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Splay Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/Splay Tree/SplayTree.playground/Contents.swift b/Splay Tree/SplayTree.playground/Contents.swift new file mode 100644 index 000000000..951ad4c5c --- /dev/null +++ b/Splay Tree/SplayTree.playground/Contents.swift @@ -0,0 +1,7 @@ +//: Playground - Splay Tree Implementation + + +let splayTree = SplayTree(array: [1]) +splayTree.insert(value: 2) +splayTree.insert(value: 10) +splayTree.insert(value: 6) diff --git a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift new file mode 100644 index 000000000..f0c45e831 --- /dev/null +++ b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift @@ -0,0 +1,509 @@ +/* + * Splay Tree + * + * Based on Binary Search Tree Implementation written by Nicolas Ameghino and Matthijs Hollemans for Swift Algorithms Club + * https://github.com/raywenderlich/swift-algorithm-club/blob/master/Binary%20Search%20Tree + * And extended for the specifics of a Splay Tree by Barbara Martina Rodeker + * + */ + +/** + Represent the 3 possible operations (combinations of rotations) that + could be performed during the Splay phase in Splay Trees + + - zigZag Left child of a right child OR right child of a left child + - zigZig Left child of a left child OR right child of a right child + - zig Only 1 parent and that parent is the root + + */ +public enum SplayOperation { + case zigZag + case zigZig + case zig + + + /** + Splay the given node up to the root of the tree + + - Parameters: + - node SplayTree node to move up to the root + */ + public static func splay(node: SplayTree) { + + while (node.parent != nil) { + operation(forNode: node).apply(onNode: node) + } + } + + /** + Compares the node and its parent and determine + if the rotations should be performed in a zigZag, zigZig or zig case. + + - Parmeters: + - forNode SplayTree node to be checked + - Returns + - Operation Case zigZag - zigZig - zig + */ + private static func operation(forNode node: SplayTree) -> SplayOperation { + + if let parent = node.parent, let grandParent = parent.parent { + if (node.isLeftChild && grandParent.isRightChild) || (node.isRightChild && grandParent.isLeftChild) { + return .zigZag + } + return .zigZig + } + return .zig + } + + /** + Applies the rotation associated to the case + Modifying the splay tree and briging the received node further to the top of the tree + + - Parameters: + - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent + */ + private func apply(onNode node: SplayTree) { + switch self { + case .zigZag: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node, parent: node.parent!) + rotate(child: node, parent: node.parent!) + + case .zigZig: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node.parent!, parent: node.parent!.parent!) + rotate(child: node, parent: node.parent!) + + case .zig: + assert(node.parent != nil && node.parent!.parent == nil, "There should be a parent which is the root") + rotate(child: node, parent: node.parent!) + } + } + + /** + Performs a single rotation from a node to its parent + re-arranging the children properly + */ + private func rotate(child: SplayTree, parent: SplayTree) { + + assert(child.parent != nil && child.parent!.value == parent.value, "Parent and child.parent should match here") + + var grandchildToMode: SplayTree? + if child.isLeftChild { + + grandchildToMode = child.right + child.right = parent + parent.left = grandchildToMode + + } else { + + grandchildToMode = child.left + child.left = parent + parent.right = grandchildToMode + } + + let grandParent = parent.parent + parent.parent = child + child.parent = grandParent + } +} + +public class SplayTree { + + fileprivate(set) public var value: T + fileprivate(set) public var parent: SplayTree? + fileprivate(set) public var left: SplayTree? + fileprivate(set) public var right: SplayTree? + + public init(value: T) { + self.value = value + } + + public convenience init(array: [T]) { + precondition(array.count > 0) + self.init(value: array.first!) + for v in array.dropFirst() { + insert(value: v) + } + } + + public var isRoot: Bool { + return parent == nil + } + + public var isLeaf: Bool { + return left == nil && right == nil + } + + public var isLeftChild: Bool { + return parent?.left === self + } + + public var isRightChild: Bool { + return parent?.right === self + } + + public var hasLeftChild: Bool { + return left != nil + } + + public var hasRightChild: Bool { + return right != nil + } + + public var hasAnyChild: Bool { + return hasLeftChild || hasRightChild + } + + public var hasBothChildren: Bool { + return hasLeftChild && hasRightChild + } + + /* How many nodes are in this subtree. Performance: O(n). */ + public var count: Int { + return (left?.count ?? 0) + 1 + (right?.count ?? 0) + } +} + +// MARK: - Adding items + +extension SplayTree { + + /* + Inserts a new element into the tree. You should only insert elements + at the root, to make to sure this remains a valid binary tree! + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func insert(value: T) { + if value < self.value { + if let left = left { + left.insert(value: value) + } else { + + left = SplayTree(value: value) + left?.parent = self + + if let left = left { + SplayOperation.splay(node: left) + self.parent = nil + self.value = left.value + self.left = left.left + self.right = left.right + } + } + } else { + + if let right = right { + right.insert(value: value) + } else { + + right = SplayTree(value: value) + right?.parent = self + + if let right = right { + SplayOperation.splay(node: right) + self.parent = nil + self.value = right.value + self.left = right.left + self.right = right.right + } + } + } + } +} + +// MARK: - Deleting items + +extension SplayTree { + /* + Deletes a node from the tree. + Returns the node that has replaced this removed one (or nil if this was a + leaf node). That is primarily useful for when you delete the root node, in + which case the tree gets a new root. + Performance: runs in O(h) time, where h is the height of the tree. + */ + @discardableResult public func remove() -> SplayTree? { + let replacement: SplayTree? + + if let left = left { + if let right = right { + replacement = removeNodeWithTwoChildren(left, right) + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + } else { + // This node has no children. We just disconnect it from its parent. + replacement = nil + } + + // Save the parent to splay before reconnecting + var parentToSplay: SplayTree? + if let replacement = replacement { + parentToSplay = replacement.parent + } else { + parentToSplay = self.parent + } + + reconnectParentTo(node: replacement) + + // performs the splay operation + if let parentToSplay = parentToSplay { + SplayOperation.splay(node: parentToSplay) + } + + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil + + return replacement + } + + private func removeNodeWithTwoChildren(_ left: SplayTree, _ right: SplayTree) -> SplayTree { + // This node has two children. It must be replaced by the smallest + // child that is larger than this node's value, which is the leftmost + // descendent of the right child. + let successor = right.minimum() + + // If this in-order successor has a right child of its own (it cannot + // have a left child by definition), then that must take its place. + successor.remove() + + // Connect our left child with the new node. + successor.left = left + left.parent = successor + + // Connect our right child with the new node. If the right child does + // not have any left children of its own, then the in-order successor + // *is* the right child. + if right !== successor { + successor.right = right + right.parent = successor + } else { + successor.right = nil + } + + // And finally, connect the successor node to our parent. + return successor + } + + private func reconnectParentTo(node: SplayTree?) { + if let parent = parent { + if isLeftChild { + parent.left = node + } else { + parent.right = node + } + } + node?.parent = parent + } +} + +// MARK: - Searching + +extension SplayTree { + + /* + Finds the "highest" node with the specified value. + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func search(value: T) -> SplayTree? { + var node: SplayTree? = self + while case let n? = node { + if value < n.value { + node = n.left + } else if value > n.value { + node = n.right + } else { + + if let node = node { + SplayOperation.splay(node: node) + } + + return node + } + } + + if let node = node { + SplayOperation.splay(node: node) + } + + return nil + } + + public func contains(value: T) -> Bool { + return search(value: value) != nil + } + + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum() -> SplayTree { + var node = self + while case let next? = node.left { + node = next + } + + SplayOperation.splay(node: node) + + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum() -> SplayTree { + var node = self + while case let next? = node.right { + node = next + } + + SplayOperation.splay(node: node) + + return node + } + + /* + Calculates the depth of this node, i.e. the distance to the root. + Takes O(h) time. + */ + public func depth() -> Int { + var node = self + var edges = 0 + while case let parent? = node.parent { + node = parent + edges += 1 + } + return edges + } + + /* + Calculates the height of this node, i.e. the distance to the lowest leaf. + Since this looks at all children of this node, performance is O(n). + */ + public func height() -> Int { + if isLeaf { + return 0 + } else { + return 1 + max(left?.height() ?? 0, right?.height() ?? 0) + } + } + + /* + Finds the node whose value precedes our value in sorted order. + */ + public func predecessor() -> SplayTree? { + if let left = left { + return left.maximum() + } else { + var node = self + while case let parent? = node.parent { + if parent.value < value { return parent } + node = parent + } + return nil + } + } + + /* + Finds the node whose value succeeds our value in sorted order. + */ + public func successor() -> SplayTree? { + if let right = right { + return right.minimum() + } else { + var node = self + while case let parent? = node.parent { + if parent.value > value { return parent } + node = parent + } + return nil + } + } +} + +// MARK: - Traversal +extension SplayTree { + + public func traverseInOrder(process: (T) -> Void) { + left?.traverseInOrder(process: process) + process(value) + right?.traverseInOrder(process: process) + } + + public func traversePreOrder(process: (T) -> Void) { + process(value) + left?.traversePreOrder(process: process) + right?.traversePreOrder(process: process) + } + + public func traversePostOrder(process: (T) -> Void) { + left?.traversePostOrder(process: process) + right?.traversePostOrder(process: process) + process(value) + } + + /* + Performs an in-order traversal and collects the results in an array. + */ + public func map(formula: (T) -> T) -> [T] { + var a = [T]() + if let left = left { a += left.map(formula: formula) } + a.append(formula(value)) + if let right = right { a += right.map(formula: formula) } + return a + } +} + +/* + Is this binary tree a valid binary search tree? + */ +extension SplayTree { + + 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 + return leftBST && rightBST + } +} + +// MARK: - Debugging + +extension SplayTree: CustomStringConvertible { + public var description: String { + var s = "" + if let left = left { + s += "(\(left.description)) <- " + } + s += "\(value)" + if let right = right { + s += " -> (\(right.description))" + } + return s + } +} + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "value: \(value)" + if let parent = parent { + s += ", parent: \(parent.value)" + } + if let left = left { + s += ", left = [" + left.debugDescription + "]" + } + if let right = right { + s += ", right = [" + right.debugDescription + "]" + } + return s + } + + public func toArray() -> [T] { + return map { $0 } + } +} diff --git a/Splay Tree/SplayTree.playground/contents.xcplayground b/Splay Tree/SplayTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Splay Tree/SplayTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Splay Tree/SplayTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Splay Tree/SplayTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Splay Tree/SplayTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift new file mode 100644 index 000000000..727ff8f50 --- /dev/null +++ b/Splay Tree/SplayTree.swift @@ -0,0 +1,552 @@ +/* + * Splay Tree + * + * Based on Binary Search Tree Implementation written by Nicolas Ameghino and Matthijs Hollemans for Swift Algorithms Club + * https://github.com/raywenderlich/swift-algorithm-club/blob/master/Binary%20Search%20Tree + * And extended for the specifics of a Splay Tree by Barbara Martina Rodeker + * + */ + +/** + Represent the 3 possible operations (combinations of rotations) that + could be performed during the Splay phase in Splay Trees + + - zigZag Left child of a right child OR right child of a left child + - zigZig Left child of a left child OR right child of a right child + - zig Only 1 parent and that parent is the root + + */ +public enum SplayOperation { + case zigZag + case zigZig + case zig + + + /** + Splay the given node up to the root of the tree + + - Parameters: + - node SplayTree node to move up to the root + */ + public static func splay(node: SplayTree) { + + while (node.parent != nil) { + operation(forNode: node).apply(onNode: node) + } + } + + /** + Compares the node and its parent and determine + if the rotations should be performed in a zigZag, zigZig or zig case. + + - Parmeters: + - forNode SplayTree node to be checked + - Returns + - Operation Case zigZag - zigZig - zig + */ + private static func operation(forNode node: SplayTree) -> SplayOperation { + + if let parent = node.parent, let _ = parent.parent { + if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { + return .zigZag + } + return .zigZig + } + return .zig + } + + /** + Applies the rotation associated to the case + Modifying the splay tree and briging the received node further to the top of the tree + + - Parameters: + - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent + */ + private func apply(onNode node: SplayTree) { + switch self { + case .zigZag: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node, parent: node.parent!) + rotate(child: node, parent: node.parent!) + + case .zigZig: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node.parent!, parent: node.parent!.parent!) + rotate(child: node, parent: node.parent!) + + case .zig: + assert(node.parent != nil && node.parent!.parent == nil, "There should be a parent which is the root") + rotate(child: node, parent: node.parent!) + } + } + + /** + Performs a single rotation from a node to its parent + re-arranging the children properly + */ + private func rotate(child: SplayTree, parent: SplayTree) { + + assert(child.parent != nil && child.parent!.value == parent.value, "Parent and child.parent should match here") + + var grandchildToMode: SplayTree? + if child.isLeftChild { + + grandchildToMode = child.right + child.right = parent + parent.left = grandchildToMode + + } else { + + grandchildToMode = child.left + child.left = parent + parent.right = grandchildToMode + } + + let grandParent = parent.parent + parent.parent = child + child.parent = grandParent + } +} + +public class Node { + + fileprivate(set) public var value: T + fileprivate(set) public var parent: SplayTree? + fileprivate(set) public var left: SplayTree? + fileprivate(set) public var right: SplayTree? + + init(value: T){ + self.value = value + } +} + +public class SplayTree { + + + fileprivate(set) public var root: Node? + public var value: T? { + get { + return root?.value + } + set { + if let value = newValue { + root?.value = value + } + } + } + + fileprivate(set) public var parent: SplayTree? { + get { + return root?.parent + } + set { + root?.parent = newValue + } + } + + fileprivate(set) public var left: SplayTree? { + get { + return root?.left + } + set { + root?.left = newValue + } + } + fileprivate(set) public var right: SplayTree? { + get { + return root?.right + } + set { + root?.right = newValue + } + } + + //MARK: - Initializer + + public init(value: T) { + self.root = Node(value:value) + } + + public var isRoot: Bool { + return parent == nil + } + + public var isLeaf: Bool { + return left == nil && right == nil + } + + public var isLeftChild: Bool { + return parent?.left === self + } + + public var isRightChild: Bool { + return parent?.right === self + } + + public var hasLeftChild: Bool { + return left != nil + } + + public var hasRightChild: Bool { + return right != nil + } + + public var hasAnyChild: Bool { + return hasLeftChild || hasRightChild + } + + public var hasBothChildren: Bool { + return hasLeftChild && hasRightChild + } + + /* How many nodes are in this subtree. Performance: O(n). */ + public var count: Int { + return (left?.count ?? 0) + 1 + (right?.count ?? 0) + } +} + +// MARK: - Adding items + +extension SplayTree { + + /* + Inserts a new element into the tree. You should only insert elements + at the root, to make to sure this remains a valid binary tree! + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func insert(value: T) -> SplayTree? { + if let selfValue = self.value { + if value < selfValue { + if let left = left { + return left.insert(value: value) + } else { + + left = SplayTree(value: value) + left?.parent = self + + if let left = left { + SplayOperation.splay(node: left) + return left + } + } + } else { + + if let right = right { + return right.insert(value: value) + } else { + + right = SplayTree(value: value) + right?.parent = self + + if let right = right { + SplayOperation.splay(node: right) + return right + } + } + } + } else { + self.root = Node(value: value) + return self + } + return nil + } +} + +// MARK: - Deleting items + +extension SplayTree { + /* + Deletes a node from the tree. + Returns the node that has replaced this removed one (or nil if this was a + leaf node). That is primarily useful for when you delete the root node, in + which case the tree gets a new root. + Performance: runs in O(h) time, where h is the height of the tree. + */ + @discardableResult public func remove() -> SplayTree? { + let replacement: SplayTree? + + if let left = left { + if let right = right { + replacement = removeNodeWithTwoChildren(left, right) + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + } else { + // This node has no children. We just disconnect it from its parent. + replacement = nil + } + + // Save the parent to splay before reconnecting + var parentToSplay: SplayTree? + if let replacement = replacement { + parentToSplay = replacement.parent + } else { + parentToSplay = self.parent + } + + reconnectParentTo(node: replacement) + + // performs the splay operation + if let parentToSplay = parentToSplay { + SplayOperation.splay(node: parentToSplay) + } + + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil + + return replacement + } + + private func removeNodeWithTwoChildren(_ left: SplayTree, _ right: SplayTree) -> SplayTree { + // This node has two children. It must be replaced by the smallest + // child that is larger than this node's value, which is the leftmost + // descendent of the right child. + let successor = right.minimum() + + // If this in-order successor has a right child of its own (it cannot + // have a left child by definition), then that must take its place. + successor.remove() + + // Connect our left child with the new node. + successor.left = left + left.parent = successor + + // Connect our right child with the new node. If the right child does + // not have any left children of its own, then the in-order successor + // *is* the right child. + if right !== successor { + successor.right = right + right.parent = successor + } else { + successor.right = nil + } + + // And finally, connect the successor node to our parent. + return successor + } + + private func reconnectParentTo(node: SplayTree?) { + if let parent = parent { + if isLeftChild { + parent.left = node + } else { + parent.right = node + } + } + node?.parent = parent + } +} + +// MARK: - Searching + +extension SplayTree { + + /* + Finds the "highest" node with the specified value. + Performance: runs in O(h) time, where h is the height of the tree. + */ + public func search(value: T) -> SplayTree? { + var node: SplayTree? = self + while case let n? = node, n.value != nil { + if value < n.value! { + node = n.left + } else if value > n.value! { + node = n.right + } else { + + if let node = node { + SplayOperation.splay(node: node) + } + + return node + } + } + + if let node = node { + SplayOperation.splay(node: node) + } + + return nil + } + + public func contains(value: T) -> Bool { + return search(value: value) != nil + } + + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum() -> SplayTree { + var node = self + while case let next? = node.left { + node = next + } + + SplayOperation.splay(node: node) + + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum() -> SplayTree { + var node = self + while case let next? = node.right { + node = next + } + + SplayOperation.splay(node: node) + + return node + } + + /* + Calculates the depth of this node, i.e. the distance to the root. + Takes O(h) time. + */ + public func depth() -> Int { + var node = self + var edges = 0 + while case let parent? = node.parent { + node = parent + edges += 1 + } + return edges + } + + /* + Calculates the height of this node, i.e. the distance to the lowest leaf. + Since this looks at all children of this node, performance is O(n). + */ + public func height() -> Int { + if isLeaf { + return 0 + } else { + return 1 + max(left?.height() ?? 0, right?.height() ?? 0) + } + } + + /* + Finds the node whose value precedes our value in sorted order. + */ + public func predecessor() -> SplayTree? { + if let left = left { + return left.maximum() + } else { + var node = self + while case let parent? = node.parent, parent.value != nil, value != nil { + if parent.value! < value! { return parent } + node = parent + } + return nil + } + } + + /* + Finds the node whose value succeeds our value in sorted order. + */ + public func successor() -> SplayTree? { + if let right = right { + return right.minimum() + } else { + var node = self + while case let parent? = node.parent, parent.value != nil , value != nil { + if parent.value! > value! { return parent } + node = parent + } + return nil + } + } +} + +// MARK: - Traversal +extension SplayTree { + + public func traverseInOrder(process: (T) -> Void) { + left?.traverseInOrder(process: process) + process(value!) + right?.traverseInOrder(process: process) + } + + public func traversePreOrder(process: (T) -> Void) { + process(value!) + left?.traversePreOrder(process: process) + right?.traversePreOrder(process: process) + } + + public func traversePostOrder(process: (T) -> Void) { + left?.traversePostOrder(process: process) + right?.traversePostOrder(process: process) + process(value!) + } + + /* + Performs an in-order traversal and collects the results in an array. + */ + public func map(formula: (T) -> T) -> [T] { + var a = [T]() + if let left = left { a += left.map(formula: formula) } + a.append(formula(value!)) + if let right = right { a += right.map(formula: formula) } + return a + } +} + +/* + Is this binary tree a valid binary search tree? + */ +extension SplayTree { + + public func isBST(minValue: T, maxValue: T) -> Bool { + if let value = value { + 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 + return leftBST && rightBST + } + return false + } +} + +// MARK: - Debugging + +extension SplayTree: CustomStringConvertible { + public var description: String { + var s = "" + if let left = left { + s += "(\(left.description)) <- " + } + s += "\(value)" + if let right = right { + s += " -> (\(right.description))" + } + return s + } +} + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "value: \(value)" + if let parent = parent { + s += ", parent: \(parent.value)" + } + if let left = left { + s += ", left = [" + left.debugDescription + "]" + } + if let right = right { + s += ", right = [" + right.debugDescription + "]" + } + return s + } + + public func toArray() -> [T] { + return map { $0 } + } +} diff --git a/Splay Tree/Tests/Info.plist b/Splay Tree/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Splay Tree/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Splay Tree/Tests/SplayTreeTests.swift b/Splay Tree/Tests/SplayTreeTests.swift new file mode 100644 index 000000000..35bdedb71 --- /dev/null +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -0,0 +1,19 @@ +import XCTest + +class SplayTreeTests: XCTestCase { + var tree: SplayTree! + + override func setUp() { + super.setUp() + tree = SplayTree(value: 1) + } + + func testElements() { + print(tree) + let tree1 = tree.insert(value: 10) + print(tree1!) + let tree2 = tree1!.insert(value: 2) + print(tree2!) + } + +} diff --git a/Splay Tree/Tests/Tests-Bridging-Header.h b/Splay Tree/Tests/Tests-Bridging-Header.h new file mode 100644 index 000000000..1b2cb5d6d --- /dev/null +++ b/Splay Tree/Tests/Tests-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Splay Tree/Tests/Tests.xcodeproj/project.pbxproj b/Splay Tree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..8a900fcd3 --- /dev/null +++ b/Splay Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,279 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 763F9E771E59DAEF00AC5031 /* SplayTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 763F9E761E59DAEF00AC5031 /* SplayTree.swift */; }; + 763F9E791E59DAFE00AC5031 /* SplayTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 763F9E781E59DAFE00AC5031 /* SplayTreeTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 056E92A21E25D04D00B30F52 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 056E92A61E25D04D00B30F52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 763F9E761E59DAEF00AC5031 /* SplayTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SplayTree.swift; path = ../SplayTree.swift; sourceTree = ""; }; + 763F9E781E59DAFE00AC5031 /* SplayTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplayTreeTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 056E929F1E25D04D00B30F52 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 056E92851E25D03300B30F52 = { + isa = PBXGroup; + children = ( + 056E92A31E25D04D00B30F52 /* Tests */, + 056E928F1E25D03300B30F52 /* Products */, + ); + sourceTree = ""; + }; + 056E928F1E25D03300B30F52 /* Products */ = { + isa = PBXGroup; + children = ( + 056E92A21E25D04D00B30F52 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 056E92A31E25D04D00B30F52 /* Tests */ = { + isa = PBXGroup; + children = ( + 056E92A61E25D04D00B30F52 /* Info.plist */, + 763F9E781E59DAFE00AC5031 /* SplayTreeTests.swift */, + 763F9E761E59DAEF00AC5031 /* SplayTree.swift */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 056E92A11E25D04D00B30F52 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 056E92A71E25D04D00B30F52 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 056E929E1E25D04D00B30F52 /* Sources */, + 056E929F1E25D04D00B30F52 /* Frameworks */, + 056E92A01E25D04D00B30F52 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 056E92A21E25D04D00B30F52 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 056E92861E25D03300B30F52 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 056E92A11E25D04D00B30F52 = { + CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 0820; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 056E92891E25D03300B30F52 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 056E92851E25D03300B30F52; + productRefGroup = 056E928F1E25D03300B30F52 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 056E92A11E25D04D00B30F52 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 056E92A01E25D04D00B30F52 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 056E929E1E25D04D00B30F52 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 763F9E771E59DAEF00AC5031 /* SplayTree.swift in Sources */, + 763F9E791E59DAFE00AC5031 /* SplayTreeTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 056E92991E25D03300B30F52 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 056E929A1E25D03300B30F52 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 056E92A81E25D04D00B30F52 /* 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_OBJC_BRIDGING_HEADER = "Tests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 056E92A91E25D04D00B30F52 /* 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_OBJC_BRIDGING_HEADER = "Tests-Bridging-Header.h"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 056E92891E25D03300B30F52 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E92991E25D03300B30F52 /* Debug */, + 056E929A1E25D03300B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 056E92A71E25D04D00B30F52 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 056E92A81E25D04D00B30F52 /* Debug */, + 056E92A91E25D04D00B30F52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 056E92861E25D03300B30F52 /* Project object */; +} diff --git a/Splay Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Splay Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Splay Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Splay Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Splay Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..b3f6d696a --- /dev/null +++ b/Splay Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 217cad58d2501c10d040fd72cbcaea96d366fc72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Mon, 20 Feb 2017 10:25:31 +0800 Subject: [PATCH 0424/1275] Update README.markdown add swift version --- Shell Sort/README.markdown | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Shell Sort/README.markdown b/Shell Sort/README.markdown index 6cb682035..a2ac843c7 100644 --- a/Shell Sort/README.markdown +++ b/Shell Sort/README.markdown @@ -111,6 +111,28 @@ This is an old Commodore 64 BASIC version of shell sort that Matthijs used a lon 61300 GOTO 61220 61310 RETURN +## The Code: +Here is an implementation of Shell Sort in Swift: +``` +var arr = [64, 20, 50, 33, 72, 10, 23, -1, 4, 5] + +var n = arr.count / 2 + +repeat +{ + for index in 0.. arr[index + n]{ + + swap(&arr[index], &arr[index + n]) + } + } + + n = n / 2 + +}while n > 0 +``` + ## See also [Shellsort on Wikipedia](https://en.wikipedia.org/wiki/Shellsort) From 31b89968878506cadb76ae2a650edbe651d5f58c Mon Sep 17 00:00:00 2001 From: Timur Galimov Date: Tue, 21 Feb 2017 22:04:11 +0300 Subject: [PATCH 0425/1275] fix typo in PointsContainer protocol --- QuadTree/QuadTree.playground/Sources/QuadTree.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/QuadTree/QuadTree.playground/Sources/QuadTree.swift b/QuadTree/QuadTree.playground/Sources/QuadTree.swift index beec4a7b7..65c55d49e 100644 --- a/QuadTree/QuadTree.playground/Sources/QuadTree.swift +++ b/QuadTree/QuadTree.playground/Sources/QuadTree.swift @@ -104,7 +104,7 @@ extension Rect: CustomStringConvertible { } } -protocol PointsContainter { +protocol PointsContainer { func add(point: Point) -> Bool func points(inRect rect: Rect) -> [Point] } @@ -185,7 +185,7 @@ class QuadTreeNode { } } -extension QuadTreeNode: PointsContainter { +extension QuadTreeNode: PointsContainer { @discardableResult func add(point: Point) -> Bool { @@ -265,7 +265,7 @@ extension QuadTreeNode: CustomStringConvertible { } } -public class QuadTree: PointsContainter { +public class QuadTree: PointsContainer { let root: QuadTreeNode From 2e5a5748fdbf92bb1f7c191af7a1c7a0e8b64de6 Mon Sep 17 00:00:00 2001 From: Timur Galimov Date: Tue, 21 Feb 2017 22:28:50 +0300 Subject: [PATCH 0426/1275] Add quadtree diagram --- QuadTree/Images/quadtree.png | Bin 0 -> 110070 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 QuadTree/Images/quadtree.png diff --git a/QuadTree/Images/quadtree.png b/QuadTree/Images/quadtree.png new file mode 100644 index 0000000000000000000000000000000000000000..53af6fb082a3e6172090bd167e4178a4b8e99e36 GIT binary patch literal 110070 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 z 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 T^->+Urc~-GI?7qcEdBl;I+hf* literal 0 HcmV?d00001 From 42032b4bec864013c7e51fff3443ec602b295741 Mon Sep 17 00:00:00 2001 From: Timur Galimov Date: Wed, 22 Feb 2017 01:04:55 +0300 Subject: [PATCH 0427/1275] Update README.md --- QuadTree/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/QuadTree/README.md b/QuadTree/README.md index 77ac8b8fa..3fc682547 100644 --- a/QuadTree/README.md +++ b/QuadTree/README.md @@ -2,6 +2,8 @@ A quadtree is a [tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Tree) in which each internal (not leaf) node has four children. + + ### 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. From 71bfd719ce6024944e7c17847952d77094be6cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Sun, 26 Feb 2017 12:41:50 +0800 Subject: [PATCH 0428/1275] add file ShellSortExample.swift update code --- Shell Sort/ShellSortExample.swift | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Shell Sort/ShellSortExample.swift diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift new file mode 100644 index 000000000..eea80e539 --- /dev/null +++ b/Shell Sort/ShellSortExample.swift @@ -0,0 +1,33 @@ +// +// ShellSortExample.swift +// +// +// Created by Cheer on 2017/2/26. +// +// + +import Foundation + +public func shellSort(_ list : inout [Int]) +{ + var sublistCount = list.count / 2 + + while sublistCount > 0 + { + for index in 0.. arr[index + sublistCount]{ + swap(&arr[index], &arr[index + sublistCount]) + } + + guard sublistCount == 1 && index > 0 else { continue } + + if arr[index - 1] > arr[index]{ + swap(&arr[index - 1], &arr[index]) + } + } + sublistCount = sublistCount / 2 + } +} From 8202cf1668a535b61fbac12962ebc5a639631ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Mon, 27 Feb 2017 10:52:37 +0800 Subject: [PATCH 0429/1275] Update ShellSortExample.swift Fix my code mistakes --- Shell Sort/ShellSortExample.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index eea80e539..68cd9ead1 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -14,18 +14,18 @@ public func shellSort(_ list : inout [Int]) while sublistCount > 0 { - for index in 0.. arr[index + sublistCount]{ - swap(&arr[index], &arr[index + sublistCount]) + if list[index] > list[index + sublistCount]{ + swap(&list[index], &list[index + sublistCount]) } guard sublistCount == 1 && index > 0 else { continue } - if arr[index - 1] > arr[index]{ - swap(&arr[index - 1], &arr[index]) + if list[index - 1] > list[index]{ + swap(&list[index - 1], &list[index]) } } sublistCount = sublistCount / 2 From 69cb42eef48c610f2f42e6c5d51781fdb3482e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Wed, 1 Mar 2017 12:13:54 +0800 Subject: [PATCH 0430/1275] Update ShellSortExample.swift let code to suit style guide --- Shell Sort/ShellSortExample.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index 68cd9ead1..efa035da3 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -8,23 +8,23 @@ import Foundation -public func shellSort(_ list : inout [Int]) -{ - var sublistCount = list.count / 2 +public func shellSort(_ list: inout [Int]) { - while sublistCount > 0 - { - for index in 0.. 0 { + + for index in 0.. list[index + sublistCount]{ + if list[index] > list[index + sublistCount] { swap(&list[index], &list[index + sublistCount]) } guard sublistCount == 1 && index > 0 else { continue } - if list[index - 1] > list[index]{ + if list[index - 1] > list[index] { swap(&list[index - 1], &list[index]) } } From a69e3d84fcdc3bb8ab1d9e788f8826e5e9ab4254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Thu, 2 Mar 2017 10:47:14 +0800 Subject: [PATCH 0431/1275] Update README.markdown update sample code --- Shell Sort/README.markdown | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Shell Sort/README.markdown b/Shell Sort/README.markdown index a2ac843c7..9c4bdf076 100644 --- a/Shell Sort/README.markdown +++ b/Shell Sort/README.markdown @@ -116,21 +116,31 @@ Here is an implementation of Shell Sort in Swift: ``` var arr = [64, 20, 50, 33, 72, 10, 23, -1, 4, 5] -var n = arr.count / 2 - -repeat -{ - for index in 0.. arr[index + n]{ +public func shellSort(_ list: inout [Int]) { + + var sublistCount = list.count / 2 + + while sublistCount > 0 { - swap(&arr[index], &arr[index + n]) + for index in 0.. list[index + sublistCount] { + swap(&list[index], &list[index + sublistCount]) + } + + guard sublistCount == 1 && index > 0 else { continue } + + if list[index - 1] > list[index] { + swap(&list[index - 1], &list[index]) + } } + sublistCount = sublistCount / 2 } - - n = n / 2 - -}while n > 0 +} + +shellSort(&arr) ``` ## See also From b4e4ef1c8095405c21e69284807095f548fea537 Mon Sep 17 00:00:00 2001 From: John Pham Date: Thu, 2 Mar 2017 17:10:59 +0700 Subject: [PATCH 0432/1275] Update dim func follow syntax change of swift 3 --- Array2D/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Array2D/README.markdown b/Array2D/README.markdown index 51e77435e..b98a09593 100644 --- a/Array2D/README.markdown +++ b/Array2D/README.markdown @@ -36,7 +36,7 @@ var cookies = [[Int]](repeating: [Int](repeating: 0, count: 7), count: 9) but that's just ugly. To be fair, you can hide the ugliness in a helper function: ```swift -func dim(count: Int, _ value: T) -> [T] { +func dim(_ count: Int, _ value: T) -> [T] { return [T](repeating: value, count: count) } ``` From 0837113e9e8a0fa69d2e8deb8302bb0a72c5d5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Thu, 2 Mar 2017 19:19:18 +0800 Subject: [PATCH 0433/1275] Add files via upload upload a radix sort implement,faster than original code --- Radix Sort/RadixSortExample.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Radix Sort/RadixSortExample.swift diff --git a/Radix Sort/RadixSortExample.swift b/Radix Sort/RadixSortExample.swift new file mode 100644 index 000000000..7d9461c5c --- /dev/null +++ b/Radix Sort/RadixSortExample.swift @@ -0,0 +1,29 @@ +// +// RadixSortExample.swift +// +// +// Created by Cheer on 2017/3/2. +// +// + +import Foundation + +func radixSort1(_ arr: inout [Int]) { + + var temp = [[Int]](repeating: [], count: 10) + + for num in arr { temp[num % 10].append(num) } + + for i in 1...Int(arr.max()!.description.characters.count) { + + for index in 0.. Date: Fri, 3 Mar 2017 11:13:22 +0800 Subject: [PATCH 0434/1275] Update LinearSearch.swift more swift --- Linear Search/LinearSearch.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Linear Search/LinearSearch.swift b/Linear Search/LinearSearch.swift index 882795180..c5374d0a4 100644 --- a/Linear Search/LinearSearch.swift +++ b/Linear Search/LinearSearch.swift @@ -4,3 +4,7 @@ func linearSearch(_ array: [T], _ object: T) -> Int? { } return nil } + +func linearSearch1(_ array: [T], _ object: T) -> Array.Index? { + return array.index { $0 == object } +} From 12b0bdbb8488f7746edac33623b2f86c57564a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Fri, 3 Mar 2017 11:34:04 +0800 Subject: [PATCH 0435/1275] Update README.markdown update some details --- Select Minimum Maximum/README.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Select Minimum Maximum/README.markdown b/Select Minimum Maximum/README.markdown index 09ca97039..fa0f8fed8 100644 --- a/Select Minimum Maximum/README.markdown +++ b/Select Minimum Maximum/README.markdown @@ -68,6 +68,13 @@ array.minElement() // This will return 3 array.maxElement() // This will return 9 ``` +``` +let array = [ 8, 3, 9, 4, 6 ] +//swift3 +array.min() // This will return 3 +array.max() // This will return 9 +``` + ## Maximum and minimum To find both the maximum and minimum values contained in array while minimizing the number of comparisons we can compare the items in pairs. From cc973dcb62d310f1af0d08d408c782a57e3523cb Mon Sep 17 00:00:00 2001 From: barbara Date: Fri, 3 Mar 2017 21:01:11 +0100 Subject: [PATCH 0436/1275] Fixes for connecting nodes during rotations --- Splay Tree/SplayTree.swift | 53 ++++++++++++++++++--------- Splay Tree/Tests/SplayTreeTests.swift | 41 +++++++++++++-------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift index 727ff8f50..2e008ba50 100644 --- a/Splay Tree/SplayTree.swift +++ b/Splay Tree/SplayTree.swift @@ -44,7 +44,7 @@ public enum SplayOperation { - Returns - Operation Case zigZag - zigZig - zig */ - private static func operation(forNode node: SplayTree) -> SplayOperation { + public static func operation(forNode node: SplayTree) -> SplayOperation { if let parent = node.parent, let _ = parent.parent { if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { @@ -62,7 +62,7 @@ public enum SplayOperation { - Parameters: - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent */ - private func apply(onNode node: SplayTree) { + public func apply(onNode node: SplayTree) { switch self { case .zigZag: assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") @@ -84,7 +84,7 @@ public enum SplayOperation { Performs a single rotation from a node to its parent re-arranging the children properly */ - private func rotate(child: SplayTree, parent: SplayTree) { + public func rotate(child: SplayTree, parent: SplayTree) { assert(child.parent != nil && child.parent!.value == parent.value, "Parent and child.parent should match here") @@ -95,16 +95,22 @@ public enum SplayOperation { child.right = parent parent.left = grandchildToMode + + } else { grandchildToMode = child.left child.left = parent parent.right = grandchildToMode - } + } + let grandParent = parent.parent parent.parent = child child.parent = grandParent + + grandParent?.left = child + } } @@ -210,9 +216,15 @@ public class SplayTree { extension SplayTree { /* - Inserts a new element into the tree. You should only insert elements - at the root, to make to sure this remains a valid binary tree! - Performance: runs in O(h) time, where h is the height of the tree. + Inserts a new element into the tree. + Returns the new Tree generated by the insertion. + + - Parameters: + - value T value to be inserted. Will be splayed to the root position + + - Returns + - SplayTree Containing the inserted value in the root node + */ public func insert(value: T) -> SplayTree? { if let selfValue = self.value { @@ -255,14 +267,17 @@ extension SplayTree { // MARK: - Deleting items extension SplayTree { + /* - Deletes a node from the tree. - Returns the node that has replaced this removed one (or nil if this was a - leaf node). That is primarily useful for when you delete the root node, in - which case the tree gets a new root. - Performance: runs in O(h) time, where h is the height of the tree. + Deletes the given node from the tree. + Return the new tree generated by the removal. + The removed node (not necessarily the one containing the value), will be splayed to the root. + + - Returns: + - SplayTree Resulting from the deletion and the splaying of the removed node + */ - @discardableResult public func remove() -> SplayTree? { + public func remove() -> SplayTree? { let replacement: SplayTree? if let left = left { @@ -521,11 +536,13 @@ extension SplayTree: CustomStringConvertible { public var description: String { var s = "" if let left = left { - s += "(\(left.description)) <- " + s += "left: (\(left.description)) <- " + } + if let v = value { + s += "\(v)" } - s += "\(value)" if let right = right { - s += " -> (\(right.description))" + s += " -> (right: \(right.description))" } return s } @@ -534,8 +551,8 @@ extension SplayTree: CustomStringConvertible { extension SplayTree: CustomDebugStringConvertible { public var debugDescription: String { var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" + if let parent = parent, let v = parent.value { + s += ", parent: \(v)" } if let left = left { s += ", left = [" + left.debugDescription + "]" diff --git a/Splay Tree/Tests/SplayTreeTests.swift b/Splay Tree/Tests/SplayTreeTests.swift index 35bdedb71..998c6d3c4 100644 --- a/Splay Tree/Tests/SplayTreeTests.swift +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -1,19 +1,30 @@ import XCTest class SplayTreeTests: XCTestCase { - var tree: SplayTree! - - override func setUp() { - super.setUp() - tree = SplayTree(value: 1) - } - - func testElements() { - print(tree) - let tree1 = tree.insert(value: 10) - print(tree1!) - let tree2 = tree1!.insert(value: 2) - print(tree2!) - } - + + var tree: SplayTree! + var tree1: SplayTree! + + override func setUp() { + super.setUp() + tree = SplayTree(value: 1) + tree1 = tree.insert(value: 10)?.insert(value: 20)?.insert(value: 3)//?.insert(value: 6)?.insert(value: 100)?.insert(value: 44) + } + + func testInsertion() { + let tree1 = tree.insert(value: 10) + assert(tree1?.root?.value == 10) + + let tree2 = tree1!.insert(value: 2) + assert(tree2?.root?.value == 2) + } + + + func testDeleteExisting() { + print(tree1) + let tree2 = tree1.search(value: 6)?.remove() + + } + + } From 72740a17e7bd9b74716e32f1ef9ef4a92534b302 Mon Sep 17 00:00:00 2001 From: barbara Date: Sat, 4 Mar 2017 09:20:25 +0100 Subject: [PATCH 0437/1275] Test for search function + fixes for rotations --- Splay Tree/SplayTree.swift | 17 +++++++++-------- Splay Tree/Tests/SplayTreeTests.swift | 7 ++++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift index 2e008ba50..bbe8491e2 100644 --- a/Splay Tree/SplayTree.swift +++ b/Splay Tree/SplayTree.swift @@ -94,7 +94,7 @@ public enum SplayOperation { grandchildToMode = child.right child.right = parent parent.left = grandchildToMode - + grandchildToMode?.parent = parent } else { @@ -102,6 +102,7 @@ public enum SplayOperation { grandchildToMode = child.left child.left = parent parent.right = grandchildToMode + grandchildToMode?.parent = parent } @@ -368,23 +369,23 @@ extension SplayTree { */ public func search(value: T) -> SplayTree? { var node: SplayTree? = self + var nodeParent: SplayTree? = self while case let n? = node, n.value != nil { if value < n.value! { + if n.left != nil { nodeParent = n.left } node = n.left } else if value > n.value! { node = n.right - } else { - - if let node = node { - SplayOperation.splay(node: node) - } - - return node + if n.right != nil { nodeParent = n.right } } } if let node = node { SplayOperation.splay(node: node) + return node + } else if let nodeParent = nodeParent { + SplayOperation.splay(node: nodeParent) + return nodeParent } return nil diff --git a/Splay Tree/Tests/SplayTreeTests.swift b/Splay Tree/Tests/SplayTreeTests.swift index 998c6d3c4..042344193 100644 --- a/Splay Tree/Tests/SplayTreeTests.swift +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -8,7 +8,7 @@ class SplayTreeTests: XCTestCase { override func setUp() { super.setUp() tree = SplayTree(value: 1) - tree1 = tree.insert(value: 10)?.insert(value: 20)?.insert(value: 3)//?.insert(value: 6)?.insert(value: 100)?.insert(value: 44) + tree1 = tree.insert(value: 10)?.insert(value: 20)?.insert(value: 3)?.insert(value: 6)?.insert(value: 100)?.insert(value: 44) } func testInsertion() { @@ -20,9 +20,10 @@ class SplayTreeTests: XCTestCase { } - func testDeleteExisting() { + func testSearchNonExisting() { print(tree1) - let tree2 = tree1.search(value: 6)?.remove() + let tree2 = tree1.search(value: 5) + assert(tree2?.root?.value == 10) } From 84e75b73e246e76fe8a22c97ef49c9d5277ea35b Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:23:31 +0100 Subject: [PATCH 0438/1275] Completing implementation + debug fixes of Splay Tree --- Splay Tree/SplayTree.swift | 321 +++++++++++++++++++++---------------- 1 file changed, 186 insertions(+), 135 deletions(-) diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift index bbe8491e2..f50af7349 100644 --- a/Splay Tree/SplayTree.swift +++ b/Splay Tree/SplayTree.swift @@ -28,7 +28,7 @@ public enum SplayOperation { - Parameters: - node SplayTree node to move up to the root */ - public static func splay(node: SplayTree) { + public static func splay(node: Node) { while (node.parent != nil) { operation(forNode: node).apply(onNode: node) @@ -44,7 +44,7 @@ public enum SplayOperation { - Returns - Operation Case zigZag - zigZig - zig */ - public static func operation(forNode node: SplayTree) -> SplayOperation { + public static func operation(forNode node: Node) -> SplayOperation { if let parent = node.parent, let _ = parent.parent { if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { @@ -62,7 +62,7 @@ public enum SplayOperation { - Parameters: - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent */ - public func apply(onNode node: SplayTree) { + public func apply(onNode node: Node) { switch self { case .zigZag: assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") @@ -84,95 +84,65 @@ public enum SplayOperation { Performs a single rotation from a node to its parent re-arranging the children properly */ - public func rotate(child: SplayTree, parent: SplayTree) { + public func rotate(child: Node, parent: Node) { assert(child.parent != nil && child.parent!.value == parent.value, "Parent and child.parent should match here") - var grandchildToMode: SplayTree? + var grandchildToMode: Node? + if child.isLeftChild { grandchildToMode = child.right - child.right = parent parent.left = grandchildToMode grandchildToMode?.parent = parent + + let grandParent = parent.parent + child.parent = grandParent + + if parent.isLeftChild { + grandParent?.left = child + } else { + grandParent?.right = child + } + + child.right = parent + parent.parent = child } else { grandchildToMode = child.left - child.left = parent parent.right = grandchildToMode grandchildToMode?.parent = parent + let grandParent = parent.parent + child.parent = grandParent + + if parent.isLeftChild { + grandParent?.left = child + } else { + grandParent?.right = child + } + + child.left = parent + parent.parent = child + } - let grandParent = parent.parent - parent.parent = child - child.parent = grandParent - - grandParent?.left = child } } public class Node { - fileprivate(set) public var value: T - fileprivate(set) public var parent: SplayTree? - fileprivate(set) public var left: SplayTree? - fileprivate(set) public var right: SplayTree? + fileprivate(set) public var value: T? + fileprivate(set) public var parent: Node? + fileprivate(set) public var left: Node? + fileprivate(set) public var right: Node? - init(value: T){ + init(value: T) { self.value = value } -} - -public class SplayTree { - - - fileprivate(set) public var root: Node? - public var value: T? { - get { - return root?.value - } - set { - if let value = newValue { - root?.value = value - } - } - } - - fileprivate(set) public var parent: SplayTree? { - get { - return root?.parent - } - set { - root?.parent = newValue - } - } - - fileprivate(set) public var left: SplayTree? { - get { - return root?.left - } - set { - root?.left = newValue - } - } - fileprivate(set) public var right: SplayTree? { - get { - return root?.right - } - set { - root?.right = newValue - } - } - - //MARK: - Initializer - - public init(value: T) { - self.root = Node(value:value) - } public var isRoot: Bool { return parent == nil @@ -212,29 +182,66 @@ public class SplayTree { } } +public class SplayTree { + + internal var root: Node? + + var value: T? { + return root?.value + } + + //MARK: - Initializer + + public init(value: T) { + self.root = Node(value:value) + } + + public func insert(value: T) { + root = root?.insert(value: value) + } + + public func remove(value: T) { + root = root?.remove(value: value) + } + + public func search(value: T) -> Node? { + root = root?.search(value: value) + return root + } + + public func minimum() -> Node? { + root = root?.minimum(splayed: true) + return root + } + + public func maximum() -> Node? { + root = root?.maximum(splayed: true) + return root + } + +} + // MARK: - Adding items -extension SplayTree { +extension Node { /* - Inserts a new element into the tree. - Returns the new Tree generated by the insertion. + Inserts a new element into the node tree. - Parameters: - value T value to be inserted. Will be splayed to the root position - - Returns - - SplayTree Containing the inserted value in the root node - + - Returns: + - Node inserted */ - public func insert(value: T) -> SplayTree? { + public func insert(value: T) -> Node { if let selfValue = self.value { if value < selfValue { if let left = left { return left.insert(value: value) } else { - left = SplayTree(value: value) + left = Node(value: value) left?.parent = self if let left = left { @@ -248,7 +255,7 @@ extension SplayTree { return right.insert(value: value) } else { - right = SplayTree(value: value) + right = Node(value: value) right?.parent = self if let right = right { @@ -257,78 +264,104 @@ extension SplayTree { } } } - } else { - self.root = Node(value: value) - return self } - return nil + return self } } // MARK: - Deleting items -extension SplayTree { +extension Node { /* - Deletes the given node from the tree. + Deletes the given node from the nodes tree. Return the new tree generated by the removal. The removed node (not necessarily the one containing the value), will be splayed to the root. + - Parameters: + - value To be removed + - Returns: - - SplayTree Resulting from the deletion and the splaying of the removed node + - Node Resulting from the deletion and the splaying of the removed node */ - public func remove() -> SplayTree? { - let replacement: SplayTree? + public func remove(value: T) -> Node? { + let replacement: Node? - if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) + if let v = self.value, v == value { + + var parentToSplay: Node? + if let left = left { + if let right = right { + + replacement = removeNodeWithTwoChildren(left, right) + + if let replacement = replacement, + let replacementParent = replacement.parent, + replacementParent.value != self.value { + + parentToSplay = replacement.parent + + } else { + parentToSplay = self.parent + } + + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + parentToSplay = parent + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + parentToSplay = parent } else { - // This node only has a left child. The left child replaces the node. - replacement = left + // This node has no children. We just disconnect it from its parent. + replacement = nil + parentToSplay = parent } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - } + + reconnectParentTo(node: replacement) + + // performs the splay operation + if let parentToSplay = parentToSplay { + SplayOperation.splay(node: parentToSplay) + } + + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil - // Save the parent to splay before reconnecting - var parentToSplay: SplayTree? - if let replacement = replacement { - parentToSplay = replacement.parent + return parentToSplay + + } else if let v = self.value, value < v { + if left != nil { + return left!.remove(value: value) + } else { + let node = self + SplayOperation.splay(node: node) + return node + + } } else { - parentToSplay = self.parent - } - - reconnectParentTo(node: replacement) - - // performs the splay operation - if let parentToSplay = parentToSplay { - SplayOperation.splay(node: parentToSplay) + if right != nil { + return right?.remove(value: value) + } else { + let node = self + SplayOperation.splay(node: node) + return node + + } } - - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - - return replacement } - private func removeNodeWithTwoChildren(_ left: SplayTree, _ right: SplayTree) -> SplayTree { + private func removeNodeWithTwoChildren(_ left: Node, _ right: Node) -> Node { // This node has two children. It must be replaced by the smallest // child that is larger than this node's value, which is the leftmost // descendent of the right child. let successor = right.minimum() - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() - // Connect our left child with the new node. successor.left = left left.parent = successor @@ -347,7 +380,7 @@ extension SplayTree { return successor } - private func reconnectParentTo(node: SplayTree?) { + private func reconnectParentTo(node: Node?) { if let parent = parent { if isLeftChild { parent.left = node @@ -361,15 +394,15 @@ extension SplayTree { // MARK: - Searching -extension SplayTree { +extension Node { /* Finds the "highest" node with the specified value. Performance: runs in O(h) time, where h is the height of the tree. */ - public func search(value: T) -> SplayTree? { - var node: SplayTree? = self - var nodeParent: SplayTree? = self + public func search(value: T) -> Node? { + var node: Node? = self + var nodeParent: Node? = self while case let n? = node, n.value != nil { if value < n.value! { if n.left != nil { nodeParent = n.left } @@ -377,6 +410,8 @@ extension SplayTree { } else if value > n.value! { node = n.right if n.right != nil { nodeParent = n.right } + } else { + break } } @@ -398,27 +433,31 @@ extension SplayTree { /* Returns the leftmost descendent. O(h) time. */ - public func minimum() -> SplayTree { + public func minimum(splayed: Bool = false) -> Node { var node = self while case let next? = node.left { node = next } - SplayOperation.splay(node: node) - + if splayed == true { + SplayOperation.splay(node: node) + } + return node } /* Returns the rightmost descendent. O(h) time. */ - public func maximum() -> SplayTree { + public func maximum(splayed: Bool = false) -> Node { var node = self while case let next? = node.right { node = next } - SplayOperation.splay(node: node) + if splayed == true { + SplayOperation.splay(node: node) + } return node } @@ -452,7 +491,7 @@ extension SplayTree { /* Finds the node whose value precedes our value in sorted order. */ - public func predecessor() -> SplayTree? { + public func predecessor() -> Node? { if let left = left { return left.maximum() } else { @@ -468,7 +507,7 @@ extension SplayTree { /* Finds the node whose value succeeds our value in sorted order. */ - public func successor() -> SplayTree? { + public func successor() -> Node? { if let right = right { return right.minimum() } else { @@ -483,7 +522,7 @@ extension SplayTree { } // MARK: - Traversal -extension SplayTree { +extension Node { public func traverseInOrder(process: (T) -> Void) { left?.traverseInOrder(process: process) @@ -518,7 +557,7 @@ extension SplayTree { /* Is this binary tree a valid binary search tree? */ -extension SplayTree { +extension Node { public func isBST(minValue: T, maxValue: T) -> Bool { if let value = value { @@ -533,7 +572,7 @@ extension SplayTree { // MARK: - Debugging -extension SplayTree: CustomStringConvertible { +extension Node: CustomStringConvertible { public var description: String { var s = "" if let left = left { @@ -549,7 +588,13 @@ extension SplayTree: CustomStringConvertible { } } -extension SplayTree: CustomDebugStringConvertible { +extension SplayTree: CustomStringConvertible { + public var description: String { + return root?.description ?? "Empty tree" + } +} + +extension Node: CustomDebugStringConvertible { public var debugDescription: String { var s = "value: \(value)" if let parent = parent, let v = parent.value { @@ -568,3 +613,9 @@ extension SplayTree: CustomDebugStringConvertible { return map { $0 } } } + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root?.debugDescription ?? "Empty tree" + } +} From efa2f4856c6e80ccd36e8de11f3fb279974d9e3e Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:23:43 +0100 Subject: [PATCH 0439/1275] Tests for max, min, search, insert and remove --- Splay Tree/Tests/SplayTreeTests.swift | 52 ++++++++++++++++++++------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/Splay Tree/Tests/SplayTreeTests.swift b/Splay Tree/Tests/SplayTreeTests.swift index 042344193..0209f8afe 100644 --- a/Splay Tree/Tests/SplayTreeTests.swift +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -2,30 +2,58 @@ import XCTest class SplayTreeTests: XCTestCase { - var tree: SplayTree! var tree1: SplayTree! + var tree2: SplayTree! override func setUp() { super.setUp() - tree = SplayTree(value: 1) - tree1 = tree.insert(value: 10)?.insert(value: 20)?.insert(value: 3)?.insert(value: 6)?.insert(value: 100)?.insert(value: 44) + tree1 = SplayTree(value: 1) + + tree2 = SplayTree(value: 1) + tree2.insert(value: 10) + tree2.insert(value: 20) + tree2.insert(value: 3) + tree2.insert(value: 6) + tree2.insert(value: 100) + tree2.insert(value: 44) } func testInsertion() { - let tree1 = tree.insert(value: 10) - assert(tree1?.root?.value == 10) + tree1.insert(value: 10) + assert(tree1.value == 10) - let tree2 = tree1!.insert(value: 2) - assert(tree2?.root?.value == 2) + tree2.insert(value: 2) + assert(tree2.root?.value == 2) } - func testSearchNonExisting() { - print(tree1) - let tree2 = tree1.search(value: 5) - assert(tree2?.root?.value == 10) - + let t = tree2.search(value: 5) + assert(t?.value == 10) + } + + func testSearchExisting() { + let t = tree2.search(value: 6) + assert(t?.value == 6) + } + + func testDeleteExistingOnlyLeftChild() { + tree2.remove(value: 3) + assert(tree2.value == 6) + } + + func testDeleteExistingOnly2Children() { + tree2.remove(value: 6) + assert(tree2.value == 20) } + func testMinimum() { + let v = tree2.minimum() + assert(v?.value == 1) + } + + func testMaximum() { + let v = tree2.maximum() + assert(v?.value == 100) + } } From c27fdde75dc064f55ea7dfdcd5c7d0d4a44aaea6 Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:24:22 +0100 Subject: [PATCH 0440/1275] Replacing SplayTree implementation inside Playground --- .../Sources/SplayTree.swift | 398 +++++++++++------- 1 file changed, 255 insertions(+), 143 deletions(-) diff --git a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift index f0c45e831..f50af7349 100644 --- a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift +++ b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift @@ -28,7 +28,7 @@ public enum SplayOperation { - Parameters: - node SplayTree node to move up to the root */ - public static func splay(node: SplayTree) { + public static func splay(node: Node) { while (node.parent != nil) { operation(forNode: node).apply(onNode: node) @@ -44,10 +44,10 @@ public enum SplayOperation { - Returns - Operation Case zigZag - zigZig - zig */ - private static func operation(forNode node: SplayTree) -> SplayOperation { + public static func operation(forNode node: Node) -> SplayOperation { - if let parent = node.parent, let grandParent = parent.parent { - if (node.isLeftChild && grandParent.isRightChild) || (node.isRightChild && grandParent.isLeftChild) { + if let parent = node.parent, let _ = parent.parent { + if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { return .zigZag } return .zigZig @@ -62,7 +62,7 @@ public enum SplayOperation { - Parameters: - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent */ - private func apply(onNode node: SplayTree) { + public func apply(onNode node: Node) { switch self { case .zigZag: assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") @@ -84,49 +84,66 @@ public enum SplayOperation { Performs a single rotation from a node to its parent re-arranging the children properly */ - private func rotate(child: SplayTree, parent: SplayTree) { + public func rotate(child: Node, parent: Node) { assert(child.parent != nil && child.parent!.value == parent.value, "Parent and child.parent should match here") - var grandchildToMode: SplayTree? + var grandchildToMode: Node? + if child.isLeftChild { grandchildToMode = child.right - child.right = parent parent.left = grandchildToMode - + grandchildToMode?.parent = parent + + let grandParent = parent.parent + child.parent = grandParent + + if parent.isLeftChild { + grandParent?.left = child + } else { + grandParent?.right = child + } + + child.right = parent + parent.parent = child + + } else { grandchildToMode = child.left - child.left = parent parent.right = grandchildToMode + grandchildToMode?.parent = parent + + let grandParent = parent.parent + child.parent = grandParent + + if parent.isLeftChild { + grandParent?.left = child + } else { + grandParent?.right = child + } + + child.left = parent + parent.parent = child + } + - let grandParent = parent.parent - parent.parent = child - child.parent = grandParent } } -public class SplayTree { +public class Node { - fileprivate(set) public var value: T - fileprivate(set) public var parent: SplayTree? - fileprivate(set) public var left: SplayTree? - fileprivate(set) public var right: SplayTree? + fileprivate(set) public var value: T? + fileprivate(set) public var parent: Node? + fileprivate(set) public var left: Node? + fileprivate(set) public var right: Node? - public init(value: T) { + init(value: T) { self.value = value } - public convenience init(array: [T]) { - precondition(array.count > 0) - self.init(value: array.first!) - for v in array.dropFirst() { - insert(value: v) - } - } - public var isRoot: Bool { return parent == nil } @@ -165,114 +182,186 @@ public class SplayTree { } } +public class SplayTree { + + internal var root: Node? + + var value: T? { + return root?.value + } + + //MARK: - Initializer + + public init(value: T) { + self.root = Node(value:value) + } + + public func insert(value: T) { + root = root?.insert(value: value) + } + + public func remove(value: T) { + root = root?.remove(value: value) + } + + public func search(value: T) -> Node? { + root = root?.search(value: value) + return root + } + + public func minimum() -> Node? { + root = root?.minimum(splayed: true) + return root + } + + public func maximum() -> Node? { + root = root?.maximum(splayed: true) + return root + } + +} + // MARK: - Adding items -extension SplayTree { +extension Node { /* - Inserts a new element into the tree. You should only insert elements - at the root, to make to sure this remains a valid binary tree! - Performance: runs in O(h) time, where h is the height of the tree. + Inserts a new element into the node tree. + + - Parameters: + - value T value to be inserted. Will be splayed to the root position + + - Returns: + - Node inserted */ - public func insert(value: T) { - if value < self.value { - if let left = left { - left.insert(value: value) - } else { - - left = SplayTree(value: value) - left?.parent = self - + public func insert(value: T) -> Node { + if let selfValue = self.value { + if value < selfValue { if let left = left { - SplayOperation.splay(node: left) - self.parent = nil - self.value = left.value - self.left = left.left - self.right = left.right + return left.insert(value: value) + } else { + + left = Node(value: value) + left?.parent = self + + if let left = left { + SplayOperation.splay(node: left) + return left + } } - } - } else { - - if let right = right { - right.insert(value: value) } else { - right = SplayTree(value: value) - right?.parent = self - if let right = right { - SplayOperation.splay(node: right) - self.parent = nil - self.value = right.value - self.left = right.left - self.right = right.right + return right.insert(value: value) + } else { + + right = Node(value: value) + right?.parent = self + + if let right = right { + SplayOperation.splay(node: right) + return right + } } } } + return self } } // MARK: - Deleting items -extension SplayTree { +extension Node { + /* - Deletes a node from the tree. - Returns the node that has replaced this removed one (or nil if this was a - leaf node). That is primarily useful for when you delete the root node, in - which case the tree gets a new root. - Performance: runs in O(h) time, where h is the height of the tree. + Deletes the given node from the nodes tree. + Return the new tree generated by the removal. + The removed node (not necessarily the one containing the value), will be splayed to the root. + + - Parameters: + - value To be removed + + - Returns: + - Node Resulting from the deletion and the splaying of the removed node + */ - @discardableResult public func remove() -> SplayTree? { - let replacement: SplayTree? + public func remove(value: T) -> Node? { + let replacement: Node? - if let left = left { - if let right = right { - replacement = removeNodeWithTwoChildren(left, right) + if let v = self.value, v == value { + + var parentToSplay: Node? + if let left = left { + if let right = right { + + replacement = removeNodeWithTwoChildren(left, right) + + if let replacement = replacement, + let replacementParent = replacement.parent, + replacementParent.value != self.value { + + parentToSplay = replacement.parent + + } else { + parentToSplay = self.parent + } + + } else { + // This node only has a left child. The left child replaces the node. + replacement = left + parentToSplay = parent + } + } else if let right = right { + // This node only has a right child. The right child replaces the node. + replacement = right + parentToSplay = parent } else { - // This node only has a left child. The left child replaces the node. - replacement = left + // This node has no children. We just disconnect it from its parent. + replacement = nil + parentToSplay = parent } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - } + + reconnectParentTo(node: replacement) + + // performs the splay operation + if let parentToSplay = parentToSplay { + SplayOperation.splay(node: parentToSplay) + } + + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil - // Save the parent to splay before reconnecting - var parentToSplay: SplayTree? - if let replacement = replacement { - parentToSplay = replacement.parent + return parentToSplay + + } else if let v = self.value, value < v { + if left != nil { + return left!.remove(value: value) + } else { + let node = self + SplayOperation.splay(node: node) + return node + + } } else { - parentToSplay = self.parent - } - - reconnectParentTo(node: replacement) - - // performs the splay operation - if let parentToSplay = parentToSplay { - SplayOperation.splay(node: parentToSplay) + if right != nil { + return right?.remove(value: value) + } else { + let node = self + SplayOperation.splay(node: node) + return node + + } } - - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - - return replacement } - private func removeNodeWithTwoChildren(_ left: SplayTree, _ right: SplayTree) -> SplayTree { + private func removeNodeWithTwoChildren(_ left: Node, _ right: Node) -> Node { // This node has two children. It must be replaced by the smallest // child that is larger than this node's value, which is the leftmost // descendent of the right child. let successor = right.minimum() - // If this in-order successor has a right child of its own (it cannot - // have a left child by definition), then that must take its place. - successor.remove() - // Connect our left child with the new node. successor.left = left left.parent = successor @@ -291,7 +380,7 @@ extension SplayTree { return successor } - private func reconnectParentTo(node: SplayTree?) { + private func reconnectParentTo(node: Node?) { if let parent = parent { if isLeftChild { parent.left = node @@ -305,31 +394,33 @@ extension SplayTree { // MARK: - Searching -extension SplayTree { +extension Node { /* Finds the "highest" node with the specified value. Performance: runs in O(h) time, where h is the height of the tree. */ - public func search(value: T) -> SplayTree? { - var node: SplayTree? = self - while case let n? = node { - if value < n.value { + public func search(value: T) -> Node? { + var node: Node? = self + var nodeParent: Node? = self + while case let n? = node, n.value != nil { + if value < n.value! { + if n.left != nil { nodeParent = n.left } node = n.left - } else if value > n.value { + } else if value > n.value! { node = n.right + if n.right != nil { nodeParent = n.right } } else { - - if let node = node { - SplayOperation.splay(node: node) - } - - return node + break } } if let node = node { SplayOperation.splay(node: node) + return node + } else if let nodeParent = nodeParent { + SplayOperation.splay(node: nodeParent) + return nodeParent } return nil @@ -342,27 +433,31 @@ extension SplayTree { /* Returns the leftmost descendent. O(h) time. */ - public func minimum() -> SplayTree { + public func minimum(splayed: Bool = false) -> Node { var node = self while case let next? = node.left { node = next } - SplayOperation.splay(node: node) - + if splayed == true { + SplayOperation.splay(node: node) + } + return node } /* Returns the rightmost descendent. O(h) time. */ - public func maximum() -> SplayTree { + public func maximum(splayed: Bool = false) -> Node { var node = self while case let next? = node.right { node = next } - SplayOperation.splay(node: node) + if splayed == true { + SplayOperation.splay(node: node) + } return node } @@ -396,13 +491,13 @@ extension SplayTree { /* Finds the node whose value precedes our value in sorted order. */ - public func predecessor() -> SplayTree? { + public func predecessor() -> Node? { if let left = left { return left.maximum() } else { var node = self - while case let parent? = node.parent { - if parent.value < value { return parent } + while case let parent? = node.parent, parent.value != nil, value != nil { + if parent.value! < value! { return parent } node = parent } return nil @@ -412,13 +507,13 @@ extension SplayTree { /* Finds the node whose value succeeds our value in sorted order. */ - public func successor() -> SplayTree? { + public func successor() -> Node? { if let right = right { return right.minimum() } else { var node = self - while case let parent? = node.parent { - if parent.value > value { return parent } + while case let parent? = node.parent, parent.value != nil , value != nil { + if parent.value! > value! { return parent } node = parent } return nil @@ -427,16 +522,16 @@ extension SplayTree { } // MARK: - Traversal -extension SplayTree { +extension Node { public func traverseInOrder(process: (T) -> Void) { left?.traverseInOrder(process: process) - process(value) + process(value!) right?.traverseInOrder(process: process) } public func traversePreOrder(process: (T) -> Void) { - process(value) + process(value!) left?.traversePreOrder(process: process) right?.traversePreOrder(process: process) } @@ -444,7 +539,7 @@ extension SplayTree { public func traversePostOrder(process: (T) -> Void) { left?.traversePostOrder(process: process) right?.traversePostOrder(process: process) - process(value) + process(value!) } /* @@ -453,7 +548,7 @@ extension SplayTree { public func map(formula: (T) -> T) -> [T] { var a = [T]() if let left = left { a += left.map(formula: formula) } - a.append(formula(value)) + a.append(formula(value!)) if let right = right { a += right.map(formula: formula) } return a } @@ -462,37 +557,48 @@ extension SplayTree { /* Is this binary tree a valid binary search tree? */ -extension SplayTree { +extension Node { 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 - return leftBST && rightBST + if let value = value { + 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 + return leftBST && rightBST + } + return false } } // MARK: - Debugging -extension SplayTree: CustomStringConvertible { +extension Node: CustomStringConvertible { public var description: String { var s = "" if let left = left { - s += "(\(left.description)) <- " + s += "left: (\(left.description)) <- " + } + if let v = value { + s += "\(v)" } - s += "\(value)" if let right = right { - s += " -> (\(right.description))" + s += " -> (right: \(right.description))" } return s } } -extension SplayTree: CustomDebugStringConvertible { +extension SplayTree: CustomStringConvertible { + public var description: String { + return root?.description ?? "Empty tree" + } +} + +extension Node: CustomDebugStringConvertible { public var debugDescription: String { var s = "value: \(value)" - if let parent = parent { - s += ", parent: \(parent.value)" + if let parent = parent, let v = parent.value { + s += ", parent: \(v)" } if let left = left { s += ", left = [" + left.debugDescription + "]" @@ -507,3 +613,9 @@ extension SplayTree: CustomDebugStringConvertible { return map { $0 } } } + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root?.debugDescription ?? "Empty tree" + } +} From 4aaec9d94b5b6a5c75b07c35fd0e4def6830ac44 Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:38:15 +0100 Subject: [PATCH 0441/1275] Test for root removal and multiple operations executed --- Splay Tree/Tests/SplayTreeTests.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Splay Tree/Tests/SplayTreeTests.swift b/Splay Tree/Tests/SplayTreeTests.swift index 0209f8afe..01201a108 100644 --- a/Splay Tree/Tests/SplayTreeTests.swift +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -46,6 +46,11 @@ class SplayTreeTests: XCTestCase { assert(tree2.value == 20) } + func testDeleteRoot() { + tree2.remove(value: 44) + assert(tree2.value == 100) + } + func testMinimum() { let v = tree2.minimum() assert(v?.value == 1) @@ -56,4 +61,16 @@ class SplayTreeTests: XCTestCase { assert(v?.value == 100) } + func testInsertionRemovals() { + let splayTree = SplayTree(value: 1) + splayTree.insert(value: 2) + splayTree.insert(value: 10) + splayTree.insert(value: 6) + + splayTree.remove(value: 10) + splayTree.remove(value: 6) + + assert(splayTree.value == 2) + } + } From 9da711ddf62bdc9b77d73ad64da8285a94f2b4cc Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:38:47 +0100 Subject: [PATCH 0442/1275] Fixes for root removal & insertions with nil root --- .../Sources/SplayTree.swift | 106 ++++++++++-------- Splay Tree/SplayTree.swift | 22 +++- 2 files changed, 78 insertions(+), 50 deletions(-) diff --git a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift index f50af7349..a4feda7ef 100644 --- a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift +++ b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift @@ -1,5 +1,5 @@ /* - * Splay Tree + * Splay Tree * * Based on Binary Search Tree Implementation written by Nicolas Ameghino and Matthijs Hollemans for Swift Algorithms Club * https://github.com/raywenderlich/swift-algorithm-club/blob/master/Binary%20Search%20Tree @@ -8,12 +8,12 @@ */ /** - Represent the 3 possible operations (combinations of rotations) that - could be performed during the Splay phase in Splay Trees + Represent the 3 possible operations (combinations of rotations) that + could be performed during the Splay phase in Splay Trees - - zigZag Left child of a right child OR right child of a left child - - zigZig Left child of a left child OR right child of a right child - - zig Only 1 parent and that parent is the root + - zigZag Left child of a right child OR right child of a left child + - zigZig Left child of a left child OR right child of a right child + - zig Only 1 parent and that parent is the root */ public enum SplayOperation { @@ -23,10 +23,10 @@ public enum SplayOperation { /** - Splay the given node up to the root of the tree + Splay the given node up to the root of the tree - - Parameters: - - node SplayTree node to move up to the root + - Parameters: + - node SplayTree node to move up to the root */ public static func splay(node: Node) { @@ -36,13 +36,13 @@ public enum SplayOperation { } /** - Compares the node and its parent and determine - if the rotations should be performed in a zigZag, zigZig or zig case. + Compares the node and its parent and determine + if the rotations should be performed in a zigZag, zigZig or zig case. - - Parmeters: - - forNode SplayTree node to be checked - - Returns - - Operation Case zigZag - zigZig - zig + - Parmeters: + - forNode SplayTree node to be checked + - Returns + - Operation Case zigZag - zigZig - zig */ public static func operation(forNode node: Node) -> SplayOperation { @@ -56,11 +56,11 @@ public enum SplayOperation { } /** - Applies the rotation associated to the case - Modifying the splay tree and briging the received node further to the top of the tree + Applies the rotation associated to the case + Modifying the splay tree and briging the received node further to the top of the tree - - Parameters: - - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent + - Parameters: + - onNode Node to splay up. Should be alwayas the node that needs to be splayed, neither its parent neither it's grandparent */ public func apply(onNode node: Node) { switch self { @@ -68,12 +68,12 @@ public enum SplayOperation { assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") rotate(child: node, parent: node.parent!) rotate(child: node, parent: node.parent!) - + case .zigZig: assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") rotate(child: node.parent!, parent: node.parent!.parent!) rotate(child: node, parent: node.parent!) - + case .zig: assert(node.parent != nil && node.parent!.parent == nil, "There should be a parent which is the root") rotate(child: node, parent: node.parent!) @@ -81,8 +81,8 @@ public enum SplayOperation { } /** - Performs a single rotation from a node to its parent - re-arranging the children properly + Performs a single rotation from a node to its parent + re-arranging the children properly */ public func rotate(child: Node, parent: Node) { @@ -95,41 +95,41 @@ public enum SplayOperation { grandchildToMode = child.right parent.left = grandchildToMode grandchildToMode?.parent = parent - + let grandParent = parent.parent child.parent = grandParent - + if parent.isLeftChild { grandParent?.left = child } else { grandParent?.right = child } - + child.right = parent parent.parent = child - - + + } else { grandchildToMode = child.left parent.right = grandchildToMode grandchildToMode?.parent = parent - + let grandParent = parent.parent child.parent = grandParent - + if parent.isLeftChild { grandParent?.left = child } else { grandParent?.right = child } - + child.left = parent parent.parent = child - + } - + } } @@ -183,13 +183,13 @@ public class Node { } public class SplayTree { - + internal var root: Node? var value: T? { return root?.value } - + //MARK: - Initializer public init(value: T) { @@ -197,13 +197,17 @@ public class SplayTree { } public func insert(value: T) { - root = root?.insert(value: value) + if let root = root { + self.root = root.insert(value: value) + } else { + root = Node(value: value) + } } public func remove(value: T) { root = root?.remove(value: value) } - + public func search(value: T) -> Node? { root = root?.search(value: value) return root @@ -229,10 +233,10 @@ extension Node { Inserts a new element into the node tree. - Parameters: - - value T value to be inserted. Will be splayed to the root position + - value T value to be inserted. Will be splayed to the root position - Returns: - - Node inserted + - Node inserted */ public func insert(value: T) -> Node { if let selfValue = self.value { @@ -275,14 +279,14 @@ extension Node { /* Deletes the given node from the nodes tree. - Return the new tree generated by the removal. + Return the new tree generated by the removal. The removed node (not necessarily the one containing the value), will be splayed to the root. - Parameters: - - value To be removed + - value To be removed - Returns: - - Node Resulting from the deletion and the splaying of the removed node + - Node Resulting from the deletion and the splaying of the removed node */ public func remove(value: T) -> Node? { @@ -302,19 +306,29 @@ extension Node { parentToSplay = replacement.parent - } else { + } else if self.parent != nil { parentToSplay = self.parent + } else { + parentToSplay = replacement } } else { // This node only has a left child. The left child replaces the node. replacement = left - parentToSplay = parent + if self.parent != nil { + parentToSplay = self.parent + } else { + parentToSplay = replacement + } } } else if let right = right { // This node only has a right child. The right child replaces the node. replacement = right - parentToSplay = parent + if self.parent != nil { + parentToSplay = self.parent + } else { + parentToSplay = replacement + } } else { // This node has no children. We just disconnect it from its parent. replacement = nil @@ -332,7 +346,7 @@ extension Node { parent = nil left = nil right = nil - + return parentToSplay } else if let v = self.value, value < v { diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift index f50af7349..a7b20743d 100644 --- a/Splay Tree/SplayTree.swift +++ b/Splay Tree/SplayTree.swift @@ -197,7 +197,11 @@ public class SplayTree { } public func insert(value: T) { - root = root?.insert(value: value) + if let root = root { + self.root = root.insert(value: value) + } else { + root = Node(value: value) + } } public func remove(value: T) { @@ -302,19 +306,29 @@ extension Node { parentToSplay = replacement.parent - } else { + } else if self.parent != nil { parentToSplay = self.parent + } else { + parentToSplay = replacement } } else { // This node only has a left child. The left child replaces the node. replacement = left - parentToSplay = parent + if self.parent != nil { + parentToSplay = self.parent + } else { + parentToSplay = replacement + } } } else if let right = right { // This node only has a right child. The right child replaces the node. replacement = right - parentToSplay = parent + if self.parent != nil { + parentToSplay = self.parent + } else { + parentToSplay = replacement + } } else { // This node has no children. We just disconnect it from its parent. replacement = nil From ecba738935641768526277d908153adc3f9d8ca6 Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 5 Mar 2017 19:38:55 +0100 Subject: [PATCH 0443/1275] Playground Splay Tree --- .../SplayTree.playground/Contents.swift | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Splay Tree/SplayTree.playground/Contents.swift b/Splay Tree/SplayTree.playground/Contents.swift index 951ad4c5c..4406a759d 100644 --- a/Splay Tree/SplayTree.playground/Contents.swift +++ b/Splay Tree/SplayTree.playground/Contents.swift @@ -1,7 +1,29 @@ //: Playground - Splay Tree Implementation -let splayTree = SplayTree(array: [1]) +let splayTree = SplayTree(value: 1) splayTree.insert(value: 2) splayTree.insert(value: 10) splayTree.insert(value: 6) + +splayTree.remove(value: 10) +splayTree.remove(value: 6) + +splayTree.insert(value: 55) +splayTree.insert(value: 559) +splayTree.remove(value: 2) +splayTree.remove(value: 1) +splayTree.remove(value: 55) +splayTree.remove(value: 559) + +splayTree.insert(value: 1843000) +splayTree.insert(value: 1238) +splayTree.insert(value: -1) +splayTree.insert(value: 87) + +splayTree.minimum() +splayTree.maximum() + + + + From cae6d08a8c1ea02fdf37c6481e965b74457b0eaa Mon Sep 17 00:00:00 2001 From: vincentngo Date: Mon, 6 Mar 2017 15:15:06 -0500 Subject: [PATCH 0444/1275] Update link for radix sort --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index e2d99e2bc..dfe451478 100644 --- a/README.markdown +++ b/README.markdown @@ -80,7 +80,7 @@ Fast sorts: Special-purpose sorts: - [Counting Sort](Counting Sort/) -- Radix Sort +- [Radix Sort](Radix Sort/) - [Topological Sort](Topological Sort/) Bad sorting algorithms (don't use these!): From ce1ec8842561fb69c02f835278539f4bab287a8e Mon Sep 17 00:00:00 2001 From: "JUNYEONG.YOO" Date: Tue, 7 Mar 2017 19:31:50 +0900 Subject: [PATCH 0445/1275] Modified typo in README.md of QuickSort --- Quicksort/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Quicksort/README.markdown b/Quicksort/README.markdown index e3d284333..d359ecb5c 100644 --- a/Quicksort/README.markdown +++ b/Quicksort/README.markdown @@ -30,7 +30,7 @@ Here's how it works. When given an array, `quicksort()` splits it up into three All the elements less than the pivot go into a new array called `less`. All the elements equal to the pivot go into the `equal` array. And you guessed it, all elements greater than the pivot go into the third array, `greater`. This is why the generic type `T` must be `Comparable`, so we can compare the elements with `<`, `==`, and `>`. -Once we have these three arrays, `quicksort()` recursively sorts the `less` array and the `right` array, then glues those sorted subarrays back together with the `equal` array to get the final result. +Once we have these three arrays, `quicksort()` recursively sorts the `less` array and the `greater` array, then glues those sorted subarrays back together with the `equal` array to get the final result. ## An example @@ -44,7 +44,7 @@ First, we pick the pivot element. That is `8` because it's in the middle of the equal: [ 8, 8 ] greater: [ 10, 9, 14, 27, 26 ] -This is a good split because `less` and `equal` roughly contain the same number of elements. So we've picked a good pivot that chopped the array right down the middle. +This is a good split because `less` and `greater` roughly contain the same number of elements. So we've picked a good pivot that chopped the array right down the middle. Note that the `less` and `greater` arrays aren't sorted yet, so we call `quicksort()` again to sort those two subarrays. That does the exact same thing: pick a pivot and split the subarray into three even smaller parts. From 7a5700dbae300b075195842482cb74981ae5fc9e Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Wed, 8 Mar 2017 19:44:06 -0500 Subject: [PATCH 0446/1275] added ExpressibleByArrayLiteral to the Linked List and wrote test for the new initializer. --- .../LinkedList.playground/Contents.swift | 22 +++++++++++++++++-- Linked List/LinkedList.swift | 10 ++++++++- Linked List/Tests/LinkedListTests.swift | 22 +++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index a90b7180c..1f7aa7dae 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -10,7 +10,7 @@ public class LinkedListNode { } } -public class LinkedList { +public final class LinkedList { public typealias Node = LinkedListNode fileprivate var head: Node? @@ -187,7 +187,7 @@ extension LinkedList { } } -extension LinkedList { +extension LinkedList: ExpressibleByArrayLiteral { convenience init(array: Array) { self.init() @@ -195,6 +195,14 @@ extension LinkedList { self.append(element) } } + + public convenience init(arrayLiteral elements: T...) { + self.init() + + for element in elements { + self.append(element) + } + } } let list = LinkedList() @@ -255,3 +263,13 @@ list[0] // "Swift" list.remove(atIndex: 0) // "Swift" list.count // 0 + +let linkedList: LinkedList = [1, 2, 3, 4] // [1, 2, 3, 4] +linkedList.count // 4 +linkedList[0] // 1 + +// Infer the type from the array +let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] +listArrayLiteral2.count // 3 +listArrayLiteral2[0] // "Swift" +listArrayLiteral2.removeLast() // "Club" diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 83f898f6c..792215a72 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -8,7 +8,7 @@ public class LinkedListNode { } } -public class LinkedList { +public final class LinkedList: ExpressibleByArrayLiteral { public typealias Node = LinkedListNode fileprivate var head: Node? @@ -203,4 +203,12 @@ extension LinkedList { self.append(element) } } + + public convenience init(arrayLiteral elements: T...) { + self.init() + + for element in elements { + self.append(element) + } + } } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 367ec8c6b..6f58d9775 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -248,4 +248,26 @@ class LinkedListTest: XCTestCase { 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) + } } From 6863590f96aa24a004af813f6c82272267c5b742 Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Wed, 8 Mar 2017 19:53:20 -0500 Subject: [PATCH 0447/1275] implemented the ExpressibleByArrayLiteral for the Linked List in a new extension instead of the class declaration for readability --- .../LinkedList.playground/Contents.swift | 80 +++++++++++-------- Linked List/LinkedList.swift | 16 ++-- 2 files changed, 55 insertions(+), 41 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 1f7aa7dae..ed46331d8 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -4,7 +4,7 @@ public class LinkedListNode { var value: T var next: LinkedListNode? weak var previous: LinkedListNode? - + public init(value: T) { self.value = value } @@ -12,17 +12,19 @@ public class LinkedListNode { public final class LinkedList { public typealias Node = LinkedListNode - + fileprivate var head: Node? - + + public init() {} + public var isEmpty: Bool { return head == nil } - + public var first: Node? { return head } - + public var last: Node? { if var node = head { while case let next? = node.next { @@ -33,7 +35,7 @@ public final class LinkedList { return nil } } - + public var count: Int { if var node = head { var c = 1 @@ -46,7 +48,7 @@ public final class LinkedList { return 0 } } - + public func node(atIndex index: Int) -> Node? { if index >= 0 { var node = head @@ -59,15 +61,19 @@ public final class LinkedList { } return nil } - + public subscript(index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) return node!.value } - + public func append(_ value: T) { let newNode = Node(value: value) + self.append(newNode) + } + + public func append(_ newNode: Node) { if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -75,64 +81,68 @@ public final class LinkedList { head = newNode } } - + 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 (prev, next) = nodesBeforeAndAfter(index: index) - let newNode = Node(value: value) + self.insert(newNode, atIndex: index) + } + + public func insert(_ newNode: Node, atIndex index: Int) { + let (prev, next) = nodesBeforeAndAfter(index: index) + newNode.previous = prev newNode.next = next prev?.next = newNode next?.previous = newNode - + if prev == nil { head = newNode } } - + public func removeAll() { head = nil } - - public func remove(node: Node) -> T { + + @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 } - - public func removeLast() -> T { + + @discardableResult public func removeLast() -> T { assert(!isEmpty) return remove(node: last!) } - - public func remove(atIndex index: Int) -> T { + + @discardableResult public func remove(atIndex index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) return remove(node: node!) @@ -173,7 +183,7 @@ extension LinkedList { } return result } - + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head @@ -187,21 +197,23 @@ extension LinkedList { } } -extension LinkedList: ExpressibleByArrayLiteral { +extension LinkedList { convenience init(array: Array) { self.init() - + for element in array { self.append(element) } } - +} + +extension LinkedList: ExpressibleByArrayLiteral { public convenience init(arrayLiteral elements: T...) { - self.init() + self.init() - for element in elements { - self.append(element) - } + for element in elements { + self.append(element) + } } } diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 792215a72..53dc77a06 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -8,7 +8,7 @@ public class LinkedListNode { } } -public final class LinkedList: ExpressibleByArrayLiteral { +public final class LinkedList { public typealias Node = LinkedListNode fileprivate var head: Node? @@ -203,12 +203,14 @@ extension LinkedList { self.append(element) } } - - public convenience init(arrayLiteral elements: T...) { - self.init() +} + +extension LinkedList: ExpressibleByArrayLiteral { + public convenience init(arrayLiteral elements: T...) { + self.init() - for element in elements { - self.append(element) - } + for element in elements { + self.append(element) } + } } From 345f8441b64003258779cd3fed692c5549a4cbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Thu, 9 Mar 2017 18:35:26 +0800 Subject: [PATCH 0448/1275] add SelectionSamplingExample.swift --- .../SelectionSamplingExample.swift | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Selection Sampling/SelectionSamplingExample.swift diff --git a/Selection Sampling/SelectionSamplingExample.swift b/Selection Sampling/SelectionSamplingExample.swift new file mode 100644 index 000000000..66648a934 --- /dev/null +++ b/Selection Sampling/SelectionSamplingExample.swift @@ -0,0 +1,32 @@ +// +// Select.swift +// +// +// Created by Cheer on 2017/3/9. +// +// + +import Foundation + +func select(from a: [T], count requested: Int) -> [T] { + + // if requested > a.count, will throw ==> fatal error: Index out of range + + if requested < a.count { + var arr = a + for i in 0.. the range is [0...n-1] + //So: arc4random_uniform(UInt32(arr.count - i - 2)) + (i + 1) ==> [0...arr.count - (i + 1) - 1] + (i + 1) ==> the range is [(i + 1)...arr.count - 1] + //Why start index is "(i + 1)"? Because in "swap(&A,&B)", if A's index == B's index, will throw a error: "swapping a location with itself is not supported" + + let nextIndex = Int(arc4random_uniform(UInt32(arr.count - i - 2))) + (i + 1) + swap(&arr[nextIndex], &arr[i]) + } + return Array(arr[0.. Date: Mon, 13 Mar 2017 17:00:42 +0600 Subject: [PATCH 0449/1275] Egg Drop Dynamic Problem Added --- Egg Drop Problem/EggDrop.swift | 31 +++++++++++++++++++ .../contents.xcworkspacedata | 7 +++++ 2 files changed, 38 insertions(+) create mode 100644 Egg Drop Problem/EggDrop.swift diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift new file mode 100644 index 000000000..6d0aab2a1 --- /dev/null +++ b/Egg Drop Problem/EggDrop.swift @@ -0,0 +1,31 @@ +func eggDrop(_ numberOfEggs: Int, numberOfFloors: Int) -> Int { + var eggFloor: [[Int]] = [] //egg(rows) floor(cols) array to store the solutions + var attempts: Int = 0 + + for var i in (0.. k-1 + //case 2: egg doesn't break. meaning we'll still have 'i' number of eggs, and we'll go upstairs -> j-k + attempts = 1 + max(eggFloor[i-1][k-1], eggFloor[i][j-k])//we add one taking into account the attempt we're taking at the moment + + if attempts < eggFloor[i][j]{ //finding the min + eggFloor[i][j] = attempts; + } + } + } + } + + return eggFloor[numberOfEggs][numberOfFloors] +} + +func max(_ x1: Int, _ x2: Int){ + return x1 > x2 ? x1 : x2 +} diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index b2ffce836..5ac8577f5 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,13 @@ + + + + From 5205fc8cf7ac1091448aecd9e7680b25779c9a88 Mon Sep 17 00:00:00 2001 From: Deep Parekh Date: Thu, 23 Feb 2017 00:08:21 -0500 Subject: [PATCH 0450/1275] Added checks for subscript and fixed initializer compile error --- Array2D/Array2D.playground/Contents.swift | 69 +++++++++++++---------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 7064de59c..38d4eff23 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -1,31 +1,42 @@ /* - 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. - Performance is always O(1). -*/ + 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. + Performance is always O(1). + */ public struct Array2D { - public let columns: Int - public let rows: Int - fileprivate var array: [T] - - public init(columns: Int, rows: Int, initialValue: T) { - self.columns = columns - self.rows = rows - array = .init(repeatElement(initialValue, count: rows*columns)) - } - - public subscript(column: Int, row: Int) -> T { - get { - return array[row*columns + column] + public let columns: Int + public let rows: Int + public var array: [T] + + public init(columns: Int, rows: Int, initialValue: T) { + self.columns = columns + self.rows = rows + array = [T](repeating: initialValue, count: rows*columns) } - set { - array[row*columns + column] = newValue + + public subscript(column: Int, row: Int) -> T { + get { + if isValidSubscript(column: column, row: row) { + return array[row*columns + column] + } else { + fatalError("Not a valid subscript") + } + } + set { + if isValidSubscript(column: column, row: row) { + array[row*columns + column] = newValue + } else { + fatalError("Not a valid subscript") + } + } + } + + private func isValidSubscript(column: Int, row: Int) -> Bool { + return column < columns && row < rows } - } } - // initialization var matrix = Array2D(columns: 3, rows: 5, initialValue: 0) @@ -51,13 +62,13 @@ print(matrix.array) // print out the 2D array with a reference around the grid for i in 0.. Date: Wed, 15 Mar 2017 19:48:51 -0700 Subject: [PATCH 0451/1275] availability check, native array loop for signal --- DiningPhilosophers/Sources/main.swift | 46 +++++++++++++-------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/DiningPhilosophers/Sources/main.swift b/DiningPhilosophers/Sources/main.swift index deff344b9..285402d53 100755 --- a/DiningPhilosophers/Sources/main.swift +++ b/DiningPhilosophers/Sources/main.swift @@ -7,17 +7,16 @@ // -import Foundation import Dispatch let numberOfPhilosophers = 4 struct ForkPair { - static let forksSemaphore:[DispatchSemaphore] = Array(repeating: DispatchSemaphore(value: 1), count: numberOfPhilosophers) - + static let forksSemaphore: [DispatchSemaphore] = Array(repeating: DispatchSemaphore(value: 1), count: numberOfPhilosophers) + let leftFork: DispatchSemaphore let rightFork: DispatchSemaphore - + init(leftIndex: Int, rightIndex: Int) { //Order forks by index to prevent deadlock if leftIndex > rightIndex { @@ -35,7 +34,7 @@ struct ForkPair { leftFork.wait() rightFork.wait() } - + func putDown() { //The order does not matter here leftFork.signal() @@ -47,61 +46,60 @@ struct ForkPair { struct Philosophers { let forkPair: ForkPair let philosopherIndex: Int - + var leftIndex = -1 var rightIndex = -1 - + init(philosopherIndex: Int) { leftIndex = philosopherIndex rightIndex = philosopherIndex - 1 - + if rightIndex < 0 { rightIndex += numberOfPhilosophers } self.forkPair = ForkPair(leftIndex: leftIndex, rightIndex: rightIndex) self.philosopherIndex = philosopherIndex - + print("Philosopher: \(philosopherIndex) left: \(leftIndex) right: \(rightIndex)") } - + func run() { while true { - print("Acquiring lock for Philosofer: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + print("Acquiring lock for Philosopher: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") forkPair.pickUp() print("Start Eating Philosopher: \(philosopherIndex)") //sleep(1000) - print("Releasing lock for Philosofer: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + print("Releasing lock for Philosopher: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") forkPair.putDown() } } } -// Layout of the table (P = philosopher, f = fork) for 4 Philosopher +// Layout of the table (P = philosopher, f = fork) for 4 Philosophers // P0 // f3 f0 // P3 P1 // f2 f1 // P2 - let globalSem = DispatchSemaphore(value: 0) for i in 0.. Date: Wed, 15 Mar 2017 19:53:29 -0700 Subject: [PATCH 0452/1275] links --- DiningPhilosophers/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 29b5916e9..ec1611c65 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -1,5 +1,5 @@ # Dining Philosophers -Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using GCD and Semaphore in Swift) +Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using [GCD](https://apple.github.io/swift-corelibs-libdispatch/) and [Semaphore](https://developer.apple.com/reference/dispatch/dispatchsemaphore) in Swift) Written for Swift Algorithm Club by Jacopo Mangiavacchi From a9655534e55620364e975cabb78242dca9db0c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Fri, 17 Mar 2017 11:06:13 +0800 Subject: [PATCH 0453/1275] Update ShellSortExample.swift Fix bug. Origin code probally get wrong answer.My fault. --- Shell Sort/ShellSortExample.swift | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index efa035da3..c41eb8889 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -8,24 +8,25 @@ import Foundation -public func shellSort(_ list: inout [Int]) { - +public func shellSort(_ list : inout [Int]) +{ var sublistCount = list.count / 2 - - while sublistCount > 0 { - - for index in 0.. 0 + { + for var index in 0.. list[index + sublistCount] { - swap(&list[index], &list[index + sublistCount]) + if arr[index] > arr[index + sublistCount]{ + swap(&arr[index], &arr[index + sublistCount]) } guard sublistCount == 1 && index > 0 else { continue } - - if list[index - 1] > list[index] { - swap(&list[index - 1], &list[index]) + + while arr[index - 1] > arr[index] && index - 1 > 0 { + swap(&arr[index - 1], &arr[index]) + index -= 1 } } sublistCount = sublistCount / 2 From beddc9a7f4dd96b9122e849ace3c7dba57caaea7 Mon Sep 17 00:00:00 2001 From: Brandon05 Date: Fri, 17 Mar 2017 13:41:49 -0400 Subject: [PATCH 0454/1275] Updated syntax for Swift 3 Hello, I was recreating this file in playground and I noticed you still had the explicit @noescape . Thought I can lend a hand by removing it. Thanks for this awesome repository! --- Binary Tree/BinaryTree.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Binary Tree/BinaryTree.swift b/Binary Tree/BinaryTree.swift index 61ae696c7..102f23e06 100644 --- a/Binary Tree/BinaryTree.swift +++ b/Binary Tree/BinaryTree.swift @@ -29,26 +29,26 @@ extension BinaryTree: CustomStringConvertible { } extension BinaryTree { - public func traverseInOrder(@noescape process: T -> Void) { + public func traverseInOrder(process: T -> Void) { if case let .node(left, value, right) = self { - left.traverseInOrder(process) + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - public func traversePreOrder(@noescape process: T -> Void) { + public func traversePreOrder(process: T -> Void) { if case let .node(left, value, right) = self { process(value) - left.traversePreOrder(process) - right.traversePreOrder(process) + left.traversePreOrder(process: process) + right.traversePreOrder(process: process) } } - public func traversePostOrder(@noescape process: T -> Void) { + public func traversePostOrder(process: T -> Void) { if case let .node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } From 9677b8c0e6bbd32831b6eca6c69c6f09d64f9f37 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 17 Mar 2017 20:10:53 -0700 Subject: [PATCH 0455/1275] Fixed indenting, and changed a scope modifier on the array property from public to fileprivate. --- Array2D/Array2D.playground/Contents.swift | 72 +++++++++++------------ Array2D/README.markdown | 24 ++++++-- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 38d4eff23..8b18a333f 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -4,36 +4,36 @@ Performance is always O(1). */ public struct Array2D { - public let columns: Int - public let rows: Int - public var array: [T] - - public init(columns: Int, rows: Int, initialValue: T) { - self.columns = columns - self.rows = rows - array = [T](repeating: initialValue, count: rows*columns) + public let columns: Int + public let rows: Int + fileprivate var array: [T] + + public init(columns: Int, rows: Int, initialValue: T) { + self.columns = columns + self.rows = rows + array = [T](repeating: initialValue, count: rows*columns) + } + + public subscript(column: Int, row: Int) -> T { + get { + if isValidSubscript(column: column, row: row) { + return array[row*columns + column] + } else { + fatalError("Not a valid subscript") + } } - - public subscript(column: Int, row: Int) -> T { - get { - if isValidSubscript(column: column, row: row) { - return array[row*columns + column] - } else { - fatalError("Not a valid subscript") - } - } - set { - if isValidSubscript(column: column, row: row) { - array[row*columns + column] = newValue - } else { - fatalError("Not a valid subscript") - } - } - } - - private func isValidSubscript(column: Int, row: Int) -> Bool { - return column < columns && row < rows + set { + if isValidSubscript(column: column, row: row) { + array[row*columns + column] = newValue + } else { + fatalError("Not a valid subscript") + } } + } + + private func isValidSubscript(column: Int, row: Int) -> Bool { + return column < columns && row < rows + } } @@ -62,13 +62,13 @@ print(matrix.array) // print out the 2D array with a reference around the grid for i in 0.. { public let columns: Int public let rows: Int - private var array: [T] - + fileprivate var array: [T] + public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = .init(repeating: initialValue, count: rows*columns) + array = [T](repeating: initialValue, count: rows*columns) } - + public subscript(column: Int, row: Int) -> T { get { - return array[row*columns + column] + if isValidSubscript(column: column, row: row) { + return array[row*columns + column] + } else { + fatalError("Not a valid subscript") + } } set { - array[row*columns + column] = newValue + if isValidSubscript(column: column, row: row) { + array[row*columns + column] = newValue + } else { + fatalError("Not a valid subscript") + } } } + + private func isValidSubscript(column: Int, row: Int) -> Bool { + return column < columns && row < rows + } } ``` From c4d39ec0dc41060f2ff5b5532e9fa69489c9bbef Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 17 Mar 2017 20:16:01 -0700 Subject: [PATCH 0456/1275] Updated the subscript check to use preconditions instead of a custom function. --- Array2D/Array2D.playground/Contents.swift | 22 +++++++--------------- Array2D/Array2D.swift | 9 +++++---- Array2D/README.markdown | 22 +++++++--------------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 8b18a333f..d088c99af 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -11,29 +11,21 @@ public struct Array2D { public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = [T](repeating: initialValue, count: rows*columns) + array = .init(repeating: initialValue, count: rows*columns) } public subscript(column: Int, row: Int) -> T { get { - if isValidSubscript(column: column, row: row) { - return array[row*columns + column] - } else { - fatalError("Not a valid subscript") - } + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") + return array[row*columns + column] } set { - if isValidSubscript(column: column, row: row) { - array[row*columns + column] = newValue - } else { - fatalError("Not a valid subscript") - } + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") + array[row*columns + column] = newValue } } - - private func isValidSubscript(column: Int, row: Int) -> Bool { - return column < columns && row < rows - } } diff --git a/Array2D/Array2D.swift b/Array2D/Array2D.swift index 6d6c01902..df4822916 100644 --- a/Array2D/Array2D.swift +++ b/Array2D/Array2D.swift @@ -7,21 +7,22 @@ public struct Array2D { public let columns: Int public let rows: Int fileprivate var array: [T] - + public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows array = .init(repeating: initialValue, count: rows*columns) } - + public subscript(column: Int, row: Int) -> T { get { + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") return array[row*columns + column] } set { - precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") - + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") array[row*columns + column] = newValue } } diff --git a/Array2D/README.markdown b/Array2D/README.markdown index 6550dc943..04afb9510 100644 --- a/Array2D/README.markdown +++ b/Array2D/README.markdown @@ -72,29 +72,21 @@ public struct Array2D { public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows - array = [T](repeating: initialValue, count: rows*columns) + array = .init(repeating: initialValue, count: rows*columns) } public subscript(column: Int, row: Int) -> T { get { - if isValidSubscript(column: column, row: row) { - return array[row*columns + column] - } else { - fatalError("Not a valid subscript") - } + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") + return array[row*columns + column] } set { - if isValidSubscript(column: column, row: row) { - array[row*columns + column] = newValue - } else { - fatalError("Not a valid subscript") - } + precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") + precondition(row < rows, "Row \(row) Index is out of range. Array(columns: \(columns), rows:\(rows))") + array[row*columns + column] = newValue } } - - private func isValidSubscript(column: Int, row: Int) -> Bool { - return column < columns && row < rows - } } ``` From 162c3453bab7fa216cd3f11a9a45488ce9515c5c Mon Sep 17 00:00:00 2001 From: Ute Schiehlen Date: Tue, 21 Mar 2017 11:21:59 +0100 Subject: [PATCH 0457/1275] Exchanged old red-black tree implementation with new one, also updated redmea --- Red-Black Tree/README.markdown | 259 +++--- .../RedBlackTree.playground/Contents.swift | 22 + .../Sources/RedBlackTree.swift | 740 ++++++++++++++++++ .../contents.xcplayground | 4 + 4 files changed, 930 insertions(+), 95 deletions(-) create mode 100644 Red-Black Tree/RedBlackTree.playground/Contents.swift create mode 100644 Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift create mode 100644 Red-Black Tree/RedBlackTree.playground/contents.xcplayground diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index 05993f016..74fffa415 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -1,120 +1,189 @@ # Red-Black Tree -A Red-Black tree is a special version of a [Binary Search Tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Search%20Tree). Binary search trees(BSTs) can become unbalanced after a lot of insertions/deletions. The only difference between a node from a BST and a Red-Black Tree(RBT) is that RBT nodes have a color property added to them which can either be red or black. A RBT rebalances itself by making sure the following properties hold: +A red-black tree (RBT) is a balanced version of a [Binary Search Tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Search%20Tree) guaranteeing that the basic operations (search, predecessor, successor, minimum, maximum, insert and delete) have a logarithmic worst case performance. -## Properties -1. A node is either red or black -2. The root is always black -3. All leaves are black -4. If a node is red, both of its children are black -5. Every path to a leaf contains the same number of black nodes (The amount of black nodes met when going down a RBT is called the black-depth of the tree.) - -## Methods -* `insert(_ value: T)` inserts the value into the tree -* `insert(_ values: [T])` inserts an array of values into the tree -* `delete(_ value: T)` deletes the value from the tree -* `find(_ value: T) -> RBTNode` looks for a node in the tree with given value and returns it -* `minimum(n: RBTNode) -> RBTNode` looks for the maximum value of a subtree starting at the given node -* `maximum(n: RBTNode) -> RBTNode` looks for the minimum value of a subtree starting at the given node -* `func verify()` verifies if the tree is still valid. Prints warning messages if this is not the case - -## Rotation +Binary search trees (BSTs) have the disadvantage that they can become unbalanced after some insert or delete operations. In the worst case, this could lead to a tree where the nodes build a linked list as shown in the following example: -In order to rebalance their nodes RBTs use an operation known as rotation. You can either left or right rotate a node and its child. Rotating a node and its child swaps the nodes and interchanges their subtrees. Left rotation swaps the parent node with its right child. while right rotation swaps the parent node with its left child. - -Left rotation: -``` -before left rotating p after left rotating p - p b - / \ / \ - a b -> p n - / \ / \ / \ -n n n n a n - / \ - n n -``` -Right rotation: ``` -before right rotating p after right rotating p - p a - / \ / \ - a b -> n p - / \ / \ / \ -n n n n n b - / \ - n n +a + \ + b + \ + c + \ + d ``` +To prevent this issue, RBTs perform rebalancing operations after an insert or delete and store an additional color property at each node which can either be red or black. After each operation a RBT satisfies the following properties: -## Insertion - -We create a new node with the value to be inserted into the tree. The color of this new node is always red. -We perform a standard BST insert with this node. Now the three might not be a valid RBT anymore. -We now go through several insertion steps in order to make the tree valid again. We call the just inserted node n. - -**Step 1**: We check if n is the rootNode, if so we paint it black and we are done. If not we go to Step 2. - -We now know that n at least has a parent as it is not the rootNode. - -**Step 2**: We check if the parent of n is black if so we are done. If not we go to Step 3. - -We now know the parent is also not the root node as the parent is red. Thus n also has a grandparent and thus also an uncle as every node has two children. This uncle may however be a nullLeaf - -**Step 3**: We check if n's uncle is red. If not we go to Step 4. If n's uncle is indeed red we recolor uncle and parent to black and n's grandparent to red. We now go back to step 1 performing the same logic on n's grandparent. - -From here there are four cases: -- **The left left case.** n's parent is the left child of its parent and n is the left child of its parent. -- **The left right case** n's parent is the left child of its parent and n is the right child of its parent. -- **The right right case** n's parent is the right child of its parent and n is the right child of its parent. -- **The right left case** n's parent is the right child of its parent and n is the left child of its parent. - -**Step 4**: checks if either the **left right** case or the **right left** case applies to the current situation. - - If we find the **left right case**, we left rotate n's parent and go to Step 5 while setting n to n's parent. (This transforms the **left right** case into the **left left** case) - - If we find the **right left case**, we right rotate n's parent and go to Step 5 while setting n to n's parent. (This transforms the **right left** case into the **right right** case) - - If we find neither of these two we proceed to Step 5. +## Properties -n's parent is now red, while n's grandparent is black. +1. Every node is either red or black +2. The root is black +3. Every leaf (nullLeaf) is black +4. If a node is red, then both its children are black +5. For each node, all paths from the node to descendant leaves contain the same number of black nodes -**Step 5**: We swap the colors of n's parent and grandparent. - - We either right rotate n's grandparent in case of the **left left** case - - Or we left rotate n's grandparent in case of the **right right** case +Property 5 includes the definition of the black-height of a node x, bh(x), which is the number of black nodes on a path from this node down to a leaf not counting the node itself. +From [CLRS] -Reaching the end we have successfully made the tree valid again. +## Methods -# Deletion +Nodes: +* `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 +Tree: +* `search(input:)` Returns the node with the given key value +* `minValue()` Returns the minimum key value of the whole tree +* `maxValue()` Returns the maximum key value of the whole tree +* `insert(key:)` Inserts the key value into the tree +* `delete(key:)` Delete the node with the respective key value from the tree +* `verify()` Verifies that the given tree fulfills the red-black tree properties -Deletion is a little more complicated than insertion. In the following we call del the node to be deleted. -First we try and find the node to be deleted using find() -we send the result of find to del. -We now go through the following steps in order to delete the node del. +The rotation, insertion and deletion algorithms are implemented based on the pseudo-code provided in [CLRS] -First we do a few checks: -- Is del the rootNode if so set the root to a nullLeaf and we are done. -- If del has 2 nullLeaf children and is red. We check if del is either a left or a right child and set del's parent left or right to a nullLeaf. -- If del has two non nullLeaf children we look for the maximum value in del's left subtree. We set del's value to this maximum value and continue to instead delete this maximum node. Which we will now call del. +## Implementation Details -Because of these checks we now know that del has at most 1 non nullLeaf child. It has either two nullLeaf children or one nullLeaf and one regular red child. (The child is red otherwise the black-depth wouldn't be the same for every leaf) +For convenience, all nil-pointers to children or the parent (except the parent of the root) of a node are exchanged with a nullLeaf. This is an ordinary node object, like all other nodes in the tree, but with a black color, and in this case a nil value for its children, parent and key. Therefore, an empty tree consists of exactly one nullLeaf at the root. -We now call the non nullLeaf child of del, child. If del has two nullLeaf children child will be a nullLeaf. This means child can either be a nullLeaf or a red node. +## Rotation -We now have three options +Left rotation (around x): +Assumes that x.rightChild y is not a nullLeaf, rotates around the link from x to y, makes y the new root of the subtree with x as y's left child and y's left child as x's right child, where n = a node, [n] = a subtree +``` + | | + x y + / \ ~> / \ + [A] y x [C] + / \ / \ + [B] [C] [A] [B] +``` +Right rotation (around y): +Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, makes x the new root of the subtree with y as x's right child and x's right child as y's left child, where n = a node, [n] = a subtree +``` + | | + x y + / \ <~ / \ + [A] y x [C] + / \ / \ + [B] [C] [A] [B] +``` +As rotation is a local operation only exchanging pointers it's runtime is O(1). -- If del is red its child is a nullLeaf and we can just delete it as it doesn't change the black-depth of the tree. We are done +## Insertion -- If child is red we recolor it black and child's parent to del's parent. del is now deleted and we are done. +We create a node with the given key and set its color to red. Then we insert it into the the tree by performing a standard insert into a BST. After this, the tree might not be a valid RBT anymore, so we fix the red-black properties by calling the insertFixup algorithm. +The only violation of the red-black properties occurs at the inserted node z and its parent. Either both are red, or the parent does not exist (so there is a violation since the root must be black). +We have three distinct cases: +**Case 1:** The uncle of z is red. If z.parent is left child, z's uncle is z.grandparent's right child. If this is the case, we recolor and move z to z.grandparent, then we check again for this new z. In the following cases, we denote a red node with (x) and a black node with {x}, p = parent, gp = grandparent and u = uncle +``` + | | + {gp} (newZ) + / \ ~> / \ + (p) (u) {p} {u} + / \ / \ / \ / \ + (z) [C] [D] [E] (z) [C] [D] [E] + / \ / \ +[A] [B] [A] [B] -- Both del and child are black we go through +``` +**Case 2a:** The uncle of z is black and z is right child. Here, we move z upwards, so z's parent is the newZ and then we rotate around this newZ. After this, we have Case 2b. +``` + | | + {gp} {gp} + / \ ~> / \ + (p) {u} (z) {u} + / \ / \ / \ / \ + [A] (z) [D] [E] (newZ) [C] [D] [E] + / \ / \ + [B] [C] [A] [B] -If both del and child are black we introduce a new variable sibling. Which is del's sibling. We also replace del with child and recolor it doubleBlack. del is now deleted and child and sibling are siblings. +``` +**Case 2b:** The uncle of z is black and z is left child. In this case, we recolor z.parent to black and z.grandparent to red. Then we rotate around z's grandparent. Afterwards we have valid red-black tree. +``` + | | + {gp} {p} + / \ ~> / \ + (p) {u} (z) (gp) + / \ / \ / \ / \ + (z) [C] [D] [E] [A] [B] [C] {u} + / \ / \ +[A] [B] [D] [E] -We now have to go through a lot of steps in order to remove this doubleBlack color. Which are hard to explain in text without just writing the full code in text. This is due the many possible combination of nodes and colors. The code is commented, but if you don't quite understand please leave me a message. Also part of the deletion is described by the final link in the Also See section. +``` +Running time of this algorithm: +* Only case 1 may repeat, but this only h/2 steps, where h is the height of the tree +* Case 2a -> Case 2b -> red-black tree +* Case 2b -> red-black tree +As we perform case 1 at most O(log n) times and all other cases at most once, we have O(log n) recolorings and at most 2 rotations. +The overall runtime of insert is O(log n). + +## Deletion + +We search for the node with the given key, and if it exists we delete it by performing a standard delete from a BST. If the deleted nodes' color was red everything is fine, otherwise red-black properties may be violated so we call the fixup procedure deleteFixup. +Violations can be that the parent and child of the deleted node x where red, so we now have two adjacent red nodes, or if we deleted the root, the root could now be red, or the black height property is violated. +We have 4 cases: We call deleteFixup on node x +**Case 1:** The sibling of x is red. The sibling is the other child of x's parent, which is not x itself. In this case, we recolor the parent of x and x.sibling then we left rotate around x's parent. In the following cases s = sibling of x, (x) = red, {x} = black, |x| = red/black. +``` + | | + {p} {s} + / \ ~> / \ + {x} (s) (p) [D] + / \ / \ / \ + [A] [B] [C] [D] {x} [C] + / \ + [A] [B] -## Also see +``` +**Case 2:** The sibling of x is black and has two black children. Here, we recolor x.sibling to red, move x upwards to x.parent and check again for this newX. +``` + | | + |p| |newX| + / \ ~> / \ + {x} {s} {x} (s) + / \ / \ / \ / \ + [A] [B] {l} {r} [A] [B] {l} {r} + / \ / \ / \ / \ + [C][D][E][F] [C][D][E][F] -* [Wikipedia](https://en.wikipedia.org/wiki/Red–black_tree) -* [GeeksforGeeks - introduction](http://www.geeksforgeeks.org/red-black-tree-set-1-introduction-2/) -* [GeeksforGeeks - insertion](http://www.geeksforgeeks.org/red-black-tree-set-2-insert/) -* [GeeksforGeeks - deletion](http://www.geeksforgeeks.org/red-black-tree-set-3-delete-2/) +``` +**Case 3:** The sibling of x is black with one black child to the right. In this case, we recolor the sibling to red and sibling.leftChild to black, then we right rotate around the sibling. After this we have case 4. +``` + | | + |p| |p| + / \ ~> / \ + {x} {s} {x} {l} + / \ / \ / \ / \ + [A] [B] (l) {r} [A] [B] [C] (s) + / \ / \ / \ + [C][D][E][F] [D]{e} + / \ + [E] [F] -Important to note is that GeeksforGeeks doesn't mention a few deletion cases that do occur. The code however does implement these. +``` +**Case 4:** The sibling of x is black with one red child to the right. Here, we recolor the sibling to the color of x.parent and x.parent and sibling.rightChild to black. Then we left rotate around x.parent. After this operation we have a valid red-black tree. Here, ||x|| denotes that x can have either color red or black, but that this can be different to |x| color. This is important, as s gets the same color as p. +``` + | | + ||p|| ||s|| + / \ ~> / \ + {x} {s} {p} {r} + / \ / \ / \ / \ + [A] [B] |l| (r) {x} |l| [E] [F] + / \ / \ / \ / \ + [C][D][E][F] [A][B][C][D] -*Written for Swift Algorithm Club by Jaap Wijnen. Updated from Ashwin Raghuraman's contribution.* +``` +Running time of this algorithm: +* Only case 2 can repeat, but this only h many times, where h is the height of the tree +* Case 1 -> case 2 -> red-black tree + Case 1 -> case 3 -> case 4 -> red-black tree + Case 1 -> case 4 -> red-black tree +* Case 3 -> case 4 -> red-black tree +* Case 4 -> red-black tree +As we perform case 2 at most O(log n) times and all other steps at most once, we have O(log n) recolorings and at most 3 rotations. +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.* diff --git a/Red-Black Tree/RedBlackTree.playground/Contents.swift b/Red-Black Tree/RedBlackTree.playground/Contents.swift new file mode 100644 index 000000000..5b19f9bd1 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/Contents.swift @@ -0,0 +1,22 @@ +//: Playground - noun: a place where people can play +// Test for the RedBlackTree implementation provided in the Source folder of this Playground +import Foundation + +let redBlackTree = RedBlackTree() + +let randomMax = Double(0x10000000) +var values = [Double]() +for _ in 0..<1000 { + let value = Double(arc4random()) / randomMax + values.append(value) + redBlackTree.insert(key: value) +} +redBlackTree.verify() + +for _ in 0..<1000 { + let rand = arc4random_uniform(UInt32(values.count)) + let index = Int(rand) + let value = values.remove(at: index) + redBlackTree.delete(key: value) +} +redBlackTree.verify() diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift new file mode 100644 index 000000000..057909b07 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -0,0 +1,740 @@ +// +// RedBlackTree.swift +// +// Created by Ute Schiehlen on 14.03.17. +// Copyright © 2017 Ute Schiehlen. All rights reserved. +// + +import Foundation + +private enum RBTreeColor { + case red + case black +} + +private enum rotationDirection { + case left + case right +} + +// MARK: - RBNode + +public class RBTreeNode: Equatable { + public typealias RBNode = RBTreeNode + + fileprivate var color: RBTreeColor = .black + fileprivate var key: Key? + fileprivate var isNullLeaf = true + var leftChild: RBNode? + var rightChild: RBNode? + fileprivate weak var parent: RBNode? + + public init(key: Key?, leftChild: RBNode?, rightChild: RBNode?, parent: RBNode?) { + self.key = key + self.leftChild = leftChild + self.rightChild = rightChild + self.parent = parent + + self.leftChild?.parent = self + self.rightChild?.parent = self + } + + public convenience init(key: Key?) { + self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) + self.isNullLeaf = false + } + + // For initialising the nullLeaf + public convenience init() { + self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) + self.color = .black + self.isNullLeaf = true + } + + var isRoot: Bool { + return parent == nil + } + + var isLeaf: Bool { + return rightChild == nil && leftChild == nil + } + + var isLeftCild: Bool { + return parent?.leftChild === self + } + + var isRightChild: Bool { + return parent?.rightChild === self + } + + var grandparent: RBNode? { + return parent?.parent + } + + var sibling: RBNode? { + if isLeftCild { + return parent?.rightChild + } else { + return parent?.leftChild + } + } + + var uncle: RBNode? { + return parent?.sibling + } +} + +// MARK: - RedBlackTree + +public class RedBlackTree { + public typealias RBNode = RBTreeNode + + fileprivate(set) var root: RBNode + fileprivate(set) var size = 0 + fileprivate let nullLeaf = RBNode() + + public init() { + root = nullLeaf + } +} + +// MARK: - Equatable protocol + +extension RBTreeNode { + static public func ==(lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { + return lhs.key == rhs.key + } +} + +// MARK: - Finding a nodes successor + +extension RBTreeNode { + /* + * Returns the inorder successor node of a node + * The successor is a node with the next larger key value of the current node + */ + public func getSuccessor() -> RBNode? { + // If node has right child: successor min of this right tree + if let rightChild = self.rightChild { + if !rightChild.isNullLeaf { + return rightChild.minimum() + } + } + // Else go upward until node left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isRightChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } +} + +// MARK: - Searching + +extension RBTreeNode { + /* + * Returns the node with the minimum key of the current subtree + */ + public func minimum() -> RBNode? { + if let leftChild = leftChild { + if !leftChild.isNullLeaf { + return leftChild.minimum() + } + return self + } + return self + } + + /* + * Returns the node with the maximum key of the current subtree + */ + public func maximum() -> RBNode? { + if let rightChild = rightChild { + if !rightChild.isNullLeaf { + return rightChild.maximum() + } + return self + } + return self + } +} + +extension RedBlackTree { + /* + * Returns the node with the given key |input| if existing + */ + public func search(input: Key) -> RBNode? { + return search(key: input, node: root) + } + + /* + * Returns the node with given |key| in subtree of |node| + */ + fileprivate func search(key: Key, node: RBNode?) -> RBNode? { + // If node nil -> key not found + guard let node = node else { + return nil + } + // If node is nullLeaf == semantically same as if nil + if !node.isNullLeaf { + if let nodeKey = node.key { + // Node found + if key == nodeKey { + return node + } else if key < nodeKey { + return search(key: key, node: node.leftChild) + } else { + return search(key: key, node: node.rightChild) + } + } + } + return nil + } +} + +// MARK: - Finding maximum and minimum value + +extension RedBlackTree { + /* + * Returns the minimum key value of the whole tree + */ + public func minValue() -> Key? { + if let minNode = root.minimum() { + return minNode.key + } else { + return nil + } + } + + /* + * Returns the maximum key value of the whole tree + */ + public func maxValue() -> Key? { + if let maxNode = root.maximum() { + return maxNode.key + } else { + return nil + } + } +} + +// MARK: - Inserting new nodes + +extension RedBlackTree { + /* + * Insert a node with key |key| into the tree + * 1. Perform normal insert operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func insert(key: Key) { + if root.isNullLeaf { + root = RBNode(key: key) + } else { + insert(input: RBNode(key: key), node: root) + } + + size += 1 + } + + /* + * Nearly identical insert operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, we color the inserted node red, + * after inserting we call insertFixup to maintain the red-black properties + */ + private func insert(input: RBNode, node: RBNode) { + guard let inputKey = input.key, let nodeKey = node.key else { + return + } + if inputKey < nodeKey { + guard let child = node.leftChild else { + addAsLeftChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsLeftChild(child: input, parent: node) + } else { + insert(input: input, node: child) + } + } else { + guard let child = node.rightChild else { + addAsRightChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsRightChild(child: input, parent: node) + } else { + insert(input: input, node: child) + } + } + } + + private func addAsLeftChild(child: RBNode, parent: RBNode) { + parent.leftChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + private func addAsRightChild(child: RBNode, parent: RBNode) { + parent.rightChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + /* + * Fixes possible violations of the red-black property after insertion + * Only violation of red-black properties occurs at inserted node |z| and z.parent + * We have 3 distinct cases: case 1, 2a and 2b + * - case 1: may repeat, but only h/2 steps, where h is the height of the tree + * - case 2a -> case 2b -> red-black tree + * - case 2b -> red-black tree + */ + private func insertFixup(node z: RBNode) { + if(!z.isNullLeaf) { + guard let parentZ = z.parent else{ + return + } + // If both |z| and his parent are red -> violation of red-black property -> need to fix it + if parentZ.color == .red { + guard let uncle = z.uncle else { + return + } + // Case 1: Uncle red -> recolor + move z + if uncle.color == .red { + parentZ.color = .black + uncle.color = .black + if let grandparentZ = parentZ.parent { + grandparentZ.color = .red + // Move z to grandparent and check again + insertFixup(node: grandparentZ) + } + } + // Case 2: Uncle black + else { + var zNew = z + // Case 2.a: z right child -> rotate + if parentZ.isLeftCild && z.isRightChild { + zNew = parentZ + leftRotate(node: zNew) + } else if parentZ.isRightChild && z.isLeftCild { + zNew = parentZ + rightRotate(node: zNew) + } + // Case 2.b: z left child -> recolor + rotate + zNew.parent?.color = .black + if let grandparentZnew = zNew.grandparent { + grandparentZnew.color = .red + if z.isLeftCild { + rightRotate(node: grandparentZnew) + } else { + leftRotate(node: grandparentZnew) + } + // We have a valid red-black-tree + } + } + } + } + root.color = .black + } +} + +// MARK: - Deleting a node +extension RedBlackTree { + /* + * Delete a node with key |key| from the tree + * 1. Perform standard delete operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func delete(key: Key) { + if size == 1 { + root = nullLeaf + size -= 1 + } else if let node = search(key: key, node: root) { + if !node.isNullLeaf { + delete(node: node) + size -= 1 + } + } + } + + /* + * Nearly identical delete operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, + * after deleting we call insertFixup to maintain the red-black properties if the delted node was + * black (as if it was red -> no violation of red-black properties) + */ + private func delete(node z: RBNode) { + var nodeY = RBNode() + var nodeX = RBNode() + if let leftChild = z.leftChild, let rightChild = z.rightChild { + if leftChild.isNullLeaf || rightChild.isNullLeaf { + nodeY = z + } else { + if let successor = z.getSuccessor() { + nodeY = successor + } + } + } + if let leftChild = nodeY.leftChild { + if !leftChild.isNullLeaf { + nodeX = leftChild + } else if let rightChild = nodeY.rightChild { + nodeX = rightChild + } + } + nodeX.parent = nodeY.parent + if let parentY = nodeY.parent { + // Should never be the case, as parent of root = nil + if parentY.isNullLeaf { + root = nodeX + } else { + if nodeY.isLeftCild { + parentY.leftChild = nodeX + } else { + parentY.rightChild = nodeX + } + } + } else { + root = nodeX + } + if nodeY != z { + z.key = nodeY.key + } + // If sliced out node was red -> nothing to do as red-black-property holds + // If it was black -> fix red-black-property + if nodeY.color == .black { + deleteFixup(node: nodeX) + } + } + + /* + * Fixes possible violations of the red-black property after deletion + * We have w distinct cases: only case 2 may repeat, but only h many steps, where h is the height + * of the tree + * - case 1 -> case 2 -> red-black tree + * case 1 -> case 3 -> case 4 -> red-black tree + * case 1 -> case 4 -> red-black tree + * - case 3 -> case 4 -> red-black tree + * - case 4 -> red-black tree + */ + private func deleteFixup(node x: RBNode) { + var xTmp = x + if !x.isRoot && x.color == .black { + guard var sibling = x.sibling else { + return + } + // Case 1: Sibling of x is red + if sibling.color == .red { + // Recolor + sibling.color = .black + if let parentX = x.parent { + parentX.color = .red + // Rotation + if x.isLeftCild { + leftRotate(node: parentX) + } else { + rightRotate(node: parentX) + } + // Update sibling + if let sibl = x.sibling { + sibling = sibl + } + } + } + // Case 2: Sibling is black with two black children + if sibling.leftChild?.color == .black && sibling.rightChild?.color == .black { + // Recolor + sibling.color = .red + // Move fake black unit upwards + if let parentX = x.parent { + deleteFixup(node: parentX) + } + // We have a valid red-black-tree + } else { + // Case 3: a. Sibling black with one black child to the right + if x.isLeftCild && sibling.rightChild?.color == .black { + // Recolor + sibling.leftChild?.color = .black + sibling.color = .red + // Rotate + rightRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Still case 3: b. One black child to the left + else if x.isRightChild && sibling.leftChild?.color == .black { + // Recolor + sibling.rightChild?.color = .black + sibling.color = .red + // Rotate + leftRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Case 4: Sibling is black with red right child + // Recolor + if let parentX = x.parent { + sibling.color = parentX.color + parentX.color = .black + // a. x left and sibling with red right child + if x.isLeftCild { + sibling.rightChild?.color = .black + // Rotate + leftRotate(node: parentX) + } + // b. x right and sibling with red left child + else { + sibling.leftChild?.color = .black + //Rotate + rightRotate(node: parentX) + } + // We have a valid red-black-tree + xTmp = root + } + } + } + xTmp.color = .black + } +} + +// MARK: - Rotation +extension RedBlackTree { + /* + * Left rotation around node x + * Assumes that x.rightChild y is not a nullLeaf, rotates around the link from x to y, + * makes y the new root of the subtree with x as y's left child and y's left child as x's right + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ ~> / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func leftRotate(node x: RBNode) { + rotate(node: x, direction: .left) + } + + + /* + * Right rotation around node y + * Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, + * makes x the new root of the subtree with y as x's right child and x's right child as y's left + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ <~ / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func rightRotate(node x: RBNode) { + rotate(node: x, direction: .right) + } + + /* + * Rotation around a node x + * Is a local operation preserving the binary-search-tree property that only exchanges pointers. + * Runntime: O(1) + */ + private func rotate(node x: RBNode, direction: rotationDirection) { + var nodeY: RBNode? = RBNode() + + // Set |nodeY| and turn |nodeY|'s left/right subtree into |x|'s right/left subtree + switch direction { + case .left: + nodeY = x.rightChild + x.rightChild = nodeY?.leftChild + x.rightChild?.parent = x + case .right: + nodeY = x.leftChild + x.leftChild = nodeY?.rightChild + x.leftChild?.parent = x + } + + // Link |x|'s parent to nodeY + nodeY?.parent = x.parent + if x.isRoot { + if let node = nodeY { + root = node + } + } else if x.isLeftCild { + x.parent?.leftChild = nodeY + } else if x.isRightChild { + x.parent?.rightChild = nodeY + } + + // Put |x| on |nodeY|'s left + switch direction { + case .left: + nodeY?.leftChild = x + case .right: + nodeY?.rightChild = x + } + x.parent = nodeY + } +} + +// MARK: - Verify +extension RedBlackTree { + /* + * Verifies that the existing tree fulfills all red-black properties + * Returns true if the tree is a valid red-black tree, false otherwise + */ + public func verify() -> Bool { + if root.isNullLeaf { + print("The tree is empty") + return true + } + return property2() && property4() && property5() + } + + // Property 1: Every node is either red or black -> fullfilled through setting node.color of type + // RBTreeColor + + + // Property 2: The root is black + private func property2() -> Bool { + if root.color == .red { + print("Property-Error: Root is red") + return false + } + return true + } + + // Property 3: Every nullLeaf is black -> fullfilled through initialising nullLeafs with color = black + + // Property 4: If a node is red, then both its children are black + private func property4() -> Bool { + return property4(node: root) + } + + private func property4(node: RBNode) -> Bool { + if node.isNullLeaf { + return true + } + if let leftChild = node.leftChild, let rightChild = node.rightChild { + if node.color == .red { + if !leftChild.isNullLeaf && leftChild.color == .red { + print("Property-Error: Red node with key \(node.key ?? nil) has red left child") + return false + } + if !rightChild.isNullLeaf && rightChild.color == .red { + print("Property-Error: Red node with key \(node.key ?? nil) has red right child") + return false + } + } + return property4(node: leftChild) && property4(node: rightChild) + } + return false + } + + // Property 5: For each node, all paths from the node to descendant leaves contain the same number + // of black nodes (same blackheight) + private func property5() -> Bool { + if property5(node: root) == -1 { + return false + } else { + return true + } + } + + private func property5(node: RBNode) -> Int { + if node.isNullLeaf { + return 0 + } + guard let leftChild = node.leftChild, let rightChild = node.rightChild else { + return -1 + } + let left = property5(node: leftChild) + let right = property5(node: rightChild) + + if left == -1 || right == -1 { + return -1 + } else if left == right { + let addedHeight = node.color == .black ? 1 : 0 + return left + addedHeight + } else { + print("Property-Error: Black height violated at node with key \(node.key ?? nil)") + return -1 + } + } +} + +// MARK: - Debugging + +extension RBTreeNode: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "" + if isNullLeaf { + s = "nullLeaf" + } else { + if let key = key { + s = "key: \(key)" + } else { + s = "key: nil" + } + if let parent = parent { + s += ", parent: \(parent.key)" + } + if let left = leftChild { + s += ", left = [" + left.debugDescription + "]" + } + if let right = rightChild { + s += ", right = [" + right.debugDescription + "]" + } + s += ", color = \(color)" + } + return s + } +} + +extension RedBlackTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root.debugDescription + } +} + +extension RBTreeNode: CustomStringConvertible { + public var description: String { + var s = "" + if isNullLeaf { + s += "nullLeaf" + } else { + if let left = leftChild { + s += "(\(left.description)) <- " + } + if let key = key { + s += "\(key)" + } else { + s += "nil" + } + s += ", \(color)" + if let right = rightChild { + s += " -> (\(right.description))" + } + } + return s + } +} + +extension RedBlackTree: CustomStringConvertible { + public var description: String { + if root.isNullLeaf { + return "[]" + } else{ + return root.description + } + } +} diff --git a/Red-Black Tree/RedBlackTree.playground/contents.xcplayground b/Red-Black Tree/RedBlackTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From cf91833f5688398045bb7b76150bc988df747580 Mon Sep 17 00:00:00 2001 From: Ute Schiehlen Date: Tue, 21 Mar 2017 11:23:37 +0100 Subject: [PATCH 0458/1275] Deleted old version --- .../Contents.swift | 20 - .../Sources/RBTree.swift | 521 ------------------ .../contents.xcplayground | 4 - .../contents.xcworkspacedata | 0 4 files changed, 545 deletions(-) delete mode 100644 Red-Black Tree/Red-Black Tree 2.playground/Contents.swift delete mode 100644 Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift delete mode 100644 Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground rename Red-Black Tree/{Red-Black Tree 2.playground => RedBlackTree.playground}/playground.xcworkspace/contents.xcworkspacedata (100%) diff --git a/Red-Black Tree/Red-Black Tree 2.playground/Contents.swift b/Red-Black Tree/Red-Black Tree 2.playground/Contents.swift deleted file mode 100644 index d55c153d5..000000000 --- a/Red-Black Tree/Red-Black Tree 2.playground/Contents.swift +++ /dev/null @@ -1,20 +0,0 @@ -//: Playground - noun: a place where people can play -import Foundation - -let tree = RBTree() -let randomMax = Double(0x100000000) -var values = [Double]() -for _ in 0..<1000 { - let value = Double(arc4random()) / randomMax - values.append(value) - tree.insert(value) -} -tree.verify() - -for _ in 0..<1000 { - let rand = arc4random_uniform(UInt32(values.count)) - let index = Int(rand) - let value = values.remove(at: index) - tree.delete(value) -} -tree.verify() diff --git a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift deleted file mode 100644 index 1735798d5..000000000 --- a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift +++ /dev/null @@ -1,521 +0,0 @@ - -private enum RBTColor { - case red - case black - case doubleBlack -} - -public class RBTNode: CustomStringConvertible { - fileprivate var color: RBTColor = .red - public var value: T! = nil - public var right: RBTNode! - public var left: RBTNode! - public var parent: RBTNode! - - public var description: String { - if self.value == nil { - return "null" - } else { - var nodeValue: String - - // If the value is encapsulated by parentheses it is red - // If the value is encapsulated by pipes it is black - // If the value is encapsulated by double pipes it is double black (This should not occur in a verified RBTree) - if self.isRed { - nodeValue = "(\(self.value!))" - } else if self.isBlack{ - nodeValue = "|\(self.value!)|" - } else { - nodeValue = "||\(self.value!)||" - } - - return "(\(self.left.description)<-\(nodeValue)->\(self.right.description))" - } - } - - init(tree: RBTree) { - right = tree.nullLeaf - left = tree.nullLeaf - parent = tree.nullLeaf - } - - init() { - //This method is here to support the creation of a nullLeaf - } - - public var isLeftChild: Bool { - return self.parent.left === self - } - - public var isRightChild: Bool { - return self.parent.right === self - } - - public var grandparent: RBTNode { - return parent.parent - } - - public var sibling: RBTNode { - if isLeftChild { - return self.parent.right - } else { - return self.parent.left - } - } - - public var uncle: RBTNode { - return parent.sibling - } - - fileprivate var isRed: Bool { - return color == .red - } - - fileprivate var isBlack: Bool { - return color == .black - } - - fileprivate var isDoubleBlack: Bool { - return color == .doubleBlack - } -} - -public class RBTree: CustomStringConvertible { - public var root: RBTNode - fileprivate let nullLeaf: RBTNode - - public var description: String { - return root.description - } - - public init() { - nullLeaf = RBTNode() - nullLeaf.color = .black - root = nullLeaf - } - - public convenience init(withValue value: T) { - self.init() - insert(value) - } - - public convenience init(withArray array: [T]) { - self.init() - insert(array) - } - - public func insert(_ value: T) { - let newNode = RBTNode(tree: self) - newNode.value = value - insertNode(n: newNode) - } - - public func insert(_ values: [T]) { - for value in values { - print(value) - insert(value) - } - } - - public func delete(_ value: T) { - let nodeToDelete = find(value) - if nodeToDelete !== nullLeaf { - deleteNode(n: nodeToDelete) - } - } - - public func find(_ value: T) -> RBTNode { - let foundNode = findNode(rootNode: root, value: value) - return foundNode - } - - public func minimum(n: RBTNode) -> RBTNode { - var min = n - if n.left !== nullLeaf { - min = minimum(n: n.left) - } - - return min - } - - public func maximum(n: RBTNode) -> RBTNode { - var max = n - if n.right !== nullLeaf { - max = maximum(n: n.right) - } - - return max - } - - public func verify() { - if self.root === nullLeaf { - print("The tree is empty") - return - } - property1() - property2(n: self.root) - property3() - } - - private func findNode(rootNode: RBTNode, value: T) -> RBTNode { - var nextNode = rootNode - if rootNode !== nullLeaf && value != rootNode.value { - if value < rootNode.value { - nextNode = findNode(rootNode: rootNode.left, value: value) - } else { - nextNode = findNode(rootNode: rootNode.right, value: value) - } - } - - return nextNode - } - - private func insertNode(n: RBTNode) { - BSTInsertNode(n: n, parent: root) - insertCase1(n: n) - } - - private func BSTInsertNode(n: RBTNode, parent: RBTNode) { - if parent === nullLeaf { - self.root = n - } else if n.value < parent.value { - if parent.left !== nullLeaf { - BSTInsertNode(n: n, parent: parent.left) - } else { - parent.left = n - parent.left.parent = parent - } - } else { - if parent.right !== nullLeaf { - BSTInsertNode(n: n, parent: parent.right) - } else { - parent.right = n - parent.right.parent = parent - } - } - } - - // if node is root change color to black, else move on - private func insertCase1(n: RBTNode) { - if n === root { - n.color = .black - } else { - insertCase2(n: n) - } - } - - // if parent of node is not black, and node is not root move on - private func insertCase2(n: RBTNode) { - if !n.parent.isBlack { - insertCase3(n: n) - } - } - - // if uncle is red do stuff otherwise move to 4 - private func insertCase3(n: RBTNode) { - if n.uncle.isRed { // node must have grandparent as children of root have a black parent - // both parent and uncle are red, so grandparent must be black. - n.parent.color = .black - n.uncle.color = .black - n.grandparent.color = .red - // now both parent and uncle are black and grandparent is red. - // we repeat for the grandparent - insertCase1(n: n.grandparent) - } else { - insertCase4(n: n) - } - } - - // parent is red, grandparent is black, uncle is black - // There are 4 cases left: - // - left left - // - left right - // - right right - // - right left - - // the cases "left right" and "right left" can be rotated into the other two - // so if either of the two is detected we apply a rotation and then move on to - // deal with the final two cases, if neither is detected we move on to those cases anyway - private func insertCase4(n: RBTNode) { - if n.parent.isLeftChild && n.isRightChild { // left right case - leftRotate(n: n.parent) - insertCase5(n: n.left) - } else if n.parent.isRightChild && n.isLeftChild { // right left case - rightRotate(n: n.parent) - insertCase5(n: n.right) - } else { - insertCase5(n: n) - } - } - - private func insertCase5(n: RBTNode) { - // swap color of parent and grandparent - // parent is red grandparent is black - n.parent.color = .black - n.grandparent.color = .red - - if n.isLeftChild { // left left case - rightRotate(n: n.grandparent) - } else { // right right case - leftRotate(n: n.grandparent) - } - } - - private func deleteNode(n: RBTNode) { - var toDel = n - - if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.parent === nullLeaf { - self.root = nullLeaf - return - } - - if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.isRed { - if toDel.isLeftChild { - toDel.parent.left = nullLeaf - } else { - toDel.parent.right = nullLeaf - } - return - } - - if toDel.left !== nullLeaf && toDel.right !== nullLeaf { - let pred = maximum(n: toDel.left) - toDel.value = pred.value - toDel = pred - } - - // from here toDel has at most 1 non nullLeaf child - - var child: RBTNode - if toDel.left !== nullLeaf { - child = toDel.left - } else { - child = toDel.right - } - - if toDel.isRed || child.isRed { - child.color = .black - - if toDel.isLeftChild { - toDel.parent.left = child - } else { - toDel.parent.right = child - } - - if child !== nullLeaf { - child.parent = toDel.parent - } - } else { // both toDel and child are black - - var sibling = toDel.sibling - - if toDel.isLeftChild { - toDel.parent.left = child - } else { - toDel.parent.right = child - } - if child !== nullLeaf { - child.parent = toDel.parent - } - child.color = .doubleBlack - - while child.isDoubleBlack || (child.parent !== nullLeaf && child.parent != nil) { - if sibling.isBlack { - - var leftRedChild: RBTNode! = nil - if sibling.left.isRed { - leftRedChild = sibling.left - } - var rightRedChild: RBTNode! = nil - if sibling.right.isRed { - rightRedChild = sibling.right - } - - if leftRedChild != nil || rightRedChild != nil { // at least one of sibling's children are red - child.color = .black - if sibling.isLeftChild { - if leftRedChild != nil { // left left case - sibling.left.color = .black - let tempColor = sibling.parent.color - sibling.parent.color = sibling.color - sibling.color = tempColor - rightRotate(n: sibling.parent) - } else { // left right case - if sibling.parent.isRed { - sibling.parent.color = .black - } else { - sibling.right.color = .black - } - leftRotate(n: sibling) - rightRotate(n: sibling.grandparent) - } - } else { - if rightRedChild != nil { // right right case - sibling.right.color = .black - let tempColor = sibling.parent.color - sibling.parent.color = sibling.color - sibling.color = tempColor - leftRotate(n: sibling.parent) - } else { // right left case - if sibling.parent.isRed { - sibling.parent.color = .black - } else { - sibling.left.color = .black - } - rightRotate(n: sibling) - leftRotate(n: sibling.grandparent) - } - } - break - } else { // both sibling's children are black - child.color = .black - sibling.color = .red - if sibling.parent.isRed { - sibling.parent.color = .black - break - } - /* - sibling.parent.color = .doubleBlack - child = sibling.parent - sibling = child.sibling - */ - if sibling.parent.parent === nullLeaf { // parent of child is root - break - } else { - sibling.parent.color = .doubleBlack - child = sibling.parent - sibling = child.sibling // can become nill if child is root as parent is nullLeaf - } - //--------------- - } - } else { // sibling is red - sibling.color = .black - - if sibling.isLeftChild { // left case - rightRotate(n: sibling.parent) - sibling = sibling.right.left - sibling.parent.color = .red - } else { // right case - leftRotate(n: sibling.parent) - sibling = sibling.left.right - sibling.parent.color = .red - } - } - - // sibling check is here for when child is a nullLeaf and thus does not have a parent. - // child is here as sibling can become nil when child is the root - if (sibling.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { - child.color = .black - } - } - } - } - - private func property1() { - - if self.root.isRed { - print("Root is not black") - } - } - - private func property2(n: RBTNode) { - if n === nullLeaf { - return - } - if n.isRed { - if n.left !== nullLeaf && n.left.isRed { - print("Red node: \(n.value), has red left child") - } else if n.right !== nullLeaf && n.right.isRed { - print("Red node: \(n.value), has red right child") - } - } - property2(n: n.left) - property2(n: n.right) - } - - private func property3() { - let bDepth = blackDepth(root: self.root) - - let leaves:[RBTNode] = getLeaves(n: self.root) - - for leaflet in leaves { - var leaf = leaflet - var i = 0 - - while leaf !== nullLeaf { - if leaf.isBlack { - i = i + 1 - } - leaf = leaf.parent - } - - if i != bDepth { - print("black depth: \(bDepth), is not equal (depth: \(i)) for leaf with value: \(leaflet.value)") - } - } - - } - - private func getLeaves(n: RBTNode) -> [RBTNode] { - var leaves = [RBTNode]() - - if n !== nullLeaf { - if n.left === nullLeaf && n.right === nullLeaf { - leaves.append(n) - } else { - let leftLeaves = getLeaves(n: n.left) - let rightLeaves = getLeaves(n: n.right) - - leaves.append(contentsOf: leftLeaves) - leaves.append(contentsOf: rightLeaves) - } - } - - return leaves - } - - private func blackDepth(root: RBTNode) -> Int { - if root === nullLeaf { - return 0 - } else { - let returnValue = root.isBlack ? 1 : 0 - return returnValue + (max(blackDepth(root: root.left), blackDepth(root: root.right))) - } - } - - private func leftRotate(n: RBTNode) { - let newRoot = n.right! - n.right = newRoot.left! - if newRoot.left !== nullLeaf { - newRoot.left.parent = n - } - newRoot.parent = n.parent - if n.parent === nullLeaf { - self.root = newRoot - } else if n.isLeftChild { - n.parent.left = newRoot - } else { - n.parent.right = newRoot - } - newRoot.left = n - n.parent = newRoot - } - - private func rightRotate(n: RBTNode) { - let newRoot = n.left! - n.left = newRoot.right! - if newRoot.right !== nullLeaf { - newRoot.right.parent = n - } - newRoot.parent = n.parent - if n.parent === nullLeaf { - self.root = newRoot - } else if n.isRightChild { - n.parent.right = newRoot - } else { - n.parent.left = newRoot - } - newRoot.right = n - n.parent = newRoot - } -} diff --git a/Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground b/Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground deleted file mode 100644 index 5da2641c9..000000000 --- a/Red-Black Tree/Red-Black Tree 2.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Red-Black Tree/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Red-Black Tree/Red-Black Tree 2.playground/playground.xcworkspace/contents.xcworkspacedata rename to Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata From dc460542ffe226bbb0175fec35a9195eac87d9a3 Mon Sep 17 00:00:00 2001 From: Ute Schiehlen Date: Tue, 21 Mar 2017 11:30:51 +0100 Subject: [PATCH 0459/1275] Added licence to file --- .../Sources/RedBlackTree.swift | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index 057909b07..a588ea6bc 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -1,9 +1,22 @@ +//Copyright (c) 2016 Matthijs Hollemans and contributors // -// RedBlackTree.swift +//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: // -// Created by Ute Schiehlen on 14.03.17. -// Copyright © 2017 Ute Schiehlen. All rights reserved. +//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. import Foundation From 37d7300627bda5538381127db68571bf7b38f57e Mon Sep 17 00:00:00 2001 From: Ute Schiehlen Date: Tue, 21 Mar 2017 11:51:08 +0100 Subject: [PATCH 0460/1275] Incorporated major swiftlint warnings --- .../Sources/RedBlackTree.swift | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index a588ea6bc..6f3b16b86 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -25,7 +25,7 @@ private enum RBTreeColor { case black } -private enum rotationDirection { +private enum RotationDirection { case left case right } @@ -114,7 +114,7 @@ public class RedBlackTree { // MARK: - Equatable protocol extension RBTreeNode { - static public func ==(lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { + static public func == (lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { return lhs.key == rhs.key } } @@ -309,8 +309,8 @@ extension RedBlackTree { * - case 2b -> red-black tree */ private func insertFixup(node z: RBNode) { - if(!z.isNullLeaf) { - guard let parentZ = z.parent else{ + if !z.isNullLeaf { + guard let parentZ = z.parent else { return } // If both |z| and his parent are red -> violation of red-black property -> need to fix it @@ -539,7 +539,6 @@ extension RedBlackTree { rotate(node: x, direction: .left) } - /* * Right rotation around node y * Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, @@ -561,7 +560,7 @@ extension RedBlackTree { * Is a local operation preserving the binary-search-tree property that only exchanges pointers. * Runntime: O(1) */ - private func rotate(node x: RBNode, direction: rotationDirection) { + private func rotate(node x: RBNode, direction: RotationDirection) { var nodeY: RBNode? = RBNode() // Set |nodeY| and turn |nodeY|'s left/right subtree into |x|'s right/left subtree @@ -616,7 +615,6 @@ extension RedBlackTree { // Property 1: Every node is either red or black -> fullfilled through setting node.color of type // RBTreeColor - // Property 2: The root is black private func property2() -> Bool { if root.color == .red { @@ -746,7 +744,7 @@ extension RedBlackTree: CustomStringConvertible { public var description: String { if root.isNullLeaf { return "[]" - } else{ + } else { return root.description } } From 306ef65bd3ef8b652b1120bc8a5b6770583c3e35 Mon Sep 17 00:00:00 2001 From: kyungkoo Date: Fri, 24 Mar 2017 17:29:41 +0900 Subject: [PATCH 0461/1275] fixed broken link --- README.markdown | 100 ++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/README.markdown b/README.markdown index dfe451478..fc034f71b 100644 --- a/README.markdown +++ b/README.markdown @@ -34,31 +34,31 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [Stack](Stack/) - [Queue](Queue/) -- [Insertion Sort](Insertion Sort/) -- [Binary Search](Binary Search/) and [Binary Search Tree](Binary Search Tree/) -- [Merge Sort](Merge Sort/) +- [Insertion Sort](Insertion%20Sort/) +- [Binary Search](Binary%20Search/) and [Binary Search Tree](Binary%20Search%20Tree/) +- [Merge Sort](Merge%20Sort/) - [Boyer-Moore string search](Boyer-Moore/) ## The algorithms ### Searching -- [Linear Search](Linear Search/). Find an element in an array. -- [Binary Search](Binary Search/). Quickly find elements in a sorted array. -- [Count Occurrences](Count Occurrences/). Count how often a value appears in an array. -- [Select Minimum / Maximum](Select Minimum Maximum). Find the minimum/maximum value in an array. -- [k-th Largest Element](Kth Largest Element/). Find the *k*-th largest element in an array, such as the median. -- [Selection Sampling](Selection Sampling/). Randomly choose a bunch of items from a collection. +- [Linear Search](Linear%20Search/). Find an element in an array. +- [Binary Search](Binary%20Search/). Quickly find elements in a sorted array. +- [Count Occurrences](Count%20Occurrences/). Count how often a value appears in an array. +- [Select Minimum / Maximum](Select%20Minimum%20Maximum). Find the minimum/maximum value in an array. +- [k-th Largest Element](Kth%20Largest%20Element/). Find the *k*-th largest element in an array, such as the median. +- [Selection Sampling](Selection%20Sampling/). Randomly choose a bunch of items from a collection. - [Union-Find](Union-Find/). Keeps track of disjoint sets and lets you quickly merge them. ### String Search -- [Brute-Force String Search](Brute-Force String Search/). A naive method. +- [Brute-Force String Search](Brute-Force%20String%20Search/). A naive method. - [Boyer-Moore](Boyer-Moore/). A fast method to search for substrings. It skips ahead based on a look-up table, to avoid looking at every character in the text. - Knuth-Morris-Pratt - [Rabin-Karp](Rabin-Karp/) Faster search by using hashing. -- [Longest Common Subsequence](Longest Common Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. +- [Longest Common Subsequence](Longest%20Common%20Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. - [Z-Algorithm](Z-Algorithm/). Finds all instances of a pattern in a String, and returns the indexes of where the pattern starts within the String. ### Sorting @@ -67,51 +67,51 @@ It's fun to see how sorting algorithms work, but in practice you'll almost never Basic sorts: -- [Insertion Sort](Insertion Sort/) -- [Selection Sort](Selection Sort/) -- [Shell Sort](Shell Sort/) +- [Insertion Sort](Insertion%20Sort/) +- [Selection Sort](Selection%20Sort/) +- [Shell Sort](Shell%20Sort/) Fast sorts: - [Quicksort](Quicksort/) -- [Merge Sort](Merge Sort/) -- [Heap Sort](Heap Sort/) +- [Merge Sort](Merge%20Sort/) +- [Heap Sort](Heap%20Sort/) Special-purpose sorts: -- [Counting Sort](Counting Sort/) -- [Radix Sort](Radix Sort/) -- [Topological Sort](Topological Sort/) +- [Counting Sort](Counting%20Sort/) +- [Radix Sort](Radix%20Sort/) +- [Topological Sort](Topological%20Sort/) Bad sorting algorithms (don't use these!): -- [Bubble Sort](Bubble Sort/) -- [Slow Sort](Slow Sort/) +- [Bubble Sort](Bubble%20Sort/) +- [Slow Sort](Slow%20Sort/) ### Compression -- [Run-Length Encoding (RLE)](Run-Length Encoding/). Store repeated values as a single byte and a count. -- [Huffman Coding](Huffman Coding/). Store more common elements using a smaller number of bits. +- [Run-Length Encoding (RLE)](Run-Length%20Encoding/). Store repeated values as a single byte and a count. +- [Huffman Coding](Huffman%20Coding/). Store more common elements using a smaller number of bits. ### Miscellaneous - [Shuffle](Shuffle/). Randomly rearranges the contents of an array. -- [Comb Sort](Comb Sort/). An improve upon the Bubble Sort algorithm. +- [Comb Sort](Comb%20Sort/). An improve upon the Bubble Sort algorithm. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. - [Permutations and Combinations](Combinatorics/). Get your combinatorics on! -- [Shunting Yard Algorithm](Shunting Yard/). Convert infix expressions to postfix. +- [Shunting Yard Algorithm](Shunting%20Yard/). Convert infix expressions to postfix. - Statistics -- [Karatsuba Multiplication](Karatsuba Multiplication/). Another take on elementary multiplication. +- [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication. - [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. ### Machine learning - [k-Means Clustering](K-Means/). Unsupervised classifier that partitions data into *k* clusters. - k-Nearest Neighbors -- [Linear Regression](Linear Regression/) +- [Linear Regression](Linear%20Regression/) - Logistic Regression - Neural Networks - PageRank @@ -129,33 +129,33 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types ### Variations on arrays - [Array2D](Array2D/). A two-dimensional array with fixed dimensions. Useful for board games. -- [Bit Set](Bit Set/). A fixed-size sequence of *n* bits. -- [Fixed Size Array](Fixed Size Array/). When you know beforehand how large your data will be, it might be more efficient to use an old-fashioned array with a fixed size. -- [Ordered Array](Ordered Array/). An array that is always sorted. -- [Rootish Array Stack](Rootish Array Stack/). A space and time efficient variation on Swift arrays. +- [Bit Set](Bit%20Set/). A fixed-size sequence of *n* bits. +- [Fixed Size Array](Fixed%20Size%20Array/). When you know beforehand how large your data will be, it might be more efficient to use an old-fashioned array with a fixed size. +- [Ordered Array](Ordered%20Array/). An array that is always sorted. +- [Rootish Array Stack](Rootish%20Array%20Stack/). A space and time efficient variation on Swift arrays. ### Queues - [Stack](Stack/). Last-in, first-out! - [Queue](Queue/). First-in, first-out! - [Deque](Deque/). A double-ended queue. -- [Priority Queue](Priority Queue). A queue where the most important element is always at the front. -- [Ring Buffer](Ring Buffer/). Also known as a circular buffer. An array of a certain size that conceptually wraps around back to the beginning. +- [Priority Queue](Priority%20Queue). A queue where the most important element is always at the front. +- [Ring Buffer](Ring%20Buffer/). Also known as a circular buffer. An array of a certain size that conceptually wraps around back to the beginning. ### Lists -- [Linked List](Linked List/). A sequence of data items connected through links. Covers both singly and doubly linked 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. ### Trees - [Tree](Tree/). A general-purpose tree structure. -- [Binary Tree](Binary Tree/). A tree where each node has at most two children. -- [Binary Search Tree (BST)](Binary Search Tree/). A binary tree that orders its nodes in a way that allows for fast queries. +- [Binary Tree](Binary%20Tree/). A tree where each node has at most two children. +- [Binary Search Tree (BST)](Binary%20Search%20Tree/). A binary tree that orders its nodes in a way that allows for fast queries. - Red-Black Tree - Splay Tree - Threaded Binary Tree -- [Segment Tree](Segment Tree/). Can quickly compute a function over a portion of an array. +- [Segment Tree](Segment%20Tree/). Can quickly compute a function over a portion of an array. - kd-Tree - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. - Fibonacci Heap @@ -164,33 +164,33 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types ### Hashing -- [Hash Table](Hash Table/). Allows you to store and retrieve objects by a key. This is how the dictionary type is usually implemented. +- [Hash Table](Hash%20Table/). Allows you to store and retrieve objects by a key. This is how the dictionary type is usually implemented. - Hash Functions ### Sets -- [Bloom Filter](Bloom Filter/). A constant-memory data structure that probabilistically tests whether an element is in a set. -- [Hash Set](Hash Set/). A set implemented using a hash table. +- [Bloom Filter](Bloom%20Filter/). A constant-memory data structure that probabilistically tests whether an element is in a set. +- [Hash Set](Hash%20Set/). A set implemented using a hash table. - Multiset -- [Ordered Set](Ordered Set/). A set where the order of items matters. +- [Ordered Set](Ordered%20Set/). A set where the order of items matters. ### Graphs - [Graph](Graph/) -- [Breadth-First Search (BFS)](Breadth-First Search/) -- [Depth-First Search (DFS)](Depth-First Search/) -- [Shortest Path](Shortest Path %28Unweighted%29/) on an unweighted tree -- [Single-Source Shortest Paths](Single-Source Shortest Paths (Weighted)/) -- [Minimum Spanning Tree](Minimum Spanning Tree %28Unweighted%29/) on an unweighted tree -- [All-Pairs Shortest Paths](All-Pairs Shortest Paths/) +- [Breadth-First Search (BFS)](Breadth-First%20Search/) +- [Depth-First Search (DFS)](Depth-First%20Search/) +- [Shortest Path](Shortest%20Path%20%28Unweighted%29/) on an unweighted tree +- [Single-Source Shortest Paths](Single-Source%20Shortest%20Paths%20(Weighted)/) +- [Minimum Spanning Tree](Minimum%20Spanning%20Tree%20%28Unweighted%29/) on an unweighted tree +- [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) ## Puzzles A lot of software developer interview questions consist of algorithmic puzzles. Here is a small selection of fun ones. For more puzzles (with answers), see [here](http://elementsofprogramminginterviews.com/) and [here](http://www.crackingthecodinginterview.com). -- [Two-Sum Problem](Two-Sum Problem/) -- [Fizz Buzz](Fizz Buzz/) -- [Monty Hall Problem](Monty Hall Problem/) +- [Two-Sum Problem](Two-Sum%20Problem/) +- [Fizz Buzz](Fizz%20Buzz/) +- [Monty Hall Problem](Monty%20Hall%20Problem/) - [Finding Palindromes](Palindromes/) - [Dining Philosophers](DiningPhilosophers/) From 943ad7e48fe966f7679c4addfafa7baa5fb81fb2 Mon Sep 17 00:00:00 2001 From: kyungkoo Date: Fri, 24 Mar 2017 18:25:24 +0900 Subject: [PATCH 0462/1275] fixed important links section link --- README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index fc034f71b..023f151fb 100644 --- a/README.markdown +++ b/README.markdown @@ -16,17 +16,17 @@ This is a work in progress. More algorithms will be added soon. :-) ## Important links -[What are algorithms and data structures?](What are Algorithms.markdown) Pancakes! +[What are algorithms and data structures?](What%20are%20Algorithms.markdown) Pancakes! -[Why learn algorithms?](Why Algorithms.markdown) Worried this isn't your cup of tea? Then read this. +[Why learn algorithms?](Why%20Algorithms.markdown) Worried this isn't your cup of tea? Then read this. -[Big-O notation](Big-O Notation.markdown). We often say things like, "This algorithm is **O(n)**." If you don't know what that means, read this first. +[Big-O notation](Big-O%20Notation.markdown). We often say things like, "This algorithm is **O(n)**." If you don't know what that means, read this first. -[Algorithm design techniques](Algorithm Design.markdown). How do you create your own algorithms? +[Algorithm design techniques](Algorithm%20Design.markdown). How do you create your own algorithms? -[How to contribute](How to Contribute.markdown). Report an issue to leave feedback, or submit a pull request. +[How to contribute](How%20to%20Contribute.markdown). Report an issue to leave feedback, or submit a pull request. -[Under construction](Under Construction.markdown). Algorithms that are under construction. +[Under construction](Under%20Construction.markdown). Algorithms that are under construction. ## Where to start? From a54e722b035ffc5eeba63fcd5b1648e56f732ec0 Mon Sep 17 00:00:00 2001 From: Jake Romer Date: Fri, 24 Mar 2017 07:58:19 -0700 Subject: [PATCH 0463/1275] Fix links to related articles Fixes links to Linked List, Ring Buffer, and Priority Queue directories. --- Queue/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Queue/README.markdown b/Queue/README.markdown index f8259c31c..9efce66b9 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -255,8 +255,8 @@ The `nil` objects at the front have been removed and the array is no longer wast ## See also -There are many other ways to create a queue. Alternative implementations use a [linked list](../Linked List/), a [circular buffer](../Ring Buffer/), or a [heap](../Heap/). +There are many other ways to create a queue. Alternative implementations use a [linked list](../Linked%20List/), a [circular buffer](../Ring%20Buffer/), or a [heap](../Heap/). -Variations on this theme are [deque](../Deque/), a double-ended queue where you can enqueue and dequeue at both ends, and [priority queue](../Priority Queue/), a sorted queue where the "most important" item is always at the front. +Variations on this theme are [deque](../Deque/), a double-ended queue where you can enqueue and dequeue at both ends, and [priority queue](../Priority%20Queue/), a sorted queue where the "most important" item is always at the front. *Written for Swift Algorithm Club by Matthijs Hollemans* From 3d033740b0d3b727d488a14121da68f822b578a2 Mon Sep 17 00:00:00 2001 From: Jake Romer Date: Sat, 25 Mar 2017 07:47:49 -0700 Subject: [PATCH 0464/1275] URL encode links in Markdown files There are a ton of broken markdown links in the READMEs throughout this repo because the files and directories they refer to have spaces in their names but these aren't HTML encoded in their links. This commit just replaces spaces with %20 to fix these. --- AVL Tree/README.markdown | 8 ++++---- Big-O Notation.markdown | 2 +- Binary Search Tree/README.markdown | 10 +++++----- Binary Search/README.markdown | 2 +- Binary Tree/README.markdown | 2 +- Bloom Filter/README.markdown | 2 +- Bounded Priority Queue/README.markdown | 2 +- Boyer-Moore/README.markdown | 2 +- Breadth-First Search/README.markdown | 4 ++-- Count Occurrences/README.markdown | 4 ++-- Hash Set/README.markdown | 2 +- How to Contribute.markdown | 2 +- Ordered Array/README.markdown | 2 +- Ordered Set/README.markdown | 2 +- Selection Sort/README.markdown | 6 +++--- Shell Sort/README.markdown | 2 +- Shortest Path (Unweighted)/README.markdown | 8 ++++---- Threaded Binary Tree/README.markdown | 10 +++++----- Topological Sort/README.markdown | 2 +- Tree/README.markdown | 4 ++-- Under Construction.markdown | 20 ++++++++++---------- 21 files changed, 49 insertions(+), 49 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 355204587..a9218203a 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -1,6 +1,6 @@ # AVL Tree -An AVL tree is a self-balancing form of a [binary search tree](../Binary Search Tree/), in which the height of subtrees differ at most by only 1. +An AVL tree is a self-balancing form of a [binary search tree](../Binary%20Search%20Tree/), in which the height of subtrees differ at most by only 1. A binary tree is *balanced* when its left and right subtrees contain roughly the same number of nodes. That is what makes searching the tree really fast. But if a binary search tree is unbalanced, searching can become really slow. @@ -8,7 +8,7 @@ This is an example of an unbalanced tree: ![Unbalanced tree](Images/Unbalanced.png) -All the children are in the left branch and none are in the right. This is essentially the same as a [linked list](../Linked List/). As a result, searching takes **O(n)** time instead of the much faster **O(log n)** that you'd expect from a binary search tree. +All the children are in the left branch and none are in the right. This is essentially the same as a [linked list](../Linked%20List/). As a result, searching takes **O(n)** time instead of the much faster **O(log n)** that you'd expect from a binary search tree. A balanced version of that tree would look like this: @@ -78,7 +78,7 @@ Insertion never needs more than 2 rotations. Removal might require up to __log(n Most of the code in [AVLTree.swift](AVLTree.swift) is just regular [binary search tree](../Binary Search Tree/) stuff. You'll find this in any implementation of a binary search tree. For example, searching the tree is exactly the same. The only things that an AVL tree does slightly differently are inserting and deleting the nodes. -> **Note:** If you're a bit fuzzy on the regular operations of a binary search tree, I suggest you [catch up on those first](../Binary Search Tree/). It will make the rest of the AVL tree easier to understand. +> **Note:** If you're a bit fuzzy on the regular operations of a binary search tree, I suggest you [catch up on those first](../Binary%20Search%20Tree/). It will make the rest of the AVL tree easier to understand. The interesting bits are in the `balance()` method which is called after inserting or deleting a node. @@ -86,6 +86,6 @@ The interesting bits are in the `balance()` method which is called after inserti [AVL tree on Wikipedia](https://en.wikipedia.org/wiki/AVL_tree) -AVL tree was the first self-balancing binary tree. These days, the [red-black tree](../Red-Black Tree/) seems to be more popular. +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* diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 8cb988168..09fbb04aa 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -19,6 +19,6 @@ Big-O | Name | Description Often you don't need math to figure out what the Big-O of an algorithm is but you can simply use your intuition. If your code uses a single loop that looks at all **n** elements of your input, the algorithm is **O(n)**. If the code has two nested loops, it is **O(n^2)**. Three nested loops gives **O(n^3)**, and so on. -Note that Big-O notation is an estimate and is only really useful for large values of **n**. For example, the worst-case running time for the [insertion sort](Insertion Sort/) algorithm is **O(n^2)**. In theory that is worse than the running time for [merge sort](Merge Sort/), which is **O(n log n)**. But for small amounts of data, insertion sort is actually faster, especially if the array is partially sorted already! +Note that Big-O notation is an estimate and is only really useful for large values of **n**. For example, the worst-case running time for the [insertion sort](Insertion%20Sort/) algorithm is **O(n^2)**. In theory that is worse than the running time for [merge sort](Merge Sort/), which is **O(n log n)**. But for small amounts of data, insertion sort is actually faster, especially if the array is partially sorted already! If you find this confusing, don't let this Big-O stuff bother you too much. It's mostly useful when comparing two algorithms to figure out which one is better. But in the end you still want to test in practice which one really is the best. And if the amount of data is relatively small, then even a slow algorithm will be fast enough for practical use. diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index bd2a00c9e..a3a84c03d 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -1,6 +1,6 @@ # Binary Search Tree (BST) -A binary search tree is a special kind of [binary tree](../Binary Tree/) (a tree in which each node has at most two children) that performs insertions and deletions such that the tree is always sorted. +A binary search tree is a special kind of [binary tree](../Binary%20Tree/) (a tree in which each node has at most two children) that performs insertions and deletions such that the tree is always sorted. If you don't know what a tree is or what it is for, then [read this first](../Tree/). @@ -49,7 +49,7 @@ If we were looking for the value `5` in the example, it would go as follows: ![Searching the tree](Images/Searching.png) -Thanks to the structure of the tree, searching is really fast. It runs in **O(h)** time. If you have a well-balanced tree with a million nodes, it only takes about 20 steps to find anything in this tree. (The idea is very similar to [binary search](../Binary Search) in an array.) +Thanks to the structure of the tree, searching is really fast. It runs in **O(h)** time. If you have a well-balanced tree with a million nodes, it only takes about 20 steps to find anything in this tree. (The idea is very similar to [binary search](../Binary%20Search) in an array.) ## Traversing the tree @@ -535,7 +535,7 @@ The code for `successor()` works the exact same way but mirrored: Both these methods run in **O(h)** time. -> **Note:** There is a cool variation called a ["threaded" binary tree](../Threaded Binary Tree) where "unused" left and right pointers are repurposed to make direct links between predecessor and successor nodes. Very clever! +> **Note:** There is a cool variation called a ["threaded" binary tree](../Threaded%20Binary%20Tree) where "unused" left and right pointers are repurposed to make direct links between predecessor and successor nodes. Very clever! ### Is the search tree valid? @@ -713,11 +713,11 @@ The root node is in the middle; a dot means there is no child at that position. A binary search tree is *balanced* when its left and right subtrees contain roughly the same number of nodes. In that case, the height of the tree is *log(n)*, where *n* is the number of nodes. That's the ideal situation. -However, if one branch is significantly longer than the other, searching becomes very slow. We end up checking way more values than we'd ideally have to. In the worst case, the height of the tree can become *n*. Such a tree acts more like a [linked list](../Linked List/) than a binary search tree, with performance degrading to **O(n)**. Not good! +However, if one branch is significantly longer than the other, searching becomes very slow. We end up checking way more values than we'd ideally have to. In the worst case, the height of the tree can become *n*. Such a tree acts more like a [linked list](../Linked%20List/) than a binary search tree, with performance degrading to **O(n)**. Not good! One way to make the binary search tree balanced is to insert the nodes in a totally random order. On average that should balance out the tree quite nicely. But it doesn't guarantee success, nor is it always practical. -The other solution is to use a *self-balancing* binary tree. This type of data structure adjusts the tree to keep it balanced after you insert or delete nodes. See [AVL tree](../AVL Tree) and [red-black tree](../Red-Black Tree) for examples. +The other solution is to use a *self-balancing* binary tree. This type of data structure adjusts the tree to keep it balanced after you insert or delete nodes. See [AVL tree](../AVL%20Tree) and [red-black tree](../Red-Black%20Tree) for examples. ## See also diff --git a/Binary Search/README.markdown b/Binary Search/README.markdown index c65d0b5fd..09b141e04 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -12,7 +12,7 @@ let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 4 numbers.indexOf(43) // returns 15 ``` -The built-in `indexOf()` function performs a [linear search](../Linear Search/). In code that looks something like this: +The built-in `indexOf()` function performs a [linear search](../Linear%20Search/). In code that looks something like this: ```swift func linearSearch(_ a: [T], _ key: T) -> Int? { diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index 896116dda..8ce398804 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -8,7 +8,7 @@ The child nodes are usually called the *left* child and the *right* child. If a Often nodes will have a link back to their parent but this is not strictly necessary. -Binary trees are often used as [binary search trees](../Binary Search Tree/). In that case, the nodes must be in a specific order (smaller values on the left, larger values on the right). But this is not a requirement for all binary trees. +Binary trees are often used as [binary search trees](../Binary%20Search%20Tree/). In that case, the nodes must be in a specific order (smaller values on the left, larger values on the right). But this is not a requirement for all binary trees. For example, here is a binary tree that represents a sequence of arithmetical operations, `(5 * (a - 10)) + (-4 * (3 / b))`: diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index a85d71be4..3fff0a379 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -18,7 +18,7 @@ An advantage of the Bloom Filter over a hash table is that the former maintains ## Inserting objects into the set -A Bloom Filter is essentially a fixed-length [bit vector](../Bit Set/), an array of bits. When we insert objects, we set some of these bits to `1`, and when we query for objects we check if certain bits are `0` or `1`. Both operations use hash functions. +A Bloom Filter is essentially a fixed-length [bit vector](../Bit%20Set/), an array of bits. When we insert objects, we set some of these bits to `1`, and when we query for objects we check if certain bits are `0` or `1`. Both operations use hash functions. To insert an element in the filter, the element is hashed with several different hash functions. Each hash function returns a value that we map to an index in the array. We then set the bits at these indices to `1` or true. diff --git a/Bounded Priority Queue/README.markdown b/Bounded Priority Queue/README.markdown index 8d47adefb..4e4c89272 100644 --- a/Bounded Priority Queue/README.markdown +++ b/Bounded Priority Queue/README.markdown @@ -1,6 +1,6 @@ # Bounded Priority queue -A bounded priority queue is similar to a regular [priority queue](../Priority Queue/), except that there is a fixed upper bound on the number of elements that can be stored. When a new element is added to the queue while the queue is at capacity, the element with the highest priority value is ejected from the queue. +A bounded priority queue is similar to a regular [priority queue](../Priority%20Queue/), except that there is a fixed upper bound on the number of elements that can be stored. When a new element is added to the queue while the queue is at capacity, the element with the highest priority value is ejected from the queue. ## Example diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown index e821b812e..5b3841eca 100644 --- a/Boyer-Moore/README.markdown +++ b/Boyer-Moore/README.markdown @@ -24,7 +24,7 @@ animals.indexOf(pattern: "🐮") > **Note:** The index of the cow is 6, not 3 as you might expect, because the string uses more storage per character for emoji. The actual value of the `String.Index` is not so important, just that it points at the right character in the string. -The [brute-force approach](../Brute-Force String Search/) works OK, but it's not very efficient, especially on large chunks of text. As it turns out, you don't need to look at _every_ character from the source string -- you can often skip ahead multiple characters. +The [brute-force approach](../Brute-Force%20String%20Search/) works OK, but it's not very efficient, especially on large chunks of text. As it turns out, you don't need to look at _every_ character from the source string -- you can often skip ahead multiple characters. The skip-ahead algorithm is called [Boyer-Moore](https://en.wikipedia.org/wiki/Boyer–Moore_string_search_algorithm) and it has been around for a long time. It is considered the benchmark for all string search algorithms. diff --git a/Breadth-First Search/README.markdown b/Breadth-First Search/README.markdown index 084f4611a..2ef92fd73 100644 --- a/Breadth-First Search/README.markdown +++ b/Breadth-First Search/README.markdown @@ -148,7 +148,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 Path/) between a source node and each of the other nodes (only for unweighted graphs). -* Calculating the [minimum spanning tree](../Minimum Spanning Tree (Unweighted)/) on an unweighted graph. +* Computing the [shortest path](../Shortest%20Path/) 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* diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 90a9ec2f3..4c65c4219 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -2,9 +2,9 @@ Goal: Count how often a certain value appears in an array. -The obvious way to do this is with a [linear search](../Linear Search/) from the beginning of the array until the end, keeping count of how often you come across the value. That is an **O(n)** algorithm. +The obvious way to do this is with a [linear search](../Linear%20Search/) from the beginning of the array until the end, keeping count of how often you come across the value. That is an **O(n)** algorithm. -However, if the array is sorted you can do it much faster, in **O(log n)** time, by using a modification of [binary search](../Binary Search/). +However, if the array is sorted you can do it much faster, in **O(log n)** time, by using a modification of [binary search](../Binary%20Search/). Let's say we have the following array: diff --git a/Hash Set/README.markdown b/Hash Set/README.markdown index 368920a1c..fb829c313 100644 --- a/Hash Set/README.markdown +++ b/Hash Set/README.markdown @@ -196,7 +196,7 @@ difference2.allElements() // [5, 6] If you look at the [documentation](http://swiftdoc.org/v2.1/type/Set/) for Swift's own `Set`, you'll notice it has tons more functionality. An obvious extension would be to make `HashSet` conform to `SequenceType` so that you can iterate it with a `for`...`in` loop. -Another thing you could do is replace the `Dictionary` with an actual [hash table](../Hash Table), but one that just stores the keys and doesn't associate them with anything. So you wouldn't need the `Bool` values anymore. +Another thing you could do is replace the `Dictionary` with an actual [hash table](../Hash%20Table), but one that just stores the keys and doesn't associate them with anything. So you wouldn't need the `Bool` values anymore. If you often need to look up whether an element belongs to a set and perform unions, then the [union-find](../Union-Find/) data structure may be more suitable. It uses a tree structure instead of a dictionary to make the find and union operations very efficient. diff --git a/How to Contribute.markdown b/How to Contribute.markdown index 258357e8b..1235f07ff 100644 --- a/How to Contribute.markdown +++ b/How to Contribute.markdown @@ -6,7 +6,7 @@ Want to help out with the Swift Algorithm Club? Great! Take a look at the [list](README.markdown). Any algorithms or data structures that don't have a link yet are up for grabs. -Algorithms in the [Under construction](Under Construction.markdown) area are being worked on. Suggestions and feedback is welcome! +Algorithms in the [Under construction](Under%20Construction.markdown) area are being worked on. Suggestions and feedback is welcome! New algorithms and data structures are always welcome (even if they aren't on the list). diff --git a/Ordered Array/README.markdown b/Ordered Array/README.markdown index ca088c325..974a42cae 100644 --- a/Ordered Array/README.markdown +++ b/Ordered Array/README.markdown @@ -83,7 +83,7 @@ a // [-2, -1, 1, 3, 4, 5, 7, 9, 10] The array's contents will always be sorted from low to high, now matter what. -Unfortunately, the current `findInsertionPoint()` function is a bit slow. In the worst case, it needs to scan through the entire array. We can speed this up by using a [binary search](../Binary Search) to find the insertion point. +Unfortunately, the current `findInsertionPoint()` function is a bit slow. In the worst case, it needs to scan through the entire array. We can speed this up by using a [binary search](../Binary%20Search) to find the insertion point. Here is the new version: diff --git a/Ordered Set/README.markdown b/Ordered Set/README.markdown index 0525a31ed..1c0d5a8ac 100644 --- a/Ordered Set/README.markdown +++ b/Ordered Set/README.markdown @@ -115,7 +115,7 @@ The next function is `indexOf()`, which takes in an object of type `T` and retur } ``` -> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary Search). +> **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. diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index c583b47ea..e95749d14 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -6,7 +6,7 @@ You are given an array of numbers and need to put them in the right order. The s [ ...sorted numbers... | ...unsorted numbers... ] -This is similar to [insertion sort](../Insertion Sort/), but the difference is in how new numbers are added to the sorted portion. +This is similar to [insertion sort](../Insertion%20Sort/), but the difference is in how new numbers are added to the sorted portion. It works as follows: @@ -108,9 +108,9 @@ The source file [SelectionSort.swift](SelectionSort.swift) has a version of this ## Performance -Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than [insertion sort](../Insertion Sort/) but better than [bubble sort](../Bubble Sort/). The killer is finding the lowest element in the rest of the array. This takes up a lot of time, especially since the inner loop will be performed over and over. +Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than [insertion sort](../Insertion%20Sort/) but better than [bubble sort](../Bubble Sort/). The killer is finding the lowest element in the rest of the array. This takes up a lot of time, especially since the inner loop will be performed over and over. -[Heap sort](../Heap Sort/) uses the same principle as selection sort but has a really fast method for finding the minimum value in the rest of the array. Its performance is **O(n log n)**. +[Heap sort](../Heap%20Sort/) uses the same principle as selection sort but has a really fast method for finding the minimum value in the rest of the array. Its performance is **O(n log n)**. ## See also diff --git a/Shell Sort/README.markdown b/Shell Sort/README.markdown index 9c4bdf076..c21c29685 100644 --- a/Shell Sort/README.markdown +++ b/Shell Sort/README.markdown @@ -39,7 +39,7 @@ As you can see, each sublist contains only every 4th item from the original arra We now call `insertionSort()` once on each sublist. -This particular version of [insertion sort](../Insertion Sort/) sorts from the back to the front. Each item in the sublist is compared against the others. If they're in the wrong order, the value is swapped and travels all the way down until we reach the start of the sublist. +This particular version of [insertion sort](../Insertion%20Sort/) sorts from the back to the front. Each item in the sublist is compared against the others. If they're in the wrong order, the value is swapped and travels all the way down until we reach the start of the sublist. So for sublist 0, we swap `4` with `72`, then swap `4` with `64`. After sorting, this sublist looks like: diff --git a/Shortest Path (Unweighted)/README.markdown b/Shortest Path (Unweighted)/README.markdown index a16519260..4c3c34d9c 100644 --- a/Shortest Path (Unweighted)/README.markdown +++ b/Shortest Path (Unweighted)/README.markdown @@ -12,11 +12,11 @@ If the [graph is unweighed](../Graph/), then finding the shortest path is easy: ## Unweighted graph: breadth-first search -[Breadth-first search](../Breadth-First Search/) is a method for traversing a tree or graph data structure. It starts at a source node and explores the immediate neighbor nodes first, before moving to the next level neighbors. As a convenient side effect, it automatically computes the shortest path between a source node and each of the other nodes in the tree or graph. +[Breadth-first search](../Breadth-First%20Search/) is a method for traversing a tree or graph data structure. It starts at a source node and explores the immediate neighbor nodes first, before moving to the next level neighbors. As a convenient side effect, it automatically computes the shortest path between a source node and each of the other nodes in the tree or graph. The result of the breadth-first search can be represented with a tree: -![The BFS tree](../Breadth-First Search/Images/TraversalTree.png) +![The BFS tree](../Breadth-First%20Search/Images/TraversalTree.png) The root of the tree is the node you started the breadth-first search from. To find the distance from node `A` to any other node, we simply count the number of edges in the tree. And so we find that the shortest path between `A` and `F` is 2. The tree not only tells you how long that path is, but also how to actually get from `A` to `F` (or any of the other nodes). @@ -57,7 +57,7 @@ queue.enqueue(element: G) G.distance = C.distance + 1 // result: 2 ``` -This continues until the queue is empty and we've visited all the nodes. Each time we discover a new node, it gets the `distance` of its parent plus 1. As you can see, this is exactly what the [breadth-first search](../Breadth-First Search/) algorithm does, except that we now also keep track of the distance travelled. +This continues until the queue is empty and we've visited all the nodes. Each time we discover a new node, it gets the `distance` of its parent plus 1. As you can see, this is exactly what the [breadth-first search](../Breadth-First%20Search/) algorithm does, except that we now also keep track of the distance travelled. Here's the code: @@ -97,6 +97,6 @@ This will output: Node(label: d, distance: 2), Node(label: e, distance: 2), Node(label: f, distance: 2), Node(label: g, distance: 2), Node(label: h, distance: 3) -> **Note:** This version of `breadthFirstSearchShortestPath()` does not actually produce the tree, it only computes the distances. See [minimum spanning tree](../Minimum Spanning Tree (Unweighted)/) on how you can convert the graph into a tree by removing edges. +> **Note:** This version of `breadthFirstSearchShortestPath()` does not actually produce the tree, it only computes the distances. See [minimum spanning tree](../Minimum%20Spanning%20Tree%20(Unweighted)/) on how you can convert the graph into a tree by removing edges. *Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* diff --git a/Threaded Binary Tree/README.markdown b/Threaded Binary Tree/README.markdown index fd05113d8..8a1c518f1 100644 --- a/Threaded Binary Tree/README.markdown +++ b/Threaded Binary Tree/README.markdown @@ -1,6 +1,6 @@ # Threaded Binary Tree -A threaded binary tree is a special kind of [binary tree](../Binary Tree/) (a +A threaded binary tree is a special kind of [binary tree](../Binary%20Tree/) (a tree in which each node has at most two children) that maintains a few extra variables to allow cheap and fast **in-order traversal** of the tree. We will explore the general structure of threaded binary trees, as well as @@ -17,7 +17,7 @@ The main motivation behind using a threaded binary tree over a simpler and smaller standard binary tree is to increase the speed of an in-order traversal of the tree. An in-order traversal of a binary tree visits the nodes in the order in which they are stored, which matches the underlying ordering of a -[binary search tree](../Binary Search Tree/). This means most threaded binary +[binary search tree](../Binary%20Search%20Tree/). This means most threaded binary trees are also binary search trees. The idea is to visit all the left children of a node first, then visit the node itself, and then visit the right children last. @@ -47,7 +47,7 @@ tree, to **O(n)** to a very unbalanced tree. A threaded binary tree fixes this problem. -> For more information about in-order traversals [see here](../Binary Tree/). +> For more information about in-order traversals [see here](../Binary%20Tree/). ## Predecessors and successors @@ -222,7 +222,7 @@ walking through some boring code, it is best to explain this with an example (although you can read through [the implementation](ThreadedBinaryTree.swift) if you want to know the finer details). Please note that this requires knowledge of binary search trees, so make sure you have -[read this first](../Binary Search Tree/). +[read this first](../Binary%20Search%20Tree/). > Note: we do allow duplicate nodes in this implementation of a threaded binary > tree. We break ties by defaulting insertion to the right. @@ -339,7 +339,7 @@ such as `searching()` for a node in the tree, finding the `depth()` or `height()` of a node, etc. You can check [the implementation](ThreadedBinaryTree.swift) for the full technical details. Many of these methods are inherent to binary search trees as well, so you can -find [further documentation here](../Binary Search Tree/). +find [further documentation here](../Binary%20Search%20Tree/). ## See also diff --git a/Topological Sort/README.markdown b/Topological Sort/README.markdown index 4429a0754..5659dc3fd 100644 --- a/Topological Sort/README.markdown +++ b/Topological Sort/README.markdown @@ -22,7 +22,7 @@ The following is not a valid topological sort for this graph, since **X** and ** Let's consider that you want to learn all the algorithms and data structures from the Swift Algorithm Club. This might seem daunting at first but we can use topological sort to get things organized. -Since you're learning about topological sort, let's take this topic as an example. What else do you need to learn first before you can fully understand topological sort? Well, topological sort uses [depth-first search](../Depth-First Search/) as well as a [stack](../Stack/). But before you can learn about the depth-first search algorithm, you need to know what a [graph](../Graph/) is, and it helps to know what a [tree](../Tree/) is. In turn, graphs and trees use the idea of linking objects together, so you may need to read up on that first. And so on... +Since you're learning about topological sort, let's take this topic as an example. What else do you need to learn first before you can fully understand topological sort? Well, topological sort uses [depth-first search](../Depth-First%20Search/) as well as a [stack](../Stack/). But before you can learn about the depth-first search algorithm, you need to know what a [graph](../Graph/) is, and it helps to know what a [tree](../Tree/) is. In turn, graphs and trees use the idea of linking objects together, so you may need to read up on that first. And so on... If we were to represent these objectives in the form of a graph it would look as follows: diff --git a/Tree/README.markdown b/Tree/README.markdown index 529a68cf1..440d9c9a4 100644 --- a/Tree/README.markdown +++ b/Tree/README.markdown @@ -16,7 +16,7 @@ The pointers in a tree do not form cycles. This is not a tree: ![Not a tree](Images/Cycles.png) -Such a structure is called a [graph](../Graph/). A tree is really a very simple form of a graph. (In a similar vein, a [linked list](../Linked List/) is a simple version of a tree. Think about it!) +Such a structure is called a [graph](../Graph/). A tree is really a very simple form of a graph. (In a similar vein, a [linked list](../Linked%20List/) is a simple version of a tree. Think about it!) This article talks about a general-purpose tree. That's a tree without any kind of restrictions on how many children each node may have, or on the order of the nodes in the tree. @@ -119,7 +119,7 @@ We often use the following definitions when talking about trees: - **Depth of a node.** The number of links between this node and the root node. For example, the depth of `tea` is 2 because it takes two jumps to reach the root. (The root itself has depth 0.) -There are many different ways to construct trees. For example, sometimes you don't need to have a `parent` property at all. Or maybe you only need to give each node a maximum of two children -- such a tree is called a [binary tree](../Binary Tree/). A very common type of tree is the [binary search tree](../Binary Search Tree/) (or BST), a stricter version of a binary tree where the nodes are ordered in a particular way to speed up searches. +There are many different ways to construct trees. For example, sometimes you don't need to have a `parent` property at all. Or maybe you only need to give each node a maximum of two children -- such a tree is called a [binary tree](../Binary%20Tree/). A very common type of tree is the [binary search tree](../Binary%20Search%20Tree/) (or BST), a stricter version of a binary tree where the nodes are ordered in a particular way to speed up searches. The general purpose tree I've shown here is great for describing hierarchical data, but it really depends on your application what kind of extra functionality it needs to have. diff --git a/Under Construction.markdown b/Under Construction.markdown index 0c59d90c1..be53e01b0 100644 --- a/Under Construction.markdown +++ b/Under Construction.markdown @@ -5,27 +5,27 @@ Here you'll find algorithms that are currently under construction. Suggestions a ### Sorting Special-purpose sorts: - - [Radix Sort](Radix Sort/) + - [Radix Sort](Radix%20Sort/) ### Special-purpose sorts: -- [Bucket Sort](Bucket Sort/) +- [Bucket Sort](Bucket%20Sort/) ### Queues -- [Bounded Priority Queue](Bounded Priority Queue). A queue that is bounded to have a limited number of elements. +- [Bounded Priority Queue](Bounded%20Priority%20Queue). A queue that is bounded to have a limited number of elements. ### Trees -- [AVL Tree](AVL Tree/). A binary search tree that balances itself using rotations. -- [Red-Black Tree](Red-Black Tree/) -- [Threaded Binary Tree](Threaded Binary Tree/) -- [Ternary Search Tree](Ternary Search Tree/) +- [AVL Tree](AVL%20Tree/). A binary search tree that balances itself using rotations. +- [Red-Black Tree](Red-Black%20Tree/) +- [Threaded Binary Tree](Threaded%20Binary%20Tree/) +- [Ternary Search Tree](Ternary%20Search%20Tree/) - [Trie](Trie/) -- [Radix Tree](Radix Tree/) +- [Radix Tree](Radix%20Tree/) ### Miscellaneous -- [Minimum Edit Distance](Minimum Edit Distance/). Measure the similarity of two strings by counting the number of operations required to transform one string into the other. +- [Minimum Edit Distance](Minimum%20Edit%20Distance/). Measure the similarity of two strings by counting the number of operations required to transform one string into the other. - [Treap](Treap/) -- [Set Cover (Unweighted)](Set Cover (Unweighted)/) +- [Set Cover (Unweighted)](Set%20Cover%20(Unweighted)/) From bd35ff8f1bb984bf5cf5eeb8375539dfcdd248ad Mon Sep 17 00:00:00 2001 From: Hunter Maximillion Monk Date: Sat, 25 Mar 2017 21:57:12 -0500 Subject: [PATCH 0465/1275] Fix binary search tree link Just need to convert spaces into %20 for relative URLs with spaces to work. --- Binary Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index 896116dda..8ce398804 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -8,7 +8,7 @@ The child nodes are usually called the *left* child and the *right* child. If a Often nodes will have a link back to their parent but this is not strictly necessary. -Binary trees are often used as [binary search trees](../Binary Search Tree/). In that case, the nodes must be in a specific order (smaller values on the left, larger values on the right). But this is not a requirement for all binary trees. +Binary trees are often used as [binary search trees](../Binary%20Search%20Tree/). In that case, the nodes must be in a specific order (smaller values on the left, larger values on the right). But this is not a requirement for all binary trees. For example, here is a binary tree that represents a sequence of arithmetical operations, `(5 * (a - 10)) + (-4 * (3 / b))`: From eb68b1d69836d3d2d1bb1cba269466a94f837aea Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 26 Mar 2017 15:38:26 -0700 Subject: [PATCH 0466/1275] updated readme --- .../README.markdown | 459 +++++++++++++++++- .../Contents.swift | 2 + .../Sources/Matrix.swift | 180 ++++--- .../Sources/MatrixSize.swift | 19 +- .../Sources/Number.swift | 12 +- 5 files changed, 571 insertions(+), 101 deletions(-) diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown index d07004bad..e4222b4f4 100644 --- a/Strassen Matrix Multiplication/README.markdown +++ b/Strassen Matrix Multiplication/README.markdown @@ -1 +1,458 @@ -## TODO: Examples & Explanation +# Strassen Matrix Multiplication + +## Goal ++ To quickly perform a matrix multiplication operation on two matricies + +## What is Matrix Multiplication?? + +> Note: If you are already familiar with Linear Algebra/Matrix Multiplication, feel free to skip this section + +Before we begin, you may ask what is matrix multiplication? Great question! It is **NOT** multiplying two matricies term-by-term. Matrix multiplication is a mathematical operation that combines two matricies into a single one. Sounds like multiplying term-by-term huh? It's not... our lives would be much easier if it were. To see how matrix multiplcation works, let's look at an example. + +### Example: Matrix Multiplication + + matrix A = |1 2| + |3 4| + + matrix B = |5 6| + |7 8| + + A * B = C + + |1 2| * |5 6| = |1*5+2*7 1*6+2*8| = |19 22| + |3 4| |7 8| |3*5+4*7 3*6+4*8| |43 48| + +What's going on here? To start, we're multiplying matricies A & B. Our new matrix, C's, elements `[i, j]` are determined by the dot product of the first matrix's ith row and the second matrix's jth column. See [here](https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/dot-cross-products/v/vector-dot-product-and-vector-length) for a refresher on the dot product. + +So the upper left element `[i=1, j=1]` of our new matrix is a combination of A's 1st row and B's 1st column. + + A's first row = [1, 2] + B's first column = [5, 7] + + [1, 2] dot [5, 7] = [1*5 + 2*7] = [19] = C[1, 1] + +Now let's try this for `[i=1, j=2]`. Because `i=1` and `j=2`, this will represent the upper right element in our new matrix, C. + + A's first row = [1, 2] + B's second column = [6, 8] + + [1, 2] dot [6, 8] = [1*6 + 2*8] = [22] = C[1, 2] + +If we do this for each row & column of A & B we'll get our result matrix C! + +Here's a great graphic that visually shows you what's going on. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Matrix_multiplication_principle.svg/1024px-Matrix_multiplication_principle.svg.png) + +[Source](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Matrix_multiplication_principle.svg/1024px-Matrix_multiplication_principle.svg.png) + + +## Matix Multiplication Algorithm + +So how do we implement matrix multiplication in an algoirthm? We'll start with the basic version and from there move on to Strassen's Algorithm. + ++ [Basic Version](#basic-version) ++ [Strassen's Algorithm](#strassens-algorithm) + +### Basic Version + +Remember the method we used to solve matrix multiplication [above](#what-is-matrix-multiplication??)? Let's try to implement that first! We first assert that the two matricies are the right size. + +`assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R")` + +> **NOTE:** A's # of columns HAS to equal B's # of rows for matrix multiplication to work + +Next, we loop over A's columns and B's rows. Because we know both A's columns & B's rows are the same length, we set that length equal to `n`. + +```swift +for i in 0..) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + let n = A.columns + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + let n = max(A.rows, A.columns, B.rows, B.columns) + let m = nextPowerOfTwo(after: n) + + var APrep = Matrix(size: m) + var BPrep = Matrix(size: m) + + A.forEach { (i, j) in + APrep[i,j] = A[i,j] + } + + B.forEach { (i, j) in + BPrep[i,j] = B[i,j] + } + + let CPrep = APrep.strassenR(by: BPrep) + var C = Matrix(rows: A.rows, columns: B.columns) + for i in 0..) -> Matrix { + let A = self + assert(A.isSquare && B.isSquare, "This function requires square matricies!") + guard A.rows > 1 && B.rows > 1 else { return A * B } + + let n = A.rows + let nBy2 = n / 2 + + /* + Assume submatricies are allocated as follows + + matrix A = |a b|, matrix B = |e f| + |c d| |g h| + */ + + var a = Matrix(size: nBy2) + var b = Matrix(size: nBy2) + var c = Matrix(size: nBy2) + var d = Matrix(size: nBy2) + var e = Matrix(size: nBy2) + var f = Matrix(size: nBy2) + var g = Matrix(size: nBy2) + var h = Matrix(size: nBy2) + + for i in 0.. Int { + return Int(pow(2, ceil(log2(Double(n))))) + } +} +``` + + +## Appendix + +### Number Protocol + +I use a number protocol to enable by Matrix to be generic. + +The Number protocol ensures three things: + +1. Everything that is a number can be multiplied +2. Everything that is a number can be added/subtracted +3. Everything that is a number has a zero value + +Extending `Int`, `Float`, and `Double` to conform to this protocol is now very straightforward. All you need to do is implement the `static var zero`! + +```swift +public protocol Number: Multipliable, Addable { + static var zero: Self { get } +} + +public protocol Addable { + static func +(lhs: Self, rhs: Self) -> Self + static func -(lhs: Self, rhs: Self) -> Self +} + +public protocol Multipliable { + static func *(lhs: Self, rhs: Self) -> Self +} +``` + +### Dot Product + +I extend `Array` to include a dot product function for when the Array's element conform to the `Number` protocol. + +```swift +extension Array where Element: Number { + public func dot(_ b: Array) -> Element { + let a = self + assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") + let c = a.indices.map{ a[$0] * b[$0] } + return c.reduce(Element.zero, { $0 + $1 }) + } +} +``` + +##Resources ++ [Intro to Matrix Multiplication | Khan Academy](https://www.khanacademy.org/math/precalculus/precalc-matrices/multiplying-matrices-by-matrices/v/matrix-multiplication-intro) ++ [Matrix Multiplication | Wikipedia](https://en.wikipedia.org/wiki/Matrix_multiplication) ++ [Strassen Algorithm | Wikipedia](https://en.wikipedia.org/wiki/Strassen_algorithm) ++ [Strassen Algorithm | Wolfram MathWorld](http://mathworld.wolfram.com/StrassenFormulas.html) ++ [Strassens Algorithm | Geeks for Geeks](http://www.geeksforgeeks.org/strassens-matrix-multiplication/) \ No newline at end of file diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift index 50af60a6f..5d82244a3 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -8,9 +8,11 @@ A[.row, 0] = [2, 3, -1, 0] A[.row, 1] = [-7, 2, 1, 10] var B = Matrix(rows: 4, columns: 2, initialValue: 0) +print(B) B[.column, 0] = [3, 2, -1, 2] B[.column, 1] = [4, 1, 2, 7] + let C = A.matrixMultiply(by: B) let D = A.strassenMatrixMultiply(by: B) let E = B.matrixMultiply(by: A) diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift index eba49ce9a..77ced4632 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift @@ -40,23 +40,26 @@ public struct Matrix { self.columns = size self.grid = Array(repeating: initialValue, count: rows * columns) } -} - -// MARK: - Public Functions - -public extension Matrix { - subscript(row: Int, column: Int) -> T { + + // MARK: - Private Functions + + fileprivate func indexIsValid(row: Int, column: Int) -> Bool { + return row >= 0 && row < rows && column >= 0 && column < columns + } + + // MARK: - Subscript + + public subscript(row: Int, column: Int) -> T { get { assert(indexIsValid(row: row, column: column), "Index out of range") return grid[(row * columns) + column] - } - set { + } set { assert(indexIsValid(row: row, column: column), "Index out of range") grid[(row * columns) + column] = newValue } } - subscript(type: RowOrColumn, value: Int) -> [T] { + public subscript(type: RowOrColumn, value: Int) -> [T] { get { switch type { case .row: @@ -64,15 +67,11 @@ public extension Matrix { return Array(grid[(value * columns)..<(value * columns) + columns]) case .column: assert(indexIsValid(row: 0, column: value), "Index out of range") - var columns: [T] = [] - for row in 0.. T in + let currentColumnIndex = currentRow * columns + value + return grid[currentColumnIndex] } - return columns + return column } } set { switch type { @@ -90,59 +89,84 @@ public extension Matrix { } } - func strassenMatrixMultiply(by B: Matrix) -> Matrix { + // MARK: - Public Functions + + public func row(for columnIndex: Int) -> [T] { + assert(indexIsValid(row: columnIndex, column: 0), "Index out of range") + return Array(grid[(columnIndex * columns)..<(columnIndex * columns) + columns]) + } + + public func column(for rowIndex: Int) -> [T] { + assert(indexIsValid(row: 0, column: rowIndex), "Index out of range") + + let column = (0.. T in + let currentColumnIndex = currentRow * columns + rowIndex + return grid[currentColumnIndex] + } + return column + } + + public func forEach(_ body: (Int, Int) throws -> Void) rethrows { + for row in 0..) -> Matrix { + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + + var C = Matrix(rows: A.rows, columns: B.columns) + + for i in 0..) -> Matrix { let A = self assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") let n = max(A.rows, A.columns, B.rows, B.columns) - let m = nextPowerOfTwo(of: n) + let m = nextPowerOfTwo(after: n) var APrep = Matrix(size: m) var BPrep = Matrix(size: m) - A.size.forEach { (i, j) in + A.forEach { (i, j) in APrep[i,j] = A[i,j] } - B.size.forEach { (i, j) in + B.forEach { (i, j) in BPrep[i,j] = B[i,j] } let CPrep = APrep.strassenR(by: BPrep) var C = Matrix(rows: A.rows, columns: B.columns) - for i in 0..) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - - var C = Matrix(rows: A.rows, columns: B.columns) - - for i in 0.. Bool { - return row >= 0 && row < rows && column >= 0 && column < columns - } - func strassenR(by B: Matrix) -> Matrix { + private func strassenR(by B: Matrix) -> Matrix { let A = self assert(A.isSquare && B.isSquare, "This function requires square matricies!") guard A.rows > 1 && B.rows > 1 else { return A * B } @@ -150,42 +174,49 @@ fileprivate extension Matrix { let n = A.rows let nBy2 = n / 2 - var a11 = Matrix(size: nBy2) - var a12 = Matrix(size: nBy2) - var a21 = Matrix(size: nBy2) - var a22 = Matrix(size: nBy2) - var b11 = Matrix(size: nBy2) - var b12 = Matrix(size: nBy2) - var b21 = Matrix(size: nBy2) - var b22 = Matrix(size: nBy2) + /* + Assume submatricies are allocated as follows + + matrix A = |a b|, matrix B = |e f| + |c d| |g h| + */ + + var a = Matrix(size: nBy2) + var b = Matrix(size: nBy2) + var c = Matrix(size: nBy2) + var d = Matrix(size: nBy2) + var e = Matrix(size: nBy2) + var f = Matrix(size: nBy2) + var g = Matrix(size: nBy2) + var h = Matrix(size: nBy2) for i in 0.. Int { + private func nextPowerOfTwo(after n: Int) -> Int { return Int(pow(2, ceil(log2(Double(n))))) } } - // Term-by-term Matrix Math extension Matrix: Addable { diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift index f4a604ade..e0d957607 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift @@ -8,26 +8,13 @@ import Foundation -public struct MatrixSize: Equatable { +public struct MatrixSize { let rows: Int let columns: Int - - public init(rows: Int, columns: Int) { - self.rows = rows - self.columns = columns - } - - public func forEach(_ body: (Int, Int) throws -> Void) rethrows { - for row in 0.. Bool { +extension MatrixSize: Equatable { + public static func ==(lhs: MatrixSize, rhs: MatrixSize) -> Bool { return lhs.columns == rhs.columns && lhs.rows == rhs.rows } } diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift index 9f4c7f4ab..7da1eee60 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift @@ -22,21 +22,15 @@ public protocol Multipliable { } extension Int: Number { - public static var zero: Int { - return 0 - } + public static var zero: Int { return 0 } } extension Double: Number { - public static var zero: Double { - return 0.0 - } + public static var zero: Double { return 0.0 } } extension Float: Number { - public static var zero: Float { - return 0.0 - } + public static var zero: Float { return 0.0 } } extension Array where Element: Number { From c94fbab56dcd0b3f483ec8a1fec718de7ef97ba2 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 26 Mar 2017 15:53:58 -0700 Subject: [PATCH 0467/1275] added authorship to readme --- Strassen Matrix Multiplication/README.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown index e4222b4f4..6949f906c 100644 --- a/Strassen Matrix Multiplication/README.markdown +++ b/Strassen Matrix Multiplication/README.markdown @@ -405,7 +405,6 @@ extension Matrix { } ``` - ## Appendix ### Number Protocol @@ -455,4 +454,6 @@ extension Array where Element: Number { + [Matrix Multiplication | Wikipedia](https://en.wikipedia.org/wiki/Matrix_multiplication) + [Strassen Algorithm | Wikipedia](https://en.wikipedia.org/wiki/Strassen_algorithm) + [Strassen Algorithm | Wolfram MathWorld](http://mathworld.wolfram.com/StrassenFormulas.html) -+ [Strassens Algorithm | Geeks for Geeks](http://www.geeksforgeeks.org/strassens-matrix-multiplication/) \ No newline at end of file ++ [Strassens Algorithm | Geeks for Geeks](http://www.geeksforgeeks.org/strassens-matrix-multiplication/) + +*Written for Swift Algorithm Club by Richard Ash* \ No newline at end of file From 09848a79e92c266b3e33006781732c1e288d7f6f Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 26 Mar 2017 15:55:13 -0700 Subject: [PATCH 0468/1275] fixed the display of the resources header --- Strassen Matrix Multiplication/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown index 6949f906c..713ab1801 100644 --- a/Strassen Matrix Multiplication/README.markdown +++ b/Strassen Matrix Multiplication/README.markdown @@ -449,7 +449,8 @@ extension Array where Element: Number { } ``` -##Resources +## Resources + + [Intro to Matrix Multiplication | Khan Academy](https://www.khanacademy.org/math/precalculus/precalc-matrices/multiplying-matrices-by-matrices/v/matrix-multiplication-intro) + [Matrix Multiplication | Wikipedia](https://en.wikipedia.org/wiki/Matrix_multiplication) + [Strassen Algorithm | Wikipedia](https://en.wikipedia.org/wiki/Strassen_algorithm) From ab37359616c210f84363b885ef0308b17cadc202 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 26 Mar 2017 16:05:27 -0700 Subject: [PATCH 0469/1275] fixed layout of code in readme --- .../README.markdown | 142 +++++++++--------- 1 file changed, 75 insertions(+), 67 deletions(-) diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown index 713ab1801..fa822d310 100644 --- a/Strassen Matrix Multiplication/README.markdown +++ b/Strassen Matrix Multiplication/README.markdown @@ -11,17 +11,16 @@ Before we begin, you may ask what is matrix multiplication? Great question! It i ### Example: Matrix Multiplication - matrix A = |1 2| - |3 4| - - matrix B = |5 6| - |7 8| - - A * B = C +``` +matrix A = |1 2|, matrix B = |5 6| + |3 4| |7 8| - |1 2| * |5 6| = |1*5+2*7 1*6+2*8| = |19 22| - |3 4| |7 8| |3*5+4*7 3*6+4*8| |43 48| +A * B = C +|1 2| * |5 6| = |1*5+2*7 1*6+2*8| = |19 22| +|3 4| |7 8| |3*5+4*7 3*6+4*8| |43 48| +``` + What's going on here? To start, we're multiplying matricies A & B. Our new matrix, C's, elements `[i, j]` are determined by the dot product of the first matrix's ith row and the second matrix's jth column. See [here](https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/dot-cross-products/v/vector-dot-product-and-vector-length) for a refresher on the dot product. So the upper left element `[i=1, j=1]` of our new matrix is a combination of A's 1st row and B's 1st column. @@ -66,14 +65,14 @@ Next, we loop over A's columns and B's rows. Because we know both A's columns & ```swift for i in 0..) -> Matrix { - let A = self - assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - let n = A.columns - var C = Matrix(rows: A.rows, columns: B.columns) + let A = self + assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") + let n = A.columns + var C = Matrix(rows: A.rows, columns: B.columns) - for i in 0.. Date: Mon, 27 Mar 2017 16:33:26 +0800 Subject: [PATCH 0470/1275] Delete SelectionSamplingExample.swift --- .../SelectionSamplingExample.swift | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 Selection Sampling/SelectionSamplingExample.swift diff --git a/Selection Sampling/SelectionSamplingExample.swift b/Selection Sampling/SelectionSamplingExample.swift deleted file mode 100644 index 66648a934..000000000 --- a/Selection Sampling/SelectionSamplingExample.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Select.swift -// -// -// Created by Cheer on 2017/3/9. -// -// - -import Foundation - -func select(from a: [T], count requested: Int) -> [T] { - - // if requested > a.count, will throw ==> fatal error: Index out of range - - if requested < a.count { - var arr = a - for i in 0.. the range is [0...n-1] - //So: arc4random_uniform(UInt32(arr.count - i - 2)) + (i + 1) ==> [0...arr.count - (i + 1) - 1] + (i + 1) ==> the range is [(i + 1)...arr.count - 1] - //Why start index is "(i + 1)"? Because in "swap(&A,&B)", if A's index == B's index, will throw a error: "swapping a location with itself is not supported" - - let nextIndex = Int(arc4random_uniform(UInt32(arr.count - i - 2))) + (i + 1) - swap(&arr[nextIndex], &arr[i]) - } - return Array(arr[0.. Date: Tue, 28 Mar 2017 15:54:51 +0800 Subject: [PATCH 0471/1275] Update ShellSortExample.swift fix code. And apologize for my carelessness. --- Shell Sort/ShellSortExample.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index c41eb8889..0beac00a3 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -14,18 +14,18 @@ public func shellSort(_ list : inout [Int]) while sublistCount > 0 { - for var index in 0.. arr[index + sublistCount]{ - swap(&arr[index], &arr[index + sublistCount]) + if list[index] > list[index + sublistCount]{ + swap(&list[index], &list[index + sublistCount]) } guard sublistCount == 1 && index > 0 else { continue } - - while arr[index - 1] > arr[index] && index - 1 > 0 { - swap(&arr[index - 1], &arr[index]) + + while list[index - 1] > list[index] && index - 1 > 0 { + swap(&list[index - 1], &list[index]) index -= 1 } } From 14fe78745ccceb2de88ed2a3dc05835d99317e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Tue, 28 Mar 2017 15:55:45 +0800 Subject: [PATCH 0472/1275] Update ShellSortExample.swift --- Shell Sort/ShellSortExample.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index 0beac00a3..05ab2518b 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -14,11 +14,11 @@ public func shellSort(_ list : inout [Int]) while sublistCount > 0 { - for var index in 0.. list[index + sublistCount]{ + if list[index] > list[index + sublistCount] { swap(&list[index], &list[index + sublistCount]) } From cf1561f885c414d8c4bb260cd21720c109468b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=98=E5=AD=90?= <726451484@qq.com> Date: Tue, 28 Mar 2017 15:56:26 +0800 Subject: [PATCH 0473/1275] Update ShellSortExample.swift --- Shell Sort/ShellSortExample.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index 05ab2518b..9174b935b 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -8,12 +8,10 @@ import Foundation -public func shellSort(_ list : inout [Int]) -{ +public func shellSort(_ list : inout [Int]) { var sublistCount = list.count / 2 - while sublistCount > 0 - { + while sublistCount > 0 { for var index in 0.. Date: Tue, 28 Mar 2017 20:01:36 -0700 Subject: [PATCH 0474/1275] Update How to Contribute link Super simple but just something I noticed while getting started. Cheers! --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 023f151fb..5e6cfbfe4 100644 --- a/README.markdown +++ b/README.markdown @@ -227,7 +227,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) 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](How to Contribute.markdown)? :] +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](How%20to%20Contribute.markdown)? :] ## License From edee6981d7e77ff88186439b2536b8cc212354c5 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 28 Mar 2017 21:31:33 -0700 Subject: [PATCH 0475/1275] =?UTF-8?q?updated=20syntax=20for=20Swift=203.1!?= =?UTF-8?q?=20=F0=9F=98=81=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contents.swift | 1 - .../Sources/Matrix.swift | 31 ++++++++++++------- .../Sources/MatrixSize.swift | 20 ------------ 3 files changed, 19 insertions(+), 33 deletions(-) delete mode 100644 Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift index 5d82244a3..9e11cb6a1 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -1,5 +1,4 @@ //: Playground - noun: a place where people can play -// Reference - http://mathworld.wolfram.com/StrassenFormulas.html import Foundation diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift index 77ced4632..c13b3eeee 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift @@ -8,37 +8,44 @@ import Foundation -public enum RowOrColumn { - case row, column -} - public struct Matrix { + // MARK: - Martix Objects + + public enum Index { + case row, column + } + + public struct Size: Equatable { + let rows: Int, columns: Int + + public static func ==(lhs: Size, rhs: Size) -> Bool { + return lhs.columns == rhs.columns && lhs.rows == rhs.rows + } + } + // MARK: - Variables let rows: Int, columns: Int + let size: Size + var grid: [T] var isSquare: Bool { return rows == columns } - var size: MatrixSize { - return MatrixSize(rows: rows, columns: columns) - } - // MARK: - Init public init(rows: Int, columns: Int, initialValue: T = T.zero) { self.rows = rows self.columns = columns + self.size = Size(rows: rows, columns: columns) self.grid = Array(repeating: initialValue, count: rows * columns) } public init(size: Int, initialValue: T = T.zero) { - self.rows = size - self.columns = size - self.grid = Array(repeating: initialValue, count: rows * columns) + self.init(rows: size, columns: size, initialValue: initialValue) } // MARK: - Private Functions @@ -59,7 +66,7 @@ public struct Matrix { } } - public subscript(type: RowOrColumn, value: Int) -> [T] { + public subscript(type: Matrix.Index, value: Int) -> [T] { get { switch type { case .row: diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift deleted file mode 100644 index e0d957607..000000000 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/MatrixSize.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// MatrixSize.swift -// -// -// Created by Richard Ash on 10/28/16. -// -// - -import Foundation - -public struct MatrixSize { - let rows: Int - let columns: Int -} - -extension MatrixSize: Equatable { - public static func ==(lhs: MatrixSize, rhs: MatrixSize) -> Bool { - return lhs.columns == rhs.columns && lhs.rows == rhs.rows - } -} From 4d1b9ff02cb46640b55f8b462be8d4536ca182bf Mon Sep 17 00:00:00 2001 From: Jim Rhoades Date: Wed, 29 Mar 2017 18:02:32 -0400 Subject: [PATCH 0476/1275] Update Big-O Notation.markdown Fixed the link to "merge sort". --- Big-O Notation.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 09fbb04aa..746cba8a3 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -19,6 +19,6 @@ Big-O | Name | Description Often you don't need math to figure out what the Big-O of an algorithm is but you can simply use your intuition. If your code uses a single loop that looks at all **n** elements of your input, the algorithm is **O(n)**. If the code has two nested loops, it is **O(n^2)**. Three nested loops gives **O(n^3)**, and so on. -Note that Big-O notation is an estimate and is only really useful for large values of **n**. For example, the worst-case running time for the [insertion sort](Insertion%20Sort/) algorithm is **O(n^2)**. In theory that is worse than the running time for [merge sort](Merge Sort/), which is **O(n log n)**. But for small amounts of data, insertion sort is actually faster, especially if the array is partially sorted already! +Note that Big-O notation is an estimate and is only really useful for large values of **n**. For example, the worst-case running time for the [insertion sort](Insertion%20Sort/) algorithm is **O(n^2)**. In theory that is worse than the running time for [merge sort](Merge%20Sort/), which is **O(n log n)**. But for small amounts of data, insertion sort is actually faster, especially if the array is partially sorted already! If you find this confusing, don't let this Big-O stuff bother you too much. It's mostly useful when comparing two algorithms to figure out which one is better. But in the end you still want to test in practice which one really is the best. And if the amount of data is relatively small, then even a slow algorithm will be fast enough for practical use. From 6d4a1eec73c92713e2e4e880b486694da545dbf9 Mon Sep 17 00:00:00 2001 From: darrellhz Date: Thu, 30 Mar 2017 14:30:01 +0900 Subject: [PATCH 0477/1275] Update README.markdown updated to swift 3 syntax --- 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 a3a84c03d..b3b955c61 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -195,7 +195,7 @@ For convenience, let's add an init method that calls `insert()` for all the elem precondition(array.count > 0) self.init(value: array.first!) for v in array.dropFirst() { - insert(v, parent: self) + insert(value: v) } } ``` From da0be01444b4dfc2cdbd2259a3e5c524e9d37434 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Sat, 1 Apr 2017 14:29:56 -0700 Subject: [PATCH 0478/1275] Update README.markdown Hello, I have revised one of your documents for my assignment. I still need to revise more documents (10 in total). I hope it will be fine if I choose some documents from your account. Thanks, Parvaneh --- Heap/README.markdown | 116 +++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 88ea25eeb..3935950a6 100644 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -1,19 +1,19 @@ # Heap -A heap is a [binary tree](../Binary Tree/) that lives inside an array, so it doesn't use parent/child pointers. The tree is partially sorted according to something called the "heap property" that determines the order of the nodes in the tree. +A heap is a [binary tree](../Binary Tree/) inside an array, so it doesn't use parent/child pointers. A heap is sorted based on the "heap property" that determines the order of the nodes in the tree. Common uses for heap: -- For building [priority queues](../Priority Queue/). -- The heap is the data structure supporting [heap sort](../Heap Sort/). -- Heaps are fast for when you often need to compute the minimum (or maximum) element of a collection. -- Impressing your non-programmer friends. +- To build [priority queues](../Priority Queue/). +- To support [heap sorts](../Heap Sort/). +- To compute the minimum (or maximum) element of a collection quickly. +- To impress your non-programmer friends. ## The heap property -There are two kinds of heaps: a *max-heap* and a *min-heap*. They are identical, except that the order in which they store the tree nodes is opposite. +There are two kinds of heaps: a *max-heap* and a *min-heap* which are different by the order in which they store the tree nodes. -In a max-heap, parent nodes must always have a greater value than each of their children. For a min-heap it's the other way around: every parent node has a smaller value than its child nodes. This is called the "heap property" and it is true for every single node in the tree. +In a max-heap, parent nodes have a greater value than each of their children. In a min-heap, every parent node has a smaller value than its child nodes. This is called the "heap property", and it is true for every single node in the tree. An example: @@ -21,33 +21,33 @@ An example: This is a max-heap because every parent node is greater than its children. `(10)` is greater than `(7)` and `(2)`. `(7)` is greater than `(5)` and `(1)`. -As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. That is very useful because heaps are often used as a [priority queue](../Priority Queue/) where you want to quickly access the "most important" element. +As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. The heap property is useful because heaps are often used as a [priority queue](../Priority Queue/)to access the "most important" element quickly. -> **Note:** You can't really say anything else about the sort order of the heap. For example, in a max-heap the maximum element is always at index 0 but the minimum element isn’t necessarily the last one -- the only guarantee you have is that it is one of the leaf nodes, but not which one. +> **Note:** The root of the heap has the maximum or minimum element, but the sort order of other elements are not predictable. For example, the maximum element is always at index 0 in a max-heap, but the minimum element isn’t necessarily the last one. -- the only guarantee you have is that it is one of the leaf nodes, but not which one. -## How does heap compare to regular trees? +## How does a heap can be compared to regular trees? -A heap isn't intended to be a replacement for a binary search tree. But there are many similarities between the two and also some differences. Here are some of the bigger differences: +A heap is not a replacement for a binary search tree, and there are similarities and differnces between them. Here are some main differences: -**Order of the nodes.** In a [binary search tree (BST)](../Binary Search Tree/), the left child must always be smaller than its parent and the right child must be greater. This is not true for a heap. In max-heap both children must be smaller; in a min-heap they both must be greater. +**Order of the nodes.** In a [binary search tree (BST)](../Binary Search Tree/), 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; in a min-heap they both must be greater. **Memory.** Traditional trees take up more memory than just the data they store. You need to allocate additional storage for the node objects and pointers to the left/right child nodes. A heap only uses a plain array for storage and uses no pointers. -**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 Tree/) or [red-black tree](../Red-Black Tree/). But with heaps we don't actually need the entire tree to be sorted. We just want the heap property to be fulfilled, and so balancing isn't an issue. Because of the way the heap is structured, heaps can guarantee **O(log n)** performance. +**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 Tree/) or [red-black tree](../Red-Black Tree/), 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.** Searching a binary tree is really fast -- that's its whole purpose. In a heap, searching is slow. The purpose of a heap is to always put the largest (or smallest) node at the front, and to allow relatively fast inserts and deletes. Searching isn't a top priority. +**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 that lived in an array +## The tree inside an array -An array may seem like an odd way to implement a tree-like structure but it is very efficient in both time and space. +An array may seem like an odd way to implement a tree-like structure, but it is efficient in both time and space. -This is how we're going to store the tree from the above example: +This is how we are going to store the tree from the above example: [ 10, 7, 2, 5, 1 ] That's all there is to it! We don't need any more storage than just this simple array. -So how do we know which nodes are the parents and which are the children if we're not allowed to use any pointers? Good question! There is a well-defined relationship between the array index of a tree node and the array indices of its parent and children. +So how do we know which nodes are the parents and which are the children if we are not allowed to use any pointers? Good question! There is a well-defined relationship between the array index of a tree node and the array indices of its parent and children. If `i` is the index of a node, then the following formulas give the array indices of its parent and child nodes: @@ -69,7 +69,7 @@ Let's use these formulas on the example. Fill in the array index and we should g Verify for yourself that these array indices indeed correspond to the picture of the tree. -> **Note:** The root node `(10)` doesn't have a parent because `-1` is not a valid array index. Likewise, nodes `(2)`, `(5)`, and `(1)` don't have children because those indices are greater than the array size. So we always have to make sure the indices we calculate are actually valid before we use them. +> **Note:** The root node `(10)` does not have a parent because `-1` is not a valid array index. Likewise, nodes `(2)`, `(5)`, and `(1)` do not have children because those indices are greater than the array size, so we always have to make sure the indices we calculate are actually valid before we use them. Recall that in a max-heap, the parent's value is always greater than (or equal to) the values of its children. This means the following must be true for all array indices `i`: @@ -79,27 +79,27 @@ array[parent(i)] >= array[i] Verify that this heap property holds for the array from the example heap. -As you can see, these equations let us find the parent or child index for any node without the need for pointers. True, it's slightly more complicated than just dereferencing a pointer but that's 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 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's important to understand this relationship between array index and position in the tree. Here's a slightly larger heap, this tree has 15 nodes divided over four levels: +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: ![Large heap](Images/LargeHeap.png) -The numbers in this picture aren't the values of the nodes but the array indices that store the nodes! Those array indices correspond to the different levels of the tree like this: +The numbers in this picture are not the values of the nodes but the array indices that store the nodes! Here is the array indices correspond to the different levels of the tree: ![The heap array](Images/Array.png) -For the formulas to work, parent nodes must always appear before child nodes in the array. You can see that in the above picture. +For the formulas to work, parent nodes must appear before child nodes in the array. You can see that in the above picture. Note that this scheme has limitations. You can do the following with a regular binary tree but not with a heap: ![Impossible with a heap](Images/RegularTree.png) -You can’t start a new level unless the current lowest level is completely full. So heaps always have this kind of shape: +You can not start a new level unless the current lowest level is completely full, so heaps always have this kind of shape: ![The shape of a heap](Images/HeapShape.png) -> **Note:** Technically speaking you *could* emulate a regular binary tree with a heap, but it would waste a lot of space and you’d need some way to mark array indices as being empty. +> **Note:** You *could* emulate a regular binary tree with a heap, but it would be a waste of space, and you would need to mark array indices as being empty. Pop quiz! Let's say we have the array: @@ -111,15 +111,15 @@ Is this a valid heap? The answer is yes! A sorted array from low-to-high is a va The heap property holds for each node because a parent is always smaller than its children. (Verify for yourself that an array sorted from high-to-low is always a valid max-heap.) -> **Note:** But not every min-heap is necessarily a sorted array! It only works one way... To turn a heap back into a sorted array, you need to use [heap sort](../Heap Sort/). +> **Note:** But not every min-heap is necessarily a sorted array! It only works one way. To turn a heap back into a sorted array, you need to use [heap sort](../Heap Sort/). ## More math! -In case you are curious, here are a few more formulas that describe certain properties of a heap. You don't need to know these by heart but they come in handy sometimes. Feel free to skip this section! +In case you are curious, here are a few more formulas that describe certain properties of a heap. You do not need to know these by heart, but they come in handy sometimes. Feel free to skip this section! -The *height* of a tree is defined as the number of steps it takes to go from the root node to the lowest leaf node. Or more formally: the height is the maximum number of edges between the nodes. A heap of height *h* has *h + 1* levels. +The *height* of a tree is defined as the number of steps it takes to go from the root node to the lowest leaf node, or more formally: the height is the maximum number of edges between the nodes. A heap of height *h* has *h + 1* levels. -This heap has height 3 and therefore has 4 levels: +This heap has height 3, so it has 4 levels: ![Large heap](Images/LargeHeap.png) @@ -145,31 +145,31 @@ 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. -The other operations are built on these primitives. They are: +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. -- `remove()`: Removes and returns the maximum value (max-heap) or the minimum value (min-heap). To fill up the hole that's left by removing the element, the very last element is moved to the root position and then `shiftDown()` fixes up the heap. (This is sometimes called "extract min" or "extract max".) +- `remove()`: Removes and returns the maximum value (max-heap) or the minimum value (min-heap). To fill up the hole left by removing the element, the very last element is moved to the root position and then `shiftDown()` fixes up the heap. (This is sometimes called "extract min" or "extract max".) -- `removeAtIndex(index)`: Just like `remove()` except it lets you remove any item from the heap, not just the root. This calls both `shiftDown()`, in case the new element is out-of-order with its children, and `shiftUp()`, in case the element is out-of-order with its parents. +- `removeAtIndex(index)`: Just like `remove()` with the exception that it allows you to remove any item from the heap, not just the root. This calls both `shiftDown()`, in case the new element is out-of-order with its children, and `shiftUp()`, in case the element is out-of-order with its parents. -- `replace(index, value)`: Assigns a smaller (min-heap) or larger (max-heap) value to a node. Because this invalidates the heap property, it uses `shiftUp()` to patch things up. (Also called "decrease key" and "increase key".) +- `replace(index, value)`: Assigns a smaller (min-heap) or larger (max-heap) value to a node. Because this invalidates the heap property, it uses `shiftUp()` to patch things up. (Also called "decrease key" and "increase key".) -All of the above take time **O(log n)** because shifting up or down is the most expensive thing they do. There are also a few operations that take more time: +All of the above take time **O(log n)** because shifting up or down is expensive. There are also a few operations that take more time: -- `search(value)`. Heaps aren't built for efficient searches but the `replace()` and `removeAtIndex()` operations require the array index of the node, so you need to find that index somehow. Time: **O(n)**. +- `search(value)`. Heaps are not built for efficient searches, but the `replace()` and `removeAtIndex()` operations require the array index of the node, so you need to find that index. Time: **O(n)**. -- `buildHeap(array)`: Converts an (unsorted) array into a heap by repeatedly calling `insert()`. If you’re smart about this, it can be done in **O(n)** time. +- `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 Sort/). Since the heap is really an array, we can use its unique properties to sort the array from low to high. Time: **O(n lg n).** +- [Heap sort](../Heap Sort/). 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).** 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)**. -> **Note:** By far the most common things you'll do with a heap are inserting new values with `insert()` and removing the maximum or minimum value with `remove()`. Both take **O(log n)** time. The other operations exist to support more advanced usage, such as building a priority queue where the "importance" of items can change after they've been added to the queue. +> **Note:** By far the most common things you will do with a heap are inserting new values with `insert()` and removing the maximum or minimum value with `remove()`. Both take **O(log n)** time. The other operations exist to support more advanced usage, such as building a priority queue where the "importance" of items can change after they have been added to the queue. ## Inserting into the heap -Let's go through an example insertion to see in more detail how this works. We'll insert the value `16` into this heap: +Let's go through an example of insertion to see in details how this works. We will insert the value `16` into this heap: ![The heap before insertion](Images/Heap1.png) @@ -185,13 +185,13 @@ This corresponds to the following tree: 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.) +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're going to swap `(16)` and `(2)`. +To restore the heap property, we are going to swap `(16)` and `(2)`. ![The heap before insertion](Images/Insert2.png) -We're not done yet because `(10)` is also smaller than `(16)`. We keep swapping our inserted value with its parent, until the parent is larger or we reach the top of the tree. This is called **shift-up** or **sifting** and is done after every insertion. It makes a number that is too large or too small "float up" the tree. +We are not done yet because `(10)` is also smaller than `(16)`. We keep swapping our inserted value with its parent, until the parent is larger or we reach the top of the tree. This is called **shift-up** or **sifting** and is done after every insertion. It makes a number that is too large or too small "float up" the tree. Finally, we get: @@ -199,7 +199,7 @@ Finally, we get: And now every parent is greater than its children again. -The time required for shifting up is proportional to the height of the tree so it takes **O(log n)** time. (The time it takes to append the node to the end of the array is only **O(1)**, so that doesn't slow it down.) +The time required for shifting up is proportional to the height of the tree, so it takes **O(log n)** time. (The time it takes to append the node to the end of the array is only **O(1)**, so that does not slow it down.) ## Removing the root @@ -211,7 +211,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'll do the opposite: we're going to 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 will do the opposite: we are going to 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) @@ -219,19 +219,19 @@ Let's look at how to **shift-down** `(1)`. To maintain the heap property for thi ![The last node goes to the root](Images/Remove3.png) -Keep shifting down until the node doesn't have any children or it is larger than both its children. For our heap we only need one more swap to restore the heap property: +Keep shifting down until the node does not have any children or it is larger than both its children. For our heap, we only need one more swap to restore the heap property: ![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 so it takes **O(log n)** time. +The time required for shifting all the way down is proportional to the height of the tree, so it 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. ## Removing any node -The vast majority of the time you'll be removing the object at the root of the heap because that's what heaps are designed for. +The vast majority of the time you will be removing the object at the root of the heap because that is what heaps are designed for. -However, it can be useful to remove an arbitrary element. This is a more general version of `remove()` and may involve either `shiftDown()` or `shiftUp()`. +However, it can be useful to remove an arbitrary element. This is a general version of `remove()` and may involve either `shiftDown()` or `shiftUp()`. Let's take the example tree again and remove `(7)`: @@ -241,13 +241,13 @@ As a reminder, the array is: [ 10, 7, 2, 5, 1 ] -As you know, removing an element could potentially invalidate the max-heap or min-heap property. To fix this, we swap the node that we're removing with the last element: +As you know, removing an element could potentially invalidate the max-heap or min-heap property. To fix this, we swap the node that we are removing with the last element: [ 10, 1, 2, 5, 7 ] -The last element is the one that we'll return; we'll call `removeLast()` to remove it from the heap. The `(1)` is now out-of-order because it's smaller than its child, `(5)`, but sits higher in the tree. We call `shiftDown()` to repair this. +The last element is the one that we will return; we will call `removeLast()` to remove it from the heap. The `(1)` is now out-of-order because it is smaller than its child, `(5)` but sits higher in the tree. We call `shiftDown()` to repair this. -However, shifting down is not the only situation we need to handle -- it may also happen that the new element must be shifted up. Consider what happens if you remove `(5)` from the following heap: +However, shifting down is not the only situation we need to handle. It may also happen that the new element must be shifted up. Consider what happens if you remove `(5)` from the following heap: ![We need to shift up](Images/Remove5.png) @@ -267,7 +267,7 @@ In code it would look like this: } ``` -We simply call `insert()` for each of the values in the array. Simple enough, but not very efficient. This takes **O(n log n)** time in total because there are **n** elements and each insertion takes **log n** time. +We simply call `insert()` for each of the values in the array. Simple enough but not very efficient. This takes **O(n log n)** time in total because there are **n** elements and each insertion takes **log n** time. If you didn't gloss over the math section, you'd have seen that for any heap the elements at array indices *n/2* to *n-1* are the leaves of the tree. We can simply skip those leaves. We only have to process the other nodes, since they are parents with one or more children and therefore may be in the wrong order. @@ -286,9 +286,9 @@ Here, `elements` is the heap's own array. We walk backwards through this array, ## Searching the heap -Heaps aren't made for fast searches, but if you want to remove an arbitrary element using `removeAtIndex()` or change the value of an element with `replace()`, then you need to obtain the index of that element somehow. Searching is one way to do this but it's kind of slow. +Heaps are not made for fast searches, but if you want to remove an arbitrary element using `removeAtIndex()` or change the value of an element with `replace()`, then you need to obtain the index of that element. Searching is one way to do this, but it is slow. -In a [binary search tree](../Binary Search Tree/) you can depend on the order of the nodes to guarantee a fast search. A heap orders its nodes differently and so a binary search won't work. You'll potentially have to look at every node in the tree. +In a [binary search tree](../Binary Search Tree/) you can depend on the order of the nodes to guarantee a fast search. A heap orders its nodes differently, so a binary search will not work. You need to look at every node in the tree. Let's take our example heap again: @@ -296,9 +296,9 @@ Let's take our example heap again: If we want to search for the index of node `(1)`, we could just step through the array `[ 10, 7, 2, 5, 1 ]` with a linear search. -But even though the heap property wasn't conceived with searching in mind, we can still take advantage of it. We know that in a max-heap a parent node is always larger than its children, so we can ignore those children (and their children, and so on...) if the parent is already smaller than the value we're looking for. +Even though the heap property was not conceived with searching in mind, we can still take advantage of it. We know that in a max-heap a parent node is always larger than its children, so we can ignore those children (and their children, and so on...) if the parent is already smaller than the value we are looking for. -Let's say we want to see if the heap contains the value `8` (it doesn't). We start at the root `(10)`. This is obviously not what we're looking for, so we recursively look at its left and right child. The left child is `(7)`. That is also not what we want, but since this is a max-heap, we know there's no point in looking at the children of `(7)`. They will always be smaller than `7` and are therefore never equal to `8`. Likewise for the right child, `(2)`. +Let's say we want to see if the heap contains the value `8` (it doesn't). We start at the root `(10)`. This is not what we are looking for, so we recursively look at its left and right child. The left child is `(7)`. That is also not what we want, but since this is a max-heap, we know there is no point in looking at the children of `(7)`. They will always be smaller than `7` and are therefore never equal to `8`; likewise, for the right child, `(2)`. Despite this small optimization, searching is still an **O(n)** operation. @@ -308,9 +308,9 @@ Despite this small optimization, searching is still an **O(n)** operation. See [Heap.swift](Heap.swift) for the implementation of these concepts in Swift. Most of the code is quite straightforward. The only tricky bits are in `shiftUp()` and `shiftDown()`. -You've seen that there are two types of heaps: a max-heap and a min-heap. The only difference between them is in how they order their nodes: largest value first or smallest value first. +You have seen that there are two types of heaps: a max-heap and a min-heap. The only difference between them is in how they order their nodes: largest value first or smallest value first. -Rather than create two different versions, `MaxHeap` and `MinHeap`, there is just one `Heap` object and it takes an `isOrderedBefore` closure. This closure contains the logic that determines the order of two values. You've probably seen this before because it's also how Swift's `sort()` works. +Rather than create two different versions, `MaxHeap` and `MinHeap`, there is just one `Heap` object and it takes an `isOrderedBefore` closure. This closure contains the logic that determines the order of two values. You have probably seen this before because it is also how Swift's `sort()` works. To make a max-heap of integers, you write: From 52855ccbd3fb95704cd6375d44f1fa22512d04e1 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Sat, 1 Apr 2017 19:38:22 -0700 Subject: [PATCH 0479/1275] Update README.markdown For an assignment in technical writings, I have revised this document. Thanks, Parvaneh --- Hash Table/README.markdown | 69 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index 4399b0f86..958c3595a 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -2,13 +2,13 @@ A hash table allows you to store and retrieve objects by a "key". -Also called dictionary, map, associative array. There are other ways to implement these, such as with a tree or even a plain array, but hash table is the most common. +A hash table is used to implement structures, such as a dictionary, a map, and an associative array. These structures can be implemented by a tree or a plain array, but it is efficient to use a hash table. -This should explain why Swift's built-in `Dictionary` type requires that keys conform to the `Hashable` protocol: internally it uses a hash table, just like the one you'll learn about here. +This should explain why Swift's built-in `Dictionary` type requires that keys conform to the `Hashable` protocol: internally it uses a hash table, like the one you will learn about here. ## How it works -At its most basic, a hash table is nothing more than an array. Initially, this array is empty. When you put a value into the hash table under a certain key, it uses that key to calculate an index in the array, like so: +A hash table is nothing more than an array. Initially, this array is empty. When you put a value into the hash table under a certain key, it uses that key to calculate an index in the array. Here is an example: ```swift hashTable["firstName"] = "Steve" @@ -48,33 +48,33 @@ hashTable["hobbies"] = "Programming Swift" +--------------+ ``` -The trick is in how the hash table calculates those array indices. That's where the hashing comes in. When you write, +The trick is how the hash table calculates those array indices. That is where the hashing comes in. When you write the following statement, ```swift hashTable["firstName"] = "Steve" ``` -the hash table takes the key `"firstName"` and asks it for its `hashValue` property. That's why keys must be `Hashable`. +the hash table takes the key `"firstName"` and asks it for its `hashValue` property. Hence, keys must be `Hashable`. -When you do `"firstName".hashValue`, it returns a big integer: -4799450059917011053. Likewise, `"hobbies".hashValue` has the hash value 4799450060928805186. (The values you see may vary.) +When you write `"firstName".hashValue`, it returns a big integer: -4799450059917011053. Likewise, `"hobbies".hashValue` has the hash value 4799450060928805186. (The values you see may vary.) -Of course, these numbers are way too big to be used as indices into our array. One of them is even negative! A common way to make these big numbers more suitable is to first make the hash positive and then take the modulo with the array size. +These numbers are big to be used as indices into our array, and one of them is even negative! A common way to make these big numbers suitable is to first make the hash positive and then take the modulo with the array size. -Our array has size 5, so the index for the `"firstName"` key becomes `abs(-4799450059917011053) % 5 = 3`. You can calculate for yourself that the array index for `"hobbies"` is 1. +Our array has size 5, so the index for the `"firstName"` key becomes `abs(-4799450059917011053) % 5 = 3`. You can calculate that the array index for `"hobbies"` is 1. -Using hashes in this manner is what makes the dictionary so efficient: to find an element in the hash table you only have to hash the key to get an array index and then look up the element in the underlying array. All these operations take a constant amount of time, so inserting, retrieving, and removing are all **O(1)**. +Using hashes in this manner is what makes the dictionary efficient: to find an element in the hash table, you must hash the key to get an array index and then look up the element in the underlying array. All these operations take a constant amount of time, so inserting, retrieving, and removing are all **O(1)**. -> **Note:** As you can see, it's hard to predict where in the array your objects end up. That's why dictionaries do not guarantee any particular order of the elements in the hash table. +> **Note:** It is difficult to predict where in the array your objects end up. Hence, dictionaries do not guarantee any particular order of the elements in the hash table. ## Avoiding collisions There is one problem: because we take the modulo of the hash value with the size of the array, it can happen that two or more keys get assigned the same array index. This is called a collision. -One way to avoid collisions is to have a very large array. That reduces the likelihood of two keys mapping to the same index. Another trick is to use a prime number for the array size. However, collisions are bound to occur so you need some way to handle them. +One way to avoid collisions is to have a large array which reduces the likelihood of two keys mapping to the same index. Another trick is to use a prime number for the array size. However, collisions are bound to occur, so you need to find a way to handle them. -Because our table is so small it's easy to show a collision. For example, the array index for the key `"lastName"` is also 3. That's a problem, as we don't want to overwrite the value that's already at this array index. +Because our table is small, it is easy to show a collision. For example, the array index for the key `"lastName"` is also 3, but we do not want to overwrite the value that is already at this array index. -There are a few ways to handle collisions. A common one is to use chaining. The array now looks as follows: +A common way to handle collisions is to use chaining. The array looks as follows: ```swift buckets: @@ -91,25 +91,25 @@ There are a few ways to handle collisions. A common one is to use chaining. The +-----+ ``` -With chaining, keys and their values are not stored directly in the array. Instead, each array element is really a list of zero or more key/value pairs. The array elements are usually called the *buckets* and the lists are called the *chains*. So here we have 5 buckets and two of these buckets have chains. The other three buckets are empty. +With chaining, keys and their values are not stored directly in the array. Instead, each array element is a list of zero or more key/value pairs. The array elements are usually called the *buckets* and the lists are called the *chains*. Here we have 5 buckets, and two of these buckets have chains. The other three buckets are empty. -If we now write the following to retrieve an item from the hash table, +If we write the following statement to retrieve an item from the hash table, ```swift let x = hashTable["lastName"] ``` -then this first hashes the key `"lastName"` to calculate the array index, which is 3. Bucket 3 has a chain, so we step through that list to find the value with the key `"lastName"`. That is done by comparing the keys, so here that involves a string comparison. The hash table sees that this key belongs to the last item in the chain and returns the corresponding value, `"Jobs"`. +it first hashes the key `"lastName"` to calculate the array index, which is 3. Since bucket 3 has a chain, we step through the list to find the value with the key `"lastName"`. This is done by comparing the keys using a string comparison. The hash table checks that the key belongs to the last item in the chain and returns the corresponding value, `"Jobs"`. -Common ways to implement this chaining mechanism are to use a linked list or another array. Technically speaking the order of the items in the chain doesn't matter, so you also can think of it as a set instead of a list. (Now you can also imagine where the term "bucket" comes from; we just dump all the objects together into the bucket.) +Common ways to implement this chaining mechanism are to use a linked list or another array. Since the order of the items in the chain does not matter, you can think of it as a set instead of a list. (Now you can also imagine where the term "bucket" comes from; we just dump all the objects together into the bucket.) -It's important that chains do not become too long or looking up items in the hash table becomes really slow. Ideally, we would have no chains at all but in practice it is impossible to avoid collisions. You can improve the odds by giving the hash table enough buckets and by using high-quality hash functions. +Chains should not become long becasuse the slow process of looking up items in the hash table. Ideally, we would have no chains at all, but in practice it is impossible to avoid collisions. You can improve the odds by giving the hash table enough buckets using high-quality hash functions. -> **Note:** An alternative to chaining is "open addressing". The idea is this: if an array index is already taken, we put the element in the next unused bucket. Of course, this approach has its own upsides and downsides. +> **Note:** An alternative to chaining is "open addressing". The idea is this: if an array index is already taken, we put the element in the next unused bucket. This approach has its own upsides and downsides. ## The code -Let's look at a basic implementation of a hash table in Swift. We'll build it up step-by-step. +Let's look at a basic implementation of a hash table in Swift. We will build it up step-by-step. ```swift public struct HashTable { @@ -127,9 +127,9 @@ public struct HashTable { } ``` -The `HashTable` is a generic container and the two generic types are named `Key` (which must be `Hashable`) and `Value`. We also define two other types: `Element` is a key/value pair for use in a chain and `Bucket` is an array of such `Elements`. +The `HashTable` is a generic container, and the two generic types are named `Key` (which must be `Hashable`) and `Value`. We also define two other types: `Element` is a key/value pair for useing in a chain, and `Bucket` is an array of such `Elements`. -The main array is named `buckets`. It has a fixed size, the so-called capacity, provided by the `init(capacity)` method. We're also keeping track of how many items have been added to the hash table using the `count` variable. +The main array is named `buckets`. It has a fixed size, the so-called capacity, provided by the `init(capacity)` method. We are also keeping track of how many items have been added to the hash table using the `count` variable. An example of how to create a new hash table object: @@ -137,7 +137,7 @@ An example of how to create a new hash table object: var hashTable = HashTable(capacity: 5) ``` -Currently the hash table doesn't do anything yet, so let's add the remaining functionality. First, add a helper method that calculates the array index for a given key: +The hash table does not do anything yet, so let's add the remaining functionality. First, add a helper method that calculates the array index for a given key: ```swift private func index(forKey key: Key) -> Int { @@ -145,9 +145,9 @@ Currently the hash table doesn't do anything yet, so let's add the remaining fun } ``` -This performs the calculation you saw earlier: it takes the absolute value of the key's `hashValue` modulo the size of the buckets array. We've put this in a function of its own because it gets used in a few different places. +This performs the calculation you saw earlier: it takes the absolute value of the key's `hashValue` modulo the size of the buckets array. We have put this in a function of its own because it gets used in a few different places. -There are four common things you'll do with a hash table or dictionary: +There are four common things you will do with a hash table or dictionary: - insert a new element - look up an element @@ -180,7 +180,7 @@ We can do all these things with a `subscript` function: } ``` -This calls three helper functions to do the actual work. Let's take a look at `value(forKey:)` first, which retrieves an object from the hash table. +This calls three helper functions to do the actual work. Let's take a look at `value(forKey:)`which retrieves an object from the hash table. ```swift public func value(forKey key: Key) -> Value? { @@ -193,10 +193,9 @@ This calls three helper functions to do the actual work. Let's take a look at `v return nil // key not in hash table } ``` +First it calls `index(forKey:)` to convert the key into an array index. That gives us the bucket number, but this bucket may be used by more than one key if there were collisions. The `value(forKey:)` loops through the chain from that bucket and compares the keys one-by-one. If found, it returns the corresponding value, otherwise it returns `nil`. -First it calls `index(forKey:)` to convert the key into an array index. That gives us the bucket number, but if there were collisions this bucket may be used by more than one key. So `value(forKey:)` loops through the chain from that bucket and compares the keys one-by-one. If found, it returns the corresponding value, otherwise it returns `nil`. - -The code to insert a new element or update an existing element lives in `updateValue(_:forKey:)`. It's a little bit more complicated: +The code to insert a new element or update an existing element lives in `updateValue(_:forKey:)`. This is more complicated: ```swift public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { @@ -218,9 +217,9 @@ The code to insert a new element or update an existing element lives in `updateV } ``` -Again, the first thing we do is convert the key into an array index to find the bucket. Then we loop through the chain for that bucket. If we find the key in the chain, it means we must update it with the new value. If the key is not in the chain, we insert the new key/value pair to the end of the chain. +Again, the first step is to convert the key into an array index to find the bucket. Then we loop through the chain for that bucket. If we find the key in the chain, we must update it with the new value. If the key is not in the chain, we insert the new key/value pair to the end of the chain. -As you can see, it's important that chains are kept short (by making the hash table large enough). Otherwise, you spend a lot of time in these `for`...`in` loops and the performance of the hash table will no longer be **O(1)** but more like **O(n)**. +As you can see, it is important to keep the chains short (by making the hash table large enough). Otherwise, you spend excessive time in these `for`...`in` loops and the performance of the hash table will no longer be **O(1)** but more like **O(n)**. Removing is similar in that again it loops through the chain: @@ -246,16 +245,16 @@ Try this stuff out in a playground. It should work just like a standard Swift `D ## Resizing the hash table -This version of `HashTable` always uses an array of a fixed size or capacity. That's fine if you've got a good idea of many items you'll be storing in the hash table. For the capacity, choose a prime number that is greater than the maximum number of items you expect to store and you're good to go. +This version of `HashTable` always uses an array of a fixed size or capacity. If you have many items to store in the hash table, for the capacity, choose a prime number greater than the maximum number of items. The *load factor* of a hash table is the percentage of the capacity that is currently used. If there are 3 items in a hash table with 5 buckets, then the load factor is `3/5 = 60%`. -If the hash table is too small and the chains are long, the load factor can become greater than 1. That's not a good idea. +If the hash table is small, and the chains are long, the load factor can become greater than 1, that is not a good idea. -If the load factor becomes too high, say > 75%, you can resize the hash table. Adding the code for this is left as an exercise for the reader. Keep in mind that making the buckets array larger will change the array indices that the keys map to! To account for this, you'll have to insert all the elements again after resizing the array. +If the load factor becomes high, greater than 75%, you can resize the hash table. Adding the code for this condition is left as an exercise for the reader. Keep in mind that making the buckets array larger will change the array indices that the keys map to! This requires you to insert all the elements again after resizing the array. ## Where to go from here? -`HashTable` is quite basic. It might be fun to integrate it better with the Swift standard library by making it a `SequenceType`, for example. +`HashTable` is quite basic. It might be efficient to integrate it with the Swift standard library by making it a `SequenceType`. *Written for Swift Algorithm Club by Matthijs Hollemans* From 7010d4ff4e28871cd06067aad15dcde031e745c8 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Sun, 2 Apr 2017 18:28:48 -0400 Subject: [PATCH 0480/1275] Fixed an issue with links that has spaces in the address --- Graph/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Graph/README.markdown b/Graph/README.markdown index 1ff1a82ac..a2531e808 100644 --- a/Graph/README.markdown +++ b/Graph/README.markdown @@ -28,7 +28,7 @@ The following are also graphs: ![Tree and linked list](Images/TreeAndList.png) -On the left is a [tree](../Tree/) structure, on the right a [linked list](../Linked List/). Both can be considered graphs, but in a simpler form. After all, they have vertices (nodes) and edges (links). +On the left is a [tree](../Tree/) structure, on the right a [linked list](../Linked%20List/). Both can be considered graphs, but in a simpler form. After all, they have vertices (nodes) and edges (links). The very first graph I showed you contained *cycles*, where you can start off at a vertex, follow a path, and come back to the original vertex. A tree is a graph without such cycles. @@ -42,7 +42,7 @@ Like a tree this does not have any cycles in it (no matter where you start, ther Maybe you're shrugging your shoulders and thinking, what's the big deal? Well, it turns out that graphs are an extremely useful data structure. -If you have some programming problem where you can represent some of your data as vertices and some of it as edges between those vertices, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First Search/) or [depth-first search](../Depth-First Search) to find a solution. +If you have some programming problem where you can represent some of your data as vertices and some of it as edges between those vertices, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First%20Search/) or [depth-first search](../Depth-First%20Search) to find a solution. For example, let's say you have a list of tasks where some tasks have to wait on others before they can begin. You can model this using an acyclic directed graph: @@ -50,7 +50,7 @@ For example, let's say you have a list of tasks where some tasks have to wait on Each vertex represents a task. Here, an edge between two vertices means that the source task must be completed before the destination task can start. So task C cannot start before B and D are finished, and B nor D can start before A is finished. -Now that the problem is expressed using a graph, you can use a depth-first search to perform a [topological sort](../Topological Sort/). This will put the tasks in an optimal order so that you minimize the time spent waiting for tasks to complete. (One possible order here is A, B, D, E, C, F, G, H, I, J, K.) +Now that the problem is expressed using a graph, you can use a depth-first search to perform a [topological sort](../Topological%20Sort/). This will put the tasks in an optimal order so that you minimize the time spent waiting for tasks to complete. (One possible order here is A, B, D, E, C, F, G, H, I, J, K.) Whenever you're faced with a tough programming problem, ask yourself, "how can I express this problem using a graph?" Graphs are all about representing relationships between your data. The trick is in how you define "relationship". From 79255d2bb83cfbbcab0fb3f983bdc96e25c0bd4b Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Sun, 2 Apr 2017 19:43:48 -0400 Subject: [PATCH 0481/1275] Fixed white-space encoding in markdown links --- Heap/README.markdown | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 88ea25eeb..1bcb05e1b 100644 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -1,11 +1,11 @@ # Heap -A heap is a [binary tree](../Binary Tree/) that lives inside an array, so it doesn't use parent/child pointers. The tree is partially sorted according to something called the "heap property" that determines the order of the nodes in the tree. +A heap is a [binary tree](../Binary%20Tree/) that lives inside an array, so it doesn't use parent/child pointers. The tree is partially sorted according to something called the "heap property" that determines the order of the nodes in the tree. Common uses for heap: -- For building [priority queues](../Priority Queue/). -- The heap is the data structure supporting [heap sort](../Heap Sort/). +- For building [priority queues](../Priority%20Queue/). +- The heap is the data structure supporting [heap sort](../Heap%20Sort/). - Heaps are fast for when you often need to compute the minimum (or maximum) element of a collection. - Impressing your non-programmer friends. @@ -21,7 +21,7 @@ An example: This is a max-heap because every parent node is greater than its children. `(10)` is greater than `(7)` and `(2)`. `(7)` is greater than `(5)` and `(1)`. -As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. That is very useful because heaps are often used as a [priority queue](../Priority Queue/) where you want to quickly access the "most important" element. +As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. That is very useful because heaps are often used as a [priority queue](../Priority%20Queue/) where you want to quickly access the "most important" element. > **Note:** You can't really say anything else about the sort order of the heap. For example, in a max-heap the maximum element is always at index 0 but the minimum element isn’t necessarily the last one -- the only guarantee you have is that it is one of the leaf nodes, but not which one. @@ -29,11 +29,11 @@ As a result of this heap property, a max-heap always stores its largest item at A heap isn't intended to be a replacement for a binary search tree. But there are many similarities between the two and also some differences. Here are some of the bigger differences: -**Order of the nodes.** In a [binary search tree (BST)](../Binary Search Tree/), the left child must always be smaller than its parent and the right child must be greater. This is not true for a heap. In max-heap both children must be smaller; in a min-heap they both must be greater. +**Order of the nodes.** In a [binary search tree (BST)](../Binary%20Search%20Tree/), the left child must always be smaller than its parent and the right child must be greater. This is not true for a heap. In max-heap both children must be smaller; in a min-heap they both must be greater. **Memory.** Traditional trees take up more memory than just the data they store. You need to allocate additional storage for the node objects and pointers to the left/right child nodes. A heap only uses a plain array for storage and uses no pointers. -**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 Tree/) or [red-black tree](../Red-Black Tree/). But with heaps we don't actually need the entire tree to be sorted. We just want the heap property to be fulfilled, and so balancing isn't an issue. Because of the way the heap is structured, heaps can guarantee **O(log n)** performance. +**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, and so balancing isn't an issue. Because of the way the heap is structured, heaps can guarantee **O(log n)** performance. **Searching.** Searching a binary tree is really fast -- that's its whole purpose. In a heap, searching is slow. The purpose of a heap is to always put the largest (or smallest) node at the front, and to allow relatively fast inserts and deletes. Searching isn't a top priority. @@ -54,7 +54,7 @@ If `i` is the index of a node, then the following formulas give the array indice parent(i) = floor((i - 1)/2) left(i) = 2i + 1 right(i) = 2i + 2 - + Note that `right(i)` is simply `left(i) + 1`. The left and right nodes are always stored right next to each other. Let's use these formulas on the example. Fill in the array index and we should get the positions of the parent and child nodes in the array: @@ -63,7 +63,7 @@ Let's use these formulas on the example. Fill in the array index and we should g |------|-------------|--------------|------------|-------------| | 10 | 0 | -1 | 1 | 2 | | 7 | 1 | 0 | 3 | 4 | -| 2 | 2 | 0 | 5 | 6 | +| 2 | 2 | 0 | 5 | 6 | | 5 | 3 | 1 | 7 | 8 | | 1 | 4 | 1 | 9 | 10 | @@ -76,7 +76,7 @@ Recall that in a max-heap, the parent's value is always greater than (or equal t ```swift array[parent(i)] >= array[i] ``` - + Verify that this heap property holds for the array from the example heap. As you can see, these equations let us find the parent or child index for any node without the need for pointers. True, it's slightly more complicated than just dereferencing a pointer but that's the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. @@ -104,14 +104,14 @@ You can’t start a new level unless the current lowest level is completely full Pop quiz! Let's say we have the array: [ 10, 14, 25, 33, 81, 82, 99 ] - + Is this a valid heap? The answer is yes! A sorted array from low-to-high is a valid min-heap. We can draw this heap as follows: ![A sorted array is a valid heap](Images/SortedArray.png) The heap property holds for each node because a parent is always smaller than its children. (Verify for yourself that an array sorted from high-to-low is always a valid max-heap.) -> **Note:** But not every min-heap is necessarily a sorted array! It only works one way... To turn a heap back into a sorted array, you need to use [heap sort](../Heap Sort/). +> **Note:** But not every min-heap is necessarily a sorted array! It only works one way... To turn a heap back into a sorted array, you need to use [heap sort](../Heap%20Sort/). ## More math! @@ -129,7 +129,7 @@ If the lowest level is completely full, then that level contains *2^h* nodes. Th The total number of nodes *n* in the entire heap is therefore *2^(h+1) - 1*. In the example, `2^4 - 1 = 16 - 1 = 15`. -There are at most *ceil(n/2^(h+1))* nodes of height *h* in an *n*-element heap. +There are at most *ceil(n/2^(h+1))* nodes of height *h* in an *n*-element heap. The leaf nodes are always located at array indices *floor(n/2)* to *n-1*. We will make use of this fact to quickly build up the heap from an array. Verify this for the example if you don't believe it. ;-) @@ -141,7 +141,7 @@ There are two primitive operations necessary to make sure the heap is a valid ma - `shiftUp()`: If the element is greater (max-heap) or smaller (min-heap) than its parent, it needs to be swapped with the parent. This makes it move up the tree. -- `shiftDown()`. If the element is smaller (max-heap) or greater (min-heap) than its children, it needs to move down the tree. This operation is also called "heapify". +- `shiftDown()`. If the element is smaller (max-heap) or greater (min-heap) than its children, it needs to move down the tree. This operation is also called "heapify". Shifting up or down is a recursive procedure that takes **O(log n)** time. @@ -161,7 +161,7 @@ All of the above take time **O(log n)** because shifting up or down is the most - `buildHeap(array)`: Converts an (unsorted) array into a heap by repeatedly calling `insert()`. If you’re smart about this, it can be done in **O(n)** time. -- [Heap sort](../Heap Sort/). Since the heap is really 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 really an array, we can use its unique properties to sort the array from low to high. Time: **O(n lg 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)**. @@ -187,7 +187,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're going to swap `(16)` and `(2)`. +To restore the heap property, we're going to swap `(16)` and `(2)`. ![The heap before insertion](Images/Insert2.png) @@ -211,7 +211,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'll do the opposite: we're going to 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'll do the opposite: we're going to 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) @@ -223,7 +223,7 @@ Keep shifting down until the node doesn't have any children or it is larger than ![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 so it takes **O(log n)** time. +The time required for shifting all the way down is proportional to the height of the tree so it 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. @@ -269,7 +269,7 @@ In code it would look like this: We simply call `insert()` for each of the values in the array. Simple enough, but not very efficient. This takes **O(n log n)** time in total because there are **n** elements and each insertion takes **log n** time. -If you didn't gloss over the math section, you'd have seen that for any heap the elements at array indices *n/2* to *n-1* are the leaves of the tree. We can simply skip those leaves. We only have to process the other nodes, since they are parents with one or more children and therefore may be in the wrong order. +If you didn't gloss over the math section, you'd have seen that for any heap the elements at array indices *n/2* to *n-1* are the leaves of the tree. We can simply skip those leaves. We only have to process the other nodes, since they are parents with one or more children and therefore may be in the wrong order. In code: @@ -288,7 +288,7 @@ Here, `elements` is the heap's own array. We walk backwards through this array, Heaps aren't made for fast searches, but if you want to remove an arbitrary element using `removeAtIndex()` or change the value of an element with `replace()`, then you need to obtain the index of that element somehow. Searching is one way to do this but it's kind of slow. -In a [binary search tree](../Binary Search Tree/) you can depend on the order of the nodes to guarantee a fast search. A heap orders its nodes differently and so a binary search won't work. You'll potentially have to look at every node in the tree. +In a [binary search tree](../Binary%20Search%20Tree/) you can depend on the order of the nodes to guarantee a fast search. A heap orders its nodes differently and so a binary search won't work. You'll potentially have to look at every node in the tree. Let's take our example heap again: @@ -302,7 +302,7 @@ Let's say we want to see if the heap contains the value `8` (it doesn't). We sta Despite this small optimization, searching is still an **O(n)** operation. -> **Note:** There is away to turn lookups into a **O(1)** operation by keeping an additional dictionary that maps node values to indices. This may be worth doing if you often need to call `replace()` to change the "priority" of objects in a [priority queue](../Priority Queue/) that's built on a heap. +> **Note:** There is away to turn lookups into a **O(1)** operation by keeping an additional dictionary that maps node values to indices. This may be worth doing if you often need to call `replace()` to change the "priority" of objects in a [priority queue](../Priority%20Queue/) that's built on a heap. ## The code From bdb1b157cc2698b3e211069475399ef19958261e Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 3 Apr 2017 21:26:14 +0100 Subject: [PATCH 0482/1275] Minimum Coin Change Problem - Dynamic Programming in Swift --- MinimumCoinChange/LICENSE | 201 ++++++++++++++++++ MinimumCoinChange/Package.swift | 7 + MinimumCoinChange/README.md | 41 ++++ .../Sources/MinimumCoinChange.swift | 76 +++++++ MinimumCoinChange/Tests/LinuxMain.swift | 6 + .../MinimumCoinChangeTests.swift | 21 ++ MinimumCoinChange/eurocoins.gif | Bin 0 -> 90051 bytes 7 files changed, 352 insertions(+) create mode 100755 MinimumCoinChange/LICENSE create mode 100644 MinimumCoinChange/Package.swift create mode 100755 MinimumCoinChange/README.md create mode 100644 MinimumCoinChange/Sources/MinimumCoinChange.swift create mode 100644 MinimumCoinChange/Tests/LinuxMain.swift create mode 100644 MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift create mode 100644 MinimumCoinChange/eurocoins.gif diff --git a/MinimumCoinChange/LICENSE b/MinimumCoinChange/LICENSE new file mode 100755 index 000000000..8dada3eda --- /dev/null +++ b/MinimumCoinChange/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MinimumCoinChange/Package.swift b/MinimumCoinChange/Package.swift new file mode 100644 index 000000000..749073782 --- /dev/null +++ b/MinimumCoinChange/Package.swift @@ -0,0 +1,7 @@ +// swift-tools-version:3.1 + +import PackageDescription + +let package = Package( + name: "MinimumCoinChange" +) diff --git a/MinimumCoinChange/README.md b/MinimumCoinChange/README.md new file mode 100755 index 000000000..c9cd71cd1 --- /dev/null +++ b/MinimumCoinChange/README.md @@ -0,0 +1,41 @@ +# Minimum Coin Change +Minimum Coin Change problem algorithm implemented in Swift comparing dynamic programming algorithm design to traditional greedy approach. + +Written for Swift Algorithm Club by Jacopo Mangiavacchi + +![Coins](eurocoins.gif) + +# Introduction + +In the traditional coin change problem you have to find all the different ways to change some given money in a particular amount of coins using a given amount of set of coins (i.e. 1 cent, 2 cents, 5 cents, 10 cents etc.). + +For example using Euro cents the total of 4 cents value of money can be changed in these possible ways: + +- Four 1 cent coins +- Two 2 cent coins +- One 2 cent coin and two 1 cent coins + +The minimum coin change problem is a variation of the generic coin change problem where you need to find the best option for changing the money returning the less number of coins. + +For example using Euro cents the best possible change for 4 cents are two 2 cent coins with a total of two coins. + + +# Greedy Solution + +A simple approach for implementing the Minimum Coin Change algorithm in a very efficient way is to start subtracting from the input value the greater possible coin value from the given amount of set of coins available and iterate subtracting the next greater possible coin value on the resulting difference. + +For example from the total of 4 Euro cents of the example above you can subtract initially 2 cents as the other biggest coins value (from 5 cents to above) are to bigger for the current 4 Euro cent value. Once used the first 2 cents coin you iterate again with the same logic for the rest of 2 cents and select another 2 cents coin and finally return the two 2 cents coins as the best change. + +Most of the time the result for this greedy approach is optimal but for some set of coins the result will not be the optimal. + +Indeed, if we use the a set of these three different coins set with values 1, 3 and 4 and execute this greedy algorithm for asking the best change for the value 6 we will get one coin of 4 and two coins of 1 instead of two coins of 3. + + +# Dynamic Programming Solution + +A classic dynamic programming strategy will iterate selecting in order a possible coin from the given amount of set of coins and finding using recursive calls the minimum coin change on the difference from the passed value and the selected coin. For any interaction the algorithm select from all possible combinations the one with the less number of coins used. + +The dynamic programming approach will always select the optimal change but it will require a number of steps that is at least quadratic in the goal amount to change. + +In this Swift implementation in order to optimize the overall performance we use an internal data structure for caching the result for best minimum coin change for previous values. + diff --git a/MinimumCoinChange/Sources/MinimumCoinChange.swift b/MinimumCoinChange/Sources/MinimumCoinChange.swift new file mode 100644 index 000000000..db7edecbe --- /dev/null +++ b/MinimumCoinChange/Sources/MinimumCoinChange.swift @@ -0,0 +1,76 @@ +// +// Minimum Coin Change Problem +// Compare Greedy Algorithm and Dynamic Programming Algorithm in Swift +// +// Created by Jacopo Mangiavacchi on 04/03/17. +// + +import Foundation + +public struct MinimumCoinChange { + private let sortedCoinSet: [Int] + private var cache: [Int : [Int]] + + public init(coinSet: [Int]) { + self.sortedCoinSet = coinSet.sorted(by: { $0 > $1} ) + self.cache = [:] + } + + //Greedy Algorithm + public func changeGreedy(_ value: Int) -> [Int] { + var change: [Int] = [] + var newValue = value + + for coin in sortedCoinSet { + while newValue - coin >= 0 { + change.append(coin) + newValue -= coin + } + + if newValue == 0 { + break + } + } + + return change + } + + //Dynamic Programming Algorithm + public mutating func changeDynamic(_ value: Int) -> [Int] { + if value <= 0 { + return [] + } + + if let cached = cache[value] { + return cached + } + + var change: [Int] = [] + + var potentialChangeArray: [[Int]] = [] + + for coin in sortedCoinSet { + if value - coin >= 0 { + var potentialChange: [Int] = [] + potentialChange.append(coin) + let newPotentialValue = value - coin + + if value > 0 { + potentialChange.append(contentsOf: changeDynamic(newPotentialValue)) + } + + //print("value: \(value) coin: \(coin) potentialChange: \(potentialChange)") + potentialChangeArray.append(potentialChange) + } + } + + if potentialChangeArray.count > 0 { + let sortedPotentialChangeArray = potentialChangeArray.sorted(by: { $0.count < $1.count }) + change = sortedPotentialChangeArray[0] + } + + cache[value] = change + return change + } +} + diff --git a/MinimumCoinChange/Tests/LinuxMain.swift b/MinimumCoinChange/Tests/LinuxMain.swift new file mode 100644 index 000000000..db61c6011 --- /dev/null +++ b/MinimumCoinChange/Tests/LinuxMain.swift @@ -0,0 +1,6 @@ +import XCTest +@testable import MinimumCoinChangeTests + +XCTMain([ + testCase(MinimumCoinChangeTests.allTests), +]) diff --git a/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift b/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift new file mode 100644 index 000000000..86c9007ba --- /dev/null +++ b/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift @@ -0,0 +1,21 @@ +import XCTest +@testable import MinimumCoinChange + +class MinimumCoinChangeTests: XCTestCase { + func testExample() { + var mcc = MinimumCoinChange(coinSet: [1, 2, 5, 10, 20, 25]) + + for i in 0..<100 { + let greedy = mcc.changeGreedy(i) + let dynamic = mcc.changeDynamic(i) + + if greedy.count != dynamic.count { + print("\(i): greedy = \(greedy) dynamic = \(dynamic)") + } + } + } + + static var allTests = [ + ("testExample", testExample), + ] +} diff --git a/MinimumCoinChange/eurocoins.gif b/MinimumCoinChange/eurocoins.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d9e81e559071eb0b63dc82d35801e5809447612 GIT binary patch literal 90051 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

CP-d(QUGY&)`KEg`5L-~O% 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 UYwfkzW~=SC+;;2joq+%VJHCEf)Bpeg literal 0 HcmV?d00001 From 3f7aaa2799db7c94076bb3155a83811a7c596708 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 4 Apr 2017 09:19:14 +0800 Subject: [PATCH 0483/1275] fix: broken links --- AVL Tree/README.markdown | 4 +- Bounded Priority Queue/README.markdown | 2 +- Count Occurrences/README.markdown | 6 +-- Depth-First Search/README.markdown | 6 +-- Deque/README.markdown | 42 +++++++++---------- Heap Sort/README.markdown | 2 +- Huffman Coding/README.markdown | 28 ++++++------- Knuth-Morris-Pratt/README.markdown | 32 +++++++------- Kth Largest Element/README.markdown | 6 +-- .../README.markdown | 4 +- Priority Queue/README.markdown | 6 +-- Quicksort/README.markdown | 24 +++++------ Segment Tree/README.markdown | 12 +++--- Selection Sort/README.markdown | 10 ++--- 14 files changed, 92 insertions(+), 92 deletions(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index a9218203a..c8d8d4628 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -53,7 +53,7 @@ For the rotation we're using the terminology: * *RotationSubtree* - subtree of the *Pivot* upon the side of rotation * *OppositeSubtree* - subtree of the *Pivot* opposite the side of rotation -Let take an example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: +Let take an example of balancing the unbalanced tree using *Right* (clockwise direction) rotation: ![Rotation1](Images/RotationStep1.jpg) ![Rotation2](Images/RotationStep2.jpg) ![Rotation3](Images/RotationStep3.jpg) @@ -76,7 +76,7 @@ Insertion never needs more than 2 rotations. Removal might require up to __log(n ## The code -Most of the code in [AVLTree.swift](AVLTree.swift) is just regular [binary search tree](../Binary Search Tree/) stuff. You'll find this in any implementation of a binary search tree. For example, searching the tree is exactly the same. The only things that an AVL tree does slightly differently are inserting and deleting the nodes. +Most of the code in [AVLTree.swift](AVLTree.swift) is just regular [binary search tree](../Binary%20Search%20Tree/) stuff. You'll find this in any implementation of a binary search tree. For example, searching the tree is exactly the same. The only things that an AVL tree does slightly differently are inserting and deleting the nodes. > **Note:** If you're a bit fuzzy on the regular operations of a binary search tree, I suggest you [catch up on those first](../Binary%20Search%20Tree/). It will make the rest of the AVL tree easier to understand. diff --git a/Bounded Priority Queue/README.markdown b/Bounded Priority Queue/README.markdown index 4e4c89272..8cbaa85b2 100644 --- a/Bounded Priority Queue/README.markdown +++ b/Bounded Priority Queue/README.markdown @@ -26,7 +26,7 @@ Suppose that we wish to insert the element `G` with priority 0.1 into this BPQ. ## Implementation -While a [heap](../Heap/) may be a really simple implementation for a priority queue, a sorted [linked list](../Linked List/) allows for **O(k)** insertion and **O(1)** deletion, where **k** is the bounding number of elements. +While a [heap](../Heap/) may be a really simple implementation for a priority queue, a sorted [linked list](../Linked%20List/) allows for **O(k)** insertion and **O(1)** deletion, where **k** is the bounding number of elements. Here's how you could implement it in Swift: diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 4c65c4219..85b77d2d0 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -36,7 +36,7 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { } return low } - + func rightBoundary() -> Int { var low = 0 var high = a.count @@ -50,12 +50,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { } return low } - + return rightBoundary() - leftBoundary() } ``` -Notice that the helper functions `leftBoundary()` and `rightBoundary()` are very similar to the [binary search](../Binary Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. +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. To test this algorithm, copy the code to a playground and then do: diff --git a/Depth-First Search/README.markdown b/Depth-First Search/README.markdown index 9e1a5112d..98a19e0cb 100644 --- a/Depth-First Search/README.markdown +++ b/Depth-First Search/README.markdown @@ -40,7 +40,7 @@ func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { } ``` -Where a [breadth-first search](../Breadth-First Search/) visits all immediate neighbors first, a depth-first search tries to go as deep down the tree or graph as it can. +Where a [breadth-first search](../Breadth-First%20Search/) visits all immediate neighbors first, a depth-first search tries to go as deep down the tree or graph as it can. Put this code in a playground and test it like so: @@ -71,13 +71,13 @@ print(nodesExplored) ``` This will output: `["a", "b", "d", "e", "h", "f", "g", "c"]` - + ## What is DFS good for? Depth-first search can be used to solve many problems, for example: * Finding connected components of a sparse graph -* [Topological sorting](../Topological Sort/) of nodes in a graph +* [Topological sorting](../Topological%20Sort/) of nodes in a graph * Finding bridges of a graph (see: [Bridges](https://en.wikipedia.org/wiki/Bridge_(graph_theory)#Bridge-finding_algorithm)) * And lots of others! diff --git a/Deque/README.markdown b/Deque/README.markdown index 67a734576..fda1de5f8 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -9,23 +9,23 @@ Here is a very basic implementation of a deque in Swift: ```swift public struct Deque { private var array = [T]() - + public var isEmpty: Bool { return array.isEmpty } - + public var count: Int { return array.count } - + public mutating func enqueue(_ element: T) { array.append(element) } - + public mutating func enqueueFront(_ element: T) { array.insert(element, atIndex: 0) } - + public mutating func dequeue() -> T? { if isEmpty { return nil @@ -33,7 +33,7 @@ public struct Deque { return array.removeFirst() } } - + public mutating func dequeueBack() -> T? { if isEmpty { return nil @@ -41,11 +41,11 @@ public struct Deque { return array.removeLast() } } - + public func peekFront() -> T? { return array.first } - + public func peekBack() -> T? { return array.last } @@ -73,7 +73,7 @@ deque.dequeue() // 5 This particular implementation of `Deque` is simple but not very efficient. Several operations are **O(n)**, notably `enqueueFront()` and `dequeue()`. I've included it only to show the principle of what a deque does. ## A more efficient version - + The reason that `dequeue()` and `enqueueFront()` are **O(n)** is that they work on the front of the array. If you remove an element at the front of an array, what happens is that all the remaining elements need to be shifted in memory. Let's say the deque's array contains the following items: @@ -92,7 +92,7 @@ Likewise, inserting an element at the front of the array is expensive because it First, the elements `2`, `3`, and `4` are moved up by one position in the computer's memory, and then the new element `5` is inserted at the position where `2` used to be. -Why is this not an issue at for `enqueue()` and `dequeueBack()`? Well, these operations are performed at the end of the array. The way resizable arrays are implemented in Swift is by reserving a certain amount of free space at the back. +Why is this not an issue at for `enqueue()` and `dequeueBack()`? Well, these operations are performed at the end of the array. The way resizable arrays are implemented in Swift is by reserving a certain amount of free space at the back. Our initial array `[ 1, 2, 3, 4]` actually looks like this in memory: @@ -120,26 +120,26 @@ public struct Deque { private var head: Int private var capacity: Int private let originalCapacity:Int - + public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) originalCapacity = self.capacity array = [T?](repeating: nil, count: capacity) head = capacity } - + public var isEmpty: Bool { return count == 0 } - + public var count: Int { return array.count - head } - + public mutating func enqueue(_ element: T) { array.append(element) } - + public mutating func enqueueFront(_ element: T) { // this is explained below } @@ -155,7 +155,7 @@ public struct Deque { return array.removeLast() } } - + public func peekFront() -> T? { if isEmpty { return nil @@ -163,7 +163,7 @@ public struct Deque { return array[head] } } - + public func peekBack() -> T? { if isEmpty { return nil @@ -176,7 +176,7 @@ public struct Deque { It still largely looks the same -- `enqueue()` and `dequeueBack()` haven't changed -- but there are also a few important differences. The array now stores objects of type `T?` instead of just `T` because we need some way to mark array elements as being empty. -The `init` method allocates a new array that contains a certain number of `nil` values. This is the free room we have to work with at the beginning of the array. By default this creates 10 empty spots. +The `init` method allocates a new array that contains a certain number of `nil` values. This is the free room we have to work with at the beginning of the array. By default this creates 10 empty spots. The `head` variable is the index in the array of the front-most object. Since the queue is currently empty, `head` points at an index beyond the end of the array. @@ -219,7 +219,7 @@ Notice how the array has resized itself. There was no room to add the `1`, so Sw | head -> **Note:** You won't see those empty spots at the back of the array when you `print(deque.array)`. This is because Swift hides them from you. Only the ones at the front of the array show up. +> **Note:** You won't see those empty spots at the back of the array when you `print(deque.array)`. This is because Swift hides them from you. Only the ones at the front of the array show up. The `dequeue()` method does the opposite of `enqueueFront()`, it reads the value at `head`, sets the array element back to `nil`, and then moves `head` one position to the right: @@ -250,7 +250,7 @@ There is one tiny problem... If you enqueue a lot of objects at the front, you'r } ``` -If `head` equals 0, there is no room left at the front. When that happens, we add a whole bunch of new `nil` elements to the array. This is an **O(n)** operation but since this cost gets divided over all the `enqueueFront()`s, each individual call to `enqueueFront()` is still **O(1)** on average. +If `head` equals 0, there is no room left at the front. When that happens, we add a whole bunch of new `nil` elements to the array. This is an **O(n)** operation but since this cost gets divided over all the `enqueueFront()`s, each individual call to `enqueueFront()` is still **O(1)** on average. > **Note:** We also multiply the capacity by 2 each time this happens, so if your queue grows bigger and bigger, the resizing happens less often. This is also what Swift arrays automatically do at the back. @@ -302,7 +302,7 @@ This way we can strike a balance between fast enqueuing and dequeuing at the fro ## See also -Other ways to implement deque are by using a [doubly linked list](../Linked List/), a [circular buffer](../Ring Buffer/), or two [stacks](../Stack/) facing opposite directions. +Other ways to implement deque are by using a [doubly linked list](../Linked%20List/), a [circular buffer](../Ring%20Buffer/), or two [stacks](../Stack/) facing opposite directions. [A fully-featured deque implementation in Swift](https://github.com/lorentey/Deque) diff --git a/Heap Sort/README.markdown b/Heap Sort/README.markdown index 5f047f82b..7fdd8d2ca 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -40,7 +40,7 @@ And fix up the heap to make it valid max-heap again: As you can see, the largest items are making their way to the back. We repeat this process until we arrive at the root node and then the whole array is sorted. -> **Note:** This process is very similar to [selection sort](../Selection Sort/), 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. +> **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. diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 6b2c0d245..4e6f75514 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -16,7 +16,7 @@ If you count how often each byte appears, you can clearly see that some bytes oc c: 2 p: 1 r: 2 e: 1 n: 2 i: 1 - + We can assign bit strings to each of these bytes. The more common a byte is, the fewer bits we assign to it. We might get something like this: space: 5 010 u: 1 11001 @@ -30,12 +30,12 @@ We can assign bit strings to each of these bytes. The more common a byte is, the Now if we replace the original bytes with these bit strings, the compressed output becomes: - 101 000 010 111 11001 0011 10001 010 0010 000 1001 11010 101 + 101 000 010 111 11001 0011 10001 010 0010 000 1001 11010 101 s o _ m u c h _ w o r d s - + 010 0010 000 0010 010 111 11011 0110 01111 010 0011 000 111 _ w o w _ m a n y _ c o m - + 11000 1001 01110 101 101 10000 000 0110 0 p r e s s i o n @@ -57,7 +57,7 @@ The edges between the nodes either say "1" or "0". These correspond to the bit-e Compression is then a matter of looping through the input bytes, and for each byte traverse the tree from the root node to that byte's leaf node. Every time we take a left branch, we emit a 1-bit. When we take a right branch, we emit a 0-bit. -For example, to go from the root node to `c`, we go right (`0`), right again (`0`), left (`1`), and left again (`1`). So the Huffman code for `c` is `0011`. +For example, to go from the root node to `c`, we go right (`0`), right again (`0`), left (`1`), and left again (`1`). So the Huffman code for `c` is `0011`. Decompression works in exactly the opposite way. It reads the compressed bits one-by-one and traverses the tree until we get to a leaf node. The value of that leaf node is the uncompressed byte. For example, if the bits are `11010`, we start at the root and go left, left again, right, left, and a final right to end up at `d`. @@ -137,7 +137,7 @@ Here are the definitions we need: ```swift class Huffman { typealias NodeIndex = Int - + struct Node { var count = 0 var index: NodeIndex = -1 @@ -152,7 +152,7 @@ class Huffman { } ``` -The tree structure is stored in the `tree` array and will be made up of `Node` objects. Since this is a [binary tree](../Binary Tree/), each node needs two children, `left` and `right`, and a reference back to its `parent` node. Unlike a typical binary tree, however, these nodes don't to use pointers to refer to each other but simple integer indices in the `tree` array. (We also store the array `index` of the node itself; the reason for this will become clear later.) +The tree structure is stored in the `tree` array and will be made up of `Node` objects. Since this is a [binary tree](../Binary%20Tree/), each node needs two children, `left` and `right`, and a reference back to its `parent` node. Unlike a typical binary tree, however, these nodes don't to use pointers to refer to each other but simple integer indices in the `tree` array. (We also store the array `index` of the node itself; the reason for this will become clear later.) Note that `tree` currently has room for 256 entries. These are for the leaf nodes because there are 256 possible byte values. Of course, not all of those may end up being used, depending on the input data. Later, we'll add more nodes as we build up the actual tree. For the moment there isn't a tree yet, just 256 separate leaf nodes with no connections between them. All the node counts are 0. @@ -183,7 +183,7 @@ Instead, we'll add a method to export the frequency table without all the pieces var byte: UInt8 = 0 var count = 0 } - + func frequencyTable() -> [Freq] { var a = [Freq]() for i in 0..<256 where tree[i].count > 0 { @@ -209,7 +209,7 @@ To build the tree, we do the following: 2. Create a new parent node that links these two nodes together. 3. This repeats over and over until only one node with no parent remains. This becomes the root node of the tree. -This is an ideal place to use a [priority queue](../Priority Queue/). A priority queue is a data structure that is optimized so that finding the minimum value is always very fast. Here, we repeatedly need to find the node with the smallest count. +This is an ideal place to use a [priority queue](../Priority%20Queue/). A priority queue is a data structure that is optimized so that finding the minimum value is always very fast. Here, we repeatedly need to find the node with the smallest count. The function `buildTree()` then becomes: @@ -233,7 +233,7 @@ The function `buildTree()` then becomes: tree[node1.index].parent = parentNode.index // 4 tree[node2.index].parent = parentNode.index - + queue.enqueue(parentNode) // 5 } @@ -286,7 +286,7 @@ Now that we know how to build the compression tree from the frequency table, we } ``` -This first calls `countByteFrequency()` to build the frequency table, then `buildTree()` to put together the compression tree. It also creates a `BitWriter` object for writing individual bits. +This first calls `countByteFrequency()` to build the frequency table, then `buildTree()` to put together the compression tree. It also creates a `BitWriter` object for writing individual bits. Then it loops through the entire input and for each byte calls `traverseTree()`. That method will step through the tree nodes and for each node write a 1 or 0 bit. Finally, we return the `BitWriter`'s data object. @@ -309,7 +309,7 @@ The interesting stuff happens in `traverseTree()`. This is a recursive method: } ``` -When we call this method from `compressData()`, the `nodeIndex` parameter is the array index of the leaf node for the byte that we're about to encode. This method recursively walks the tree from a leaf node up to the root, and then back again. +When we call this method from `compressData()`, the `nodeIndex` parameter is the array index of the leaf node for the byte that we're about to encode. This method recursively walks the tree from a leaf node up to the root, and then back again. As we're going back from the root to the leaf node, we write a 1 bit or a 0 bit for every node we encounter. If a child is the left node, we emit a 1; if it's the right node, we emit a 0. @@ -395,10 +395,10 @@ Here's how you would use the decompression method: ```swift let frequencyTable = huffman1.frequencyTable() - + let huffman2 = Huffman() let decompressedData = huffman2.decompressData(compressedData, frequencyTable: frequencyTable) - + let s2 = String(data: decompressedData, encoding: NSUTF8StringEncoding)! ``` diff --git a/Knuth-Morris-Pratt/README.markdown b/Knuth-Morris-Pratt/README.markdown index f01b87b3d..95fdea9e9 100644 --- a/Knuth-Morris-Pratt/README.markdown +++ b/Knuth-Morris-Pratt/README.markdown @@ -1,9 +1,9 @@ # Knuth-Morris-Pratt String Search -Goal: Write a linear-time string matching algorithm in Swift that returns the indexes of all the occurrencies of a given pattern. - +Goal: Write a linear-time string matching algorithm in Swift that returns the indexes of all the occurrencies of a given pattern. + In other words, we want to implement an `indexesOf(pattern: String)` extension on `String` that returns an array `[Int]` of integers, representing all occurrences' indexes of the search pattern, or `nil` if the pattern could not be found inside the string. - + For example: ```swift @@ -16,7 +16,7 @@ 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 idea behind the algorithm is not too different from the [naive string search](../Brute-Force String Search/) 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. +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. The pre-processing stage produces an array (called `suffixPrefix` in the code) of integers in which every element `suffixPrefix[i]` records the length of the longest proper suffix of `P[0...i]` (where `P` is the pattern) that matches a prefix of `P`. In other words, `suffixPrefix[i]` is the longest proper substring of `P` that ends at position `i` and that is a prefix of `P`. Just a quick example. Consider `P = "abadfryaabsabadffg"`, then `suffixPrefix[4] = 0`, `suffixPrefix[9] = 2`, `suffixPrefix[14] = 4`. There are different ways to obtain the values of `SuffixPrefix` array. We will use the method based on the [Z-Algorithm](../Z-Algorithm/). This function takes in input the pattern and produces an array of integers. Each element represents the length of the longest substring starting at position `i` of `P` and that matches a prefix of `P`. You can notice that the two arrays are similar, they record the same informations but on the different places. We only have to find a method to map `Z[i]` to `suffixPrefix[j]`. It is not that difficult and this is the code that will do for us: @@ -93,10 +93,10 @@ extension String { ``` Let's make an example reasoning with the code above. Let's consider the string `P = ACTGACTA"`, the consequentially obtained `suffixPrefix` array equal to `[0, 0, 0, 0, 0, 0, 3, 1]`, and the text `T = "GCACTGACTGACTGACTAG"`. The algorithm begins with the text and the pattern aligned like below. We have to compare `T[0]` with `P[0]`. - + 1 0123456789012345678 - text: GCACTGACTGACTGACTAG + text: GCACTGACTGACTGACTAG textIndex: ^ pattern: ACTGACTA patternIndex: ^ @@ -104,54 +104,54 @@ Let's make an example reasoning with the code above. Let's consider the string ` suffixPrefix: 00000031 We have a mismatch and we move on comparing `T[1]` and `P[0]`. We have to check if a pattern occurrence is present but there is not. So, we have to shift the pattern right and by doing so we have to check `suffixPrefix[1 - 1]`. Its value is `0` and we restart by comparing `T[1]` with `P[0]`. Again a mismath occurs, so we go on with `T[2]` and `P[0]`. - + 1 0123456789012345678 text: GCACTGACTGACTGACTAG - textIndex: ^ + textIndex: ^ pattern: ACTGACTA patternIndex: ^ suffixPrefix: 00000031 This time we have a match. And it continues until position `8`. Unfortunately the length of the match is not equal to the pattern length, we cannot report an occurrence. But we are still lucky because we can use the values computed in the `suffixPrefix` array now. In fact, the length of the match is `7`, and if we look at the element `suffixPrefix[7 - 1]` we discover that is `3`. This information tell us that that the prefix of `P` matches the suffix of the susbtring `T[0...8]`. So the `suffixPrefix` array guarantees us that the two substring match and that we do not have to compare their characters, so we can shift right the pattern for more than one character! The comparisons restart from `T[9]` and `P[3]`. - + 1 0123456789012345678 - text: GCACTGACTGACTGACTAG + text: GCACTGACTGACTGACTAG textIndex: ^ pattern: ACTGACTA patternIndex: ^ suffixPrefix: 00000031 They match so we continue the compares until position `13` where a misatch occurs beetwen charcter `G` and `A`. Just like before, we are lucky and we can use the `suffixPrefix` array to shift right the pattern. - + 1 0123456789012345678 - text: GCACTGACTGACTGACTAG + text: GCACTGACTGACTGACTAG textIndex: ^ pattern: ACTGACTA patternIndex: ^ suffixPrefix: 00000031 Again, we have to compare. But this time the comparisons finally take us to an occurrence, at position `17 - 7 = 10`. - + 1 0123456789012345678 - text: GCACTGACTGACTGACTAG + text: GCACTGACTGACTGACTAG textIndex: ^ pattern: ACTGACTA patternIndex: ^ suffixPrefix: 00000031 The algorithm than tries to compare `T[18]` with `P[1]` (because we used the element `suffixPrefix[8 - 1] = 1`) but it fails and at the next iteration it ends its work. - + The pre-processing stage involves only the pattern. The running time of the Z-Algorithm is linear and takes `O(n)`, where `n` is the length of the pattern `P`. After that, the search stage does not "overshoot" the length of the text `T` (call it `m`). It can be be proved that number of comparisons of the search stage is bounded by `2 * m`. The final running time of the Knuth-Morris-Pratt algorithm is `O(n + m)`. > **Note:** To execute the code in the [KnuthMorrisPratt.swift](./KnuthMorrisPratt.swift) you have to copy the [ZAlgorithm.swift](../Z-Algorithm/ZAlgorithm.swift) file contained in the [Z-Algorithm](../Z-Algorithm/) folder. The [KnuthMorrisPratt.playground](./KnuthMorrisPratt.playground) already includes the definition of the `Zeta` function. -Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"](https://books.google.it/books/about/Algorithms_on_Strings_Trees_and_Sequence.html?id=Ofw5w1yuD8kC&redir_esc=y) by Dan Gusfield, Cambridge University Press, 1997. +Credits: This code is based on the handbook ["Algorithm on String, Trees and Sequences: Computer Science and Computational Biology"](https://books.google.it/books/about/Algorithms_on_Strings_Trees_and_Sequence.html?id=Ofw5w1yuD8kC&redir_esc=y) by Dan Gusfield, Cambridge University Press, 1997. *Written for Swift Algorithm Club by Matteo Dunnhofer* diff --git a/Kth Largest Element/README.markdown b/Kth Largest Element/README.markdown index d50d691a1..53bec1c1c 100644 --- a/Kth Largest Element/README.markdown +++ b/Kth Largest Element/README.markdown @@ -44,7 +44,7 @@ Of course, if you were looking for the k-th *smallest* element, you'd use `a[k]` ## A faster solution -There is a clever algorithm that combines the ideas of [binary search](../Binary Search/) and [quicksort](../Quicksort/) to arrive at an **O(n)** solution. +There is a clever algorithm that combines the ideas of [binary search](../Binary%20Search/) and [quicksort](../Quicksort/) to arrive at an **O(n)** solution. Recall that binary search splits the array in half over and over again, to quickly narrow in on the value you're searching for. That's what we'll do here too. @@ -86,7 +86,7 @@ The following function implements these ideas: ```swift public func randomizedSelect(array: [T], order k: Int) -> T { var a = array - + func randomPivot(inout a: [T], _ low: Int, _ high: Int) -> T { let pivotIndex = random(min: low, max: high) swap(&a, pivotIndex, high) @@ -120,7 +120,7 @@ public func randomizedSelect(array: [T], order k: Int) -> T { return a[low] } } - + precondition(a.count > 0) return randomizedSelect(&a, 0, a.count - 1, k) } diff --git a/Minimum Spanning Tree (Unweighted)/README.markdown b/Minimum Spanning Tree (Unweighted)/README.markdown index cfd29c987..23f18c335 100644 --- a/Minimum Spanning Tree (Unweighted)/README.markdown +++ b/Minimum Spanning Tree (Unweighted)/README.markdown @@ -16,7 +16,7 @@ Drawn as a more conventional tree it looks like this: ![An actual tree](Images/Tree.png) -To calculate the minimum spanning tree on an unweighted graph, we can use the [breadth-first search](../Breadth-First Search/) algorithm. Breadth-first search starts at a source node and traverses the graph by exploring the immediate neighbor nodes first, before moving to the next level neighbors. If we tweak this algorithm by selectively removing edges, then it can convert the graph into the minimum spanning tree. +To calculate the minimum spanning tree on an unweighted graph, we can use the [breadth-first search](../Breadth-First%20Search/) algorithm. Breadth-first search starts at a source node and traverses the graph by exploring the immediate neighbor nodes first, before moving to the next level neighbors. If we tweak this algorithm by selectively removing edges, then it can convert the graph into the minimum spanning tree. Let's step through the example. We start with the source node `a`, add it to a queue and mark it as visited. @@ -185,6 +185,6 @@ print(minimumSpanningTree) // [node: a edges: ["b", "h"]] // [node: h edges: ["g", "i"]] ``` -> **Note:** On an unweighed graph, any spanning tree is always a minimal spanning tree. This means you can also use a [depth-first search](../Depth-First Search) to find the minimum spanning tree. +> **Note:** On an unweighed graph, any spanning tree is always a minimal spanning tree. This means you can also use a [depth-first search](../Depth-First%20Search) to find the minimum spanning tree. *Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* diff --git a/Priority Queue/README.markdown b/Priority Queue/README.markdown index 8308ec16f..fbbcaa0f3 100644 --- a/Priority Queue/README.markdown +++ b/Priority Queue/README.markdown @@ -12,7 +12,7 @@ Examples of algorithms that can benefit from a priority queue: - Event-driven simulations. Each event is given a timestamp and you want events to be performed in order of their timestamps. The priority queue makes it easy to find the next event that needs to be simulated. - Dijkstra's algorithm for graph searching uses a priority queue to calculate the minimum cost. -- [Huffman coding](../Huffman Coding/) for data compression. This algorithm builds up a compression tree. It repeatedly needs to find the two nodes with the smallest frequencies that do not have a parent node yet. +- [Huffman coding](../Huffman%20Coding/) for data compression. This algorithm builds up a compression tree. It repeatedly needs to find the two nodes with the smallest frequencies that do not have a parent node yet. - A* pathfinding for artificial intelligence. - Lots of other places! @@ -31,8 +31,8 @@ Common operations on a priority queue: There are different ways to implement priority queues: -- As a [sorted array](../Ordered Array/). The most important item is at the end of the array. Downside: inserting new items is slow because they must be inserted in sorted order. -- As a balanced [binary search tree](../Binary Search Tree/). This is great for making a double-ended priority queue because it implements both "find minimum" and "find maximum" efficiently. +- As a [sorted array](../Ordered%20Array/). The most important item is at the end of the array. Downside: inserting new items is slow because they must be inserted in sorted order. +- As a balanced [binary search tree](../Binary%20Search%20Tree/). This is great for making a double-ended priority queue because it implements both "find minimum" and "find maximum" efficiently. - As a [heap](../Heap/). The heap is a natural data structure for a priority queue. In fact, the two terms are often used as synonyms. A heap is more efficient than a sorted array because a heap only has to be partially sorted. All heap operations are **O(log n)**. Here's a Swift priority queue based on a heap: diff --git a/Quicksort/README.markdown b/Quicksort/README.markdown index d359ecb5c..e0bd8e604 100644 --- a/Quicksort/README.markdown +++ b/Quicksort/README.markdown @@ -14,7 +14,7 @@ func quicksort(_ a: [T]) -> [T] { let less = a.filter { $0 < pivot } let equal = a.filter { $0 == pivot } let greater = a.filter { $0 > pivot } - + return quicksort(less) + equal + quicksort(greater) } ``` @@ -30,7 +30,7 @@ Here's how it works. When given an array, `quicksort()` splits it up into three All the elements less than the pivot go into a new array called `less`. All the elements equal to the pivot go into the `equal` array. And you guessed it, all elements greater than the pivot go into the third array, `greater`. This is why the generic type `T` must be `Comparable`, so we can compare the elements with `<`, `==`, and `>`. -Once we have these three arrays, `quicksort()` recursively sorts the `less` array and the `greater` array, then glues those sorted subarrays back together with the `equal` array to get the final result. +Once we have these three arrays, `quicksort()` recursively sorts the `less` array and the `greater` array, then glues those sorted subarrays back together with the `equal` array to get the final result. ## An example @@ -73,7 +73,7 @@ The `less` array is empty because there was no value smaller than `-1`; the othe That `greater` array was: [ 3, 2, 5 ] - + This works just the same way as before: we pick the middle element `2` as the pivot and fill up the subarrays: less: [ ] @@ -122,7 +122,7 @@ There is no guarantee that partitioning keeps the elements in the same relative [ 3, 0, 5, 2, -1, 1, 8, 8, 14, 26, 10, 27, 9 ] -The only guarantee is that to the left of the pivot are all the smaller elements and to the right are all the larger elements. Because partitioning can change the original order of equal elements, quicksort does not produce a "stable" sort (unlike [merge sort](../Merge Sort/), for example). Most of the time that's not a big deal. +The only guarantee is that to the left of the pivot are all the smaller elements and to the right are all the larger elements. Because partitioning can change the original order of equal elements, quicksort does not produce a "stable" sort (unlike [merge sort](../Merge%20Sort/), for example). Most of the time that's not a big deal. ## Lomuto's partitioning scheme @@ -133,7 +133,7 @@ Here's an implementation of Lomuto's partitioning scheme in Swift: ```swift func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[high] - + var i = low for j in low..(_ a: inout [T], low: Int, high: Int) -> Int i += 1 } } - + (a[i], a[high]) = (a[high], a[i]) return i } @@ -168,7 +168,7 @@ After partitioning, the array looks like this: The variable `p` contains the return value of the call to `partitionLomuto()` and is 7. This is the index of the pivot element in the new array (marked with a star). -The left partition goes from 0 to `p-1` and is `[ 0, 3, 2, 1, 5, 8, -1 ]`. The right partition goes from `p+1` to the end, and is `[ 9, 10, 14, 26, 27 ]` (the fact that the right partition is already sorted is a coincidence). +The left partition goes from 0 to `p-1` and is `[ 0, 3, 2, 1, 5, 8, -1 ]`. The right partition goes from `p+1` to the end, and is `[ 9, 10, 14, 26, 27 ]` (the fact that the right partition is already sorted is a coincidence). You may notice something interesting... The value `8` occurs more than once in the array. One of those `8`s did not end up neatly in the middle but somewhere in the left partition. That's a small downside of the Lomuto algorithm as it makes quicksort slower if there are a lot of duplicate elements. @@ -281,11 +281,11 @@ func partitionHoare(_ a: inout [T], low: Int, high: Int) -> Int { let pivot = a[low] var i = low - 1 var j = high + 1 - + while true { repeat { j -= 1 } while a[j] > pivot repeat { i += 1 } while a[i] < pivot - + if i < j { swap(&a[i], &a[j]) } else { @@ -309,9 +309,9 @@ The result is: [ -1, 0, 3, 8, 2, 5, 1, 27, 10, 14, 9, 8, 26 ] -Note that this time the pivot isn't in the middle at all. Unlike with Lomuto's scheme, the return value is not necessarily the index of the pivot element in the new array. +Note that this time the pivot isn't in the middle at all. Unlike with Lomuto's scheme, the return value is not necessarily the index of the pivot element in the new array. -Instead, the array is partitioned into the regions `[low...p]` and `[p+1...high]`. Here, the return value `p` is 6, so the two partitions are `[ -1, 0, 3, 8, 2, 5, 1 ]` and `[ 27, 10, 14, 9, 8, 26 ]`. +Instead, the array is partitioned into the regions `[low...p]` and `[p+1...high]`. Here, the return value `p` is 6, so the two partitions are `[ -1, 0, 3, 8, 2, 5, 1 ]` and `[ 27, 10, 14, 9, 8, 26 ]`. The pivot is placed somewhere inside one of the two partitions, but the algorithm doesn't tell you which one or where. If the pivot value occurs more than once, then some instances may appear in the left partition and others may appear in the right partition. @@ -357,7 +357,7 @@ And again: And so on... -That's no good, because this pretty much reduces quicksort to the much slower insertion sort. For quicksort to be efficient, it needs to split the array into roughly two halves. +That's no good, because this pretty much reduces quicksort to the much slower insertion sort. For quicksort to be efficient, it needs to split the array into roughly two halves. The optimal pivot for this example would have been `4`, so we'd get: diff --git a/Segment Tree/README.markdown b/Segment Tree/README.markdown index 15b1a3227..9897c9c3b 100644 --- a/Segment Tree/README.markdown +++ b/Segment Tree/README.markdown @@ -18,7 +18,7 @@ var a = [ 20, 3, -1, 101, 14, 29, 5, 61, 99 ] We want to query this array on the interval from 3 to 7 for the function "sum". That means we do the following: 101 + 14 + 29 + 5 + 61 = 210 - + because `101` is at index 3 in the array and `61` is at index 7. So we pass all the numbers between `101` and `61` to the sum function, which adds them all up. If we had used the "min" function, the result would have been `5` because that's the smallest number in the interval from 3 to 7. Here's naive approach if our array's type is `Int` and **f** is just the sum of two integers: @@ -43,7 +43,7 @@ The main idea of segment trees is simple: we precalculate some segments in our a ## Structure of segment tree -A segment tree is just a [binary tree](../Binary Tree/) where each node is an instance of the `SegmentTree` class: +A segment tree is just a [binary tree](../Binary%20Tree/) where each node is an instance of the `SegmentTree` class: ```swift public class SegmentTree { @@ -116,18 +116,18 @@ Here's the code: if self.leftBound == leftBound && self.rightBound == rightBound { return self.value } - + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } - + // 2 if leftChild.rightBound < leftBound { return rightChild.query(withLeftBound: leftBound, rightBound: rightBound) - + // 3 } else if rightChild.leftBound > rightBound { return leftChild.query(withLeftBound: leftBound, rightBound: rightBound) - + // 4 } else { let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound) diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index e95749d14..cb8ed59c2 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -2,7 +2,7 @@ Goal: Sort an array from low to high (or high to low). -You are given an array of numbers and need to put them in the right order. The selection sort algorithm divides the array into two parts: the beginning of the array is sorted, while the rest of the array consists of the numbers that still remain to be sorted. +You are given an array of numbers and need to put them in the right order. The selection sort algorithm divides the array into two parts: the beginning of the array is sorted, while the rest of the array consists of the numbers that still remain to be sorted. [ ...sorted numbers... | ...unsorted numbers... ] @@ -23,7 +23,7 @@ It's called a "selection" sort, because at every step you search through the res ## An example -Let's say the numbers to sort are `[ 5, 8, 3, 4, 6 ]`. We also keep track of where the sorted portion of the array ends, denoted by the `|` symbol. +Let's say the numbers to sort are `[ 5, 8, 3, 4, 6 ]`. We also keep track of where the sorted portion of the array ends, denoted by the `|` symbol. Initially, the sorted portion is empty: @@ -65,14 +65,14 @@ func selectionSort(_ array: [Int]) -> [Int] { var a = array // 2 for x in 0 ..< a.count - 1 { // 3 - + var lowest = x for y in x + 1 ..< a.count { // 4 if a[y] < a[lowest] { lowest = y } } - + if x != lowest { // 5 swap(&a[x], &a[lowest]) } @@ -108,7 +108,7 @@ The source file [SelectionSort.swift](SelectionSort.swift) has a version of this ## Performance -Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than [insertion sort](../Insertion%20Sort/) but better than [bubble sort](../Bubble Sort/). The killer is finding the lowest element in the rest of the array. This takes up a lot of time, especially since the inner loop will be performed over and over. +Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than [insertion sort](../Insertion%20Sort/) but better than [bubble sort](../Bubble%20Sort/). The killer is finding the lowest element in the rest of the array. This takes up a lot of time, especially since the inner loop will be performed over and over. [Heap sort](../Heap%20Sort/) uses the same principle as selection sort but has a really fast method for finding the minimum value in the rest of the array. Its performance is **O(n log n)**. From 93cbde7ae9f22d800bb30050b504e13a652ce5a2 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Tue, 4 Apr 2017 02:46:04 -0400 Subject: [PATCH 0484/1275] Fixed a bug when appending or inserting a node --- .../LinkedList.playground/Contents.swift | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index ed46331d8..6e743ba89 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -73,7 +73,8 @@ public final class LinkedList { self.append(newNode) } - public func append(_ newNode: Node) { + public func append(_ node: Node) { + let newNode = LinkedListNode(value: node.value) if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -104,9 +105,9 @@ public final class LinkedList { self.insert(newNode, atIndex: index) } - public func insert(_ newNode: Node, atIndex index: Int) { + 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 @@ -264,16 +265,16 @@ f // [Universe, Swifty] //list.removeAll() //list.isEmpty -list.remove(node: list.first!) // "Hello" +list.remove(node: list.first!) // "Universe" list.count // 2 -list[0] // "Swift" -list[1] // "World" +list[0] // "Swifty" +list[1] // "Hello" -list.removeLast() // "World" +list.removeLast() // "Hello" list.count // 1 -list[0] // "Swift" +list[0] // "Swifty" -list.remove(atIndex: 0) // "Swift" +list.remove(atIndex: 0) // "Swifty" list.count // 0 let linkedList: LinkedList = [1, 2, 3, 4] // [1, 2, 3, 4] @@ -281,7 +282,7 @@ linkedList.count // 4 linkedList[0] // 1 // Infer the type from the array -let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] -listArrayLiteral2.count // 3 -listArrayLiteral2[0] // "Swift" -listArrayLiteral2.removeLast() // "Club" +let listArrayLiteral2: LinkedList? = ["Swift", "Algorithm", "Club"] +listArrayLiteral2?.count // 3 +listArrayLiteral2?[0] // "Swift" +listArrayLiteral2?.removeLast() // "Club" From 3028c6500f4b2bf8ac4fe899f238b32f946fa879 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Tue, 4 Apr 2017 03:07:05 -0400 Subject: [PATCH 0485/1275] Corrected comments in playground. Fixed a logic bug when inserting/appending a node --- Linked List/LinkedList.playground/Contents.swift | 8 ++++---- Linked List/LinkedList.swift | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 6e743ba89..abbb90467 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -282,7 +282,7 @@ linkedList.count // 4 linkedList[0] // 1 // Infer the type from the array -let listArrayLiteral2: LinkedList? = ["Swift", "Algorithm", "Club"] -listArrayLiteral2?.count // 3 -listArrayLiteral2?[0] // "Swift" -listArrayLiteral2?.removeLast() // "Club" +let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] +listArrayLiteral2.count // 3 +listArrayLiteral2[0] // "Swift" +listArrayLiteral2.removeLast() // "Club" diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 53dc77a06..55593cdc9 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -71,7 +71,8 @@ public final class LinkedList { self.append(newNode) } - public func append(_ newNode: Node) { + public func append(_ node: Node) { + let newNode = Node(value: node.value) if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -102,9 +103,9 @@ public final class LinkedList { self.insert(newNode, atIndex: index) } - public func insert(_ newNode: Node, atIndex index: Int) { + public func insert(_ node: Node, atIndex index: Int) { let (prev, next) = nodesBeforeAndAfter(index: index) - + let newNode = Node(value: node.value) newNode.previous = prev newNode.next = next prev?.next = newNode From b0204d3e0a9a84c8ddb4fdce3fa9dc8276e755ed Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Tue, 4 Apr 2017 10:08:48 +0300 Subject: [PATCH 0486/1275] Dijkstra's algorithm --- .../Dijkstra.playground/Contents.swift | 122 +++++++ .../Dijkstra.playground/contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + Dijkstra Algorithm/README.md | 23 ++ .../Screenshots/screenshot1.jpg | Bin 0 -> 214771 bytes .../Screenshots/screenshot2.jpg | Bin 0 -> 225916 bytes .../Screenshots/screenshot3.jpg | Bin 0 -> 224243 bytes .../Contents.swift | 57 ++++ .../Resources/Pause.png | Bin 0 -> 712 bytes .../Resources/Start.png | Bin 0 -> 1044 bytes .../Resources/Stop.png | Bin 0 -> 498 bytes .../Sources/CustomUI/EdgeRepresentation.swift | 109 ++++++ .../Sources/CustomUI/ErrorView.swift | 30 ++ .../Sources/CustomUI/MyShapeLayer.swift | 7 + .../Sources/CustomUI/RoundedButton.swift | 20 ++ .../Sources/CustomUI/VertexView.swift | 63 ++++ .../Sources/Graph.swift | 308 +++++++++++++++++ .../Sources/GraphColors.swift | 15 + .../Sources/GraphView.swift | 246 ++++++++++++++ .../Sources/SimpleObjects/Edge.swift | 12 + .../Sources/SimpleObjects/Vertex.swift | 62 ++++ .../Sources/Window.swift | 319 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../timeline.xctimeline | 6 + README.markdown | 1 + 26 files changed, 1422 insertions(+) create mode 100644 Dijkstra Algorithm/Dijkstra.playground/Contents.swift create mode 100644 Dijkstra Algorithm/Dijkstra.playground/contents.xcplayground create mode 100644 Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Dijkstra Algorithm/README.md create mode 100644 Dijkstra Algorithm/Screenshots/screenshot1.jpg create mode 100644 Dijkstra Algorithm/Screenshots/screenshot2.jpg create mode 100644 Dijkstra Algorithm/Screenshots/screenshot3.jpg create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Pause.png create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphColors.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Edge.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/contents.xcplayground create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/timeline.xctimeline diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift new file mode 100644 index 000000000..8d600d577 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -0,0 +1,122 @@ +//: Playground - noun: a place where people can play + +import Foundation +import UIKit + +open class ProductVertex: Vertex {} + +open class Vertex: Hashable, Equatable { + + open var identifier: String! + open var neighbors: [(Vertex, Double)] = [] + open var pathLengthFromStart: Double = Double.infinity + open var pathVerticesFromStart: [Vertex] = [] +// open var point: CGPoint! + + public init(identifier: String/*, point: CGPoint*/) { + self.identifier = identifier +// self.point = point + } + + open var hashValue: Int { + return self.identifier.hashValue + } + + public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { + if lhs.hashValue == rhs.hashValue { + return true + } + return false + } + + open func clearCache() { + self.pathLengthFromStart = Double.infinity + self.pathVerticesFromStart = [] + } +} + +public class Dijkstra { + private var totalVertices: Set + + public init(vertices: Set) { + self.totalVertices = vertices + } + + private func clearCache() { + self.totalVertices.forEach { $0.clearCache() } + } + + public func findShortestPaths(from startVertex: Vertex) { + self.clearCache() + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) + var currentVertex: Vertex! = startVertex + while currentVertex != nil { + totalVertices.remove(currentVertex) + let filteredNeighbors = currentVertex.neighbors.filter { totalVertices.contains($0.0) } + for neighbor in filteredNeighbors { + let neighborVertex = neighbor.0 + let weight = neighbor.1 + + let theoreticNewWeight = currentVertex.pathLengthFromStart + weight + if theoreticNewWeight < neighborVertex.pathLengthFromStart { + neighborVertex.pathLengthFromStart = theoreticNewWeight + neighborVertex.pathVerticesFromStart = currentVertex.pathVerticesFromStart + neighborVertex.pathVerticesFromStart.append(neighborVertex) + } + } + if totalVertices.isEmpty { + currentVertex = nil + break + } + currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } + } + } +} + +var _vertices: Set = Set() + +func createNotConnectedVertices() { + for i in 0..<15 { + let vertex = Vertex(identifier: "\(i)") + _vertices.insert(vertex) + } +} + +func setupConnections() { + for vertex in _vertices { + let randomEdgesCount = arc4random_uniform(4) + 1 + for _ in 0.. Vertex { + var newSet = _vertices + newSet.remove(vertex) + let offset = Int(arc4random_uniform(UInt32(newSet.count))) + let index = newSet.index(newSet.startIndex, offsetBy: offset) + return newSet[index] +} + +createNotConnectedVertices() +setupConnections() +let dijkstra = Dijkstra(vertices: _vertices) +let offset = Int(arc4random_uniform(UInt32(_vertices.count))) +let index = _vertices.index(_vertices.startIndex, offsetBy: offset) +let startVertex = _vertices[index] +dijkstra.findShortestPaths(from: startVertex) +let destinationVertex = randomVertex(except: startVertex) +destinationVertex.pathLengthFromStart +destinationVertex.pathVerticesFromStart + + diff --git a/Dijkstra Algorithm/Dijkstra.playground/contents.xcplayground b/Dijkstra Algorithm/Dijkstra.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/contents.xcworkspacedata b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md new file mode 100644 index 000000000..872e9f851 --- /dev/null +++ b/Dijkstra Algorithm/README.md @@ -0,0 +1,23 @@ +# Dijkstra-algorithm +WWDC 2017 Scholarship Project +Created by [Taras Nikulin](https://github.com/crabman448) + +## About +Dijkstra's algorithm is used for finding shortest paths from start vertex in graph(with weighted vertices) to all other vertices. +More algorithm's description can be found in playground or on wikipedia: +[Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) + +To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. + +If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. + +## Demo video +Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) + +## Screenshots + + + + + + diff --git a/Dijkstra Algorithm/Screenshots/screenshot1.jpg b/Dijkstra Algorithm/Screenshots/screenshot1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..390bc658224310c7720678cffd68bf1654b5c045 GIT binary patch literal 214771 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

@lrF z%#k0h?z`?++%I+3yCSG;7<_kyQ`)>Lmd(IA9czn1PT!k6wFA|p?d$;%9#LEoJ z5l2H{1}8P8#QjV0$U&py4XW$oPV_0d$Y5UMMC)Ve5`nt84xSKk2M#ra_`>5B=_6`0J?suOI&;lKL-7{tzn}h=|+xQS5?KI9Y>O z13^s|G$FhY3r9J|=U#Wi@yJDI%L>pP{vYym?qW)icZ$RL zF4+{{xtW-Al6y&3@{k=PG%l19G~76*5MgvZ)G?S$+751|2ik4ZW~kh+ip*0{fN3d! zZSji_Fay z;zevifo_+hPBsVtzdZ6mwIH_zVON0Iz2X)l)NVV0ai9m#1&StsQP)oWccz|}`p-mY z$TH1nqEn}dJEEPhu)skqzkqF*vihqG4pFY%&s(nZ_czi`P@og2r!b}xz@FfF-BEY- zv-(4Ii8NWEbC1RbZ8E}KVq4ga-X6YX$bGlEN@(kxyGlA)o6pg=4BS3GT^uX;Lmr;V z15+wV#rKsSB33I7LwAFSQNSGCw1h74PXBg1DDjFlkvH&-QOQe-R8ceT#bt)IBitw^ z-gDj&;7;*5(&b+%xLNk(O z(8^(Ojn^~Mx#~NUPtgu=b|a!+NKIN2$f+}@r@Y}8k$L4m2rMh|4gZg~_YP|^UDv*` zAc_SQ=_M*nx{63Aq5}vBh)9P-MWloDo~VdOjevlF5Ebbq^bV2U1f=)gdqN2zg!tXe z-m~`X{m#suwZ8XVe{e(y$ANir=YFpHy3X@=!q~d6b{b@6Lqp+XAdKS(j-ltp1!}Dq z(ub6Lato0mdXcVy`}$t2o5Xp0%}rS|S(>SM+t*c>dx}I&;)1{WP}QKm^&6#l%iu=e zu{GA&S;=KaXZ>P zh$h^fJ!l~<6c71@#@N|m=JYSaRvd_jdO*)pCyjio$Hm~lRK{cTeYNp}o)h|cCDo37 zSB210GJSOP*=!OI-aC}tCUvM+92r233fUe%V+>N5T|2J8P>nID`-o+fH|0hvhLIRo zpI?NY400{@Pn3kp)43vow%GS#e{{*Sx4K9WP=VR39`Fd(TyEfJ*he1P?O~06QE0+C zv4l8R`ndONagPoCoLcG zJpe=fAEZ*ZG*_B<}9@hXuATXh&c6 z?pi4{=P|aGEQhV<$yxoRde~i%TCu7$c@Z`odg8#Qf|2N<@cjZ`se%+(ry2RV9X;&x z&bx6d)kdCG(?xVxR?Qn2lOu2Iqce)3@5t6&H`?e`I=i36*}TKQ`euge4OJm8#}dg( zeJPMC_)IVcma+rdH2j<#_{PAd2%}O^&a^j7qb&L%M8av;SmhV8&?MXNyH$f%Dg31@ z1QT+&K)(4j+G{l?`xsU%H*%hn zE`SdWJsL(*HJ_{w0|vimz$gSJFlMjgrS|R5RL+)B%qTvgr_@=LU_%M}dd{B04ByJyEMDIHiDm*X^2)8DnoaIFypRD)7!%qarQ;RR#CONoYJf$wjFd3(g)n799B@CvMbKdDrExggi=Say_7L1QqFl?~24y%YK9IEfYK zh;}>oHfbM7@p0VGAKyrOAn&%<_=mj$8XEj%^#sO9V1y3CETb0<6HcO9a77=ha@T;< zIRM&MIv)7I7DqlVUD-lWVD5iBSwhCpEv7BnG9r=`Fvp@w-;Y})5l1H8l*D+lJ^WL{ z^*^=H|HlFAAFi0*rT;1{s5XZ{{|5T=--wdIS3>5AXz%gSO{C)C1A$5{8d?{xg)N__ z1XH_9b>Ocq1KVc<`Qg6iKQX8}*oI5SS&5#*M%}C)22n=Lv*B_jGpp_033V?`BCp@= z(;ws8%RUahV@%AHwd#(P%1AcXjs0kBfbV6nA`BVHG-vU$!I;b*ubtMx)R{5H$KX#J z3|zsS+W+iK7XsrZx{1W$*o=#Q$lkNNWG_EM#Y%;A53J{=Z47nYYHDg%&Txl~!wYcj z5!O=~sp~GOwineFCr!fCoO54_eVKS{uyO0#bk3sgA`i6;Mk7gbueh`vXaIhpX4oCZ z(@l%6GT^xgL46b|M2B0M-kV8WOFNb&U~bPS>#x+dGnDYR9o2GVx|_7aKX37OINy z-`u&Gq4!Hc3AWdEW%cPbH9=dwqaj~+n&tyrvH?@IFwU45#@C=bbkk{@%Yx!!;6i5& z@;D1*#pSKSP%(o8-op91n=W3BB~Hx`ca?mao1sZ=o^Jj(kS=i7Nk`21A zXaUogQ>wulS}=hbciYKdwtUQAJ9$9GT!{aJR{DR-H~i6G{L-gNZ<%E;;c4*(m8C|o4*y>a$A zELU_Ebv5`#*5=)Dl>Mh~7|1eng&s~X-`}l#%j68yQWx{BRL`w+o>88r-}}yUaZyGS z=_5_3i&b*hcJ6x}BGPWFi{0%maF=gO{+5&C?P9v5GD8thQuJhIPY=kx$r$``K=hPv<-ZLiGE(G;F(`Yv$};3mMHN*p1&I z^?%Z1nW8(gKw4XTwI8(roErL#+LW#>XvbK|g>t1`7kL-$7K|ey2C2?;fJ?TBJt(zq1M?E(+_ZevYc`^K0BeZh54-x zN>0Mr?e^EF7$#?M=dt+fAmOK;hFno zNl9SCRoW`e18J60V<(ydh8`mzBxD=Ig>HoL^v_tsPw9W?PbS+x-sYQuH$n|#J0{yx z(!Ps&YazbRrwamI#oUAs)#VEFcvVdK>*U$FE!23=G-)~Ey(v;I>~lIZ*`Qv`B~Muj)!H7?azP z6Uuxf-BHn%^zH5Xo^FtQu($JslsQi}@Q!Lc^3_}Fhx2Hj34hfGw+KMbJp+~PcLOB7 zSCa29U-?G$=+FwaeBgFYiNHfW;VWNVx)P5IDjZ;*m;M%&QZ}MtjHM(WtmoGlh3`(k zxP4FS=OTUs4p4tYRpFq!c3mHZJLh~bPmeym@&d9#4h6`zW#NaIWqo0MQ|hdn)n)1K z(F)9k&vt+K^a%IfrA)hmv5xnc$om`@7;kt5q^=z4fxz}w4COkTt(xL0`v|Frq6y}2CVRG(I39w`H)~kcn@Ih3f#+`bwzznB4&HSGh5vJ?_P2KenmBK*qD|-H z*;I2UdeDi7p$URnxVDZVvRsOWhRVxBq|_m#*24;GTVQBeIycQ@x(Qt$JiRX{Hd)z$ zo^(%aM|5z9QObb?*a~O5_Dmgl19{;mRnvsw6L_pl%O6TbHjp5+NHZsBuPYxpE(mLp}v8*=hD-;bj1SXGqkMzsr%G_ zUwQFQoGT9hx%2hkh&91uPXGnV+3hIG`Vdm(;enZj$Tg2|FXr2K+keI|F$dJWwU~8; z|1r_&l%;>NS#VIExW<_beqXGQd2OX_s+peQ;-bzEP8Q5q)0P1dlSpJxfdb{tUK&6 ztHB-cOqor^eMqilW=-ae2MeZ5o)au_-$~5gF>s1pc#nC7eTv$ZMh`(K*j4Nnzo6ul ziJ{K>@Ex1JAoT~7Y}M3Rmht3qk4>f;^x#hY(E6%5{?50XXhvDJr11sas15bZ;gP)Y zaepJn^OLo&s@+~lL7nwhpS?`(NVG6?MLBtiB#MU=T$SsYckV8@d!hBxyvU55>5}zk z?Supwz0(NYqZtJMk#g02p3MA_U*;wGkwWmXFy^I@0<_sKwa-c1^e?tz%GQhhHvM%s z>5eMNug^D=Gup`Xll(5Ng_Y$GimtNfLN_}7aVUF362Fel?bL7VR5G+XL^b|!q+x0$ z^!wKJk6hTo=qAG}U#hltKrir5xC8&n&jn8!;(5b9DVN{>c;a|V1NKJ97NloF*Twqw zN8`DbfR7+At8Hk;}}5WU|tr$iZv?Yj9tF5QfZsg;xj z+zA;UCUlmIG)--m=siKFGyory+Vx-S*%L*kk^S5?#j*l+o;!5!CXDm+Ot`1@bOm;o z@1Id~3$E}UfGikVLtJh{ColJ0 zUWe=`_`QCf*;6#?K}ET+L8~5%2CD?dwBODyD|1S06tHb74VnPk2IiJQR__uPV~l2l zwRXFWprG2#WSVLHqA{xe!cxWYK>I=D!0F1y90~(j4CepUUGH}1)jr+UIn*vFF~lh5 zDU*Rygn<=h-1N%y=n`dp^V&Q{d(t?g16i^O7X;YXpHzMHDT7$k577_}6D+4-a+f@- zMUl+Y9u`azN8Bt5y5<`}jM%~`eJM-~(|RzUIWjwDNMU0-b(DS%T|sX8^y;KV6q`lg zmHsb)@cM%`3P?p&gwG8DKg?g_B|$;*-^8N={1b2Hn2JjjxE~zOOnIlUBw%=;nY!U_ z@?8Q135$2S*s$7)EKH!Z_PZ%v1UZnvLWpA;+8OqXXsR7&(^Ryti|YL z&-jHz&I!Ur0#~8?T(l1ow_{|>rOm4@JuxH6{s_l`jG&_wAuQpd8Rle`e>jWlDIKC~ z&}x8GS$n9>6~+@{7T}xs;-T+5g#|_Vsu;2Ef4MIYPRs)1MnUC*L3g?=MxpDU6g})~ zf_w?KO3fwL%H*MAM!{Rr~LTm^gg{_?4c zaUl1_25I(E{z*;8p@T|Pe`w4v#hUP@iy}My-l6u=HVt{M$Rcy8D|l*B+`0Mv!^jvM zdX-`C>VUTiPI&x9g^u__rwH#G*OG3-8}awfaNqZCnx%SrikuSqS}%sIMWmhpP73Hr zVZ>Qt_y%QIxqvY+Z%F05F*?_FW1~y)vQvTGuKWi~ci;?JCE5M4P;$?9+}*(^EF;JI zO$QEN3->(L-(*^1S?x5rfZ}U_>f=v_-@1rHAcv25yNK}jb?i;j0>mOZGuUJaU=tb>ofQ_>>>?s_bW7npQ6WbJK& z&W7kU{}S-@=&o9P`zUb>lts13)7f?`BHJsqbXv!uGCmGJ5QU8BsncH7EyCNvER5Hx zpC=eW_AEZ7WiP7}Lnd2SxYzm|IlEBN&~*{z`9Q+;@4V-=HJP->bh}iCJ=a_xTWUF0 z8dwi5xDp6B!`o4Poo~McKh{yAVh~rbcd~V3j_rFGE7lq2OZWZZHi=!>tTlH_pzjCR zx<3D}643umBKqs|51Ax%`<@rpkNhf)d_gm1c{9A6-gP7)e_L2jqf5B0JyH5we16X! zl@#A1%r?_o*<+T{fh#OGzBhmP_E*ql%!$|Rq39T?5pu+9`q+nyBCmRupndqx3Ub0%acjYdvahp7nK`)9y!Fp2Kw}` zH_8Uw+FnJWTL`=I{zq!s6AEDQG5v>+H_fmb;wJfmy{U$ceL$wx=sP;hLug80xtHi$ z1Y2pogxGi6ubP$guZ*B86YM{!K28?{0xU_nDTXWs{Xo+DGBh|eP$RrD3A!Z=7q09J z)H5tjUSGPvkftcwu`UhLjx;C0`CQL3=l@U7S(ol@!AZ??maAqC8zpm6*IFbn-95V7 z4DnXi(r8X(B;T9(S_*3nCaS^9aebf081Qt>%r?Kw;9hUd?}ZEyD6lqTw_sU8y0r76Sut0!|_@$qjTi?2ULtCR&s_s%^2~##hgbC5~fWzRD8fQS{4P zXTo9k3wH^USK7Lw^AbiO3!ae|wBSmfm;Tkx15Dfle4fSw@3(f^1ybandO^1Y2!?pf zTX2kFrG#aK-ke60rY5nVtKc3qn#hW6y@G9|oT&b=NG;MP24=sQ%YR_EJkqd^?UEN5 z2B0We0wT=*AaWdJgxw`($f7qpkc*5h1VfyouunyKJN$F?%RT$O{|C{NUx20YH{)tX zuQE86qE7sz8ohC7z5pD)kv}{Coi}>FaXAWxZx5Xz?saK87LR>hE1VA6Sjo^mId>`4 z-Wm%sXhZTEq#bK&ZvR01=YqrdOew)TzhZ29O>*OYTr@mJ$GG` z#b_yq$c2{&mkm_xZJGN8`{6|0pHwsU`h!N6ePQ}TyiJcy(xGWPa_WGuMq;k#4j?jaag;YbXIU!XqBX1tHGd;bDvHViu|L*n~ zqGbt`&t*p}Wa50^$B#&^_8a2?Wej8Ice(SNMnV>MF`${RYZ&q-5fb;k8)f!xnRwtihng#BnHgwWi#cnW){QVmhQcW(CqA;u39DDY(i z?8?z2>;rG@-basgn0%=)S{*+xD^cI0M4?_&j=i>Aif|zIHN@l9?tOT>t!60<|7^C~ z4=@cgR*QJ*lN-Gikex^@hd+Bw{3_UW6A~587D;0f>DkVECG*hH)0=eZ3CgpEkt^M4 zEZG+2iAC4dO~9?_k0ZVg7WH3!CFcw9yIs;zQjw(+4C*JlC0fLN3aRRMmfV<@JwoYr zhNKa)8Ej?ErW?+i6b}^4NgbiSk1|`DAHlB)Hq@Kn53Y=40LbrcpECj_11YW4-^rn9 z7!j4CA7Pz{8P4`R23e{mg&N_e$4ZCoX^DyT-NHKocC16=>7SWxka_V;OCF^D&ld7@ zodr~!W1=^wE4qMx!i)@+Ub0S*GO@Wc*U+jtYvjH6E+;=N%Y4I#c?jyil|>5?)Oc}; z>(qR-eFjn^G9Re#x{{a`m1vvRf-mTVgOg3c|L*9^Y*RDn+ImYKRh_-aaf@#bs>qK1 zrWXf-e>go5&6BOXB?nMN4aD0DbR8UtN`M3X+g?9V zcg5B5xdGz7!gg3G6bETZg3$8r(Tl+`L!_4lyU5#~6iKq+5Ea!Ut=p4J+B><|oucCk zE6)!=^Am-wBzWC*BQe(UN8ek<_P)4Thg( z-qvoS=yAZ45i+{l7Yj`jwFh$|RU3E(~akL7Q}xHWrxLSg4G|SLiBerg%a$8gopUGeXkgwTWj9e+rT_5C@-vfX=gKQ z@C6Z^a=Fs@jJfhztn2nt!t#vEkGh(an${bCm;4Bp|6hBUJOJ;Cdng=fYk4bczv{%v z>UW~|Oo{&Xu!P9P3wpc~G^Z3LG?F`To7XW);#{p$QO>d!|RFwSDrrk{FLm8M9Q)!%5)e| z*@YY0#oX_y?eul*Mk8VKH(3iJ2s#q*Kxr$`WbZEdpRI$x^SxjzMZm}-RxaxY%hk4G zoC~yvcAIv(!poL`rX726z4PchQHpYg9 zk1-d6(b=8ozC!CjqK^{+MLYD$@v$finK_Jf&LqqEk-(nnS+p~j%aDHVwb?p|a=j?m4{ew<$%zT`U0 zu4;h##DE9b8w9rnd?-ycz$H#yti!gb(|APr#KnZe{*S}GrYdCDCH3`r7(C>nm!3~M zBs5!O53U$S*BeKp?&VW^97>Wy9-@dhxNFwuxtnBD71JlRw~b7M#56#qr@6wV5)Ga_ zTA04{e&(##EB@`>HsehO>D&x{YqnvhgX(i!1#o{5X&bi~@bc$&3OrVI_&pCITa zyeJI4{k7%|z?@T-8Z7sYy{C3h$?V7wV84nXqG92~3g=de=B1Lv*-91Ei?~E=qZK;v0 z=)PMdeP1;MGNooOvOeQ5wOlfEmWbYVa{I=~5ff9PoiV#+r(#j;QtRThHd+6X4+4lA;Q)B?u?j5| zW#dV=9k9!Z#4iC?LulJWm?w0Dci^o}4=6>{Kq<0EHwE#R>J|x^IY|~6Zh(#;&^Xq7 zYy5RWi-PSGhj^kx&!;QnJGCH}UUD86RCM_aU7O|3=S*+iNcw=43wol-#E#n7WX6;A zp?ApVDXaO59W*%JvgZmc?7p!2Q;O0-u^%IV%|Sp(74OCfwA(@8Ui{boDnUV=zOAST2TBIp+VOQE^A zxACRKUV>3VP&N^xj3b@%5LwKvQ`wXPIld!P747Oq4V+S8Sz9IlEtHq6=q$}t>!s$( z6uX7CE#Y&x2V9$u9`=oZ&=bS%Q1iPGH-_qMV_iYR^>9c_F(PxGpkqb0k90L657t^h z=(c@OGK%g6Nmr z)XgHF-Uvqaivuj<;cCqJWS?WZS36xGQR5Q1^+Mi8v&p6C=-v2s%yb8xrA#8dPxfQ- zS@H-l7eEqxGW_l7iT(BWp8OD2&nlhv{7GfNc7(D^)o=FITORPCi&PRN^693cBRle( z$(tr+|G=p+K(rh5C~_Ki386o!Bmj4bwO3xsz!g5{p%jN}QsEl{AJYEw#X_l?e51n= zyL4HeO7UMUWADLq<89uF`Xokd%V|zoD+O*{^)R7j?GCNnL3(s5pVUCtyaH|ETMNIf zpX)BRbZY$-CBvL) zUaZczOqbfT0Q!g~dXD=f3|}zjOP@VUWylloc;}){?2}cyD)|Au~YehUF}R6u@+eJ-*x(kkq>L zW^U+Y6L(=Lm`uFNO!<7QVx?77|E-{miWT~q)05{*Usn3Qe@?V!^jv-I=@(%Jf1|w< zR-U%QkO5=5Yy~;Jy?#@!+tSTEC7r}M++UnZc35?Fi|Qxjju}dZvnb6z9?>;`Jz7f9 zNH4s*hSiyA1}4;X7E7MeXW+fmU;gdA{M(Nmy{lD&NiaiGUW=y++h!Ma{TRevy*Gwy zshH?*VEiOxwpxep{iI6&0Np2mcXQCX*Set!0#aSD^@dduKTZ=N+b#D%RPUg5{bY0T z>tNW@@|roLF#x4SEPevp{TfI0Z=I04cc~(NJm{5E(iGGzjou5BL8z+Vn|(SEmsbi} zle7xqKDx7IXu+RUoFc$a=^;_`7XKJ2x|5^`1de*Zefq2d#uk$Ekb;bp%DE4x4JN{Nyz_7{leGztJ5-{E$CcPMpQ}wN+?k6I(oHUmL4ZOp-o0=6t2iJna36 zJyiLY13VX9VE#sgY>I<6BtW`5lgi7wFpL*qS(p530LBI@iG6J1+M%}}=Pma5B&uNH ziHZE2d7I{JEQMdnU@*q7|nn~hjb|YcEOJo}? zzr;E{*4u0;T}efif-IwvuWqrW7@PA}IVMTAvS^|)!uy7LdmYja8U^-!{gUY8lv)Vw zHtIEwFIYIKN7goTD5yN%VgB7{)=F!|-H>uWU9Q=N;YgUimcs`c{Qc$DivE%&x~pF2~1EMq=ySP37J)WsoUa+3`$!}TcS3H67B zZ&Xe&wVzZ+^SZLvy~XhKQ~UvmIe3Y;_U47pCZz2iwxI4c!m5;Yv#i>B+^kf`j7EJ% zWkV}Y%}VWokUMlHD2Whne2)LUW~fI8s^b2TNov;(0xx0ZQRLEF_v!uQ1t?T?wqg3x z?T8Gy=xtMh-bl&PyK`inbQAY-!=M_H*t0Q-{b^L$cj;UpK!j=&^)fA`O|nB$>QfA| zx!$_0HI_r1jK^Pji&R0n$-|Kl+fu3~WQoj0lG_f6b~U5D<+)RNT|aS_C=x_&_vT@- z)=jDVNkx4CLnpNV`0^L6ko10C*XZ0`iFaQYkbXT^$sq<`-hYYBr`H?VTveMa_QyC9 zKCgWIN!1|+W(Zm6AAxgpuVrl~H{iFhn^Umc$A)(kXQ76KK*7eWcavXtzm&q=7k^S6 z!AbGGNFMFV-}r$~t-54Q`sLMlou}p2$e{ofR!W=rq+D2{ag4PmCwY1$4>I||2Fy82 z;eBPhj|1JmYkz49>D50>H(?#pQw4FizTe7ytm_W>etaTjR|?*w3)N}VqHrjR4;ex$ z5y^;_3V9ZI&&qVT)O{6t8l{DYGmtv%<%Xv?x&UWAF{0B0A?ekTC#I{R4=Iw#m=Iah zPv;iZB*(_am;-NorTw{u_}<4{KmOE4_CMCTha%KVs$Xy z5)3eV>fp8(B=hWyR5H_r?Kc224|4lnF;!pSE2ieZL7d7oPim;^!`wPh8H%b z`_5@vBrVwY%iCZ4)uQ{7J~}oyaNADw*7!G>WHn# z<3UhfNv=l-E$#Nx1F(;7T@AXS<9@cL9tbtt@@W?TmH>_=LQ}iL^7Eg_>YzJ6Ad8%$ z*nb5iPBP!MG{_oV3>GlFT|AX*Lr!W8^GtwIx&b@=s)%sb`Xy_x)IR-> zk3hC3krjt$5%Q?aW;Kr37$hYICZB*O#LXi6??@=)k40wJ&MkKPU-WKrcOhZ67uSu% zXUZCDV}$1@ow&?Z`|Ip)gU7f=#kvlJ3QaZ&QjWj>Z!gFX| zUfu&B#)viX4)=)KzACQnp)O>&PII8f!uW(2PaY#0 zO6ijD(Rs>XbH{@9U`BPb&rsx|Yb0gUm-=h^osLcLN&Fr7OpvM0(E|qQL6;OoLmv1u z6dE^%aBozIrWR*mmZn|Dp2~L zRAm-NIxK+f=;yzODRM5-L^Y>L_8dHNoDusdOH>n|fSK0x8@mpo>i0y?-+kI6Tp$y6 zx*&AiBiKx%0XoL+rMDC*-pPH3J&;BJ(W~pnv)K_RhwntnfZ-7C)U^v9(@$4A+OU4; zquz8l-|F*3wwi0IQ9B4zlTp>Z?6u_gkLRMaUKx{uO^XC&CMCW>k9l+9l#*~isqV!t z>vt7eW`hl0RYA(Z>D}Us^zy3?!A|46RV#S-E3!PuOHVs`?8N7gk2W^^k0hI7mC&Hp@@4{Eep1qE5b5&llGB% zo(XGArzS8GzY?V9|H2FK+h<1cMyFBDW_vYPFyk{hD)w+o30r*@&P)Bm70_fAB=q~Z z>y5QFPdYpSBZIr?=aez7GPQ5L6S{KmQhBjDaSH}Y^gf2DFUwOB0gi6G(dNX*Vn3-q z%R>)sVV(zGnFzS(cUzg6HeC|X(it{CxNHwm#^AO7wR3yqGGuLnEp)sio-AlDF%k|= zIA7&1{>eV{hh5ySW~XR#n&b|4aw&DSYI(Mvjjkb~>yT;x9rF!#NS)p}2VB2)_l$%* zM^B*S0`rGq3P}U|4g-*BnHnl@($^-|K@bKfLW~ z9E`+5AUnOz()M+$XO>SO!VRR>l(xwI=&s7krK@T+Rgm7i{wS3Sph-QA+RYXt_KOk_ zBGEWO6W1tg=p0-xi*B-=qDgL36IRpgG2Ijr;VOX>m~YB|a?U86al@V@$H;enwxT-~ z)Dj@=yR!TWDv(4N58z~*n&Uzq-r;Iz-X1A&Aa?F!45L283VSr_fQ$jS(MMwqy@NcA3Z6 zc`YX$hUiw@$dKfay2;(ujF4jtY;DYZFp8*8 zp?~G5b9~1x+s7ZGx_*Q1@WK%1U_7GVS!$D;{RpLH3zD{z4Z%!ZGkna|3YkNGxk{>6 zEqkDAGQJSXC=6-flnk?T@lcNpkkYvb$fwt~p}OSd?i~hFB)?Q z%-NxVE7dbwX=+1iV}OUg>v}WMHy8pumyf|lpXuWFr=uAVNpq7Bc4Oy3<~5A2;|039 zE?XYg(-B%Q`wa5E&dhwq*bpDl)LpKQo?!Ghgm@c>kgdiev(e9fQt7`(^$zdq1sTbI zNorPIpa`Aa7XpNEXuQWI^PFA z7#((GtI{qwJ$yq!qZ!H-T_-lY<(S%-$4tgD$3oA16jy^yf@_uh_YvdItYU8-2!(xA zsbjq8Yx%byNHL@+DyllfI)s;900$RY!=37}%eacwRHE+eT(Bb;NpsRXsboh~jV?PW z5K(5XH613JIU`42k$0c&%}0{mcQESNcj{s6KelD~*D=!@vwkN%nrq34Sj;q0@1?d- z+MCLI?3rcts~amG8#OKHN=0(QIF6PgfR9gpc{r(PI4CXJ@ru;_l*IEgo}T@FRtWCC zLd%n5qcZ#yD%Ve>D^pc`_~=!q#Kp1eJ>Jx~{%X>Aor#g6jLVU)w>Zao8y|Y;zr+q4 zmN6G!giu#O-S14BR3+Lc8JR4Utp!fW-BIazvLPz0zcm&kr9I$_YN(QtXfzeXSaMIF z8J`CSTRc8;`Jr)}0Vkfl`}XjZtI{^jvGNW&vO;e`>3P8&iKx-zrqM?RQ5)j(nJs}P zO*&fPnzyLE^)e|#o-DnE7V;1xeH}uobL#}F;J%(pp@A)M01`t68#XFQXLjp7Vr=l& zqHl6k%CDpEM4uK&8;jZFd5pA9GgS6^Hgz|NkdDT-+FHb(Q@>mG7xZNfD;c%oLt|*K{5}r)Va2)x13wYy=V_HC;oM$!kW;Vx z2uSKb9f%D7n?Cxlz6UNN!f>XL=ru~ZE@7JjOFLtSBJuY*@w*w zr9kSB>2Ps!u3s~=)Zcl=O)1>Xn1&xm3?)$E5;CTt=g1CSSzDu=V`?!Yiw@7jvhPAl zW)fcLRU#V31c+JFn3qFt!Brq*F<-Y&gg0U6&V}d2164Xf{H&=gW{#50N7<(tcHda8 zrq}n!>+pCPz;Wtavv>_Bjju__3evh}pSYZG?SOHGq*P5r!M^ex*f3D!awO+1r&v8w zbVW=9n*t8nv4v@dhWw;rt`c%joEAo{4DUfrj1~>MhEMLB8pJc2`R6c<<^cR7d|AKMl&;4TmKCX-umigxRDJwoo%(>k@NUZ|u6#sVA z9dd?ILtAl8*~_0)kLcR`0H&T9mr2t*10~`y$5P0_i4>aMkLLkC1cpu<1!s-FiS2{Q zO#9f)8}@MF-UMt$J?G{6{J4FDBnqTi%X&J~s0*hL*RBw<0MY!oCV}ZQFc^?nQzk@D z#`FGIDqg0#=RbJOKgcLQ?9(eks47zTcqXXj7L`~_?pL;D>d5T^p zH>M14C|`%VIrV_Dtk4!%`3usN&fR~Nr|f+3OE@?g>H7WQ`TkGqgx{ncIvjVjbGowH z+CNKIGp{vbayV273}Uf?a}jy;mV$ZPPnJ0^bva+DXj6I~tfWIDGOkFe6l^PmK&*y( z{}EDG>h1ZmQ@M0sU@QbT(JD&t59G6s`M7rN4Ikfr@e;y!Q+%RBGXB}*E0n|zx(54w zBI>%fcYzL>#NL;ZYLy^gz9%1+eEFA@7=wo(GxDx7M4_Xvh^EGM?;_v*`hM-#-;oMU zP}Cx<(%#nIk`^#ka_T-(-=~7SNL%8^&GHw^YR^aPibndemx+#LWXL`=B;Um~9UcwY zFLS2atvyn7h8@B1*%YsMjvV4x{h!m|g@bAEvd-;2weCXhjrG;U5{}|jZXY@=qAq$+ zd=Xi$Yu#dqAs!)pog_<<6Os{eQz10EHG{B*cI3-YpsB1fI!a-{!YtFguXftyk-YN^ z0Pv%aZw54r8Z&72PEIlTOLeV*k#MI@@hM~}pC<7%WJt0M-k9hzCQV`U?-QsczQd;M za&{}aZx`2x=~w@le;#~7^SKXnF( zge+L?9E|X}0{pYyygr~}yJa2C5R$0iq!SL@>@~p6E_W=a(Ej{F>=meena(?8tN5>V zmNGPf+QWaC3>slV?*c=)Bnb()9AiHLJ!hSl zH6AEBNMrJ1-C+g#5_t-6yoH4_S1vIU?teXpnpC8Psurq04b7OV?{V4~f;v*abnGj@ z%;rf|a@BaA2`bE7^#w)hSF{Y}=oa~!3C{(+LZ#RIjlc5GZ1@}g6Hfmx4F?6^<7+he zUKjpSWE)<7@OO>+)Zc+J$s@Eg9E&;e$Exk(n$4_O+Z!w!F6mY=;(gu}dpS6YpEy4<+9((m`q1s70%VV{#!k^;8Uo>jh9W)GJ>i(#S8JM!q=Ey-25q&MS!8kqyfHCYGl z>rzQ;ep6U#E(4y@{8)JL9Zv6x z3`Ypq0RDM)!qW3A9QJ6=(@wl7oK{{r{5%+rW*lnwpjx2T1rYThXO%-XP3j% zHC~*j%|~y)EP|}H#mv&EKMp4z2M7+mDz`sBr2V$}{_!KH+_dN!6N~=D`UJ@LXE(>M zV{i#8G&`Djy2aS_3b82}__@WYB_ZzSmqI?h*lz@AUm35C%asY>r=)qOfH~WLqkR3a zH9yAUQ(jw3PJeqFSmR2-)(^1AXXf~jm@^ZA$j z8zF`rMmYeVX4{F?8r65vUK7-)3XH$oE}#Yc^`_jtKft}w^zV*duaOmO32kR61E->2 z-SfE}4mF%YFdFa1^3>Afx={e8faJ72x}_;AtS9`>2Bk6V@X*m5=0!bGXNM*dI_g=;La zviQv^Uuns?v}f0plG>?eCPK#wCmlFhU7m*rGmHgKeovF?vf`WNTZN~Olg)`}P{0jJ z)Y4zCPE(Cdc{>Zlm}%Xs!;XoZF^*p+c4(o2*jqO$uh%Me3*Yb&VJOPa4Y>G*d-8!~ zkH8fI)gky9O5NCresML(c|<2g{&h+~6}NH0k4)dWqHa^0J7?RE(^!!Fw8ttVjQ2lH zb|Nj*nI`ygz2psRMx_-i3+w`Z+M}Ae`H1=V!D%iWd6PxGC}*qiKA;xC7dPZx3yk(h z5FJ|`@z7@ugz;gzX+j#}vwdQC3q#XxMf_W7(%HAxKppt%_3*Izo)9tC;M=&pJevEL z;IND3LCmBrvULlB&v*%&SG;=13%|B}uMA7{nI68IxgC&ozok#lVfA5HqH%mlh{JN! zk&j2dg9}n@yJrJ;_nM&jCTKmXeXj~zRMsypQ4}?H(o5g?s`0(ly7lVC=0i#<(_JaI zo$4Ocf$(jm^)GpPurdxU-^jZUjVy_fd}v z^E{IK3jG)Yqa%O+Nwo%{j66qv*V`{A#e*&8PtwbNf1Ma&GOdcrM9?CMuFu0lXQ?A@DFUymev6hT~xfW?5ftQirKGv z=v}U8hPN}is5*iWQB$=H56c$~Ec{${0Xdqsms$Ji$X*%=-B6jFF=S{oFsx{9^-A(H zK(gg9Ji!Qk6OxnHUFXa28PvCd=7*GRAB+#^KmFB_^^c!>_wG|Z`=Msu7mS}1rcUa| zdc`na`4ze2qmq3DP7Fy}Ov)&d`ogtZSs?b`RPy~>t0vU;9@+k8KA zX*^W^P3j`$XrIgQ%QW|*#fG(CW0)yRbdO1TUoEQGyKXQSS>mW2uXag@jBD>7qqYO` zCjnh=;-C}K#gc*YRERx!H$!IES!`=nRI|&rz9{~1H3W#Y)-)d=3O|E$$8B1EC4r{( z;0L;(q}Mt1+a_21e-&4g#^xP4(!aSR&czn!8j@nQ@U~YXW zy(Y;j9+_S(CQxt*8eoif0vj8vyZ8DJQ8Kad(h=K^UI;&_dkO@Ha$HuRdArr+WjFN1 zbiMr{g&AX(IvdFUqyGAdb7dJ+3gpus$N|TcY{m>!6j1l@^%x`lc(E58NcN}-@zhE6 z#=)o1+N%Hpk8;Fjxn65#Z{iN9O>{PsqQNsXEWzo>;;Cj)BSTHdK>7mYxGZMT*k&T0`C1aXrQ)4_-E%n)0VMka(wH;~Z<&^j_uT(3m*wuQRki^}#)Au(V+F(rjAb61 zkA@`1mHm9?5#+c^Bs5aHM;3`$7CUKVpsoJqPHa zP*$t3@If+pU#|X&YGtqFt`%iJ2sZXB zN{>6Jx=IMo9po@&)P2;A@oHQxtcK1m%W3VYK)Ys8;NpQ(iaDG#RBQYQvS}U?lMnM^(Z)eO6q9L{BF0u*6 zXUj`h(p9p%m54_2g-+CK`J16V1{_U;SIOGn%h1?dx@nqoYOxO`$8W+>kltV&D{|0XRsfU9-^NFO?@`Aq!^msdQds1j%BfEo{0j;h z7aqLV)_r0{;$#BnIl4C_g1qHcM*c2lV+@;0!mmaZ>+TfcM~6zn`EQv${_+12_ugSm zt!w%}Zd6oMq>2he1w=ZCNGFN{3IZb1A(18^0@7PZ6a=J;2q-Pmq!Z~#NUfEd*+;(efI1#zq!u$4=zFyt_xPyde`$l&wYPxe_hG&OQ1@N)~Yc{+feAK z65D2-@@C8S8PhP^IAIfQA!r3JnoYy(@c|>o?D{=N(d=f?@jLSr{9s4&6L`G`|F;)Nxz21Qev*Bfl6=f;!)JweWL==k*r?r zoAH=7Ag);m8KH|M4iH=bv-N5Y5K`cWo?2{ZqaQ_D{U@sE9gnTRRp-lAW_}Fk{k2j9 zpAi|D5z>_*`qe*F6X>1I+FP+JyOH=s7~IXm%}O-Ji}og8S~eXd+!qCtnsgi`O)8fy zQURuy>&;J^00b8b*KG!|S63O(o6jDbIfJ-ZF_|)>2jl43L=77o%6}y@=}&#$u)!LU$E7!8#dl}QsyVKa zEHoh-Um>mW1fY!J=0`n8S|3D>z%v(IOa1~_(m7d_D1_wby8H5`X{aBNd4(UAJplJJxv{KGTbgV5M$BVARoYcNiOCNs*(At>PP*BV3TP1Z>}y^{o}L>%Re2>o6&H+i6Sp0wH!<3na{{>Uc_UYfK*y;{ zblsYZEg^cVYj}AIG)ORrzZg)GQyy0af{A*T_TBey$L_y*t#9ryP}IXZ11?sUk^~RS zqO#YEkow!#k%`Q^y6S*s?a){G(KD{c1UjdLj}*D^nculGlt|u^;WAT}bKxpgwwOP= z6<44Pq%gta+iwUho2-SfQh~z62k%!RvYPLhiltUi9P4)#pL02WXic{=*NVSMa^Fon zwtmKK^fYNerL@ERn!6!ROd5P*kG1Bo`CgxfCSuO`NUmxX^?+%Z%%TN1-M3QTs1ZA= zbVrHskJUZhAHdVCod{}yl3}{_tpXa=Nl~scOQ?C5!CnsIl57PZyB zXlpy}8)=`nKEULgq_yf!YR#K8k%cu-P~x(EJxh2b;E3ZzIgTbs^7lY)#7 zcj;AnSBfs9%ukB>tiwjM8d#a{H6TQ@hyB}leRKyaHrlKo%htY2Z<<+<;{PoEy55@Y z#0U8wPA0?wCU$}xU}FEIIV`pAeZfsMIMq!mzh^xCXA#QBrdeDyUI*n@;KaPGnCcA5k(>bxXl$U}8av(v$j=<{Cr? ztgzvNJHm{Owp_G?t(YJiMZ6eQ=HuvV%4nD3rp0}NR^X=myC=P;p-l`c?NidwmjwkO z8)>m--3sv^^5-2zc#}uZBn-_br`%$cUFywvtd6z$}0KJn8xPcS*aO z9zbniii50z{%Wy)Ne9g5>jk>Dzy$v_Z{OBg&m;M^<;-m*qrtnJy-ZXYp~P)&Z=_xO zyyuFQZ z(@A2!z1&1>5( zJ%PYsJOdr3JF$OG>E^@QWTWC|{43?Sd3yF?L3v;h^XG2jf8ur87eu;euHn|MTeu~C z)ucH^Jt){|)IX%yg@)=AQO_-n?Txs-%n}8e)b>+F6vIi!wss>7Qj@O*T7t;7<9Sz( zY#**R(NjMyYIkEztFnK$Ad}UE$q}gd9&rUt_;S}X&NMzzJ8ZmEuoJ)~>GY@7H*_7(=(-}j$t zY#bed)BmKo$R={nyyPc6bIv7VoAGrhuhhzAVlAO!1|E3Q7c zap*TTz`+Q@uG%#)3d;-S}1Fq09mM>&7IyuilRE708^=**1byC>IH3 z_IN6PvsPD~U?O_Yg{(e`U&qkX!aR*akD3lc13(;x-R|7e9|;+v77CTn9~+gx()V&h z>F*l#|6tx$9W+sLyl}pJ{&RSe#L83L&e_d{F-2ZuFDkp26DWPw8h_HDoA)o4D0JuS z=Wdw(Ua2&ZP;-X6yfn!n->d=_eeu(-SerqC_2+V^9icHv#HH*4gtEsA&2a6RGs{`; z3foKn94M@7`-+!WrP8&jPp(Ek_(Tiub zSEUo#Detk>|4UTDZ-3?g|Hm`Me;px8es#jd0{2+K`o^w!LG+i^uIavEm`Qy+!*g z-;MX0`i~1%L~d}+zQ>&VvE)$gHE~q3P20)Lp-zA+h$GKpr~D@k3_YQsve;O;1mox! zq%g6yeA-Kote)-nX3*JWT^x9nWS8F8klA0*m%`4KzRfq3tbyqIN#lTV+;O7=`L^oh zs2S{NH+2E);Dp#6(mUGTakQ3;nA0vczyG-ueU=K z>%5~DeDHY)qi)F)a&_CCwql{7{Ra%pg+Jaouji)J^xphE^8l7h9qfq7s_6&ZXqgt^7_=Q2FkxicG zyNm~;+%ZwR%*qJmJ>ary^j-;{1o9)#OknWUOQr#Yi||Z4ousu9VkHi8Aw*Dg!SLHh?RJyiUOPHt_&hJxcW}HCSfxrP${j|b^5u2 z=HwR!m-ZT@sv)x8yEbL)DiMYu($?D&{U!#Nt@X}^g|bMk$d8^^Iyrg)e&jm$c}si9 zG!XL}Sm*x%P$hf{|q_`|1hoDB!$B&c0n2GpC2up}07*C(i{~rGd>$n2_Jq%X}KqWv*Pb}gh&=o+;wmk*)j}T zH&Bn0Qdd33(X@R7Lx#4;mtGCExk{CE3PfRT<$W08rIpw)GBnNM&dR}JQF3wU?32AM zNHFUTBN11JVoI@hu`L*T63L6;f9dJXiPF{J)9bq6zNau; z-JsvP)(pMsQyjGn|Iks{a`r3Qt&V%nZcT10grtmO2(IPu)M-c-1&o$@hEtw?%_&!M zZp9ke=X%8{nusS}cF1VwbCAiL!fZtH5I=lo`+w;K=+kD@c~ zth>l5_~g#l)*2;?@WRABs=CQbB;7ISNoo(A4S9jALBiNmDpEaN9z@^jxZ0mo+jjiv zWl@oa^K6JPw8@^udy;)RZchf;n@{lnvP2|tH}2{@?$tX!JyBHUr&J_#qc{M;q}nyq zv)Y$4AxdxelZH)^dEv#4JXo)MW3v`hiC%tOV^RofzF3jXxU<>%mvt7!{%HL=g`*`l1vgD&k zp>8DG{2H@Jj2mxmgcA09#g;tdZm(89l859-xfOKpxex8^ac{GaKWSooG*~AejPIVF zNgaZ0n__7r3=yK9KA5j->W~n@a}>16M^7FYdsE+D+QZ0Jyw?X(+V!4~LYRA1C|XW{ zlSY&sB@3$T-Ti%Z4;$=eQVhx>3;K80vfIQN`W)pccKKo5s?`jNk)|AlWHZ(A$EoW; zu=lFM=~REVXhm|2vS;}g9dJFkWSAy=I-M%$05(+4n!vbSXipTq_wkjnXQ+nFklW>B zQWOFOC9Ww$KEE97@4s&3JIAIds1{tmbyhH@3t=~2qeag;(Qtu!6y=V5Cl9HMU$}9c zmjA25VqZ#drml<5YrC&Y0k@lBA`{>qP-yml(MNdTcH$aNxBOb=3wn9$;*-f^Ao5pt zLBRSDZws&MrD#3t@CC(#y;lW6vrTRK`v{`wDQScAEeKXAxvKS&xPyL36uQ(oezNQQ z{nMa8)P-ht*4+Oni9KO^mh9s=P8nl2)DJ#QT-}gi9c#awt-L;#;kbeg0JDiY!fXGT z)aB_PgMl^$7Y*OLy_Pzor}Ij+kd@c-#Qx<`4HzkS~V`*WM+zdB|7 z^}clm4$^(Yb~2CAWqzN-XL^9@E=>gb5(%JPnH?scODy6n!!m#ls5m1zr;_ev>4ZE% zG=W_#Udz1T_@1^EmJqbvRJb~aI<_p>NQRFuVi`s;q4LnZkNK4kw7*1mPwwRpx$nAe zXq_MhcGY`(4}V@$`^40gti3;drFf6Eh!@}YG*N9VL$w0-_q+B$jNqOCnu)CG2mY5Q z|Fc=Oj;LEcK$gkEg`s)-7+lW}VwO-B1%QTBV`_%Kbt&=_Q2^;^X9>$_@lcxQj5 z2sV!|EO@Hf<#esM%UszR3A+PI>3?_dVa{~`R2U!p4!&g_b)9KHKjSkBOB^Y6>SlmK z!qOlao-&Q4ABogW>eN#U$t1~{{{?CLZ%0yp_V~}nbN@PAm^^MG7gZn8zFVhY5P$8q1&(p|@wPkWOb2=DWJ)1cu z8$U*-dv5|ChK9N&HVfq$of>XlAW=Xcst0z`E;w=OqbsCFc+`sOnDRL^YpRFcVS7zg zf2{p@W{~UnERCaxSZ8@=Di~FPcG%g=7&v`kz}d%1lBu%uI`=}t+(CO&Z|3=5TANtE zEK(IaHtc^Gmk&AwojXO&K@B*dpEVae(c4c_?1_m=GV1WFP6~mrJt{0DXsndxm^4{i zq(_zxX-T}C2w{J-8a4d#SWbE@AUs9G6VR-+hv%UsCfAVsKd6^Ukt&@I8=HQY$#OY4 zw)#$S9?bGKK)23N^6?3)E@$qlU=3|OmN}oVnE0EJk?_RT`!_FA7jCB?GDOrC9FcBu zT7@U#M+--nj}k--$rlK6lgu{M!|{e(jqMLQQ@Slb-Z3cVVXkPVNoIY<`TdR%5+ZRw zA6n2=%~Yh3&$T<305dWm5Tz2fI<^u0ZPcdSt-`TU7Sj5b5#GLJhlga(TM`=|nDDsF z*2^A|{J6CKP7L!{wlf3ID`$NdIqES9Yd5K-9*^wL=hRO|=GvCKWSu$8o6vHhrd$@J z3qlSpD;P!u46-TBIr;I zQMiJoNPEU|rO{%SomX;%;SJN0mB_nbAG#9h`up(na%#meyupYq zG^VCP2Z+{UZP&3=vPkK?T>Sv)^#|@S%kNGh)kzT{xu)Qw`(j-UC`@kF57R(WM+I>U zoBz#TUi4uLwcm6_p`C!4jCaG}hOPDA!aP4vicrsueI~p3rs24Y)%r=5n7E@F?d>*{ zr3p{G@MW;I_LD4i3?48o6q^^9T&kgkL`jgyO>1O3+9mWUd3ak_0=?9d3sV$zZfB4< zIZ`8ahtL?DO7lcm*AlYUQELrEf{|J{R;>D-C?niNR|6U=D~fd&&FKad%{A3zTgZtG z1?ZEwK}-f@bVo<=8#G&T9A1K53MZ^?1(bA2Dk$-9U{1{)Yq7|(ElMzc6CQEb3{P_T z%2lx`x!J%vr_*v-DIrr+zBYj}d+X`PFfa2wqya*V5(}&VsQNfA{^2Y;4GpBNDOh8_g1Iz0BYF!Guf3s9fG?(a|FF%v(vquL9FH*xi2ehh0Vb-D#K zrag&ftTPwG&8bSZKmu#oMX{Fey&Wfa^uL;utl1Z2lrmO7RLZ%_hg4WOJem|lC!txO zR-?ZmjEM4FqRb1j48gtPbb}kAfn~`ydpuQ05@#`72iZDWgny2;&X?U?z2#@S8E!^y zsT%CpXqd{R#;XlQ&&m0^!0*^5b9Iy;UH2Y@S2`>-5#@V(eBLSEkv%HgHB;6C+L97g zbbfCXWlX?%vMbT?r}e`A{M_qI;L7jw^T!P=87w_-<16YO!%vXqeB#PL2s~bkE1At1uj>MSI^6=7b4$K>;^7lxN2_(Cd`CP`%Y$(Xymja z|0{L+AeA}5RGHx4oVn-q_ly{1+*HZsPVxe-WG+#pb~#U^mZJyK(M^5s#PfAh23_7o$=PX0tEDz6$5Z}=5_z)#rfAg2!H!Kg26<(=U07QT#1-| zkw``Jlc4x6sbRqTubP&!wg-RF$>&lltdz)AlhAuzG2WcziK}zCfYmCSuNz}hzXa_^ z=J-Z(`PE1%5n+)N2Y>r+8a)ZJfFL)9d_v}6S7Xk~u*iymbOFW{!Pd>uAhz<8j;==) z8=hu91y~}qxs1-nWS@TM=3PBz6S>)-wHkbybWMyA9EWHr9-V5}O070;YK;F$6IgIs zgJ@O!&Hp(cak3jyIZ14<@h*6mJ3r8d9dPaMwOozJ@nz>yorDF_NoK%@LrY@k=Q=uW zo<0^Y3~~4XsIai8&Oa-4{`NIs>r{zQKAv~ve3&1@J-d2IU)jC7vz>NEw?#9*KW*-_ zjy{Kygih^+>s1$*bqiY-Ro~#b5}udYMfMeJYhBxf@iz?EJ=lY;$rMVXY)U%v-@(;- zge61SH|hC+W0|Nk#Ml?of%#3!C=%!EY-jMbvN*{jhdCUVl)ft_578!BFlZC;!IDSm z>C4JAn;E{+O~^o#JTW1*ok7B$Sep`CBr=G(jhodLf5`eWxEm zqApdfG9c6|B9zPUb+09!&tArfRvq{ZQOo0F8(&b5wQa(ib+*kn_s{v*vvNo%JN;WG zumJAWjn(`5-I=~x55NiX@NbXE?~k>+-OgzUd{AnQeGJ zD&O8^EtP`_I$+jJ)tyC`(KS)%#?XP2-J5SSYMkc}WrT6GdHGyJe0t@3*ro4LEvMr^ z?nK*& zP29ilT;c&$CUZ{OY%UqV4{$Dog+1k=&E}$})*Qxi)dHvjRkE{|4>Tc9Dqi!vP7*ch zrTSi4I8(hR_wL?o^N^Q*lSMZ%gyPZVc=}$~@@jNCF&D|>0?(Xc-z~j3uTP3CUy01B z(@%^O*1%7|zy&?0bzQKLdKL-zR6Q#-ps^fT0Z@ZTTlp-@xV;dqDZyq%X4SoXO&zkv zDY8Fg5q8q7K{q#`xNNezG4vZ!r9$N^J-oNU5YZL2`FOqdwmx zZ7SaC{)Yo{;MP1faD%s}<>f@Mx&+s=lckcL_^{1T4CCWMlKL&VZbe?RjzqVEKWW@# z(Wnfsomd64`E{e^xj1*138!O;j`$Rn0YS{mT3)+s9IzY@QW6Q+RjAIKqF>Dy=}sPl zw0l|4Xy|AT{5aO~W5dprUL#bql!H%bc(`2;3jg6`v>B`W%=O`{_K0&2wyT3V;Qbgz zGi;cBbYVd=b%czy0nGuX~&KjN~ZW z+`w-!m2s_~noc#fP!)nEVP0+%qs*QK?jH#aRfD*WbO?$ok8*lWW;=hGe!M0;fxgC` zI{Z{qZGGB*HQAUrIZ%D(QK=I{+@W)zLy4$L6lIl-*M>_Kw$-LgLO3e|KPxt5M*H0m zcnf-yyX8Ne76i+G$RA3ZtFlf)_PffAp5J-!lcuPKu6qja@G|OsgygXtF&cInpJQ&W zX3hpGu-@WXv`1IRlh6#m5X3s7y;UH8ItF0h?0lHom^by#us#mi;$`W1*VnUQ{T5CZ z?sVWx{x+j-0=UQr>UNzO7IlSdSq#%2El{T6%Gc4^!mv_h&$aO-<~WHDSV)US)bxfi zmOnDxMiv%yIwtcvcl(G%i&S@S1B-sX+8Z-gc0ukOac#ZZVErrd3#soxsHV>4Xr{Pk zQC=ZH(i=D5u6`m6DAPA(!s7y#&LnQQo32Kh=GN`LR`z<^I?8Zk?Yq&I5%$weerV>2 zbNIr=;`T!&8j`J{EOtGK0kjJmURxNVsB+;jTXMed~`(iO5%G2zeCXjP~xJDkakrlz0mN8rbaeao09_?9t&q)VN;08_R&;W=v*IEx{ zbjEC1u$!bWus*sXKidjKh164=ifw!AOi`QDz(}l|j=0h(EH0AG4Qs(eoS|QxQOqR$ z3~i&1ueSUyy$;T+qHBFw4=*5X_u5%dc z{wXv%uz{~=}DSH_t#+}d|xmUbWf_mPfe@M-{G<#xnaP$;HrZM-i!x((RYDk<) z_Jxk=Vn2|zIz&Fkzi>8`S#X-+n*p`jWa+#v(1^mX16zFA?eC~?6)@1QjXOw{Y@sBD zW{{8JO*1f)6>&WaIFbt%vlD+!HaRJq@12ED!R3Q8jI`&N!YNC&477P`JH!{cm%C|2h}=lb=~uOZJ4-hVvcA4JRDO&CvDU5GRm0O`_H56oHnI zxt$mOJ@wfkOaZ`Az;P!n6-00w=IgcD;9F-g0RdXUcB9!-yQ1}vLf}iQEOqvoH%q>< zJV*b^WcsR~Z9H_t?bwjQlO1FT}<+5 zK+?a%xE_sP>5{Rel}D9BP&t5NBQ-cdKsUfTIq~&1`Z@{8`J$mCk;u$4pgkD>N%PWM zFSl&)UPE~E-guXvuudsIik1BQ6`_wf~ z*>663{x6q1(k+(KBpoUkAR<3$jy%?$ywIT=lvDg{G^GGx>S(RzcKX)nP}o9ytcYnO z4l)3x9%G#dG_|gWAK18nnH%7k=SstvrX?xBRMt9=i0QY=Ks`AgT3R|oRpdppwem=g zYCS7{dHAxAt>d2eI?r1~K8Yu(Zfy`U1If&LoC~$*2+2t&V?G!T8wlOI{+tnotWZo( zo|=komfYHYhMH0#Y*YM~Q5*O1(}w<;vW&S$`YY677<=mawA0BeA2L~csDX5i3?VQs zk~m?}fD}1l-)5EG$gc8s{ZdRHkJAUw7IE4>%j81{Z8Om58eFVTW`T#wUh{u%G_RxN zu)J|pPX{Gjcn&`^ME6#oor4)&6%TYuexXuZLH74rT-9nDE`ZMtJuFX%+wX|CB5UB4u(6dzMC>NHx2T4qe6{(zi# zNIZ;Y9#G5YaT&OM!^imTZKisy%nNZnnx2?qL83nOD43lyIS$;M-1aY-UfXD4U}_W6 z#_X1?hj+%%ez+cdWA_*(2h&;Pu~&Ym$lLpB{2s<){;A`z(;OC@9rr-d(<}Q&MGr$0 zbWjDlj2^TYg9n!K4rltNZr?jH>NHy#$jsQJ^k8a-$BZf1 zO`^h}kW$eBXdQ;2Keinp`Dqiwx>SlyxL4$(?nD3ReEZC8GII%IgtQD-%nsGgFTO!Z z-Et5KTaTg6k|5B~G*LUYGWe{^61*SxpsKg_HxivTR>(S9rTDmUtbNprgXpIcaA}h8 zX`l)4drlfz)q!8pVj#f=&WVwin7#!hDM-|S{c#`Ja8e!9KldQZxad4t%6a9LD{;t}ePUHCF@icPuqc95j0)ZV%JQwAyVGb{|X z{GAtCXq*yJuHG}%@>d;Y!+lFd;MiT&6OtZ+zUfP%WEMt!Es__|v#||?S0)Edm@3-o z!+4IjJ_t}8nDl8096poe8Azh%9Jtl_+cTw5Q{J zM*~jOYD(my$taF}%hNuA>aDrFdzl(DHX+$+E7IY(AuV9{GBQnp2}}$;|Drnae?S2L z*ZboCbHwHT-C5pcqN9E5{z<9_wHa1_n1(B663tR;H+%`YJHHzPB1-7MYUo>!B~Vol zLr9xQ_&&SrkGklr(fNyPm262OX|A4{tUgs-A&S_R_>fZWBNfg47p-_=`ddh=4UoQA zxLL8|#$rl9(*wCBzgLmvh;gl=tYr=UU!57I&NEqR>4$peXpsb{cv2Mlc^` zo9e%gxzlykS4zcyY4-{JvF)Z2M`tZQV!lAUp+q*X&KVJp!6i%_{H^NYDPUu%9X_^I z7F#AJT$-qU{7%QchsYRnum=R*6;)@weLCd7I|cLdwM;r)T}QJ`c@(}x$3m6Q@U3NK z-xo9Ka#sR++DG|U?r;YmfBo?m?2g4Vx(dlDAa7w>5t#-ijXWb;VA7yx-T=-FLXH#Z zW&`z-8@k>ja71Y8g51m9i{q;6TNoy$k!;$Vo!O6ksG@Lx=Gr%Fxc{WF0g=$@ zqcZIu=b#5n?X|ka-G0)HJa#VVpcvF*^fHOO`w2+X1NyiVifqh_I;FtxoEvj@4_%EC zhlN{PfV}AQh0o82xdWpzhg+_zeujUG%{_Q!I2KwxpB5MZ-M8wSHje+LVaq=!IzOzJ zmNI|#Blo?M2n))D*r@+;#vMFu7FoC}g?)=7g~h>j$Dpm2S7lrWJ*3*7S~ zDK6yW?$D_|K0<+C_27MyMar<%63^@A_Uk7%$O&k&HyGHHRH^4ZU6L-XEhPPvD%F+b-GvZCNR%~79ID14TiIf6q9XmTew>JLy`2tJ@!E=35k7M zFsebs09mS#e(3Qa(j`hi`4?23&_D8b_WAq3K3@=W{U!})sw(l@_52qD{Xfv<{Xs9| zq+C7Mk&eyfE|xt>AT)?AjL4*9066tXHN`>RV(j$Mr+=Sup6?Sb3HWc)$MeK)OfkX~ zMK8UWUba=dvklK#aO(NoQ0pnDUMZ7A*RTtH$--NbtlKCPsCkaCgqtVfwPCgxvUFjM zg-5DbVFjI>>TZ#5;WsLWkKQ44DEZE~AzqWH0XRL%uPEe`3&Rki%yxmzOzG3rxO1G) zclPT`j|z1%GpyE)xq6hXY>j%~<$vDKM}5OkU2_ICqVqN1Xgj+*Y$Ais^*gCqaz9qv z;E$@D-}Vnf@unSXcS%da;mP*!H$F_#&?Fme9cg~$hNT9c_+lsvb}YSYZGhTBU8)@=B@r^O zlb)OL7)2!6Wd#jbmQ@E_@-t7&zC0fHbm=zcBwn7|_7Yk&kbEOuStNPxqL1OY{_`kr zk;X&E!j3zIkgKlNwH!}VNjDCO_EkADI)WL7H_JggCv^x33LE~dfNn{IiK@Z0QoBJ4^p;>L-H>=PfQ&dMdi zLu26atS`u|>c?q+0A}4%i{Lq9dIMLA?6B~1evd`Sxtw$xB0<({O+`8}oSh&=Fxko|1Ts)JP_v^%P z=?@~Bbcqh9#cDjqB|%!A^pWb?gudJ@ZT#>GP?F4|f|YJeISeg9`>iB*YfR{H%N80n z9p+v6+{Rvc-GcRUk*kpwqd%yuqxkv$2Ppy|FufK_P&7tFW_~FdORo$7o$BBp;A8%e zkcQtME6bl6R@&M=!V_^__s!Z7$??k7FZ0WnUN7Rl7O7qs>L3(AxulSMk}Dhf32&z# zIB8Gk)cR^ZQDI}%O-G=iL8XhXUVL2zjNFIbg=v%=Xy%z@=PI?kNhrvl5Gs9h^Q&H8 zr_6yHjZO=m3IV#bG*x5AKYQ^+Z31cMw;c8P-^do6?VBYvi%F!Xi3GGY3s_>(+*Q1>wHDVU>N{ z%(W@&%Z7My!imWH{Xpi$|tNSB(sz_u9g61Ph=ED0Qz$638AEA zA4nOFA};-;QR^f;K`vmUsW9gtI-z@P#K3`Qgz!y8k7L-DXmDw?QtWcb8I6uv%pqX*0I|` zk7Glp1@fK)e-UUTs;@rR=kIby7#OlikHC@WZ&yteG3#Rw7 z(rdR66q5=2y^ycFp_;^?pi=ozpHe+qUdx>$v>2FRYe7aOSZ$O`%7x;sQl_!}?ZVXc z4K9BoMgU_%vc?PyR?WFwY+NsNedYG3X&4%$R(Ynou;)Thy^(lr*g7bLXS~lI(uqwqlJ56|F`jdbPgNo^5*hAvmK*n(?@l?bp@*}#9e&c>KxY-Gand)8T#Irjtq4y_cFs|e{z>x)x-gpW zQAy`_)t>&zXT>g8=yaaHG>F#NPwwu+3$zGM_%2!IVPovqeeY89W#fCj-Qn5obIE5q zHjWU@7*=oN)PB-j4I(aYu(JXJgindhm&6C>^CISMC>!nPfp!0zgQ0lyguX^+>U!z9 z7tehhLF-U!EO(msC;fby+idn(* zovylg9mi|$V-s#D2nnS&%;8KaG9!zvNvsS*g(!ld@Drrb2Fp7ICJE~9vldQGC3cZy zpTkx5+;xgvon>E%zTn+12%KU|*ACiyy|yY0Lq3KGtuEgYU6-MhK1Soh<2p0zo@NKPKB(c`E?0}P=O#4beFe6ygtYK?(BPy6(jND*=F$d{?oVG*%xrzCUA7HMRm2KAb-tt1B4k=x;C;$T6 z&VBIj{$7c%lJKDNN>>o{hGhC=GqoS|hU+)}wB`6cy@PtO-BxPLF=Tn*C`fa=e*_#b zXcjrQcM)Rn!!_R>!l(W0PGseN;H?{3R^MNTFNR+r4of}BI) z?RU|ePmq}_6oy&-pzm=~MfFXuVLnh5SzGoWT`MqeC?QasCt+1AcE~x<4EpV|J`FX$}DMzIGLF4Jn;mHZ}iyX z3xX3E21Ha~YnJQ<1yAav2PZZz!_x;|LOhvVUe;t6!4p|2mD%-UJ3pH{!e)T~fvog} zH~T|!WzWD&i~ZnsQ~kS#HLi_~rN~_Wf?TW&U6<{=4*!1PNl>R1l<=xze`2F~pEVDn_p}{1_ zA*49ZZQZVRdcH&!Uk)%JnXK4%KzE}ijEO1(NWZyE>MbqNoe+Wx*8PFN*6Y1@po010 zi=Ocj{*M~LtGt2#8p)f5O8Lf6CwO+TS`rd7zAOoyAK)g%9R36iS+meA4BhK2MvV%B z&Unm+rfJ*WLXp4F7DO}^ysa>g|>D@W;NuUf8N_s&-I=U9QH zjQJg)JCC0dT~3<#Ndwk#X5=CGW0(-Z1tCl5jd8IO3tU?e%w5)8xzl@jLOJxe%abQN z#U0<3g&lu{)hA2XyI7CcTlN+^nm| z4TUA|E`x=TG}tuCs3?jsB28wKkB}}D;KqgJzUUR2*zJy&t2e*EbBi0*MXvch@H0NY zIc1MCA;F1K;7|JkkCgSOiwp;8+?Rvu^@`x09;WJUCGVz6&&2lHbWIDfFrDK`mXZ7T z30w4hjVe#=D8s+-t+wmc9QklK!h(VGDO=oDB4vA7d{5e_pKsf6tDS0} zkOl3K>`gaT2jh`}(YW~SQB+L$Ymjggqw+PG+=&z|Rjfm1x*d!MAYZl@ zn4e8qS->nE-%~SbN2+U4i~u&{T#61F1F)I#L=FyADW7BN`ewfG>G8@lilY;@Z9^*_ z>^LT1%W-q;B4V`tjtH9@2&WmO-3ZX7p;35-k?S)jq8gCjIpgXn@SEuVo?PNyZn;kT z21Ae$EM9L`=i=^c0XuS8t7w~y641Z<5)eoxwP-0^<`^_8O!5e^t0AuAAEyG zpc&>rX)HPPCGMI>ERb|a6D#w@Q_A~W{VZwBVG!e$BMsF&`>+fOSun7)8Bxb zUp_&LWG&o^eM012*Wz~8J<3Bdt$;ow+jU-TV^-^!T-zA53@SWt71n13a!P>sLbat@+0Ngl2Cru-*(q+Y(mNJ3h^Eym8!HhSuq#mPcR0I3^#IO1%=* z`;Wo&@>TsvAwNb$pBG4I&K&wK^(>?}!AZVLgOrjwY$kamy?CD{ny1xze1Bj)Vz3bJ zo}O$K(CR^3+juZCYXN#TCEL^D#{LLfyBIyGT?kA+8K0ryPd!HI(^S_t)VH7GW0+ii z;o7;?(PC+px~F3!$pMI4Qflfe*7@2n;jPGEMbJz%+4ufL%^vqv;Xq2}W|HrJjCx^I znl>msR)knYKYgmYsIT?%GCa2EDQZNItQKKLKj0C%u5dr(Ygg&=IX&7v#Wfkwi9aHZ z+M61q#$bSl8f3irSFZi@Ch7upIN?zwCNTEaodK++O0(2gQZnqKoz{?NG+abuHHieW46)9Q|X`Db}4v5bbQVD49k^*H<(lmsPA zI)pYU3QMANbZ?w`&J{DPw|Q9ymgct8J;sbDA(qP?Q3lbK0hMCVAqQ#@5tER?_bew{ zopitdCyn3|xeDYQJUNGJi6JvMigFLky+5U*%(~I^;g7B&)=4ePdrM6{6a2|Gg`_8Mu_v;wW&M0kz?DzLo#{cCO?@tDG|2jOK zykk8US|84js+vMZfNVa`kc8-Tf}XVC!$7LOUr6)>ucY$U!S@1v`?O^@1QRQ1_##I zBBeB(x1p$qTR^lUuWse#Ul0C{AFSX2;wk?^$=rG%I?zMY}bCmbBvZN}UH)a`f zEi{d!^9664)sSkFFEnaj6GSmKsjegY^GzR|ViG&r=F2!Kd~VWywgG!e0RAtS7NqO5ki3)S59qfux?$MJ(t$JL`N6#E>EANTX6V` zsWI!O&=}QN1Hr~E&;%3h7c{<=Z-o+}TKntJ!?iqau18P6Kchmq&XI6ZO_=_bMGe`q zLYr8lk*M6$>grQ3%=z_hKeu{!{g~|W17FYidqbAS_oT^&#JHw|lr)r0Zn*q{tZ=TO z%>XQ}W@+g)d^584-kFStw;kU9=EZFTuPMO<#1g*p_N*YrK>mUS4aH!6_t>Voot=*~ z(?G8{%WbioG@4`E&QH*cZbE8zcpa}*NevRqg52qk>Uf8eo99wP_9XiMZiV3g4`M&f zvGs7D3B{y`8U+zp2N2)Riu zigvFr*>$_380KYJV6Y?_mEZH`lY6Fop1?#&cKx_25;}Fx*`+6!u$PO~Y1n0n!PA8y+uEDupY-le*)iyPt8h~BhP=NmJGy75+rb6M)wxoB+##0$n4#kf~HG@6- zv0?Pbd>lu!z|}sNbU<0ZqOz>`WxI#K&9j@pBeE_z>y51+zSJddt6d5V9=>1KH|5bS z!~%JknTlVHA@2^QQPSzu2h25ZE0?p_u&XCdJDUszUxM#gpZ>nHAw7oV(NFS%oI=1s zb%cIIi7>yfm{^6B*Vjr%NOlNaYepIY@%?J7Jct&OrSecf#&}0PzUzc$%T7k-P`M1U zSP%8(S6@m_Dneds;^tSAXMBis+!}EV!A^-Kk*KdC?4EsNMuBeog;dW1;B>n9f z=m_@=M1>>rd#O!Uwx)zhk-ie3rdh`>Kkd_7R%S{dMfgK8*T=X?tCv6Me`v3wk4_tqw@GPvzNwfYoM2AH?y|90w95Ezs$x_@}K@KB>FZ8iKa3FM~KTzrwA2)Y(x185ll6ax(e9( zBrUC9UgOJ?+4n3Q_ogeU=JD<0bWiSbK;nU4qgO##fDiI@>+mmL=W`IRA^6P=INv`S zech_$F?WX@$0WVmqQ&%n!i1nslSR`#ZC6(}rAxv^#Ee!ZmU|B>bFvh3xQxc{Bz%TI z6i*;-caJI)RKu<=!zc$7Z%L%QdET8fE2Pk<>{&5-s=Jq6BX-Rw(O~F{u{IzTrK1_; z4VEh$dg$Hv{i5B=f9E(@++;pfe#EUIETXapI^y5@O3|N~|rlP3fa8 z|6cXZOsOf=uii4b&IK;0D&5GRc{UttOr?uCZe_UaKr`LgRJJC+(OHQ_Y(+sz31aXGCm> zVviqpMJ#SAMjr~z`r}*T%g|G*dy$|K2CGnhYT-N}9kADcQSCvr3XZ2}`+QyFesU5;m{ z_o44)i|?caPI0h77n--*1xdtJ*z3H4lple5XAU|a!NBPvGhp)F87>9ko)7f>Il*1o z@Z%q;xb+1mu*Z!_uW>EoBB{+GS~n?OODN6K9&LjOF+wh#W@@G7gAbXf&ph!G^^@0f zvULKrcR|hD*%wQ}=mJ%8F&`KhW8sq+jpO5Z+U8|JxUoLLMnbDim?ZeF9>mZpr(EC)-za)qL6~BCaf{DnHrP| z7U>PX_rHHmzkg@_N?I9QhOyS(yJ7)o^mXjayN@at(y|AA%QdQs8xf===xWBrio!QF z8E0^nb_9w1lQz=Zs=|boSrBGYrsVw4mK(a=VYbU?TH~eqB{XTkcQYB)qlN)Z)&l63 z(Wdw0*M;?Q{+4f}?t$!Q*0n=_O|NwFh#1zNH0g+2ofj9Fmv+cJ!mt*YWELtNp;H!# zi7Va+tML)`l(|+a&P3gVJAL-+)rIU=m4BpG`sZXE2mYw>_$O&~|2kfvyyLwcs(`WR zwmUK^8rBSx5^X11o!^XDcd_sLCQ> z_;%~JH|ejdnB9BcBKe8O0oU*B{Ku~5m;eT%RQ4997Qowl!qSkuZKoYs7tg$&7>f<^ zfG6alF*lY;dLl`VE=2nJ$gGiUjceV{PM3`|Z#v|mc6(L?azYqsbhV#>Svy?jMQ9^_ zx3%^N$mym!uE{T`4{8lS1MI2h9pD@bO8@=b`nT^UGZhp0kn2jKkA|;Zxv2H7eZ0>n zQBODbOQP3;-2d0!cZW5#uK8j`P>hWtEh;KX6$O!+Z2?3Cq<13HL8L=yiGqOC2nYxY zktR)u^cINp-b_qbM~EQ?%Dg!-0=?{HHj<9;#=Q(-}l!p@v4jH zM0G7J2jeKNDOO%d@?@i~>DEv@h^*Y@BO%*g)0|DLZM-Q~6?H!UEANSK(T2dlM`H_G zr(^!fTee5kr(hIWJQD7HXYU*!L%`51A^tGco9Lij2ggE0-0Fsr3iwN3W*T$4JBd?& zXg_T1a+!Ueb=}Mf=6f=+*(m46QnW&sH#o(LPSGBm;3V13D+sXESFnNeMq11`zvj%| z*uoEhgn{&HN*GkM$mhG7oSbOaa6_-*!#sIR%(HW#OtEEgJG}uVIgc?kf%n1JQLdM^ ziwe7N-Ax*S_7aF|L%!h_o;o7w^I`XVkRxq(+`cxLkUd|hS$5snX_X7X6@GpC6G}j4 ze#X-xXDSTz;4swa8W0U3x`*1}f^h02jC$Y2iNz_S{J*fBrI>p+9>Rfvfl%=G9{71{ z?NsHg7F_-||1MAGWHSXINp2|_C>dOPz~Yd48Z8I#q%P``Io)`sBh$HCb#}M*PB$B; z*X`*5awv}(w{g(+sEwM()Q25F2SaDKCR4DhgKzibj+nFqJvi{iPNy9Z+tMs4oq*J~ ztJ~=PV-!ekQ(ipQJsSv3OJ`EYRRCpg<^2o*&G`@KCH=pCE#L7F1KZLzamUNuiCIf* zaQXD)D8+0MF=v9(PF=SsgoQRZ&Qx`V*!}>1%*z@*(EP!!a&&`lMS+WiiYWsRI|Jxo73JpbuSJF)u7RnF8@}t>oKNSf-cvDKNMBEM5QTRV5sI?w z8Lx{1dS8@&;nhRtUW{39g(ObraXcJ3Cb5lv4Y5YPHl`=~;5&@OpAcg52%v^U-odnm zCpNn^>rJ+SbnPejZk*Ryf9T}c%Zz89Yz=ws8mzo%$6n#SYWo6qOFJuOs8SXPGO6u6 z17?G<{z6a+mCZCiQVXaf7LLQq&~JXweHFzbp~aSOMAtbD8na;Tlb;jl3VY|d%?peT z!HJ4I5T4V+7jOfzZ2g!k`0N_^2|PGhEJQ|FEq>rQzbttNZB*(3wa%$I<4@t zeS)$qwBa$49*p88Jp=Fiy>@FZgJw^IMDeJx3%p^Yd1FJ z)5G^~P22msfL@MsSFw4k5xq=~27-cwKgjj3KJPLZ9+A5=%asy(cmzZ@g>{scuHRx3 zLu%MD0A@2s;Md{3tN@GfEKSlIOuRMeu0&NI)}jqmh2LhHF?dj_PVBhpX_*7hHXx=n z$TA1;D??Q_?LKMAU2&V#e0t#0tf!~1?IMuWk;JB%o0x?wB2^e}Ik@(ndAD8+sGf&2 z(6YUNqmJh;gNt!y?2|J zn&?ZH0!JLT(T<;9$}@SewIwDfdgz!@ zePGs@KgzL3)-g5qngRvJ8)ui#s{q1^-@=9~t5P<^S`3KDeU-*@%-!QgLzav)Gt<-{ zDJlml%}Jo6`25B+Px_`{m2FaRT}NVcOag8Rkdg+az(N#p$(y2!wKvXN4FfZ>A9QN< zcDTw%Uo4rgNu^ZXQrCG5T+Us;u@wG}qKm#xX!M^CwkJLk6=-y380SmZKu&W{6Dt*D z%eHO!L%^>BE`3OcM6HnD<3436M1PEZ?X5;1B;Z6;YWn5Oryq1(vEOM4GWn&0NKm&kFN z^6&@UOlvt6k!|9iyS}pItwh+oodLMAgm)$X-3JB!ey9NhEUq&@=vbFXI&#!G$m+-U z;G})j(ViGX(WFl{0(Z6{!6as&B9Vry^(F| zl_m{TkuLo}9S2-AuYp*Dc)HCYV2TF$@h3X_y%0uC^_J{9lMJSSk=Bdad19v1_~61wCj?faT~5%>1N)0=0O1E?H^^UF`%pU?+Yo=3F&V<$ z9>JrrPsagjIapZpegi!H6J-haiXtR>98_o|44CU40n)^co2jbUo+|ennF3nS%wG7? zfPHI8Hmy9-?UKqDYN*>XO+h(j@pk!D6ib5DjfiknH`9J(S&rm2G(6!>4WEei!!4e3 zzp_jI!m{3XDvtMNa`n1deP-L@4w#0uQICAIx^Q(hTToj&JI6X+fE%7BSqHk?|6w5| z%GfT8@}L5XB8%6!wF@A>y~_oxfDzi13?QI=%;qd0q=e$@lO1+YnR<OyxP!>4TIlBk`_Gnso=#f=l~YAucZTP>}wj$a#u8D=hwkK7}Tmwe_@S!InCM% z+x`({@DXqw2Y={3hlcYkvA-TS#n<~umB_majXwzil$r48!?MQ+3UAB|&}YZlVly7E zn{27QhSqMN4f16BdM6`o}F7Kb@EcWkp9)Iv- z^fBHhM2QJdxbg8aym+0_RW1YN_ko)4I2$ifaq{ZtA9iY8z||x&QA1@3rg)pS}#UX2h725FKAbWhoxC# z3Dee`yr1t;#!>ov!JNE7>W2N#V+Ja5p9iGNJ(M5x&*p8EtW1-6DA$R{uQXInDjyIK zlbSfxE)Z#G2zcYYP}BpeAeX0J7F87&PWv^97U~R}IOL_Be6T*Z3r{b56zQ8U;iFVt z#o2$eckqi7csgX)4)rTwSUc){tFj2!?4=zsD7UX?Vwq>ikh}6BF`fDhZi=F~Ro?tsBz$5) zvRHZh-*W_c(Lr_E5H)xsyfpJ=E*<5*UO4LS#jLo< zac`j@XlJ)@BE7MuVh5-|=olsJ$!66Rm_7Ab!o4GF2yc;Xwy4b%vVNuTZoKe-Bzp5c zX=L)RQdTVhHp~O)z&pt2)4t7{xjxm^V1U->hE1{ghOit{;0I53fN6VoAZhNC&W18} z*W1O1(If4P`$|@edSEE@>fhxz?>B(VO!XL6hoZ_hTLG0DE#FQd4r!<54vSa+?Rj^RP=fHO$oHZ42hMp8_aBQ?xSVWRWnVAtpmY1aSJ5VWi@~0Y2Hb_lQVqhpAR5az%%3 zRoHJfY7N8(2PhLRw{rFPbW1ms@bFNFhQW<~Lo}Y;sgfKY9+}+CK`(#)FsH9fm}F&N z$G;_S9h7($3`=BqC+&3bORCu^Pe0>}KDG$_vZ2wvy7MlrQNF2!@Cp$5{yweBD?zuP#O9*F^*6@NZg5( z3qR;?_#9i;v8@$&fu?cUhNX|66^e6mVmm3)3j;JaE&#wcfVL0TO%J;2@7H+Y#FvwI z>66Zx$018XLi^LX*lFcAYM)8;Cq^11KlNb9L+)0JW(Q9)V$=4rohSoQ?KX={6Oi$ z)(U%qewQ2b#p9rsOlmM}bOG{vc3Gaf4}G3e-K$^N3nu?ca(gZ6R#Vuoe6B zc>l)B4ndXcfXYN#6n0}*kQbdDHoe3Ou6|7FyZis-hGKev6_@PB( z6{r?nk@0Tw`F)5xFuXm`^|4_AD-3p%|`BM zWRglIZ0qahpQ!I>vPzSID5(WUt%lUS>$w&#?DKUYO76Ek4YD}<8Z_l-&V0F!#!ljPO(9lYDYWTzuut48e?_Sgx= z&L%lGs0WsDLCrj?(sHczAHXfroZg=NbaoS*9IiUS-@XkFiZoQ(fiMkDOct*9G zHHwI;L4Br(C`7FqU&PqP8N@u`Jxnf}q1~(GRqb&ZDQ)_vJtuG;L{dnY)&wE32u^u+<)=x9*N0-Qz_tSyq7HzovuYk^fCN}?H;8-`ena(Qq z>+Du8y?3L|UX69WlD*A1E=l7$Mrrp9W3CQv!EXa`7{KTZf^}vr z)psUFOpQPN6(HOG4Iq=>2gnfLY-VHYj|Qj~EDw3zzl3j)1vtnrWq~8(Y!cQIOfnj0 zp~H<1RpCi_Tb+-9t301y9Z2{2f_qm4#hG-ugXpB$Z~0!6={w#2^t@Dr0XQ zyVv*86Wn>FOJU!UOH#p`pySK2iD&!9YiJjwE{u{(Ag&AxcWKjbfWu>*t5iS6>Q@(Y z=kb-93-5upXF(7^i>ivI=3wVH1ysPqh#z##v6du+_Ei0oXlfcH2rjE&Am^d_ilQd% zjHnULos)X6(iBJfh&ZqduJH<&xwX_k{Ic=>X=Tm8b~m4}1syG(Hs9cDxxG*SGWIwW zO!T+gK{AfsIDg~aTlk3sREA7%dgmP!}vZM0tFJFT0pZRB&B#Hu4r7dRnD`)@; zHDDMtDtchP5Lm>BAAh0^mVFHbQYT|wDck#lF6G_642%e#CsdX2Qr)Q*%=?wlI-Y~J zg}vn`MB~^tkz=lh4c8x^q(WLsOm>FfJ}@PxRG`xB0YSY1bFe@AiyVby$))}$A@7PM zR5_P{s%i^XsK1glcMMZLUoU%|;N5OIS>aY(ve0po1H1~6Bc1eV_kfLz zMYA>&l=AyO7Uenk&5rIUd|Dp6(OpPqS{l_+%5@QW1Uq3AOQ2+Tu&*~5OPg|KQA1RC z5Bq8z+kKJi6Ubdt9!5XeknmJ);OqE{(&fS*bXoKZ9`=n$o8f+M>&em6-Z3AQFP%8{ z>A;)D7qV)^_>JtEBHhht%aut=<`NaU5UwBWq?0403lODm-~9w*mG9bVTi&Ti>WsTE z0p8L1L{+VH!2t%)Y4!6RAOACffbv{O4Q})RH zt)PGsaVKg)9j;w8tXcC}9n}c?iDErTSdJZ>-Fi_`$-4J7-N+yo#3Z$XortnQoc%Pu zV|1`TH_g=F{qS|!7Fko0wk{r^Ond9zU)DL=FuL*C|Ovw z6QaM`uXT>^CEdh4x(l)Ik-8q`99PmFhg%MfIPr@*HdD*~0tj~~MWqaiPuSNfWH!Zk%&lKM+8 zg!&P6qNxFk%l=uDv*qNt)@^R+q$0YW)A$47c&&Z_i(-3fAkl(Dfx2}Q8<*R0J*hNQ z>Cl%qqrhF3cBza@>6MtYAORZ~KI&P!dRkb=9B@^MILl9BU)&lG zG6q-H7_H|!Qwe3xw2k@ggT*N*lhi$nzbL#)O&3cnRw!FCjKMj!UY0)K1anCh)R_DU z$fE+|I1-ZBjw?jZfAp0S_^HqCX;IV4+)i0jh+pG4x*i`1`_;@?~j7H(+fb3 zBwV&NDLOp!g;3$%01W9WBlBhnl$YA)QVG!pT>L`;7yr+bO|qZ10q;PK3>eq|Pp$5w zTya{XzbgHbxJ6q=K7$-G)*`@ENgg0d93rlnyaX9TP6N}z9ew^*7f8^lX5R1K3a1Nz zpv=a|8Ryu=p^hWAF$=X+#rEziW5kduos|})w{(@EYlwebJu9X z8EX)5`X`-8;&?49ODq^4Z6y&7Q`ys!oI$XGNvGCv165w&z(nqph9^2S^HKM0C=P{s z^Lep#SYr>}x1GfwjZY6+r6`)rImD_xRRSl`@H>$7M@!kmwNn?h8PmjFI)+@&O{H-G zTX#;#{$+9S0Grq}^d#uJ>nil2v|T57yS@e3bov2A<2IBaNKBKKVOhY^9w-AzcFZt| z#tH+FPGJrZdc)&)K6SCRW87n|1(PcyF-9p>X)2#5TbDzh;P0{sed}K8;G3- zT7cy^+OwBZeE-A-M%o@gnLDQvEL3*^<52!Vz(SP6n>3ckyEohJb^hXAi#vxRm0{B2 zv?bIB%3yU2;FstPAea#CenA&o23L-TI>(a<-*?p3ls$y~3oFp9%TB};J;PzZc)Q~M zu3n%Vcm<8nAofWXjpFJ+rxj8cS9Da0F2{1+xMK~%CI6t?ZugRjPN+iJGDjyLoAkez z!R<#P4V>B!I%@wxC-iBHwpBs8#JWC@$j7qiCnqPu1fN;2nE^VR7>f&ZGR3bxTP_48VMRZ1H|t$J9R!lrb2>7e2e zB|Corif2+1KBPZ1uS+PxTbM?MT|FQhIu95G&DqSZ*BNmrhw8#!baoEcn0S{~?|@;n zds%uE$$l|K0NoTGe7`Mcx4tz31HZgf$)Sj!3rWtPbrxv?oGw97+dS>C2cgA>UC#6Xi3?9OD8+9DWkz~TUf$91{=_*C4J)TTnxI+%(0PCK<(PUKsa*DtC!sX z`OUvh7y2Li?*nw9>~mtmM~Tjwt*RE87io8}ZiCx~;`tk6?y3lX0EyGjY?0#{ z@Tc{AU+~5)V$X@%e!QA;BF26MImSCDLFLEf^}CEJi!bhqbjY0k&3-b|#+bdU==q1` zJENV1S4F>Se{xR(QH{?pQm8C@tD_!jymw^VN_jR!%QhLM($qY>&=g_QY zzH2)%dJ}GG$p+m6&GMKKs`Rekj?`7orbDC(2WbqWowZR0Yl&*1~nx zInN?yWID`GuKy*i6BDitsr?9{Za5$weMdh_&~10VJLGvuGK+S#vL<-Lu}p?9 zA0Uldj@oaoIcZln*vDCsQ~ZIF7Fif(YgbuKX6~LgMMWdYg1z`V5dF3603clvc*+G2 z${Xc&|Foz3t7&=PQ`~9pOaN3m_^_Dt(PCGXp0O?xcqelbx;wB-hrP{_%}&G-gNTD? zCm{#;)O+&F*RUER*K*zO5mW&8@*i~fVxNCAPlj{Cxf)AzgDZ!`Ce`^|M!UxuGWqLA zfv>3l?%b(k)xemNpn7JZB=KawM%@tI@bh+Z9oY4_t2(4~v=TIFoSwAo=1EJ8-Ldqm zOYRo$B_ocHB;Z#*`6IHHL$Kk+VohS(JA6DZ{lPHr^Ay09X}S4P1Ia4A~xqPcF0 zJ;O5_0pEzx01Z$xV-ZBtws@F_v+%3+**UK?X7vUVPQ5Ug)L!?tIsxJ@u1l3M801uC8Cf>L6T>#z3t6XA zp!wR?Ox?j|mE}zJlH+RMqems&3S^uxyHjQ#q;HkbJe7e);ue*^EWec1&B5qol>9zh z^91grw^kJUl`qh-Qu+;fAlrUeDx)e*U8!Ww_%^gGYD04USmP|rQW>hNg zCn?NY#d||XO5VU9@@rS%BWBZ%?I>-CC+8f-05wIf-!K2nHvO;1`n`7j&$4Vu<)w=n z0u1*i?K^$4ftwM)6H@O-G}3t9=M$k1TSrDF&4>GrF8GaBkbP|5;A7vU;MYE68#&-^ zd0b~qT-}^OnJ*y@jD3M2GmM8|$v)wvdLEcALXW)>`l{x!}8F z1=nWC{MdSwl+vlnQ0sKtvGx42-+X4f%C@Z8N|Rk+KrDxzl1-Nx$u$;xQMKFDKL`uP6WQ4u|S|@*Bja9R#dglh&H&k}{)!q10wf&JV zN=FL!bs0~N9Kth;F>kXyKElq}mmIr2vbAV3dBlnzxT1|Ls{deA{lI_c;Au6O`#os6;h2)Re;L(`85jR!QI%O|;GWN013nW}&(>;0a*by9p7VvHha0^Q7tip|0?|=w|_Z30mzcifEqv1l_+x z&Xt)wj=VM(mK=8|C6w9ZtwPdKlpNE6*`fJbFAwPI7+36yJEQyI=0ViX!&%ii+30AK zX&>j>l0%Py=!^33!|yo=%c%0{5l(Xaj!haOU3V#F4)?_0^39G(?+EuNaxgyI43qEb z5IGZTpHJ1<IVoguly}7doR!h?t2*M8$Nee0E9Y=dM+J^ z`Mu&&*JIO$AH7Ke3YoRyA??qPS9DlPaU&xoOX^ybC|yXHZjhagT@T&Bv{Kp3c;U6)%MF$0YGr zSsCrLCFt=LGDN5`K}F?t*%f>x27|N!@Ww^ehy1?82)lWrv7QL3pqUdD2Z&<}bi8zp zd5g)=z#=x0$fr)SS>m8R9Tsz?A(N&1<%o!YtDJo^m|!?#8Cl1FYws37V?pe$MAM?{ zDSA;XL(idO9vrkiMo5m0w{Y2}H$<>Zx?1YM*3)BDXI<3UA9RRJYnG~tA9RErH7fsn zUjN?4J5mudG1X&xzWudoGk1k8INI(UbVLr?^ei0+)am>3#d8tZryd{t9j@qq`ni9c z=IK?BVC1sty2Q@Tw%F$U8);}Z%=ccwLzCiFMou9a zfLjYMnw%Tl<`gd9jKI<)FQnG!a*SV~V& zz%1&*OQV_}bQk)k#PGs(!o$LKn-qmU_*q&97Bo)`$+3E!o8mn0!Q!@-eni}qp59ll z>(IC64p|lH`{8wpS+^BEt(V3E-xaWLb3DnXVLGcCr7f8k;pe)&nO*a?`G3$!0`AAH ztkf3EUWrz?=_2$a_z=Q24&yVuNIU7Riw|q8UFViNAH%OWvuRQ;cO)pNC6k`+t*rS4 zP7!IHA=gQbsx#>I%uLUvO07al$FZ?cDshBF>*?reIDO>Z^%M7#ll{SIdgwTc)U=Vo zUGor+(n79h&RvLnF9aWnUVdOjY*@tODLGJHqxRy~CG4Y?TUl(;txW8TG=-i?k*`@_ z3Vp&nfdNQC;Xb_n^XET)4){1iY`rqt#MK1;LjC`|PyN4PHL)!mXv~Rit>(~c@~VRa z)m*s~L_p{2*fD~eZ-eT|C0U!3ZbvtoN!jM0sr|UBOTWfdsR40SNsSr@9;qzq?ODNU zV4L;qJjc8hKCg3$uZo=A;^9LuE^h(;5gdIt@*mq>mif#E-tB6kndv-Vh`bmscQOaa zQ3BVLF)4k61Jm4w;gufn)N4TR+vox9`AYgMiNt4J&+QpsmxniCWEr41N=N?rNnj9c zf2k#``&|G%fmskXGJbNqo$tQmWcx!uYR_Zkt)?bOIG-?4N!oF8J=Q3X{6MLH5SU2( zI@^U5&#FGw;suLkk-L0c8;M_S2?{`#fyZacBRqBP%(_n$YCWtKXa|H4Px#ABnq^pk$*b0LS#=pK$%BIH}#JYe;YRVbn z_bfC~7dopWALSca7%_FrN>&j6IL9NY&0e4&=E+YJ-r+nH*+fqk><8ts?Vy#qy!BFuukH=C&US{Iz&U+n z6nY7{ZQPD3Un)Q11jvxyvLa41vpwU;m5%t*bvBqb`1Ih5H-{@t~x37 zo%w!|3bbL~7yB}4NSmT+2HZy1L9jn+Q~BNL>K|;t(9!QIWd~OMpjLh-{NhJ<-mly< z17R@tdM5MFm4R|WRZ0%rcb8V~Py#p6x9+sb=G@crT&YwswBQ-kaFQnL57>(h?+LGS zTnT6Py0mjJ-zpi)m94H3^)X>sR#x4~-SRj=3K~^|J&948dicR~vD~L^sWI)PMTWbp3bY<4pJRKP3VU^pi+wl+d&x37@= zp4msK;TL9LN=P}2tb4lzDZu03?S*LKKc~2wyT71FKPVoV#i?}O=1{gE`@3=Uyy2iUcwAQ2H90oM8}wgO zIB3iF$mDU?E$TfiJ_#XW>s~tqWWg03#*|3huL~N)m6Ay8HOZJ3u{4!O4sKSnuScLa zWh?V4OZuKqRTbHFKTdi_MPy{VPD78o#*8{9wT+mzhwR+|Mza73@cYIW&$_NK<4PaZ z{2JWOTaEo`|Jgre+W$wb^Z!!E<&kE;_UWXhI^I1{>~T?j{N+I6Gh6y{`Ed(qVdf~4tcn))U46*6*=*l58GUI3vgs6W0I|<5Y~?sb z&bu0EwAciIKiYF22=^6AYiw>bTTq**Q*hHcDu1snNF6`mpKUg-*RX~NW!j%H2{Ab# zET%FM6$9m~f(WiQc#bx>76t59aZa_`y(?=EVtTF#KBrW7`UZ=5q19x`Y8;>?# zG@CiJ(&`K0(Ho`#wC43g8Q-uw-@&uI8!2S%zauq|K17@Wi)F5?1zlpBdD2n~L=-8M zqD664oO+`om@X7R>|JB%j8QF?fYu^yasc9UfyIVvh)X%p8I`J&yqbet zAvevMQqB+kpxbS(rt-}~4}~LntZ7W1t{e%BOYP&E(p9Yu#uxGRHH%ezB_1i93=kxD zQu!T<^SW_P+A{l#0{S7*!2$C%`V;BhuV%DDhB;*9fxMn1y{Q*jwU9SkvQrqqbPJJT z?G7G-pDr_Voo^8g;BFZ`wqxHmApIW0TT5<2%(POPifjzLx+#c>#A;)?X(*E+pns{4 zKWZ9zb^KFBpDNF4;MA0YjsHQT5t`{uH04j3UM#dWJ(oKQ_1(*dmcyf@-98L+)6`iAww7|AHaaS)zi++ zbc$wBQmj&+>Ezq;`4MJwS`qYav_0+es8Kq9(RZKQ{$=MP2aQJ< z)Y#)4Kzdh&-}U_?da3&-s_0mB={1oMc9ujp}FMua=>&NBA~)b}M1`;EghDRDV`J$}2Y!Ekz76E2aS=qKJ_ zA2N0WH3bSEyLFEBX5;K#tJkNz3k3%6Tn3eANBMV(?G&9;ubWEOH|%H2>VG#n17O|G zaS6Pyh1z3-1g>@*czclqX+b3TC_*nT4%5c%W~u8UBHQgg9?&Gbk^G`2(gF)6nl9w) zdF2CxZk?e-zy|sMl#TcE`TxKv4;U=dX!DFRMFUO*BLZIWjx^5kl)h=pO28#$@|3EmozRU6tScW%j`uw2MDX;QwD=VIXd7;fDIp&v} zjS_&%76(G6F99(P^-EsmjfTY+hy;W&kdTN=OKo;*hV%)Aghie3JQ5}r{+ z3v=A7@ZMe^x2|eR5ohjTXIMwBAjd~9!Wxy=oA zZ)HMPhn#_DByKX2&Pl&BS&i66gU@~_GZ=!vr4;$aX0HJ0)pwRmgt4ei0QT>;-R4na2qqnqRhPG$ua=bw0{ z2H)ogWzwA{;#~2G(&ILOSk+AwN?wSf@;{cndFM+_m{!UXroWM~CHK-9C?sOFPfZRU z?sMTkuuSOwGq3r7sWAoiMZlfOVy8Pmy37!?>s(Ed^D#H(BHWj^vNst>hDJ^teoK-J zhlo(JXNcHi^MP8dg9txb#LV1QS>~ot;5(go@27oLm#x7kU2_yBxj!65PnDXqM;Emo z2^*K*Haq;P>BvjoP+S@=fYy_EivX@2e^qsZfO?(lAA?T)t|U{~Ao}id@Exhk+8SFI zf+@?#S@|Lqp;}erx8|++n=iX!8C*ec^wG5m$JL10>9uLFT$ng?*x;>cxN_YIlaB{= z4!>+X9AO*+J#B+xqg@<^*Fo@Q7yJ6X4XDBPvbdRh3aHYsF*Q~G66MkzG%uc|jBE?< z9tXLovJ-{thY+a^7$2zGJ6D>Z@)K2!>4y_R-`DS*G32mpz{0 zIir+8=icrNE)Z`N4mG|)K!sr~$HN3|0fGt6|H9^{zMN#u;Hj(MPBtYyiKsm9mONv2 z>KHoA5)WCu2eGq-g0OXAG8k_co=din!LQT=J4fNQs?OQxqqW|{&Yk+p-)0@d^s?H$ zvX;GML_Gz=GECGzXcPwnI&E+s_N2YEdj^bO2}AslKC}qujbIxa){}@F6F*t~;JIGV zk=rPY$JGj(Y080gSfe7|EiT>rm;Pj&_x;0W#>Tab)tnnIF5hfOx))Z;M(2`SgWlL4(5BARURom1-AXFnZ?_jF?yRVo&Du;kzs3-X0wgJ9S-r>?a zoueI+rUTfU*hwu!H2{(?6j_0Z{6MPK3?l(~iiq18C%O`9zkwNwI)g~|LE9i^!_+9f z@7Be^CV2|nW>L5FlC=0ZeKC`4gy33+*p6FsDf-ea>+)pVu3%k@G?+4Uo~E$Q9Y@e+ zy(ngT54Bq71X+*jTsHpjd5QD_4H^<%+)qYNSpxA8(2;y=sEn~icYb#h{`-8p;HL1Y z$`kY~IKM|&4EAga=tGB4Z$H?m+fd=Px4He)wW>~s!{SY{=3Jbf=xyd<+ycx{OR`Jr zdc|iSCceCn9?4rkqg~GQpN1a(Q3?K!OXxpXRM*k((rRa_`az}qe7IWZE`1*N#6TGH zE#G&BW`)o8J?@&z2f{p(pv@+*Qa-1gL0lg5hWl#N54x+(1bSMvGlGw*fWtscra11~ zdX}2cUIu%BN=h=&Apmx+`bxhfoW@QJnH<5Ts}|#OjK4!uAy&G6p)W+%A4e?c`q*w7 zy2(jjf%S(M_Nq{emc0ADkEf_9dyA8ioj&$7wPeVO0ffY%(+BiZo>}k?Svt)F3Oi=r zAUB(iDry34kSvO*l|t0qEudXVSEcomuX;v$cNXkb{Qx#-ifzB_IT(n>99WA2Q6OaZ zo!A}btYM$@mJRRG)PynP`C;7W>20(yYj8T>%~0c9JIWVl?QGVgQDkKl6Y!SZ`ROQ@4Z%m&vR<$N}J+3a|d4lOkKH8h}>D^H(=^ zR`+P#a|z?_=`pf}N@N)iY+)O?5V}K?4&x`^BHvo6guV4ZS#2VQ$yGWpFu41T>T>`E zVPicucjtSFvH1AP@SM*TgDUQ>7nJ)MR}xBVPMX1+Dm!sq+NeNp=4{)x{FU1~fnRbZ zkvj^AS?DhdLstU)Ed*B1S}nDCSjwgj4Dy0B>l8J!azLHEl-6&vJsEpx$wIn=28#oZ zx zWJUn%x`C>vWu@_JQ%c!^!UA9P-fv&V`4ITE#LK^bm2cBlDmg@6ZAIKQc7;Y0WX+bJ zafwpDFK#Y%Mz;}!TqU%dfM3&ILAwY>4!vm1(&Y*|vmATeHhs}S(b9kq!aIFqKVpT6yvjh+`qnW4D> z8xl58GnI7Cw%ApjTWmt~pv~SP@{=IhIy#?W{I&7M?EGq?e#F_m&gI5MBcpTpJt3AT z%=K*Q54!h@6PXISb&?Li0^92Nr=QY)_OIx_>G2NDgc$?2;Ax{c%1-p~=H&rbC28do zoyVy&&(fFp_$Yi|K1A6&Pg<-Eo5-EhJmUdJ;Y}xVV+l9O)6AcdKj@ePQs|1~X-XkM zs*wkCzfVQV2g{xVjV32z$DRWAM+6zmkw5z*7o$~2z4iYr#gEYu1U*L&jAX%b% z@|OBT1s%N(Gwi0is%>8_O1hfP%C%;6yDv%sx8D%Y`854!n%&>~Kfl`u|9NTw;C%ck zDOmqg-$&Mn;P1Cc5x0p<#q zNqm}c;_-C%QssF9aY-ma8!1UFnrOG30@vm^S0{4e=J8c2S;Oy>`t0(}UIlf?56D+9 zIDDJ-dj3LnH)G)_RKA#GtFan z)u|0tpi^ggPb(nI)%On1jMyf-k}yR|B|=mE4usuIo zwZg2569)XFg4@dX)r&)AS`W;<4R-o+t$u7<2;ga5-+rLFU;TpVAfT2kYn-)dbJ?M`%JLRecI{l_5(!>2Qbc#^RFCx z49$esaL62ZBSi|&3gGR;TaWQz|JT`R*2lWP@xE=nigSCr=G?sZeqb;^jZrhR*XJxz zy^1upyT=-$7Rtj`6+29jdbI2fdWNH2EqHSCYf1cAwFC{8`>1kyGSPQH`=%}H@t_yq zbT@}Y#%YHU(WY-F61+88<+Arqzx*_>CDgd@nNHfDdwr5hQfaa88hvqDn0fHs zeIIL`h>zx{>U(EB6`upXaDm*n7})a)Mkr`%E-=6tlI1~sX9qxlU&J=gAX;v6(CPu| z^_Dn#Ks6YAzy-<)v)9De&z9`Ogk;y?jr63^XQcs4r+oRQTAosKo&gN|@&xkLiYz^rcgU}5Z{q7vCc5$6Zo(v z`PA^;Iq53Hr;$hZ^geDcwJAGmV~@eP2ECQaiPd(gD+JfsjQkjK=f|}Ywi=JCs+V0j zUw2k|;2WwnbNC@1qE+^po$QN`>?=FpY>)3LmIOjpG!V1y(A1)8z{kB>va_DwKBUV^ z)p?p<>AorRlCp!_aKc1-B)FM&doS2B5yMDwuf?925hyXf@H9(e!wfRyuTa z3v{3F9=_dunPq_|T*P0Cjn0cP2K%7p=6jRt8;#n#mfcVB5osKPHGtG!_n+^>@;AH4 z%D?U-zi@j2TNM3|KY=^?vxNEcN;qFHTieu)wP%V^-F-JGVXAUhqqLuPw;RHwYQ+_9 zE&`mRZ%!x@!#M*Yr1o~Yi1q#h`GDs4v{+BKA@)fU+};Ac5L)?K7_PN@s@mS(CQ++U z>5S(kfAHJPjO6l2MLqU?8}J){$WHh>%k&Rsko{buf8G-Pv(EMJtfoJh;PGdD!=LZ- z=dIe`SxtYQ_3|IG>;7Ctf8Hwk>$(1&)$|7=XMg zF_wG5H91T|j`luh6VD~26Q*9u9Q;SP?$5`6H}2v8>+_ajV|JWjliI7Z3^M+xU^(ml zb{fywMbG+cw+IZr0R-bvS&x1F$N^5;j)>oyjIA-I=X|Q~T><5y*h<$O{gJaTW5E?s zTcQWbE&q%Nocsgz69FS~!3{&CoOtn2(yOuQ_DhRLrGUuM{u2 z(s&GW4RFp{?i&iv7F=KJoq6N71}}>G72OB_04ANl^4rHr4{F9+{h;e_YTdf5iG5M| zgANr0Sudc8X$R94?JSS)5u<2i$h5*R8ZkemN(O{?VOq&A1%1kQY4FQHY)&V!`){w( zvifu!`nO|<{@ttk^{*Yo{oO&pe|y=_xB8dU{PP6Os+gGE-9|*$;9qPGDoXHPjr^Oj%a6hT1%9Go Ag8%>k literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Screenshots/screenshot2.jpg b/Dijkstra Algorithm/Screenshots/screenshot2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bc51046fb36bd2c77b11cf8f6bc28afd0a2faff8 GIT binary patch literal 225916 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Screenshots/screenshot3.jpg b/Dijkstra Algorithm/Screenshots/screenshot3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9f7a1207f315e8f5aa20c72f3264c65edafd3a8 GIT binary patch literal 224243 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift new file mode 100644 index 000000000..e4b3e6732 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift @@ -0,0 +1,57 @@ +/*: + ## Dijkstra's algorithm visualization + This playground is about the [Dijkstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). + Plyground works in 2 modes: + * Auto visualization + * Interactive visualization + + */ +import UIKit +import PlaygroundSupport +/*: + 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. + */ +GraphColors.sharedInstance.visitedColor = #colorLiteral(red: 0, green: 0.5898008943, blue: 1, alpha: 1) +GraphColors.sharedInstance.checkingColor = #colorLiteral(red: 0.9411764741, green: 0.4980392158, blue: 0.3529411852, alpha: 1) +GraphColors.sharedInstance.defaultEdgeColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) +GraphColors.sharedInstance.defaultVertexColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) + +GraphColors.sharedInstance.mainWindowBackgroundColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1) +GraphColors.sharedInstance.topViewBackgroundColor = #colorLiteral(red: 1, green: 0.4932718873, blue: 0.4739984274, alpha: 1) +GraphColors.sharedInstance.buttonsBackgroundColor = #colorLiteral(red: 0, green: 0.3285208941, blue: 0.5748849511, alpha: 1) +GraphColors.sharedInstance.graphBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) +/*: + Now, we need to create some graph. You can create graph with any vertices amount but I aware you from setting up too many, otherwise it will be hard to place all of them nicely on the screen. Also, you can change the animations' duration: slow down or speed up. + */ +let graph = Graph(verticesCount: 6) +graph.interactiveNeighborCheckAnimationDuration = 1.2 +graph.visualizationNeighborCheckAnimationDuration = 1.2 +/*: + Now, let's configure the graph's visual representation by passing the virtual graph to our window. For better perception open live view in full screen. + */ +let screenBounds = UIScreen.main.bounds +let frame = CGRect(x: 0, y: 0, width: screenBounds.width * 0.8, height: screenBounds.height * 0.8) +let window = Window(frame: frame) +window.configure(graph: graph) +PlaygroundPage.current.liveView = window +/*: + **Great!** + + Now we have graph on the screen. It is beautiful, isn't it? ;) Before the visualization starts, I recommend you to move vertices around the screen using you finger to be sure that all vertices and edges are properly visible. + + And a final step! Before you will see the visualization **(by pressing "Visualization" button),** please, read explanation of how the Dijkstra's algorithm works. + + Algorithm's flow: + First of all, this program randomly decides which vertex will be the start one, then the program assigns a zero value to the start vertex path length from the start. + + Then the algorithm repeats following cycle until all vertices are marked as visited. + Cycle: + 1) From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) + 2) The algorithm marks picked vertex as visited. + 3) The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. + When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. + + Now, try yourself at the Dijkstra's algorithm. Press **"Interactive" button.** The program will mark the start vertex as visited and calculate new paths for its neighbors. You have to pick next vertex for the algorithm to check. If you are wrong, you will see a message on the screen. + + Good luck and have fun! ;) + */ diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Pause.png b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Pause.png new file mode 100644 index 0000000000000000000000000000000000000000..12a5d49228a5ed6708e3478435ea0c60885c958f GIT binary patch literal 712 zcmeAS@N?(olHy`uVBq!ia0vp^6(G#P1|%(0%q{^b#^NA%Cx&(BWL`2bFg1C)IEGX( zzP)&mmqCH&utUQCxs8f{HfWVMXq*p literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab9556297d800bdd36cdbc8f1a256467230cab9 GIT binary patch literal 1044 zcmeAS@N?(olHy`uVBq!ia0vp^6(G#P1|%(0%q{^b#^NA%Cx&(BWL`2bFrV{uaSW+o ze0w)L@3sR^YvAq|hc<1|I~zH3wb+gh-PeZvlV%-HS6HBXw%|~;(9`t1^UptTtf{?Q z(L3`%(`xYx%0k}XmonK3ec^udOZS4Z!}?HjJLbE_U)WyUQ(aKqa__Ru4!#oq3+xlp zw>P|F{N-c#(C&h+vpT~vJ;q(GFGBYAlsar@naenRx5x{z1;tmnt})lDmM})V6kD*q zLGS9S8|)=2C9END!xktn$ezmcjrlD{?SJ+sH|&>x{l4kP`M-7bPjZsp7BcBFzP4tK z@|3tD)@Ukr!E4c?Z9Ho>HiQYWZe>sCW!*CA#0p!+Y@G#DU7X$uMkF(?RpHAze?W>m zLv>@IJHxdI2kp-3Rze$&F-3Xml)5DJvVVDSz`>u%#`MdH{)~g`UWfF*lWb(QWBqdG zK(GU|&a>OOC+=r7)Hi(1)5vHz`YW=%f$fKIS?$v7jE3uTe$U_C!d4+)^4>4}0>gX5 zdGYU=q#hKX*evSn%v^J9dfk4{jE2jM!Qp1Cyaig(|8}V@U_94;`fj17$$_0QPhaad zvh9#rQa$u>?*WXSH7}vG0di#Kjw?Mc5Zk>2W!`p^6Rx_QLbB-q6Kh7eRP%ZJg zFZ2RKbn%a`+D&XX_>ZhE7Be{z$Mdgt@&d+h?H}wO3P>fq|MB=&z7w+yyFlqBX_Eti z8;{TbEdML~&(1j#GY`B!ao9pzrE$Bv$pOWg?J}R(RtqzR3H`n18_~}+gYklMfDfR@_i+Q?DS1lN{JHKU#t~tgS;khN)H^G$efY+m6SzN0N z8N!6Fhl+!Z=vcoFtV1x|8LZ&Y{x-0YE%AF|ub!8sJynnC^dFi9Xc+d^gn1J4@gcZs_E z4UN3P1vVMX5)sGu9FE@4z$`tl?m#2A!3IXl_|hZsa-!ywxqaHDf!UnF)78&qol`;+ E0JOlxT>t<8 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png new file mode 100644 index 0000000000000000000000000000000000000000..b74585cbe2b300ac7126e7bc63c0968843432f8b GIT binary patch literal 498 zcmeAS@N?(olHy`uVBq!ia0vp^6(G#P1|%(0%q{^b#^NA%Cx&(BWL^TXLn;{G zUS{NFP~bV@aA5y)#|anj$ZWa$zH)oawF4(7G5%&_>9cP-z;vAV$VZ)s2Rj-q=CN|i zm ULH=xDyfH9%y85}Sb4q9e0I4;^asU7T literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift new file mode 100644 index 000000000..5ff656dab --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift @@ -0,0 +1,109 @@ +import UIKit + +public class EdgeRepresentation: Equatable { + private var graphColors: GraphColors = GraphColors.sharedInstance + + public private(set)var label: UILabel! + public private(set)var layer: MyShapeLayer! + + public init(from vertex1: Vertex, to vertex2: Vertex, weight: Double) { + guard let vertex1View = vertex1.view, let vertex2View = vertex2.view else { + assertionFailure("passed vertices without configured views") + return + } + let x1 = vertex1View.frame.origin.x + let y1 = vertex1View.frame.origin.y + let width1 = vertex1View.frame.width + let height1 = vertex1View.frame.height + + let x2 = vertex2View.frame.origin.x + let y2 = vertex2View.frame.origin.y + let width2 = vertex2View.frame.width + let height2 = vertex2View.frame.height + + var startPoint: CGPoint + var endPoint: CGPoint + + if y1 == y2 { + if x1 < x2 { + startPoint = CGPoint(x: x1 + width1, y: y1 + height1 / 2) + endPoint = CGPoint(x: x2, y: y2 + height2 / 2) + } else { + startPoint = CGPoint(x: x1, y: y1 + height1 / 2) + endPoint = CGPoint(x: x2 + width2, y: y2 + height2 / 2) + } + } else { + startPoint = CGPoint(x: x1 + width1 / 2, y: y1 + height1) + endPoint = CGPoint(x: x2 + width2 / 2, y: y2) + } + + let arcDiameter: CGFloat = 20 + var circleOrigin: CGPoint! + + if endPoint.x == startPoint.x { + startPoint.y -= 1 + endPoint.y += 1 + let x = startPoint.x - arcDiameter / 2 + let y = startPoint.y + ((endPoint.y - startPoint.y) / 2 * 1.25 - arcDiameter / 2) + circleOrigin = CGPoint(x: x, y: y) + } else if endPoint.y == startPoint.y { + let x = startPoint.x + ((endPoint.x - startPoint.x) / 2 * 1.25 - arcDiameter / 2) + let y = startPoint.y + ((endPoint.y - startPoint.y) / 2 * 1.25 - arcDiameter / 2) + circleOrigin = CGPoint(x: x, y: y) + } else { + startPoint.x -= 1 + endPoint.x += 1 + startPoint.y -= 1 + endPoint.y += 1 + let x = startPoint.x + ((endPoint.x - startPoint.x) / 2 * 1.25 - arcDiameter / 2) + let y = startPoint.y + ((endPoint.y - startPoint.y) / 2 * 1.25 - arcDiameter / 2) + circleOrigin = CGPoint(x: x, y: y) + } + + + let path = UIBezierPath() + path.move(to: startPoint) + path.addLine(to: endPoint) + + let label = UILabel(frame: CGRect(origin: circleOrigin, size: CGSize(width: arcDiameter, height: arcDiameter))) + label.textAlignment = .center + label.backgroundColor = self.graphColors.defaultEdgeColor + label.clipsToBounds = true + label.adjustsFontSizeToFitWidth = true + label.layer.cornerRadius = arcDiameter / 2 + label.text = "" + + let shapeLayer = MyShapeLayer() + shapeLayer.path = path.cgPath + shapeLayer.strokeColor = self.graphColors.defaultEdgeColor.cgColor + shapeLayer.fillColor = UIColor.clear.cgColor + shapeLayer.lineWidth = 2.0 + shapeLayer.startPoint = startPoint + shapeLayer.endPoint = endPoint + shapeLayer.actions = ["position" : NSNull(), "bounds" : NSNull(), "path" : NSNull()] + self.layer = shapeLayer + self.label = label + self.label.text = "\(weight)" + } + + public func setCheckingColor() { + self.layer.strokeColor = self.graphColors.checkingColor.cgColor + self.label.backgroundColor = self.graphColors.checkingColor + } + + public func setDefaultColor() { + self.layer.strokeColor = self.graphColors.defaultEdgeColor.cgColor + self.label.backgroundColor = self.graphColors.defaultEdgeColor + } + + public func setText(text: String) { + self.label.text = text + } + + public static func ==(lhs: EdgeRepresentation, rhs: EdgeRepresentation) -> Bool { + if lhs.label.hashValue == rhs.label.hashValue && lhs.layer.hashValue == rhs.layer.hashValue { + return true + } + return false + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift new file mode 100644 index 000000000..69874e5d7 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift @@ -0,0 +1,30 @@ +import UIKit + +public class ErrorView: UIView { + private var label: UILabel! + public override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + self.backgroundColor = UIColor(red: 242/255, green: 156/255, blue: 84/255, alpha: 1) + self.layer.cornerRadius = 10 + + let labelFrame = CGRect(x: 10, y: 10, width: self.frame.width - 20, height: self.frame.height - 20) + self.label = UILabel(frame: labelFrame) + self.label.numberOfLines = 0 + self.label.adjustsFontSizeToFitWidth = true + self.label.textAlignment = .center + self.label.textColor = UIColor.white + self.addSubview(self.label) + } + + public func setText(text: String) { + self.label.text = text + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift new file mode 100644 index 000000000..54147f5e1 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift @@ -0,0 +1,7 @@ +import Foundation +import UIKit + +public class MyShapeLayer: CAShapeLayer { + public var startPoint: CGPoint? + public var endPoint: CGPoint? +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift new file mode 100644 index 000000000..2647c4525 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift @@ -0,0 +1,20 @@ +import UIKit + +public class RoundedButton: UIButton { + private var graphColors: GraphColors = GraphColors.sharedInstance + + public override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + self.backgroundColor = self.graphColors.buttonsBackgroundColor + self.titleLabel?.adjustsFontSizeToFitWidth = true + self.layer.cornerRadius = 7 + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift new file mode 100644 index 000000000..29c971411 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift @@ -0,0 +1,63 @@ +import UIKit + +public class VertexView: UIButton { + + public var vertex: Vertex? + private var idLabel: UILabel! + private var pathLengthLabel: UILabel! + private var graphColors: GraphColors = GraphColors.sharedInstance + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override init(frame: CGRect) { + precondition(frame.height == frame.width) + precondition(frame.height >= 30) + super.init(frame: frame) + self.backgroundColor = self.graphColors.defaultVertexColor + self.layer.cornerRadius = frame.width / 2 + self.clipsToBounds = true + self.setupIdLabel() + self.setupPathLengthFromStartLabel() + } + + private func setupIdLabel() { + let x: CGFloat = self.frame.width * 0.2 + let y: CGFloat = 0 + let width: CGFloat = self.frame.width * 0.6 + let height: CGFloat = self.frame.height / 2 + let idLabelFrame = CGRect(x: x, y: y, width: width, height: height) + + self.idLabel = UILabel(frame: idLabelFrame) + self.idLabel.textAlignment = .center + self.idLabel.adjustsFontSizeToFitWidth = true + self.addSubview(self.idLabel) + } + + private func setupPathLengthFromStartLabel() { + let x: CGFloat = self.frame.width * 0.2 + let y: CGFloat = self.frame.height / 2 + let width: CGFloat = self.frame.width * 0.6 + let height: CGFloat = self.frame.height / 2 + let pathLengthLabelFrame = CGRect(x: x, y: y, width: width, height: height) + + self.pathLengthLabel = UILabel(frame: pathLengthLabelFrame) + self.pathLengthLabel.textAlignment = .center + self.pathLengthLabel.adjustsFontSizeToFitWidth = true + self.addSubview(self.pathLengthLabel) + } + + public func setIdLabel(text: String) { + self.idLabel.text = text + } + + public func setPathLengthLabel(text: String) { + self.pathLengthLabel.text = text + } + + public func setLabelsTextColor(color: UIColor) { + self.idLabel.textColor = color + self.pathLengthLabel.textColor = color + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift new file mode 100644 index 000000000..0b0b97b92 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift @@ -0,0 +1,308 @@ +import Foundation +import UIKit + +public enum GraphState { + case initial + case autoVisualization + case interactiveVisualization + case parsing + case completed +} + +public class Graph { + private init() { } + + private var verticesCount: UInt! + private var _vertices: Set = Set() + public weak var delegate: GraphDelegate? + public var nextVertices: [Vertex] = [] + public var state: GraphState = .initial + public var pauseVisualization: Bool = false + public var stopVisualization: Bool = false + public var startVertex: Vertex! + public var interactiveNeighborCheckAnimationDuration: Double = 1.8 { + didSet { + self._interactiveOneSleepDuration = UInt32(self.interactiveNeighborCheckAnimationDuration * 1000000.0 / 3.0) + } + } + private var _interactiveOneSleepDuration: UInt32 = 600000 + + public var visualizationNeighborCheckAnimationDuration: Double = 2.25 { + didSet { + self._visualizationOneSleepDuration = UInt32(self.visualizationNeighborCheckAnimationDuration * 1000000.0 / 3.0) + } + } + private var _visualizationOneSleepDuration: UInt32 = 750000 + + public var vertices: Set { + return self._vertices + } + + public init(verticesCount: UInt) { + self.verticesCount = verticesCount + } + + public func removeGraph() { + self._vertices.removeAll() + self.startVertex = nil + } + + public func createNewGraph() { + guard self._vertices.isEmpty, self.startVertex == nil else { + assertionFailure("Clear graph before creating new one") + return + } + self.createNotConnectedVertices() + self.setupConnections() + let offset = Int(arc4random_uniform(UInt32(self._vertices.count))) + let index = self._vertices.index(self._vertices.startIndex, offsetBy: offset) + self.startVertex = self._vertices[index] + self.setVertexLevels() + } + + private func clearCache() { + self._vertices.forEach { $0.clearCache() } + } + + public func reset() { + for vertex in self._vertices { + vertex.clearCache() + } + } + + private func createNotConnectedVertices() { + for i in 0.. Vertex { + var newSet = self._vertices + newSet.remove(vertex) + let offset = Int(arc4random_uniform(UInt32(newSet.count))) + let index = newSet.index(newSet.startIndex, offsetBy: offset) + return newSet[index] + } + + private func setVertexLevels() { + self._vertices.forEach { $0.clearLevelInfo() } + guard let startVertex = self.startVertex else { + assertionFailure() + return + } + var queue: [Vertex] = [startVertex] + startVertex.levelChecked = true + + //BFS + while !queue.isEmpty { + let currentVertex = queue.first! + for edge in currentVertex.edges { + let neighbor = edge.neighbor + if !neighbor.levelChecked { + neighbor.levelChecked = true + neighbor.level = currentVertex.level + 1 + queue.append(neighbor) + } + } + queue.removeFirst() + } + } + + public func findShortestPathsWithVisualization(completion: () -> Void) { + self.clearCache() + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(self.startVertex) + var currentVertex: Vertex! = self.startVertex + + var totalVertices = self._vertices + + breakableLoop: while currentVertex != nil { + totalVertices.remove(currentVertex) + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + DispatchQueue.main.async { + currentVertex.setVisitedColor() + } + usleep(750000) + currentVertex.visited = true + let filteredEdges = currentVertex.edges.filter { !$0.neighbor.visited } + for edge in filteredEdges { + let neighbor = edge.neighbor + let weight = edge.weight + let edgeRepresentation = edge.edgeRepresentation + + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + DispatchQueue.main.async { + edgeRepresentation?.setCheckingColor() + neighbor.setCheckingPathColor() + self.delegate?.willCompareVertices(startVertexPathLength: currentVertex.pathLengthFromStart, + edgePathLength: weight, + endVertexPathLength: neighbor.pathLengthFromStart) + } + usleep(self._visualizationOneSleepDuration) + + + let theoreticNewWeight = currentVertex.pathLengthFromStart + weight + + if theoreticNewWeight < neighbor.pathLengthFromStart { + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + neighbor.pathLengthFromStart = theoreticNewWeight + neighbor.pathVerticesFromStart = currentVertex.pathVerticesFromStart + neighbor.pathVerticesFromStart.append(neighbor) + } + usleep(self._visualizationOneSleepDuration) + + DispatchQueue.main.async { + self.delegate?.didFinishCompare() + edge.edgeRepresentation?.setDefaultColor() + edge.neighbor.setDefaultColor() + } + usleep(self._visualizationOneSleepDuration) + } + if totalVertices.isEmpty { + currentVertex = nil + break + } + currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } + } + if self.stopVisualization == true { + DispatchQueue.main.async { + self.delegate?.didStop() + } + } else { + completion() + } + } + + public func parseNeighborsFor(vertex: Vertex, completion: @escaping () -> ()) { + DispatchQueue.main.async { + vertex.setVisitedColor() + } + DispatchQueue.global(qos: .background).async { + vertex.visited = true + + let nonVisitedVertices = self._vertices.filter { $0.visited == false } + if nonVisitedVertices.isEmpty { + self.state = .completed + DispatchQueue.main.async { + self.delegate?.didCompleteGraphParsing() + } + return + } + + let filteredEdges = vertex.edges.filter { !$0.neighbor.visited } + breakableLoop: for edge in filteredEdges { + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + let weight = edge.weight + let neighbor = edge.neighbor + + DispatchQueue.main.async { + edge.neighbor.setCheckingPathColor() + edge.edgeRepresentation?.setCheckingColor() + self.delegate?.willCompareVertices(startVertexPathLength: vertex.pathLengthFromStart, + edgePathLength: weight, + endVertexPathLength: neighbor.pathLengthFromStart) + } + usleep(self._interactiveOneSleepDuration) + + let theoreticNewWeight = vertex.pathLengthFromStart + weight + if theoreticNewWeight < neighbor.pathLengthFromStart { + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + neighbor.pathLengthFromStart = theoreticNewWeight + neighbor.pathVerticesFromStart = vertex.pathVerticesFromStart + neighbor.pathVerticesFromStart.append(neighbor) + } + + usleep(self._interactiveOneSleepDuration) + while self.pauseVisualization == true { + if self.stopVisualization == true { + break breakableLoop + } + } + if self.stopVisualization == true { + break breakableLoop + } + DispatchQueue.main.async { + self.delegate?.didFinishCompare() + edge.neighbor.setDefaultColor() + edge.edgeRepresentation?.setDefaultColor() + } + usleep(self._interactiveOneSleepDuration) + } + if self.stopVisualization == true { + DispatchQueue.main.async { + self.delegate?.didStop() + } + } else { + let nextVertexPathLength = nonVisitedVertices.sorted { $0.pathLengthFromStart < $1.pathLengthFromStart }.first!.pathLengthFromStart + self.nextVertices = nonVisitedVertices.filter { $0.pathLengthFromStart == nextVertexPathLength } + completion() + } + } + } + + public func didTapVertex(vertex: Vertex) { + if self.nextVertices.contains(vertex) { + self.delegate?.willStartVertexNeighborsChecking() + self.state = .parsing + self.parseNeighborsFor(vertex: vertex) { + self.state = .interactiveVisualization + self.delegate?.didFinishVertexNeighborsChecking() + } + } else { + self.delegate?.didTapWrongVertex() + } + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphColors.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphColors.swift new file mode 100644 index 000000000..95e9b8d74 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphColors.swift @@ -0,0 +1,15 @@ +import UIKit + +public class GraphColors { + public static let sharedInstance: GraphColors = GraphColors() + private init() { } + + public var mainWindowBackgroundColor: UIColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1) + public var topViewBackgroundColor: UIColor = #colorLiteral(red: 1, green: 0.4932718873, blue: 0.4739984274, alpha: 1) + public var graphBackgroundColor: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + public var defaultVertexColor: UIColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) + public var defaultEdgeColor: UIColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) + public var checkingColor: UIColor = #colorLiteral(red: 0.9411764741, green: 0.4980392158, blue: 0.3529411852, alpha: 1) + public var visitedColor: UIColor = #colorLiteral(red: 0, green: 0.5898008943, blue: 1, alpha: 1) + public var buttonsBackgroundColor: UIColor = #colorLiteral(red: 0, green: 0.3285208941, blue: 0.5748849511, alpha: 1) +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift new file mode 100644 index 000000000..49bc6853f --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift @@ -0,0 +1,246 @@ +import UIKit + +public class GraphView: UIView { + private var graph: Graph! + private var panningView: VertexView? = nil + private var graphColors: GraphColors = GraphColors.sharedInstance + + public override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = self.graphColors.graphBackgroundColor + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + + } + + public func configure(graph: Graph) { + self.graph = graph + } + + public func removeGraph() { + for vertex in self.graph.vertices { + if let view = vertex.view { + view.removeFromSuperview() + vertex.view = nil + } + } + for vertex in self.graph.vertices { + for edge in vertex.edges { + if let edgeRepresentation = edge.edgeRepresentation { + edgeRepresentation.layer.removeFromSuperlayer() + edgeRepresentation.label.removeFromSuperview() + edge.edgeRepresentation = nil + } + } + } + } + + public func createNewGraph() { + self.setupVertexViews() + self.setupEdgeRepresentations() + self.addGraph() + } + + public func reset() { + for vertex in self.graph.vertices { + vertex.edges.forEach { $0.edgeRepresentation?.setDefaultColor() } + vertex.setDefaultColor() + } + } + + private func addGraph() { + for vertex in self.graph.vertices { + for edge in vertex.edges { + if let edgeRepresentation = edge.edgeRepresentation { + self.layer.addSublayer(edgeRepresentation.layer) + self.addSubview(edgeRepresentation.label) + } + } + } + for vertex in self.graph.vertices { + if let view = vertex.view { + self.addSubview(view) + } + } + } + + private func setupVertexViews() { + var level = 0 + var buildViewQueue = [self.graph.startVertex!] + let itemWidth: CGFloat = 40 + while !buildViewQueue.isEmpty { + let levelItemsCount = CGFloat(buildViewQueue.count) + let xStep = (self.frame.width - levelItemsCount * itemWidth) / (levelItemsCount + 1) + var previousVertexMaxX: CGFloat = 0.0 + for vertex in buildViewQueue { + let x: CGFloat = previousVertexMaxX + xStep + let y: CGFloat = CGFloat(level * 100) + previousVertexMaxX = x + itemWidth + let frame = CGRect(x: x, y: y, width: itemWidth, height: itemWidth) + let vertexView = VertexView(frame: frame) + vertex.view = vertexView + vertexView.vertex = vertex + vertex.view?.setIdLabel(text: vertex.identifier) + vertex.view?.setPathLengthLabel(text: "\(vertex.pathLengthFromStart)") + vertex.view?.addTarget(self, action: #selector(self.didTapVertex(sender:)), for: .touchUpInside) + let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(recognizer:))) + vertex.view?.addGestureRecognizer(panGesture) + } + level += 1 + buildViewQueue = self.graph.vertices.filter { $0.level == level } + } + } + + private var movingVertexInputEdges: [EdgeRepresentation] = [] + private var movingVertexOutputEdges: [EdgeRepresentation] = [] + + @objc private func handlePan(recognizer: UIPanGestureRecognizer) { + guard let vertexView = recognizer.view as? VertexView, let vertex = vertexView.vertex else { + return + } + if self.panningView != nil { + if self.panningView != vertexView { + return + } + } + + switch recognizer.state { + case .began: + let movingVertexViewFrame = vertexView.frame + let sizedVertexView = CGRect(x: movingVertexViewFrame.origin.x - 10, + y: movingVertexViewFrame.origin.y - 10, + width: movingVertexViewFrame.width + 20, + height: movingVertexViewFrame.height + 20) + vertex.edges.forEach { edge in + if let edgeRepresentation = edge.edgeRepresentation{ + if sizedVertexView.contains(edgeRepresentation.layer.startPoint!) { + movingVertexOutputEdges.append(edgeRepresentation) + } else { + movingVertexInputEdges.append(edgeRepresentation) + } + } + } + self.panningView = vertexView + case .changed: + if self.movingVertexOutputEdges.isEmpty && self.movingVertexInputEdges.isEmpty { + return + } + let translation = recognizer.translation(in: self) + if vertexView.frame.origin.x + translation.x <= 0 + || vertexView.frame.origin.y + translation.y <= 0 + || (vertexView.frame.origin.x + vertexView.frame.width + translation.x) >= self.frame.width + || (vertexView.frame.origin.y + vertexView.frame.height + translation.y) >= self.frame.height { + break + } + self.movingVertexInputEdges.forEach { edgeRepresentation in + let originalLabelCenter = edgeRepresentation.label.center + edgeRepresentation.label.center = CGPoint(x: originalLabelCenter.x + translation.x * 0.625, + y: originalLabelCenter.y + translation.y * 0.625) + + CATransaction.begin() + CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) + let newPath = self.path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: false) + edgeRepresentation.layer.path = newPath + CATransaction.commit() + + } + + self.movingVertexOutputEdges.forEach { edgeRepresentation in + let originalLabelCenter = edgeRepresentation.label.center + edgeRepresentation.label.center = CGPoint(x: originalLabelCenter.x + translation.x * 0.375, + y: originalLabelCenter.y + translation.y * 0.375) + + CATransaction.begin() + CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) + let newPath = self.path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: true) + edgeRepresentation.layer.path = newPath + CATransaction.commit() + } + + vertexView.center = CGPoint(x: vertexView.center.x + translation.x, + y: vertexView.center.y + translation.y) + recognizer.setTranslation(CGPoint.zero, in: self) + case .ended: + self.movingVertexInputEdges = [] + self.movingVertexOutputEdges = [] + self.panningView = nil + default: + break + } + } + + private func path(fromEdgeRepresentation edgeRepresentation: EdgeRepresentation, movingVertex: Vertex, translation: CGPoint, outPath: Bool) -> CGPath { + let bezier = UIBezierPath() + + if outPath == true { + bezier.move(to: edgeRepresentation.layer.endPoint!) + let startPoint = CGPoint(x: edgeRepresentation.layer.startPoint!.x + translation.x, + y: edgeRepresentation.layer.startPoint!.y + translation.y) + edgeRepresentation.layer.startPoint = startPoint + bezier.addLine(to: startPoint) + } else { + bezier.move(to: edgeRepresentation.layer.startPoint!) + let endPoint = CGPoint(x: edgeRepresentation.layer.endPoint!.x + translation.x, + y: edgeRepresentation.layer.endPoint!.y + translation.y) + edgeRepresentation.layer.endPoint = endPoint + bezier.addLine(to: endPoint) + } + return bezier.cgPath + } + + @objc private func didTapVertex(sender: AnyObject) { + DispatchQueue.main.async { + if self.graph.state == .completed { + for vertex in self.graph.vertices { + vertex.edges.forEach { $0.edgeRepresentation?.setDefaultColor() } + vertex.setVisitedColor() + } + if let vertexView = sender as? VertexView, let vertex = vertexView.vertex { + for (index, pathVertex) in vertex.pathVerticesFromStart.enumerated() { + pathVertex.setCheckingPathColor() + if vertex.pathVerticesFromStart.count > index + 1 { + let nextVertex = vertex.pathVerticesFromStart[index + 1] + + if let edge = pathVertex.edges.filter({ $0.neighbor == nextVertex }).first { + edge.edgeRepresentation?.setCheckingColor() + } + } + + } + } + } else if self.graph.state == .interactiveVisualization { + if let vertexView = sender as? VertexView, let vertex = vertexView.vertex { + if vertex.visited { + return + } else { + self.graph.didTapVertex(vertex: vertex) + } + } + } + } + } + + private func setupEdgeRepresentations() { + var edgeQueue: [Vertex] = [self.graph.startVertex!] + + //BFS + while !edgeQueue.isEmpty { + let currentVertex = edgeQueue.first! + currentVertex.haveAllEdges = true + for edge in currentVertex.edges { + let neighbor = edge.neighbor + let weight = edge.weight + if !neighbor.haveAllEdges { + let edgeRepresentation = EdgeRepresentation(from: currentVertex, to: neighbor, weight: weight) + edge.edgeRepresentation = edgeRepresentation + let index = neighbor.edges.index(where: { $0.neighbor == currentVertex })! + neighbor.edges[index].edgeRepresentation = edgeRepresentation + edgeQueue.append(neighbor) + } + } + edgeQueue.removeFirst() + } + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Edge.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Edge.swift new file mode 100644 index 000000000..6f4493bbe --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Edge.swift @@ -0,0 +1,12 @@ +import Foundation + +public class Edge { + public var neighbor: Vertex + public var weight: Double + public var edgeRepresentation: EdgeRepresentation? + + public init(vertex: Vertex, weight: Double) { + self.neighbor = vertex + self.weight = weight + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift new file mode 100644 index 000000000..c9270b0df --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift @@ -0,0 +1,62 @@ +import UIKit + +public class Vertex: Hashable, Equatable { + private var graphColors: GraphColors = GraphColors.sharedInstance + + public var identifier: String + public var edges: [Edge] = [] + public var pathLengthFromStart: Double = Double.infinity { + didSet { + DispatchQueue.main.async { + self.view?.setPathLengthLabel(text: "\(self.pathLengthFromStart)") + } + } + } + public var pathVerticesFromStart: [Vertex] = [] + public var level: Int = 0 + public var levelChecked: Bool = false + public var haveAllEdges: Bool = false + public var visited: Bool = false + + public var view: VertexView? + + public init(identifier: String) { + self.identifier = identifier + } + + public var hashValue: Int { + return self.identifier.hashValue + } + + public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { + if lhs.hashValue == rhs.hashValue { + return true + } + return false + } + + public func clearCache() { + self.pathLengthFromStart = Double.infinity + self.pathVerticesFromStart = [] + self.visited = false + } + + public func clearLevelInfo() { + self.level = 0 + self.levelChecked = false + } + + public func setVisitedColor() { + self.view?.backgroundColor = self.graphColors.visitedColor + self.view?.setLabelsTextColor(color: UIColor.white) + } + + public func setCheckingPathColor() { + self.view?.backgroundColor = self.graphColors.checkingColor + } + + public func setDefaultColor() { + self.view?.backgroundColor = self.graphColors.defaultVertexColor + self.view?.setLabelsTextColor(color: UIColor.black) + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift new file mode 100644 index 000000000..e8aabad27 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -0,0 +1,319 @@ +import Foundation +import UIKit + +public protocol GraphDelegate: class { + func willCompareVertices(startVertexPathLength: Double, edgePathLength: Double, endVertexPathLength: Double) + func didFinishCompare() + func didCompleteGraphParsing() + func didTapWrongVertex() + func didStop() + func willStartVertexNeighborsChecking() + func didFinishVertexNeighborsChecking() +} + +public class Window: UIView, GraphDelegate { + public var graphView: GraphView! + + private var topView: UIView! + private var createGraphButton: RoundedButton! + private var startVisualizationButton: RoundedButton! + private var startInteractiveVisualizationButton: RoundedButton! + private var startButton: UIButton! + private var pauseButton: UIButton! + private var stopButton: UIButton! + private var comparisonLabel: UILabel! + private var activityIndicator: UIActivityIndicatorView! + private var graph: Graph! + private var numberOfVertices: UInt! + private var graphColors: GraphColors = GraphColors.sharedInstance + + public override init(frame: CGRect) { + super.init(frame: frame) + self.frame = frame + self.backgroundColor = self.graphColors.mainWindowBackgroundColor + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func configure(graph: Graph) { + self.graph = graph + self.graph.createNewGraph() + self.graph.delegate = self + let frame = CGRect(x: 10, y: 170, width: self.frame.width - 20, height: self.frame.height - 180) + self.graphView = GraphView(frame: frame) + self.graphView.layer.cornerRadius = 15 + + self.graphView.configure(graph: self.graph) + self.graphView.createNewGraph() + self.addSubview(self.graphView) + + self.configureCreateGraphButton() + self.configureStartVisualizationButton() + self.configureStartInteractiveVisualizationButton() + self.configureStartButton() + self.configurePauseButton() + self.configureStopButton() + self.configureComparisonLabel() + self.configureActivityIndicator() + + self.topView = UIView(frame: CGRect(x: 10, y: 10, width: self.frame.width - 20, height: 150)) + self.topView.backgroundColor = self.graphColors.topViewBackgroundColor + self.topView.layer.cornerRadius = 15 + self.addSubview(self.topView) + + self.topView.addSubview(self.createGraphButton) + self.topView.addSubview(self.startVisualizationButton) + self.topView.addSubview(self.startInteractiveVisualizationButton) + self.topView.addSubview(self.startButton) + self.topView.addSubview(self.pauseButton) + self.topView.addSubview(self.stopButton) + self.topView.addSubview(self.comparisonLabel) + self.topView.addSubview(self.activityIndicator) + } + + private func configureCreateGraphButton() { + let frame = CGRect(x: self.center.x - 200, y: 12, width: 100, height: 34) + self.createGraphButton = RoundedButton(frame: frame) + self.createGraphButton.setTitle("New graph", for: .normal) + self.createGraphButton.addTarget(self, action: #selector(self.createGraphButtonTap), for: .touchUpInside) + } + + private func configureStartVisualizationButton() { + let frame = CGRect(x: self.center.x - 50, y: 12, width: 100, height: 34) + self.startVisualizationButton = RoundedButton(frame: frame) + self.startVisualizationButton.setTitle("Auto", for: .normal) + self.startVisualizationButton.addTarget(self, action: #selector(self.startVisualizationButtonDidTap), for: .touchUpInside) + } + + private func configureStartInteractiveVisualizationButton() { + let frame = CGRect(x: self.center.x + 100, y: 12, width: 100, height: 34) + self.startInteractiveVisualizationButton = RoundedButton(frame: frame) + self.startInteractiveVisualizationButton.setTitle("Interactive", for: .normal) + self.startInteractiveVisualizationButton.addTarget(self, action: #selector(self.startInteractiveVisualizationButtonDidTap), for: .touchUpInside) + } + + private func configureStartButton() { + let frame = CGRect(x: self.center.x - 65, y: 56, width: 30, height: 30) + self.startButton = UIButton(frame: frame) + let playImage = UIImage(named: "Start.png") + self.startButton.setImage(playImage, for: .normal) + self.startButton.isEnabled = false + self.startButton.addTarget(self, action: #selector(self.didTapStartButton), for: .touchUpInside) + } + + private func configurePauseButton() { + let frame = CGRect(x: self.center.x - 15, y: 56, width: 30, height: 30) + self.pauseButton = UIButton(frame: frame) + let pauseImage = UIImage(named: "Pause.png") + self.pauseButton.setImage(pauseImage, for: .normal) + self.pauseButton.isEnabled = false + self.pauseButton.addTarget(self, action: #selector(self.didTapPauseButton), for: .touchUpInside) + } + + private func configureStopButton() { + let frame = CGRect(x: self.center.x + 35, y: 56, width: 30, height: 30) + self.stopButton = UIButton(frame: frame) + let stopImage = UIImage(named: "Stop.png") + self.stopButton.setImage(stopImage, for: .normal) + self.stopButton.isEnabled = false + self.stopButton.addTarget(self, action: #selector(self.didTapStopButton), for: .touchUpInside) + } + + private func configureComparisonLabel() { + let size = CGSize(width: 250, height: 42) + let origin = CGPoint(x: self.center.x - 125, y: 96) + let frame = CGRect(origin: origin, size: size) + self.comparisonLabel = UILabel(frame: frame) + self.comparisonLabel.textAlignment = .center + self.comparisonLabel.text = "Have fun!" + } + + private func configureActivityIndicator() { + let size = CGSize(width: 50, height: 42) + let origin = CGPoint(x: self.center.x - 25, y: 100) + let activityIndicatorFrame = CGRect(origin: origin, size: size) + self.activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) + self.activityIndicator.activityIndicatorViewStyle = .whiteLarge + } + + @objc private func createGraphButtonTap() { + self.comparisonLabel.text = "" + self.graphView.removeGraph() + self.graph.removeGraph() + self.graph.createNewGraph() + self.graphView.createNewGraph() + self.graph.state = .initial + } + + @objc private func startVisualizationButtonDidTap() { + self.comparisonLabel.text = "" + self.pauseButton.isEnabled = true + self.stopButton.isEnabled = true + self.createGraphButton.isEnabled = false + self.startVisualizationButton.isEnabled = false + self.startInteractiveVisualizationButton.isEnabled = false + self.createGraphButton.alpha = 0.5 + self.startVisualizationButton.alpha = 0.5 + self.startInteractiveVisualizationButton.alpha = 0.5 + + if self.graph.state == .completed { + self.graphView.reset() + self.graph.reset() + } + self.graph.state = .autoVisualization + DispatchQueue.global(qos: .background).async { + self.graph.findShortestPathsWithVisualization { + self.graph.state = .completed + + DispatchQueue.main.async { + self.startButton.isEnabled = false + self.pauseButton.isEnabled = false + self.stopButton.isEnabled = false + self.createGraphButton.isEnabled = true + self.startVisualizationButton.isEnabled = true + self.startInteractiveVisualizationButton.isEnabled = true + self.createGraphButton.alpha = 1 + self.startVisualizationButton.alpha = 1 + self.startInteractiveVisualizationButton.alpha = 1 + self.comparisonLabel.text = "Completed!" + } + } + } + } + + @objc private func startInteractiveVisualizationButtonDidTap() { + self.comparisonLabel.text = "" + self.pauseButton.isEnabled = true + self.stopButton.isEnabled = true + self.createGraphButton.isEnabled = false + self.startVisualizationButton.isEnabled = false + self.startInteractiveVisualizationButton.isEnabled = false + self.createGraphButton.alpha = 0.5 + self.startVisualizationButton.alpha = 0.5 + self.startInteractiveVisualizationButton.alpha = 0.5 + + if self.graph.state == .completed { + self.graphView.reset() + self.graph.reset() + } + + self.graph.startVertex.pathLengthFromStart = 0 + self.graph.startVertex.pathVerticesFromStart.append(self.graph.startVertex) + self.graph.state = .parsing + self.graph.parseNeighborsFor(vertex: self.graph.startVertex) { + self.graph.state = .interactiveVisualization + DispatchQueue.main.async { + self.comparisonLabel.text = "Pick next vertex" + } + } + } + + @objc private func didTapStartButton() { + self.startButton.isEnabled = false + self.pauseButton.isEnabled = true + DispatchQueue.global(qos: .utility).async { + self.graph.pauseVisualization = false + } + } + + @objc private func didTapPauseButton() { + self.startButton.isEnabled = true + self.pauseButton.isEnabled = false + DispatchQueue.global(qos: .utility).async { + self.graph.pauseVisualization = true + } + } + + @objc private func didTapStopButton() { + self.startButton.isEnabled = false + self.pauseButton.isEnabled = false + self.comparisonLabel.text = "" + self.activityIndicator.startAnimating() + if self.graph.state == .parsing || self.graph.state == .autoVisualization { + self.graph.stopVisualization = true + } else if self.graph.state == .interactiveVisualization { + self.didStop() + } + } + + private func setButtonsToInitialState() { + self.createGraphButton.isEnabled = true + self.startVisualizationButton.isEnabled = true + self.startInteractiveVisualizationButton.isEnabled = true + self.startButton.isEnabled = false + self.pauseButton.isEnabled = false + self.stopButton.isEnabled = false + self.createGraphButton.alpha = 1 + self.startVisualizationButton.alpha = 1 + self.startInteractiveVisualizationButton.alpha = 1 + } + + private func showError(error: String) { + DispatchQueue.main.async { + let size = CGSize(width: 250, height: 42) + let origin = CGPoint(x: self.topView.center.x - 125, y: 96) + let frame = CGRect(origin: origin, size: size) + let errorView = ErrorView(frame: frame) + errorView.setText(text: error) + self.topView.addSubview(errorView) + UIView.animate(withDuration: 2, animations: { + errorView.alpha = 0 + }, completion: { _ in + errorView.removeFromSuperview() + }) + } + } + + // MARK: GraphDelegate + public func didCompleteGraphParsing() { + self.graph.state = .completed + self.setButtonsToInitialState() + self.comparisonLabel.text = "Completed!" + } + + public func didTapWrongVertex() { + if !self.subviews.contains { $0 is ErrorView } { + self.showError(error: "You have picked wrong next vertex") + } + } + + public func willCompareVertices(startVertexPathLength: Double, edgePathLength: Double, endVertexPathLength: Double) { + DispatchQueue.main.async { + if startVertexPathLength + edgePathLength < endVertexPathLength { + self.comparisonLabel.text = "\(startVertexPathLength) + \(edgePathLength) < \(endVertexPathLength) 👍" + } else { + self.comparisonLabel.text = "\(startVertexPathLength) + \(edgePathLength) >= \(endVertexPathLength) 👎" + } + } + } + + public func didFinishCompare() { + DispatchQueue.main.async { + self.comparisonLabel.text = "" + } + } + + public func didStop() { + self.graph.state = .initial + self.graph.stopVisualization = false + self.graph.pauseVisualization = false + self.graphView.reset() + self.graph.reset() + self.setButtonsToInitialState() + self.activityIndicator.stopAnimating() + } + + public func willStartVertexNeighborsChecking() { + DispatchQueue.main.async { + self.comparisonLabel.text = "" + } + } + + public func didFinishVertexNeighborsChecking() { + DispatchQueue.main.async { + self.comparisonLabel.text = "Pick next vertex" + } + } +} diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/contents.xcplayground b/Dijkstra Algorithm/VisualizedDijkstra.playground/contents.xcplayground new file mode 100644 index 000000000..35968656f --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/contents.xcworkspacedata b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/timeline.xctimeline b/Dijkstra Algorithm/VisualizedDijkstra.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/README.markdown b/README.markdown index 5e6cfbfe4..eee5cbb46 100644 --- a/README.markdown +++ b/README.markdown @@ -183,6 +183,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Single-Source Shortest Paths](Single-Source%20Shortest%20Paths%20(Weighted)/) - [Minimum Spanning Tree](Minimum%20Spanning%20Tree%20%28Unweighted%29/) on an unweighted tree - [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) +- [Dijkstra's shortest path algorithm](Dijkstra%20Algorithm/) ## Puzzles From 8efb7354645763fce0823ec74c2fe3ffb904f4df Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Tue, 4 Apr 2017 10:25:36 +0100 Subject: [PATCH 0487/1275] MIT License --- MinimumCoinChange/LICENSE | 222 ++++---------------------------------- 1 file changed, 21 insertions(+), 201 deletions(-) diff --git a/MinimumCoinChange/LICENSE b/MinimumCoinChange/LICENSE index 8dada3eda..fda6e6146 100755 --- a/MinimumCoinChange/LICENSE +++ b/MinimumCoinChange/LICENSE @@ -1,201 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +MIT License + +Copyright (c) 2017 Jacopo Mangiavacchi + +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. From 63257f629f99ba76a7997a1e0b18b8236cefa57b Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 4 Apr 2017 13:37:53 -0700 Subject: [PATCH 0488/1275] fixed typos in readme --- Strassen Matrix Multiplication/README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown index fa822d310..07ce534b2 100644 --- a/Strassen Matrix Multiplication/README.markdown +++ b/Strassen Matrix Multiplication/README.markdown @@ -18,7 +18,7 @@ matrix A = |1 2|, matrix B = |5 6| A * B = C |1 2| * |5 6| = |1*5+2*7 1*6+2*8| = |19 22| -|3 4| |7 8| |3*5+4*7 3*6+4*8| |43 48| +|3 4| |7 8| |3*5+4*7 3*6+4*8| |43 50| ``` What's going on here? To start, we're multiplying matricies A & B. Our new matrix, C's, elements `[i, j]` are determined by the dot product of the first matrix's ith row and the second matrix's jth column. See [here](https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/dot-cross-products/v/vector-dot-product-and-vector-length) for a refresher on the dot product. @@ -72,7 +72,7 @@ Then, for each row in A and column in B, we take the dot product of the ith row ```swift for k in 0..) -> Matrix { for i in 0.. Date: Tue, 4 Apr 2017 14:07:19 -0700 Subject: [PATCH 0489/1275] Update README.markdown --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 5e6cfbfe4..067de2418 100644 --- a/README.markdown +++ b/README.markdown @@ -106,6 +106,7 @@ Bad sorting algorithms (don't use these!): - Statistics - [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication. - [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. +- [Strassen's Multiplication Matrix](Strassen%20Multiplication%20Matrix). Efficient way to handle matrix multiplication. ### Machine learning From bbba068205500a62943a601540d4dfba205586f2 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 4 Apr 2017 14:09:02 -0700 Subject: [PATCH 0490/1275] Updated a link to Strassen Multiplication Matrix. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 067de2418..29fc9d748 100644 --- a/README.markdown +++ b/README.markdown @@ -106,7 +106,7 @@ Bad sorting algorithms (don't use these!): - Statistics - [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication. - [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. -- [Strassen's Multiplication Matrix](Strassen%20Multiplication%20Matrix). Efficient way to handle matrix multiplication. +- [Strassen's Multiplication Matrix](Strassen%20Matrix%20Multiplication/). Efficient way to handle matrix multiplication. ### Machine learning From 20d7c1fd66b93c2a3933abe5d048169cea888ced Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Tue, 4 Apr 2017 17:46:46 -0700 Subject: [PATCH 0491/1275] Revisions in README.md # Coherence & Sentence structures # Grammar and spelling --- DiningPhilosophers/README.md | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index ec1611c65..0bf4f28ce 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -1,22 +1,22 @@ # Dining Philosophers -Dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using [GCD](https://apple.github.io/swift-corelibs-libdispatch/) and [Semaphore](https://developer.apple.com/reference/dispatch/dispatchsemaphore) in Swift) +The dining philosophers problem Algorithm implemented in Swift (concurrent algorithm design to illustrate synchronization issues and techniques for resolving them using [GCD](https://apple.github.io/swift-corelibs-libdispatch/) and [Semaphore](https://developer.apple.com/reference/dispatch/dispatchsemaphore) in Swift) Written for Swift Algorithm Club by Jacopo Mangiavacchi # Introduction -In computer science, the dining philosophers problem is an example problem often used in concurrent algorithm design to illustrate synchronization issues and techniques for resolving them. +In computer science, the dining philosophers problem is often used in the concurrent algorithm design to illustrate synchronization issues and techniques for resolving them. It was originally formulated in 1965 by Edsger Dijkstra as a student exam exercise, presented in terms of computers competing for access to tape drive peripherals. Soon after, Tony Hoare gave the problem its present formulation. -This Swift implementation is based on the Chandy/Misra solution and it use GCD Dispatch and Semaphone on Swift cross platform +This Swift implementation is based on the Chandy/Misra solution, and it uses the GCD Dispatch and Semaphone on the Swift cross platform. # Problem statement Five silent philosophers sit at a round table with bowls of spaghetti. Forks are placed between each pair of adjacent philosophers. -Each philosopher must alternately think and eat. However, a philosopher can only eat spaghetti when they have both left and right forks. Each fork can be held by only one philosopher and so a philosopher can use the fork only if it is not being used by another philosopher. After an individual philosopher finishes eating, they need to put down both forks so that the forks become available to others. A philosopher can take the fork on their right or the one on their left as they become available, but cannot start eating before getting both forks. +Each philosopher must alternately think and eat. A philosopher can only eat spaghetti when they have both left and right forks. Since each fork can be held by only one philosopher, a philosopher can use the fork only if it is not being used by another philosopher. When a philosopher finishes eating, they need to put down both forks so that the forks become available to others. A philosopher can take the fork on their right or the one on their left as they become available, but they cannot start eating before getting both forks. Eating is not limited by the remaining amounts of spaghetti or stomach space; an infinite supply and an infinite demand are assumed. @@ -26,35 +26,32 @@ This is an illustration of an dinining table: ![Dining Philosophers table](https://upload.wikimedia.org/wikipedia/commons/7/7b/An_illustration_of_the_dining_philosophers_problem.png) - # Solution -There are different solutions for this classic algorithm and this Swift implementation is based on the on the Chandy/Misra solution that more generally allows for arbitrary agents to contend for an arbitrary number of resources in a completely distributed scenario with no needs for a central authority to control the locking and serialization of resources. - -However, it is very important to note here that this solution violates the requirement that "the philosophers do not speak to each other" (due to the request messages). +There are different solutions for this classic algorithm, and this Swift implementation is based on the Chandy/Misra solution. This implementation allows agents to contend for an arbitrary number of resources in a completely distributed scenario with no needs for a central authority to control the locking and serialization of resources. +However, this solution violates the requirement that "the philosophers do not speak to each other" (due to the request messages). # Description For every pair of philosophers contending for a resource, create a fork and give it to the philosopher with the lower ID (n for agent Pn). Each fork can either be dirty or clean. Initially, all forks are dirty. -When a philosopher wants to use a set of resources (i.e. eat), said philosopher must obtain the forks from their contending neighbors. For all such forks the philosopher does not have, they send a request message. -When a philosopher with a fork receives a request message, they keep the fork if it is clean, but give it up when it is dirty. If the philosopher sends the fork over, they clean the fork before doing so. +When a philosopher wants to use a set of resources (i.e. eat), said philosopher must obtain the forks from their contending neighbors. The philospher send a message for all such forks needed. When a philosopher with a fork receives a request message, they keep the fork if it is clean, but give it up when it is dirty. If the philosopher sends the fork over, they clean the fork before doing so. After a philosopher is done eating, all their forks become dirty. If another philosopher had previously requested one of the forks, the philosopher that has just finished eating cleans the fork and sends it. -This solution also allows for a large degree of concurrency, and will solve an arbitrarily large problem. +This solution also allows for a large degree of concurrency, and it will solve an arbitrarily large problem. -It also solves the starvation problem. The clean / dirty labels act as a way of giving preference to the most "starved" processes, and a disadvantage to processes that have just "eaten". One could compare their solution to one where philosophers are not allowed to eat twice in a row without letting others use the forks in between. Chandy and Misra's solution is more flexible than that, but has an element tending in that direction. +In addition, it solves the starvation problem. The clean / dirty labels give a preference to the most "starved" processes and a disadvantage to processes that have just "eaten". One could compare their solution to one where philosophers are not allowed to eat twice in a row without letting others use the forks in between. The Chandy and Misra's solution is more flexible but has an element tending in that direction. -In their analysis they derive a system of preference levels from the distribution of the forks and their clean/dirty states. They show that this system may describe an acyclic graph, and if so, the operations in their protocol cannot turn that graph into a cyclic one. This guarantees that deadlock cannot occur. However, if the system is initialized to a perfectly symmetric state, like all philosophers holding their left side forks, then the graph is cyclic at the outset, and their solution cannot prevent a deadlock. Initializing the system so that philosophers with lower IDs have dirty forks ensures the graph is initially acyclic. +Based on the Chandy and Misra's analysis, a system of preference levels is derived from the distribution of the forks and their clean/dirty states. This system may describe an acyclic graph, and if so, the solution's protocol cannot turn that graph into a cyclic one. This guarantees that deadlock cannot occur. However, if the system is initialized to a perfectly symmetric state, such as all philosophers holding their left side forks, then the graph is cyclic at the outset, and the solution cannot prevent a deadlock. Initializing the system so that philosophers with lower IDs have dirty forks ensures the graph is initially acyclic. # Swift implementation -This Swift 3.0 implementation of the Chandy/Misra solution is based on GCD and Semaphore tecnique and it could be built on both macOS and Linux. +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. 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. The ForkPair DispatchSemaphore static array is used for waking the neighbour Philosophers any time a fork pair is put down on the table. -A background DispatchQueue is then used to let any Philosopher run asyncrounosly on the background and a global DispatchSemaphore is simply used in order to keep the main thread on wait forever and let the Philosophers contienue forever in their alternate think and eat cycle. - +A background DispatchQueue is then used to let any Philosopher run asyncrounosly on the background, and a global DispatchSemaphore is used to keep the main thread on wait forever and let the Philosophers continue forever in their alternate think and eat cycle. + # See also Dining Philosophers on Wikipedia https://en.wikipedia.org/wiki/Dining_philosophers_problem From 56c5ecf2c5c6baf4b7442dbf46db5c9d13fda523 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Tue, 4 Apr 2017 19:31:26 -0700 Subject: [PATCH 0492/1275] Revisions in README.markdown 1- Coherence, Sentence structure, & Consistency 2- Grammar, Word choice, & Spelling --- Huffman Coding/README.markdown | 82 +++++++++++++++++----------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 4e6f75514..69e105c87 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -1,12 +1,12 @@ # Huffman Coding -The idea: Encode objects that occur often with a smaller number of bits than objects that occur less frequently. +The idea: To encode objects that occur with a smaller number of bits than objects that occur less frequently. -Although you can encode any type of objects with this scheme, it's most common to compress a stream of bytes. Let's say you have the following text, where each character is one byte: +Although any type of objects can be encoded with this scheme, it is common to compress a stream of bytes. Suppose you have the following text, where each character is one byte: so much words wow many compression -If you count how often each byte appears, you can clearly see that some bytes occur more than others: +If you count how often each byte appears, you can see some bytes occur more than others: space: 5 u: 1 o: 5 h: 1 @@ -41,11 +41,11 @@ Now if we replace the original bytes with these bit strings, the compressed outp The extra 0-bit at the end is there to make a full number of bytes. We were able to compress the original 34 bytes into merely 16 bytes, a space savings of over 50%! -But hold on... to be able to decode these bits we need to have the original frequency table. That table needs to be transmitted or saved along with the compressed data, otherwise the decoder doesn't know how to interpret the bits. Because of the overhead of this frequency table (about 1 kilobyte), it doesn't really pay to use Huffman encoding on very small inputs. +To be able to decode these bits, we need to have the original frequency table. That table needs to be transmitted or saved along with the compressed data. Otherwise, the decoder does not know how to interpret the bits. Because of the overhead of this frequency table (about 1 kilobyte), it is not beneficial to use Huffman encoding on small inputs. ## How it works -When compressing a stream of bytes, the algorithm first creates a frequency table that counts how often each byte occurs. Based on this table it creates a binary tree that describes the bit strings for each of the input bytes. +When compressing a stream of bytes, the algorithm first creates a frequency table that counts how often each byte occurs. Based on this table, the algorithm creates a binary tree that describes the bit strings for each of the input bytes. For our example, the tree looks like this: @@ -53,17 +53,17 @@ For our example, the tree looks like this: Note that the tree has 16 leaf nodes (the grey ones), one for each byte value from the input. Each leaf node also shows the count of how often it occurs. The other nodes are "intermediate" nodes. The number shown in these nodes is the sum of the counts of their child nodes. The count of the root node is therefore the total number of bytes in the input. -The edges between the nodes either say "1" or "0". These correspond to the bit-encodings of the leaf nodes. Notice how each left branch is always 1 and each right branch is always 0. +The edges between the nodes are either "1" or "0". These correspond to the bit-encodings of the leaf nodes. Notice how each left branch is always 1 and each right branch is always 0. -Compression is then a matter of looping through the input bytes, and for each byte traverse the tree from the root node to that byte's leaf node. Every time we take a left branch, we emit a 1-bit. When we take a right branch, we emit a 0-bit. +Compression is then a matter of looping through the input bytes and for each byte traversing the tree from the root node to that byte's leaf node. Every time we take a left branch, we emit a 1-bit. When we take a right branch, we emit a 0-bit. -For example, to go from the root node to `c`, we go right (`0`), right again (`0`), left (`1`), and left again (`1`). So the Huffman code for `c` is `0011`. +For example, to go from the root node to `c`, we go right (`0`), right again (`0`), left (`1`), and left again (`1`). This gives the Huffman code as `0011` for `c`. -Decompression works in exactly the opposite way. It reads the compressed bits one-by-one and traverses the tree until we get to a leaf node. The value of that leaf node is the uncompressed byte. For example, if the bits are `11010`, we start at the root and go left, left again, right, left, and a final right to end up at `d`. +Decompression works in exactly the opposite way. It reads the compressed bits one-by-one and traverses the tree until it reaches to a leaf node. The value of that leaf node is the uncompressed byte. For example, if the bits are `11010`, we start at the root and go left, left again, right, left, and a final right to end up at `d`. ## The code -Before we get to the actual Huffman coding scheme, it's useful to have some helper code that can write individual bits to an `NSData` object. The smallest piece of data that `NSData` understands is the byte, but we're dealing in bits, so we need to translate between the two. +Before we get to the actual Huffman coding scheme, it is useful to have some helper code that can write individual bits to an `NSData` object. The smallest piece of data that `NSData` understands is the byte, but we are dealing in bits, so we need to translate between the two. ```swift public class BitWriter { @@ -92,11 +92,11 @@ public class BitWriter { } ``` -To add a bit to the `NSData` you call `writeBit()`. This stuffs each new bit into the `outByte` variable. Once you've written 8 bits, `outByte` gets added to the `NSData` object for real. +To add a bit to the `NSData`, you can call `writeBit()`. This helper object stuffs each new bit into the `outByte` variable. Once you have written 8 bits, `outByte` gets added to the `NSData` object for real. The `flush()` method is used for outputting the very last byte. There is no guarantee that the number of compressed bits is a nice round multiple of 8, in which case there may be some spare bits at the end. If so, `flush()` adds a few 0-bits to make sure that we write a full byte. -We'll use a similar helper object for reading individual bits from `NSData`: +Here is a similar helper object for reading individual bits from `NSData`: ```swift public class BitReader { @@ -122,15 +122,15 @@ public class BitReader { } ``` -This works in a similar fashion. We read one whole byte from the `NSData` object and put it in `inByte`. Then `readBit()` returns the individual bits from that byte. Once `readBit()` has been called 8 times, we read the next byte from the `NSData`. +By using this helper object, we can read one whole byte from the `NSData` object and put it in `inByte`. Then, `readBit()` returns the individual bits from that byte. Once `readBit()` has been called 8 times, we read the next byte from the `NSData`. -> **Note:** It's no big deal if you're unfamiliar with this sort of bit manipulation. Just know that these two helper objects make it simple for us to write and read bits and not worry about all the messy stuff of making sure they end up in the right place. +> **Note:** If you are unfamiliar with this type of bit manipulation, just know that these two helper objects make it simple for us to write and read bits. ## The frequency table -The first step in Huffman compression is to read the entire input stream and build a frequency table. This table contains a list of all 256 possible byte values and how often each of these bytes occurs in the input data. +The first step in the Huffman compression is to read the entire input stream and build a frequency table. This table contains a list of all 256 possible byte values and shows how often each of these bytes occurs in the input data. -We could store this frequency information in a dictionary or an array, but since we're going to need to build a tree anyway, we might as well store the frequency table as the leaves of the tree. +We could store this frequency information in a dictionary or an array, but since we need to build a tree, we might store the frequency table as the leaves of the tree. Here are the definitions we need: @@ -152,9 +152,9 @@ class Huffman { } ``` -The tree structure is stored in the `tree` array and will be made up of `Node` objects. Since this is a [binary tree](../Binary%20Tree/), each node needs two children, `left` and `right`, and a reference back to its `parent` node. Unlike a typical binary tree, however, these nodes don't to use pointers to refer to each other but simple integer indices in the `tree` array. (We also store the array `index` of the node itself; the reason for this will become clear later.) +The tree structure is stored in the `tree` array and will be made up of `Node` objects. Since this is a [binary tree](../Binary%20Tree/), each node needs two children, `left` and `right`, and a reference back to its `parent` node. Unlike a typical binary tree, these nodes do not use pointers to refer to each other but use simple integer indices in the `tree` array. (We also store the array `index` of the node itself; the reason for this will become clear later.) -Note that `tree` currently has room for 256 entries. These are for the leaf nodes because there are 256 possible byte values. Of course, not all of those may end up being used, depending on the input data. Later, we'll add more nodes as we build up the actual tree. For the moment there isn't a tree yet, just 256 separate leaf nodes with no connections between them. All the node counts are 0. +Note that the `tree` currently has room for 256 entries. These are for the leaf nodes because there are 256 possible byte values. Of course, not all of those may end up being used, depending on the input data. Later, we will add more nodes as we build up the actual tree. For the moment, there is not a tree yet. It includes 256 separate leaf nodes with no connections between them. All the node counts are 0. We use the following method to count how often each byte occurs in the input data: @@ -170,13 +170,13 @@ We use the following method to count how often each byte occurs in the input dat } ``` -This steps through the `NSData` object from beginning to end and for each byte increments the `count` of the corresponding leaf node. That's all there is to it. After `countByteFrequency()` completes, the first 256 `Node` objects in the `tree` array represent the frequency table. +This steps through the `NSData` object from beginning to end and for each byte increments the `count` of the corresponding leaf node. After `countByteFrequency()` completes, the first 256 `Node` objects in the `tree` array represent the frequency table. -Now, I mentioned that in order to decompress a Huffman-encoded block of data, you also need to have the original frequency table. If you were writing the compressed data to a file, then somewhere in the file you'd include the frequency table. +To decompress a Huffman-encoded block of data, we need to have the original frequency table. If we were writing the compressed data to a file, then somewhere in the file we should include the frequency table. -You could simply dump the first 256 elements from the `tree` array but that's not very efficient. It's likely that not all of these 256 elements will be used, plus you don't need to serialize the `parent`, `right`, and `left` pointers. All we need is the frequency information, not the entire tree. +We could dump the first 256 elements from the `tree` array, but that is not efficient. Not all of these 256 elements will be used, and we do not need to serialize the `parent`, `right`, and `left` pointers. All we need is the frequency information and not the entire tree. -Instead, we'll add a method to export the frequency table without all the pieces we don't need: +Instead, we will add a method to export the frequency table without all the pieces we do not need: ```swift struct Freq { @@ -193,7 +193,7 @@ Instead, we'll add a method to export the frequency table without all the pieces } ``` -The `frequencyTable()` method looks at those first 256 nodes from the tree but keeps only those that are actually used, without the `parent`, `left`, and `right` pointers. It returns an array of `Freq` objects. You have to serialize this array along with the compressed data so that it can be properly decompressed later. +The `frequencyTable()` method looks at those first 256 nodes from the tree but keeps only those that are used, without the `parent`, `left`, and `right` pointers. It returns an array of `Freq` objects. You have to serialize this array along with the compressed data, so that it can be properly decompressed later. ## The tree @@ -201,7 +201,7 @@ As a reminder, there is the compression tree for the example: ![The compression tree](Images/Tree.png) -The leaf nodes represent the actual bytes that are present in the input data. The intermediary nodes connect the leaves in such a way that the path from the root to a frequently-used byte value is shorter than the path to a less common byte value. As you can see, `m`, `s`, space, and `o` are the most common letters in our input data and therefore they are highest up in the tree. +The leaf nodes represent the actual bytes that are present in the input data. The intermediary nodes connect the leaves in such a way that the path from the root to a frequently-used byte value is shorter than the path to a less common byte value. As you can see, `m`, `s`, space, and `o` are the most common letters in our input data and the highest up in the tree. To build the tree, we do the following: @@ -209,7 +209,7 @@ To build the tree, we do the following: 2. Create a new parent node that links these two nodes together. 3. This repeats over and over until only one node with no parent remains. This becomes the root node of the tree. -This is an ideal place to use a [priority queue](../Priority%20Queue/). A priority queue is a data structure that is optimized so that finding the minimum value is always very fast. Here, we repeatedly need to find the node with the smallest count. +This is an ideal place to use a [priority queue](../Priority%20Queue/). A priority queue is a data structure that is optimized, so that finding the minimum value is always fast. Here, we repeatedly need to find the node with the smallest count. The function `buildTree()` then becomes: @@ -252,15 +252,15 @@ Here is how it works step-by-step: 4. Link the two nodes into their new parent node. Now this new intermediate node has become part of the tree. -5. Put the new intermediate node back into the queue. At this point we're done with `node1` and `node2`, but the `parentNode` still need to be connected to other nodes in the tree. +5. Put the new intermediate node back into the queue. At this point we are done with `node1` and `node2`, but the `parentNode` still needs to be connected to other nodes in the tree. -6. Repeat steps 2-5 until there is only one node left in the queue. This becomes the root node of the tree, and we're done. +6. Repeat steps 2-5 until there is only one node left in the queue. This becomes the root node of the tree, and we are done. The animation shows what the process looks like: ![Building the tree](Images/BuildTree.gif) -> **Note:** Instead of using a priority queue, you can repeatedly iterate through the `tree` array to find the next two smallest nodes, but that makes the compressor quite slow, **O(n^2)**. Using the priority queue, the running time is only **O(n log n)** where **n** is the number of nodes. +> **Note:** Instead of using a priority queue, you can repeatedly iterate through the `tree` array to find the next two smallest nodes, but that makes the compressor slow as **O(n^2)**. Using the priority queue, the running time is only **O(n log n)** where **n** is the number of nodes. > **Fun fact:** Due to the nature of binary trees, if we have *x* leaf nodes we can at most add *x - 1* additional nodes to the tree. Given that at most there will be 256 leaf nodes, the tree will never contain more than 511 nodes total. @@ -286,11 +286,11 @@ Now that we know how to build the compression tree from the frequency table, we } ``` -This first calls `countByteFrequency()` to build the frequency table, then `buildTree()` to put together the compression tree. It also creates a `BitWriter` object for writing individual bits. +This first calls `countByteFrequency()` to build the frequency table and then calls `buildTree()` to put together the compression tree. It also creates a `BitWriter` object for writing individual bits. -Then it loops through the entire input and for each byte calls `traverseTree()`. That method will step through the tree nodes and for each node write a 1 or 0 bit. Finally, we return the `BitWriter`'s data object. +Then, it loops through the entire input and calls `traverseTree()`for each byte. This method will step through the tree nodes and for each node write a 1 or 0 bit. Finally, we return the `BitWriter`'s data object. -> **Note:** Compression always requires two passes through the entire input data: first to build the frequency table, second to convert the bytes to their compressed bit sequences. +> **Note:** Compression always requires two passes through the entire input data: first to build the frequency table, and second to convert the bytes to their compressed bit sequences. The interesting stuff happens in `traverseTree()`. This is a recursive method: @@ -309,15 +309,15 @@ The interesting stuff happens in `traverseTree()`. This is a recursive method: } ``` -When we call this method from `compressData()`, the `nodeIndex` parameter is the array index of the leaf node for the byte that we're about to encode. This method recursively walks the tree from a leaf node up to the root, and then back again. +When we call this method from `compressData()`, the `nodeIndex` parameter is the array index of the leaf node for the byte that we need to encode. This method recursively walks the tree from a leaf node up to the root and then back again. -As we're going back from the root to the leaf node, we write a 1 bit or a 0 bit for every node we encounter. If a child is the left node, we emit a 1; if it's the right node, we emit a 0. +As we are going back from the root to the leaf node, we write a 1 bit or a 0 bit for every node we encounter. If a child is the left node, we emit a 1; if it is the right node, we emit a 0. In a picture: ![How compression works](Images/Compression.png) -Even though the illustration of the tree shows a 0 or 1 for each edge between the nodes, the bit values 0 and 1 aren't actually stored in the tree! The rule is that we write a 1 bit if we take the left branch and a 0 bit if we take the right branch, so just knowing the direction we're going in is enough to determine what bit value to write. +Even though the illustration of the tree shows a 0 or 1 for each edge between the nodes, the bit values 0 and 1 are not actually stored in the tree! The rule is that we write a 1 bit if we take the left branch and a 0 bit if we take the right branch, so just knowing the direction we are going in is enough to determine what bit value to write. You use the `compressData()` method as follows: @@ -332,9 +332,9 @@ if let originalData = s1.dataUsingEncoding(NSUTF8StringEncoding) { ## Decompression -Decompression is pretty much compression in reverse. However, the compressed bits are useless to us without the frequency table. Earlier you saw the `frequencyTable()` method that returns an array of `Freq` objects. The idea is that if you were saving the compressed data into a file or sending it across the network, you'd also save that `[Freq]` array along with it. +Decompression is the compression in reverse. However, the compressed bits are useless without the frequency table. As mentioned, the `frequencyTable()` method returns an array of `Freq` objects. If we were saving the compressed data into a file or sending it across the network, we'd also save that `[Freq]` array along with it. -We first need some way to turn the `[Freq]` array back into a compression tree. Fortunately, this is pretty easy: +We first need some way to turn the `[Freq]` array back into a compression tree: ```swift fileprivate func restoreTree(fromTable frequencyTable: [Freq]) { @@ -349,7 +349,7 @@ We first need some way to turn the `[Freq]` array back into a compression tree. We convert the `Freq` objects into leaf nodes and then call `buildTree()` to do the rest. -Here is the code for `decompressData()`, which takes an `NSData` object with Huffman-encoded bits and a frequency table, and returns the original data: +Here is the code for `decompressData()`, which takes an `NSData` object with Huffman-encoded bits and a frequency table, and it returns the original data: ```swift func decompressData(data: NSData, frequencyTable: [Freq]) -> NSData { @@ -385,13 +385,13 @@ This also uses a helper method to traverse the tree: } ``` -`findLeafNode()` walks the tree from the root down to the leaf node given by `nodeIndex`. At each intermediate node we read a new bit and then step to the left (bit is 1) or the right (bit is 0). When we get to the leaf node, we simply return its index, which is equal to the original byte value. +`findLeafNode()` walks the tree from the root down to the leaf node given by `nodeIndex`. At each intermediate node, we read a new bit and then step to the left (bit is 1) or the right (bit is 0). When we get to the leaf node, we simply return its index, which is equal to the original byte value. In a picture: ![How decompression works](Images/Decompression.png) -Here's how you would use the decompression method: +Here is how we use the decompression method: ```swift let frequencyTable = huffman1.frequencyTable() @@ -402,9 +402,9 @@ Here's how you would use the decompression method: let s2 = String(data: decompressedData, encoding: NSUTF8StringEncoding)! ``` -First you get the frequency table from somewhere (in this case the `Huffman` object we used to encode the data) and then call `decompressData()`. The string that results should be equal to the one you compressed in the first place. +First we get the frequency table from somewhere (in this case the `Huffman` object we used to encode the data) and then call `decompressData()`. The string that results should be equal to the one we compressed in the first place. -You can see how this works in more detail in the Playground. +we can see how this works in more detail in the Playground. ## See also From d70f40ed8668e60584dc1bd9d5b859b7ad2e91de Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Wed, 5 Apr 2017 10:34:21 -0700 Subject: [PATCH 0493/1275] Revisions in README.markdown I have revised your document to be simplified and concise. --- Array2D/README.markdown | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Array2D/README.markdown b/Array2D/README.markdown index d67079691..88f25c99a 100644 --- a/Array2D/README.markdown +++ b/Array2D/README.markdown @@ -1,14 +1,14 @@ # Array2D -In C and Objective-C you can write the following line, +In C and Objective-C, you can write the following line, int cookies[9][7]; -to make a 9x7 grid of cookies. This would create a two-dimensional array of 63 elements. To find the cookie at column 3, row 6, you'd write: +to make a 9x7 grid of cookies. This creates a two-dimensional array of 63 elements. To find the cookie at column 3 and row 6, you can write: myCookie = cookies[3][6]; -Unfortunately, you can't write the above in Swift. To create a multi-dimensional array in Swift you'd have to do something like this: +This statement is not acceptable in Swift. To create a multi-dimensional array in Swift, you can write: ```swift var cookies = [[Int]]() @@ -21,19 +21,19 @@ for _ in 1...9 { } ``` -And then to find a cookie: +Then, to find a cookie, you can write: ```swift let myCookie = cookies[3][6] ``` -Actually, you could create the array in a single line of code, like so: +You can also create the array in a single line of code: ```swift var cookies = [[Int]](repeating: [Int](repeating: 0, count: 7), count: 9) ``` -but that's just ugly. To be fair, you can hide the ugliness in a helper function: +This looks complicated, but can simplfy it in a helper function: ```swift func dim(_ count: Int, _ value: T) -> [T] { @@ -41,13 +41,13 @@ func dim(_ count: Int, _ value: T) -> [T] { } ``` -And then creating the array looks like this: +Then, you can create the array: ```swift var cookies = dim(9, dim(7, 0)) ``` -Swift infers that the datatype of the array should be `Int` because you specified `0` as the default value of the array elements. To use a string instead, you'd write: +Swift infers that the datatype of the array must be `Int` because you specified `0` as the default value of the array elements. To use a string instead, you can write: ```swift var cookies = dim(9, dim(7, "yum")) @@ -59,9 +59,9 @@ The `dim()` function makes it easy to go into even more dimensions: var threeDimensions = dim(2, dim(3, dim(4, 0))) ``` -The downside of using multi-dimensional arrays in this fashion -- actually, multiple nested arrays -- is that it's easy to lose track of what dimension represents what. +The downside of using multi-dimensional arrays or multiple nested arrays in this way is to lose track of what dimension represents what. -So instead let's create our own type that acts like a 2-D array and that is more convenient to use. Here it is, short and sweet: +Instead, you can create your own type that acts like a 2-D array which is more convenient to use: ```swift public struct Array2D { @@ -92,26 +92,24 @@ public struct Array2D { `Array2D` is a generic type, so it can hold any kind of object, not just numbers. -To create an instance of `Array2D` you'd write: +To create an instance of `Array2D`, you can write: ```swift var cookies = Array2D(columns: 9, rows: 7, initialValue: 0) ``` -Thanks to the `subscript` function, you can do the following to retrieve an object from the array: +By using the `subscript` function, you can retrieve an object from the array: ```swift let myCookie = cookies[column, row] ``` -Or change it: +Or, you can change it: ```swift cookies[column, row] = newCookie ``` -Internally, `Array2D` uses a single one-dimensional array to store the data. The index of an object in that array is given by `(row x numberOfColumns) + column`. But as a user of `Array2D` you don't have to worry about that; you only have to think in terms of "column" and "row", and let `Array2D` figure out the details for you. That's the advantage of wrapping primitive types into a wrapper class or struct. - -And that's all there is to it. +Internally, `Array2D` uses a single one-dimensional array to store the data. The index of an object in that array is given by `(row x numberOfColumns) + column`, but as a user of `Array2D`, you only need to think in terms of "column" and "row", and the details will be done by `Array2D`. This is the advantage of wrapping primitive types into a wrapper class or struct. *Written for Swift Algorithm Club by Matthijs Hollemans* From 777bf7b948e75d77bbac8cbba5dc40716c6b5d61 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 6 Apr 2017 16:34:58 +0300 Subject: [PATCH 0494/1275] Deleted unnecessary code and added comments --- .../Dijkstra.playground/Contents.swift | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index 8d600d577..13087a8f9 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -3,19 +3,15 @@ import Foundation import UIKit -open class ProductVertex: Vertex {} - open class Vertex: Hashable, Equatable { open var identifier: String! open var neighbors: [(Vertex, Double)] = [] open var pathLengthFromStart: Double = Double.infinity open var pathVerticesFromStart: [Vertex] = [] -// open var point: CGPoint! - public init(identifier: String/*, point: CGPoint*/) { + public init(identifier: String) { self.identifier = identifier -// self.point = point } open var hashValue: Int { @@ -77,7 +73,9 @@ public class Dijkstra { var _vertices: Set = Set() func createNotConnectedVertices() { - for i in 0..<15 { + //change this value to increase or decrease amount of vertices in the graph + let numberOfVerticesInGraph = 15 + for i in 0.. Vertex { return newSet[index] } +func randomVertex() -> Vertex { + let offset = Int(arc4random_uniform(UInt32(_vertices.count))) + let index = _vertices.index(_vertices.startIndex, offsetBy: offset) + return _vertices[index] +} + +//initialize random graph createNotConnectedVertices() setupConnections() + +//initialize Dijkstra algorithm with graph vertices let dijkstra = Dijkstra(vertices: _vertices) -let offset = Int(arc4random_uniform(UInt32(_vertices.count))) -let index = _vertices.index(_vertices.startIndex, offsetBy: offset) -let startVertex = _vertices[index] + +//decide which vertex will be the starting one +let startVertex = randomVertex() + +//ask algorithm to find shortest paths from start vertex to all others dijkstra.findShortestPaths(from: startVertex) + +//printing results let destinationVertex = randomVertex(except: startVertex) -destinationVertex.pathLengthFromStart -destinationVertex.pathVerticesFromStart +print(destinationVertex.pathLengthFromStart) +var pathVerticesFromStartString: [String] = [] +for vertex in destinationVertex.pathVerticesFromStart { + pathVerticesFromStartString.append(vertex.identifier) +} +print(pathVerticesFromStartString.joined(separator: "->")) From 11fdc6ca756b4d402e807a0f9b6063fd6f38dab1 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Thu, 6 Apr 2017 11:57:03 -0700 Subject: [PATCH 0495/1275] Revisions in README.markdown I have revised your document to be more concise. --- Graph/README.markdown | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Graph/README.markdown b/Graph/README.markdown index a2531e808..bc33b044a 100644 --- a/Graph/README.markdown +++ b/Graph/README.markdown @@ -1,26 +1,26 @@ # Graph -A graph is something that looks like this: +A graph looks like the following picture: ![A graph](Images/Graph.png) -In computer-science lingo, a graph is a set of *vertices* paired with a set of *edges*. The vertices are the round things and the edges are the lines between them. Edges connect a vertex to other vertices. +In computer science, a graph is defined as a set of *vertices* paired with a set of *edges*. The vertices are represented by circles, and the edges are the lines between them. Edges connect a vertex to other vertices. -> **Note:** Vertices are sometimes also called "nodes" and edges are also called "links". +> **Note:** Vertices are sometimes called "nodes", and edges are called "links". -For example, a graph can represent a social network. Each person is a vertex, and people who know each other are connected by edges. A somewhat historically inaccurate example: +A graph can represent a social network. Each person is a vertex, and people who know each other are connected by edges. Here is a somewhat historically inaccurate example: ![Social network](Images/SocialNetwork.png) -Graphs come in all kinds of shapes and sizes. The edges can have a *weight*, where a positive or negative numeric value is assigned to each edge. Consider an example of a graph representing airplane flights. Cities can be vertices, and flights can be edges. Then an edge weight could describe flight time or the price of a ticket. +Graphs have various shapes and sizes. The edges can have a *weight*, where a positive or negative numeric value is assigned to each edge. Consider an example of a graph representing airplane flights. Cities can be vertices, and flights can be edges. Then, an edge weight could describe flight time or the price of a ticket. ![Airplane flights](Images/Flights.png) With this hypothetical airline, flying from San Francisco to Moscow is cheapest by going through New York. -Edges can also be *directed*. So far the edges you've seen have been undirected, so if Ada knows Charles, then Charles also knows Ada. A directed edge, on the other hand, implies a one-way relationship. A directed edge from vertex X to vertex Y connects X to Y, but *not* Y to X. +Edges can also be *directed*. In examples mentioned above, the edges are undirected. For instance, if Ada knows Charles, then Charles also knows Ada. A directed edge, on the other hand, implies a one-way relationship. A directed edge from vertex X to vertex Y connects X to Y, but *not* Y to X. -Continuing from the flights example, a directed edge from San Francisco to Juneau in Alaska would indicate that there is a flight from San Francisco to Juneau, but not from Juneau to San Francisco (I suppose that means you're walking back). +Continuing from the flights example, a directed edge from San Francisco to Juneau in Alaska indicates that there is a flight from San Francisco to Juneau, but not from Juneau to San Francisco (I suppose that means you're walking back). ![One-way flights](Images/FlightsDirected.png) @@ -28,51 +28,51 @@ The following are also graphs: ![Tree and linked list](Images/TreeAndList.png) -On the left is a [tree](../Tree/) structure, on the right a [linked list](../Linked%20List/). Both can be considered graphs, but in a simpler form. After all, they have vertices (nodes) and edges (links). +On the left is a [tree](../Tree/) structure, on the right a [linked list](../Linked%20List/). They can be considered graphs but in a simpler form. They both have vertices (nodes) and edges (links). -The very first graph I showed you contained *cycles*, where you can start off at a vertex, follow a path, and come back to the original vertex. A tree is a graph without such cycles. +The first graph includes *cycles*, where you can start off at a vertex, follow a path, and come back to the original vertex. A tree is a graph without such cycles. -Another very common type of graph is the *directed acyclic graph* or DAG: +Another common type of graph is the *directed acyclic graph* or DAG: ![DAG](Images/DAG.png) -Like a tree this does not have any cycles in it (no matter where you start, there is no path back to the starting vertex), but unlike a tree the edges are directional and the shape doesn't necessarily form a hierarchy. +Like a tree, this graph does not have any cycles (no matter where you start, there is no path back to the starting vertex), but this graph has directional edges with the shape that does not necessarily form a hierarchy. ## Why use graphs? -Maybe you're shrugging your shoulders and thinking, what's the big deal? Well, it turns out that graphs are an extremely useful data structure. +Maybe you're shrugging your shoulders and thinking, what's the big deal? Well, it turns out that a graph is a useful data structure. -If you have some programming problem where you can represent some of your data as vertices and some of it as edges between those vertices, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First%20Search/) or [depth-first search](../Depth-First%20Search) to find a solution. +If you have a programming problem where you can represent your data as vertices and edges, then you can draw your problem as a graph and use well-known graph algorithms such as [breadth-first search](../Breadth-First%20Search/) or [depth-first search](../Depth-First%20Search) to find a solution. -For example, let's say you have a list of tasks where some tasks have to wait on others before they can begin. You can model this using an acyclic directed graph: +For example, suppose you have a list of tasks where some tasks have to wait on others before they can begin. You can model this using an acyclic directed graph: ![Tasks as a graph](Images/Tasks.png) -Each vertex represents a task. Here, an edge between two vertices means that the source task must be completed before the destination task can start. So task C cannot start before B and D are finished, and B nor D can start before A is finished. +Each vertex represents a task. An edge between two vertices means the source task must be completed before the destination task can start. As an example, task C cannot start before B and D are finished, and B nor D can start before A is finished. Now that the problem is expressed using a graph, you can use a depth-first search to perform a [topological sort](../Topological%20Sort/). This will put the tasks in an optimal order so that you minimize the time spent waiting for tasks to complete. (One possible order here is A, B, D, E, C, F, G, H, I, J, K.) -Whenever you're faced with a tough programming problem, ask yourself, "how can I express this problem using a graph?" Graphs are all about representing relationships between your data. The trick is in how you define "relationship". +Whenever you are faced with a tough programming problem, ask yourself, "how can I express this problem using a graph?" Graphs are all about representing relationships between your data. The trick is in how you define "relationships". -If you're a musician you might appreciate this graph: +If you are a musician you might appreciate this graph: ![Chord map](Images/ChordMap.png) -The vertices are chords from the C major scale. The edges -- the relationships between the chords -- represent how [likely one chord is to follow another](http://mugglinworks.com/chordmaps/genmap.htm). This is a directed graph, so the direction of the arrows shows how you can go from one chord to the next. It's also a weighted graph, where the weight of the edges -- portrayed here by line thickness -- shows a strong relationship between two chords. As you can see, a G7-chord is very likely to be followed by a C chord, and much less likely by a Am chord. +The vertices are chords from the C major scale. The edges -- the relationships between the chords -- represent how [likely one chord is to follow another](http://mugglinworks.com/chordmaps/genmap.htm). This is a directed graph, so the direction of the arrows shows how you can go from one chord to the next. It is also a weighted graph, where the weight of the edges -- portrayed here by line thickness -- shows a strong relationship between two chords. As you can see, a G7-chord is very likely to be followed by a C chord, and much less likely by a Am chord. -You're probably already using graphs without even knowing it. Your data model is also a graph (from Apple's Core Data documentation): +You are probably already using graphs without even knowing it. Your data model is also a graph (from Apple's Core Data documentation): ![Core Data model](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreDataVersioning/Art/recipe_version2.0.jpg) -Another common graph that's used by programmers is the state machine, where edges depict the conditions for transitioning between states. Here is a state machine that models my cat: +Another common graph used by programmers is the state machine, where edges depict the conditions for transitioning between states. Here is a state machine that models my cat: ![State machine](Images/StateMachine.png) -Graphs are awesome. Facebook made a fortune from their social graph. If you're going to learn any data structure, it should be the graph and the vast collection of standard graph algorithms. +Graphs are awesome. Facebook made a fortune from their social graph. If you are going to learn any data structure, you must choose the graph and the vast collection of standard graph algorithms. ## Vertices and edges, oh my! -In theory, a graph is just a bunch of vertex objects and a bunch of edge objects. But how do you describe these in code? +In theory, a graph is just a bunch of vertex and edge objects, but how do you describe this in code? There are two main strategies: adjacency list and adjacency matrix. @@ -80,9 +80,9 @@ There are two main strategies: adjacency list and adjacency matrix. ![Adjacency list](Images/AdjacencyList.png) -The adjacency list describes outgoing edges. A has an edge to B but B does not have an edge back to A, so A does not appear in B's adjacency list. Finding an edge or weight between two vertices can be expensive because there is no random access to edges–you must traverse the adjacency lists until it is found. +The adjacency list describes outgoing edges. A has an edge to B, but B does not have an edge back to A, so A does not appear in B's adjacency list. Finding an edge or weight between two vertices can be expensive because there is no random access to edges. You must traverse the adjacency lists until it is found. -**Adjacency Matrix.** In an adjacency matrix implementation, a matrix with rows and columns representing vertices stores a weight to indicate if vertices are connected, and by what weight. For example, if there is a directed edge of weight 5.6 from vertex A to vertex B, then the entry with row for vertex A, column for vertex B would have value 5.6: +**Adjacency Matrix.** In an adjacency matrix implementation, a matrix with rows and columns representing vertices stores a weight to indicate if vertices are connected and by what weight. For example, if there is a directed edge of weight 5.6 from vertex A to vertex B, then the entry with row for vertex A and column for vertex B would have the value 5.6: ![Adjacency matrix](Images/AdjacencyMatrix.png) @@ -103,7 +103,7 @@ Let *V* be the number of vertices in the graph, and *E* the number of edges. Th In the case of a *sparse* graph, where each vertex is connected to only a handful of other vertices, an adjacency list is the best way to store the edges. If the graph is *dense*, where each vertex is connected to most of the other vertices, then a matrix is preferred. -We'll show you sample implementations of both adjacency list and adjacency matrix. +Here are sample implementations of both adjacency list and adjacency matrix: ## The code: edges and vertices @@ -137,9 +137,9 @@ It stores arbitrary data with a generic type `T`, which is `Hashable` to enforce ## The code: graphs -> **Note:** There are many, many ways to implement graphs. The code given here is just one possible implementation. You probably want to tailor the graph code to each individual problem you're trying to solve. For instance, your edges may not need a `weight` property, or you may not have the need to distinguish between directed and undirected edges. +> **Note:** There are many ways to implement graphs. The code given here is just one possible implementation. You probably want to tailor the graph code to each individual problem you are trying to solve. For instance, your edges may not need a `weight` property, or you may not have the need to distinguish between directed and undirected edges. -Here's an example of a very simple graph: +Here is an example of a simple graph: ![Demo](Images/Demo1.png) @@ -165,7 +165,7 @@ for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { } ``` -As mentioned earlier, to create an undirected edge you need to make two directed edges. If we wanted undirected graphs, we'd call this method instead, which takes care of that work for us: +As mentioned earlier, to create an undirected edge you need to make two directed edges. For undirected graphs, we call the following method instead: ```swift graph.addUndirectedEdge(v1, to: v2, withWeight: 1.0) @@ -198,7 +198,7 @@ private class EdgeList where T: Equatable, T: Hashable { } ``` -They are implemented as a class as opposed to structs so we can modify them by reference, in place, like when adding an edge to a new vertex, where the source vertex already has an edge list: +They are implemented as a class as opposed to structs, so we can modify them by reference, in place, like when adding an edge to a new vertex, where the source vertex already has an edge list: ```swift open override func createVertex(_ data: T) -> Vertex { @@ -231,7 +231,7 @@ where the general form `a -> [(b: w), ...]` means an edge exists from `a` to `b` ## The code: adjacency matrix -We'll keep track of the adjacency matrix in a two-dimensional `[[Double?]]` array. An entry of `nil` indicates no edge, while any other value indicates an edge of the given weight. If `adjacencyMatrix[i][j]` is not nil, then there is an edge from vertex `i` to vertex `j`. +We will keep track of the adjacency matrix in a two-dimensional `[[Double?]]` array. An entry of `nil` indicates no edge, while any other value indicates an edge of the given weight. If `adjacencyMatrix[i][j]` is not nil, then there is an edge from vertex `i` to vertex `j`. To index into the matrix using vertices, we use the `index` property in `Vertex`, which is assigned when creating the vertex through the graph object. When creating a new vertex, the graph must resize the matrix: @@ -277,6 +277,6 @@ Then the adjacency matrix looks like this: ## See also -This article described what a graph is and how you can implement the basic data structure. But we have many more articles on practical uses for graphs, so check those out too! +This article described what a graph is, and how you can implement the basic data structure. We have other articles on practical uses of graphs, so check those out too! *Written by Donald Pinckney and Matthijs Hollemans* From 0a77b0685a7c26512377ba57ed02d2ee4644a880 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Thu, 6 Apr 2017 13:57:39 -0700 Subject: [PATCH 0496/1275] Revisions in README.markdown I have revised your document to be more concise. --- Binary Search Tree/README.markdown | 138 ++++++++++++++--------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index b3b955c61..14ef931b9 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -2,7 +2,7 @@ A binary search tree is a special kind of [binary tree](../Binary%20Tree/) (a tree in which each node has at most two children) that performs insertions and deletions such that the tree is always sorted. -If you don't know what a tree is or what it is for, then [read this first](../Tree/). +For more iformation about a tree, [read this first](../Tree/). ## "Always sorted" property @@ -12,56 +12,56 @@ Here is an example of a valid binary search tree: Notice how each left child is smaller than its parent node, and each right child is greater than its parent node. This is the key feature of a binary search tree. -For example, `2` is smaller than `7` so it goes on the left; `5` is greater than `2` so it goes on the right. +For example, `2` is smaller than `7`, so it goes on the left; `5` is greater than `2`, so it goes on the right. ## Inserting new nodes When performing an insertion, we first compare the new value to the root node. If the new value is smaller, we take the *left* branch; if greater, we take the *right* branch. We work our way down the tree this way until we find an empty spot where we can insert the new value. -Say we want to insert the new value `9`: +Suppose we want to insert the new value `9`: - We start at the root of the tree (the node with the value `7`) and compare it to the new value `9`. - `9 > 7`, so we go down the right branch and repeat the same procedure but this time on node `10`. - Because `9 < 10`, we go down the left branch. -- We've now arrived at a point where there are no more values to compare with. A new node for `9` is inserted at that location. +- We now arrived at a point where there are no more values to compare with. A new node for `9` is inserted at that location. -The tree now looks like this: +Here is the tree after inserting the new value `9`: ![After adding 9](Images/Tree2.png) -There is always only one possible place where the new element can be inserted in the tree. Finding this place is usually pretty quick. It takes **O(h)** time, where **h** is the height of the tree. +There is only one possible place where the new element can be inserted in the tree. Finding this place is usually quick. It takes **O(h)** time, where **h** is the height of the tree. > **Note:** The *height* of a node is the number of steps it takes to go from that node to its lowest leaf. The height of the entire tree is the distance from the root to the lowest leaf. Many of the operations on a binary search tree are expressed in terms of the tree's height. -By following this simple rule -- smaller values on the left, larger values on the right -- we keep the tree sorted in a way such that whenever we query it, we can quickly check if a value is in the tree. +By following this simple rule -- smaller values on the left, larger values on the right -- we keep the tree sorted, so whenever we query it, we can check if a value is in the tree. ## Searching the tree -To find a value in the tree, we essentially perform the same steps as with insertion: +To find a value in the tree, we perform the same steps as with insertion: - If the value is less than the current node, then take the left branch. - If the value is greater than the current node, take the right branch. -- And if the value is equal to the current node, we've found it! +- If the value is equal to the current node, we've found it! -Like most tree operations, this is performed recursively until either we find what we're looking for, or run out of nodes to look at. +Like most tree operations, this is performed recursively until either we find what we are looking for or run out of nodes to look at. -If we were looking for the value `5` in the example, it would go as follows: +Here is an example for searching the value `5`: ![Searching the tree](Images/Searching.png) -Thanks to the structure of the tree, searching is really fast. It runs in **O(h)** time. If you have a well-balanced tree with a million nodes, it only takes about 20 steps to find anything in this tree. (The idea is very similar to [binary search](../Binary%20Search) in an array.) +Searching is fast using the structure of the tree. It runs in **O(h)** time. If you have a well-balanced tree with a million nodes, it only takes about 20 steps to find anything in this tree. (The idea is very similar to [binary search](../Binary%20Search) in an array.) ## Traversing the tree -Sometimes you don't want to look at just a single node, but at all of them. +Sometimes you need to look at all nodes rather than only one. There are three ways to traverse a binary tree: -1. *In-order* (or *depth-first*): first look at the left child of a node, then at the node itself, and finally at its right child. -2. *Pre-order*: first look at a node, then its left and right children. +1. *In-order* (or *depth-first*): first look at the left child of a node then at the node itself and finally at its right child. +2. *Pre-order*: first look at a node then its left and right children. 3. *Post-order*: first look at the left and right children and process the node itself last. -Once again, this happens recursively. +Traversing the tree also happens recursively. If you traverse a binary search tree in-order, it looks at all the nodes as if they were sorted from low to high. For the example tree, it would print `1, 2, 5, 7, 9, 10`: @@ -69,7 +69,7 @@ If you traverse a binary search tree in-order, it looks at all the nodes as if t ## Deleting nodes -Removing nodes is also easy. After removing a node, we replace the node with either its biggest child on the left or its smallest child on the right. That way the tree is still sorted after the removal. In following example, 10 is removed and replaced with either 9 (Figure 2), or 11 (Figure 3). +Removing nodes is easy. After removing a node, we replace the node with either its biggest child on the left or its smallest child on the right. That way the tree is still sorted after the removal. In the following example, 10 is removed and replaced with either 9 (Figure 2) or 11 (Figure 3). ![Deleting a node with two children](Images/DeleteTwoChildren.png) @@ -80,9 +80,9 @@ Note the replacement needs to happen when the node has at least one child. If it ## The code (solution 1) -So much for the theory. Let's see how we can implement a binary search tree in Swift. There are different approaches you can take. First, I'll show you how to make a class-based version but we'll also look at how to make one using enums. +So much for the theory. Let's see how we can implement a binary search tree in Swift. There are different approaches you can take. First, I will show you how to make a class-based version, but we will also look at how to make one using enums. -Here's a first stab at a `BinarySearchTree` class: +Here is an example for a `BinarySearchTree` class: ```swift public class BinarySearchTree { @@ -133,21 +133,21 @@ public class BinarySearchTree { } ``` -This class describes just a single node, not the entire tree. It's a generic type, so the node can store any kind of data. It also has references to its `left` and `right` child nodes and a `parent` node. +This class describes just a single node not the entire tree. It is a generic type, so the node can store any kind of data. It also has references to its `left` and `right` child nodes and a `parent` node. -Here's how you'd use it: +Here is how you can use it: ```swift let tree = BinarySearchTree(value: 7) ``` -The `count` property determines how many nodes are in the subtree described by this node. This doesn't just count the node's immediate children but also their children and their children's children, and so on. If this particular object is the root node, then it counts how many nodes are in the entire tree. Initially, `count = 0`. +The `count` property determines how many nodes are in the subtree described by this node. This does not just count the node's immediate children but also their children and their children's children, and so on. If this particular object is the root node, then it counts how many nodes are in the entire tree. Initially, `count = 0`. -> **Note:** Because `left`, `right`, and `parent` are optionals, we can make good use of Swift's optional chaining (`?`) and nil-coalescing operators (`??`). You could also write this sort of thing with `if let` but that is less concise. +> **Note:** Because `left`, `right`, and `parent` are optional, we can make good use of Swift's optional chaining (`?`) and nil-coalescing operators (`??`). You could also write this sort of thing with `if let`, but that is less concise. ### Inserting nodes -A tree node by itself is pretty useless, so here is how you would add new nodes to the tree: +A tree node by itself is useless, so here is how you would add new nodes to the tree: ```swift public func insert(value: T) { @@ -173,9 +173,9 @@ Like so many other tree operations, insertion is easiest to implement with recur If there is no more left or right child to look at, we create a `BinarySearchTree` object for the new node and connect it to the tree by setting its `parent` property. -> **Note:** Because the whole point of a binary search tree is to have smaller nodes on the left and larger ones on the right, you should always insert elements at the root, to make to sure this remains a valid binary tree! +> **Note:** Because the whole point of a binary search tree is to have smaller nodes on the left and larger ones on the right, you should always insert elements at the root to make sure this remains a valid binary tree! -To build the complete tree from the example you'd do: +To build the complete tree from the example you can do: ```swift let tree = BinarySearchTree(value: 7) @@ -186,7 +186,7 @@ tree.insert(9) tree.insert(1) ``` -> **Note:** For reasons that will become clear later, you should insert the numbers in a somewhat random order. If you insert them in sorted order, the tree won't have the right shape. +> **Note:** For reasons that will become clear later, you should insert the numbers in a random order. If you insert them in a sorted order, the tree will not have the right shape. For convenience, let's add an init method that calls `insert()` for all the elements in an array: @@ -210,7 +210,7 @@ The first value in the array becomes the root of the tree. ### Debug output -When working with somewhat complicated data structures such as this, it's useful to have human-readable debug output. +When working with complicated data structures, it is useful to have human-readable debug output. ```swift extension BinarySearchTree: CustomStringConvertible { @@ -236,11 +236,11 @@ The root node is in the middle. With some imagination, you should see that this ![The tree](Images/Tree2.png) -By the way, you may be wondering what happens when you insert duplicate items? We always insert those in the right branch. Try it out! +You may be wondering what happens when you insert duplicate items? We always insert those in the right branch. Try it out! ### Searching -What do we do now that we have some values in our tree? Search for them, of course! Being able to find items quickly is the entire purpose of a binary search tree. :-) +What do we do now that we have some values in our tree? Search for them, of course! To find items quickly is the main purpose of a binary search tree. :-) Here is the implementation of `search()`: @@ -258,11 +258,11 @@ Here is the implementation of `search()`: I hope the logic is clear: this starts at the current node (usually the root) and compares the values. If the search value is less than the node's value, we continue searching in the left branch; if the search value is greater, we dive into the right branch. -Of course, if there are no more nodes to look at -- when `left` or `right` is nil -- then we return `nil` to indicate the search value is not in the tree. +If there are no more nodes to look at -- when `left` or `right` is nil -- then we return `nil` to indicate the search value is not in the tree. -> **Note:** In Swift that's very conveniently done with optional chaining; when you write `left?.search(value)` it automatically returns nil if `left` is nil. There's no need to explicitly check for this with an `if` statement. +> **Note:** In Swift, that is conveniently done with optional chaining; when you write `left?.search(value)` it automatically returns nil if `left` is nil. There is no need to explicitly check for this with an `if` statement. -Searching is a recursive process but you can also implement it with a simple loop instead: +Searching is a recursive process, but you can also implement it with a simple loop instead: ```swift public func search(value: T) -> BinarySearchTree? { @@ -280,9 +280,9 @@ Searching is a recursive process but you can also implement it with a simple loo } ``` -Verify for yourself that you understand that these two implementations are equivalent. Personally, I prefer to use iterative code over recursive code but your opinion may differ. ;-) +Verify that you understand these two implementations are equivalent. Personally, I prefer to use iterative code over recursive code, but your opinion may differ. ;-) -Here's how to test searching: +Here is how to test searching: ```swift tree.search(5) @@ -291,9 +291,9 @@ tree.search(7) tree.search(6) // nil ``` -The first three lines all return the corresponding `BinaryTreeNode` object. The last line returns `nil` because there is no node with value `6`. +The first three lines return the corresponding `BinaryTreeNode` object. The last line returns `nil` because there is no node with value `6`. -> **Note:** If there are duplicate items in the tree, `search()` always returns the "highest" node. That makes sense, because we start searching from the root downwards. +> **Note:** If there are duplicate items in the tree, `search()` returns the "highest" node. That makes sense, because we start searching from the root downwards. ### Traversal @@ -319,9 +319,9 @@ Remember there are 3 different ways to look at all nodes in the tree? Here they } ``` -They all do pretty much the same thing but in different orders. Notice once again that all the work is done recursively. Thanks to Swift's optional chaining, the calls to `traverseInOrder()` etc are ignored when there is no left or right child. +They all work the same but in different orders. Notice that all the work is done recursively. The Swift's optional chaining makes it clear that the calls to `traverseInOrder()` etc are ignored when there is no left or right child. -To print out all the values from the tree sorted from low to high you can write: +To print out all the values of the tree sorted from low to high you can write: ```swift tree.traverseInOrder { value in print(value) } @@ -336,7 +336,7 @@ This prints the following: 9 10 -You can also add things like `map()` and `filter()` to the tree. For example, here's an implementation of map: +You can also add things like `map()` and `filter()` to the tree. For example, here is an implementation of map: ```swift @@ -365,11 +365,11 @@ This turns the contents of the tree back into a sorted array. Try it out in the tree.toArray() // [1, 2, 5, 7, 9, 10] ``` -As an exercise for yourself, see if you can implement filter and reduce. +As an exercise, see if you can implement filter and reduce. ### Deleting nodes -We can make the code much more readable by defining some helper functions. +We can make the code more readable by defining some helper functions. ```swift private func reconnectParentToNode(node: BinarySearchTree?) { @@ -384,7 +384,7 @@ We can make the code much more readable by defining some helper functions. } ``` -Making changes to the tree involves changing a bunch of `parent` and `left` and `right` pointers. This function helps with that. It takes the parent of the current node -- that is `self` -- and connects it to another node. Usually that other node will be one of the children of `self`. +Making changes to the tree involves changing a bunch of `parent` and `left` and `right` pointers. This function helps with this implementation. It takes the parent of the current node -- that is `self` -- and connects it to another node which will be one of the children of `self`. We also need a function that returns the minimum and maximum of a node: @@ -407,7 +407,7 @@ We also need a function that returns the minimum and maximum of a node: ``` -The rest of the code is pretty self-explanatory: +The rest of the code is self-explanatory: ```swift @discardableResult public func remove() -> BinarySearchTree? { @@ -457,7 +457,7 @@ Recall that the height of a node is the distance to its lowest leaf. We can calc We look at the heights of the left and right branches and take the highest one. Again, this is a recursive procedure. Since this looks at all children of this node, performance is **O(n)**. -> **Note:** Swift's null-coalescing operator is used as shorthand to deal with `left` or `right` pointers that are nil. You could write this with `if let` but this is a lot more concise. +> **Note:** Swift's null-coalescing operator is used as shorthand to deal with `left` or `right` pointers that are nil. You could write this with `if let`, but this is more concise. Try it out: @@ -479,7 +479,7 @@ You can also calculate the *depth* of a node, which is the distance to the root. } ``` -It steps upwards through the tree, following the `parent` pointers until we reach the root node (whose `parent` is nil). This takes **O(h)** time. Example: +It steps upwards through the tree, following the `parent` pointers until we reach the root node (whose `parent` is nil). This takes **O(h)** time. Here is an example: ```swift if let node9 = tree.search(9) { @@ -489,11 +489,11 @@ if let node9 = tree.search(9) { ### Predecessor and successor -The binary search tree is always "sorted" but that doesn't mean that consecutive numbers are actually next to each other in the tree. +The binary search tree is always "sorted" but that does not mean that consecutive numbers are actually next to each other in the tree. ![Example](Images/Tree2.png) -Note that you can't find the number that comes before `7` by just looking at its left child node. The left child is `2`, not `5`. Likewise for the number that comes after `7`. +Note that you cannot find the number that comes before `7` by just looking at its left child node. The left child is `2`, not `5`. Likewise for the number that comes after `7`. The `predecessor()` function returns the node whose value precedes the current value in sorted order: @@ -512,11 +512,11 @@ The `predecessor()` function returns the node whose value precedes the current v } ``` -It's easy if we have a left subtree. In that case, the immediate predecessor is the maximum value in that subtree. You can verify in the above picture that `5` is indeed the maximum value in `7`'s left branch. +It is easy if we have a left subtree. In that case, the immediate predecessor is the maximum value in that subtree. You can verify in the above picture that `5` is indeed the maximum value in `7`'s left branch. -However, if there is no left subtree then we have to look at our parent nodes until we find a smaller value. So if we want to know what the predecessor is of node `9`, we keep going up until we find the first parent with a smaller value, which is `7`. +If there is no left subtree, then we have to look at our parent nodes until we find a smaller value. If we want to know what the predecessor is of node `9`, we keep going up until we find the first parent with a smaller value, which is `7`. -The code for `successor()` works the exact same way but mirrored: +The code for `successor()` works the same way but mirrored: ```swift public func successor() -> BinarySearchTree? { @@ -535,11 +535,11 @@ The code for `successor()` works the exact same way but mirrored: Both these methods run in **O(h)** time. -> **Note:** There is a cool variation called a ["threaded" binary tree](../Threaded%20Binary%20Tree) where "unused" left and right pointers are repurposed to make direct links between predecessor and successor nodes. Very clever! +> **Note:** There is a variation called a ["threaded" binary tree](../Threaded%20Binary%20Tree) where "unused" left and right pointers are repurposed to make direct links between predecessor and successor nodes. Very clever! ### Is the search tree valid? -If you were intent on sabotage you could turn the binary search tree into an invalid tree by calling `insert()` on a node that is not the root, like so: +If you were intent on sabotage you could turn the binary search tree into an invalid tree by calling `insert()` on a node that is not the root. Here is an example: ```swift if let node1 = tree.search(1) { @@ -547,7 +547,7 @@ if let node1 = tree.search(1) { } ``` -The value of the root node is `7`, so a node with value `100` is supposed to be in the tree's right branch. However, you're not inserting at the root but at a leaf node in the tree's left branch. So the new `100` node is in the wrong place in the tree! +The value of the root node is `7`, so a node with value `100`must be in the tree's right branch. However, you are not inserting at the root but at a leaf node in the tree's left branch. So the new `100` node is in the wrong place in the tree! As a result, doing `tree.search(100)` gives nil. @@ -562,7 +562,7 @@ You can check whether a tree is a valid binary search tree with the following me } ``` -This verifies that the left branch does indeed contain values that are less than the current node's value, and that the right branch only contains values that are larger. +This verifies the left branch contains values that are less than the current node's value, and that the right branch only contains values that are larger. Call it as follows: @@ -577,11 +577,11 @@ if let node1 = tree.search(1) { ## The code (solution 2) -We've implemented the binary tree node as a class but you can also use an enum. +We have implemented the binary tree node as a class, but you can also use an enum. -The difference is reference semantics versus value semantics. Making a change to the class-based tree will update that same instance in memory. But the enum-based tree is immutable -- any insertions or deletions will give you an entirely new copy of the tree. Which one is best totally depends on what you want to use it for. +The difference is reference semantics versus value semantics. Making a change to the class-based tree will update that same instance in memory, but the enum-based tree is immutable -- any insertions or deletions will give you an entirely new copy of the tree. Which one is best, totally depends on what you want to use it for. -Here's how you'd make a binary search tree using an enum: +Here is how you can make a binary search tree using an enum: ```swift public enum BinarySearchTree { @@ -597,9 +597,9 @@ The enum has three cases: - `Leaf` for a leaf node that has no children. - `Node` for a node that has one or two children. This is marked `indirect` so that it can hold `BinarySearchTree` values. Without `indirect` you can't make recursive enums. -> **Note:** The nodes in this binary tree don't have a reference to their parent node. It's not a major impediment but it will make certain operations slightly more cumbersome to implement. +> **Note:** The nodes in this binary tree do not have a reference to their parent node. It is not a major impediment, but it will make certain operations more cumbersome to implement. -As usual, we'll implement most functionality recursively. We'll treat each case of the enum slightly differently. For example, this is how you could calculate the number of nodes in the tree and the height of the tree: +This implementation is recursive, and each case of the enum will be treated differently. For example, this is how you can calculate the number of nodes in the tree and the height of the tree: ```swift public var count: Int { @@ -655,7 +655,7 @@ tree = tree.insert(9) tree = tree.insert(1) ``` -Notice that each time you insert something, you get back a completely new tree object. That's why you need to assign the result back to the `tree` variable. +Notice that for each insertion, you get back a new tree object, so you need to assign the result back to the `tree` variable. Here is the all-important search function: @@ -678,7 +678,7 @@ Here is the all-important search function: } ``` -As you can see, most of these functions have the same structure. +Most of these functions have the same structure. Try it out in a playground: @@ -688,7 +688,7 @@ tree.search(1) tree.search(11) // nil ``` -To print the tree for debug purposes you can use this method: +To print the tree for debug purposes, you can use this method: ```swift extension BinarySearchTree: CustomDebugStringConvertible { @@ -703,21 +703,21 @@ extension BinarySearchTree: CustomDebugStringConvertible { } ``` -When you do `print(tree)` it will look something like this: +When you do `print(tree)`, it will look like this: ((1 <- 2 -> 5) <- 7 -> (9 <- 10 -> .)) -The root node is in the middle; a dot means there is no child at that position. +The root node is in the middle, and a dot means there is no child at that position. ## When the tree becomes unbalanced... -A binary search tree is *balanced* when its left and right subtrees contain roughly the same number of nodes. In that case, the height of the tree is *log(n)*, where *n* is the number of nodes. That's the ideal situation. +A binary search tree is *balanced* when its left and right subtrees contain the same number of nodes. In that case, the height of the tree is *log(n)*, where *n* is the number of nodes. That is the ideal situation. -However, if one branch is significantly longer than the other, searching becomes very slow. We end up checking way more values than we'd ideally have to. In the worst case, the height of the tree can become *n*. Such a tree acts more like a [linked list](../Linked%20List/) than a binary search tree, with performance degrading to **O(n)**. Not good! +If one branch is significantly longer than the other, searching becomes very slow. We end up checking more values than we need. In the worst case, the height of the tree can become *n*. Such a tree acts like a [linked list](../Linked%20List/) than a binary search tree, with performance degrading to **O(n)**. Not good! -One way to make the binary search tree balanced is to insert the nodes in a totally random order. On average that should balance out the tree quite nicely. But it doesn't guarantee success, nor is it always practical. +One way to make the binary search tree balanced is to insert the nodes in a totally random order. On average that should balance out the tree well, but it not guaranteed, nor is it always practical. -The other solution is to use a *self-balancing* binary tree. This type of data structure adjusts the tree to keep it balanced after you insert or delete nodes. See [AVL tree](../AVL%20Tree) and [red-black tree](../Red-Black%20Tree) for examples. +The other solution is to use a *self-balancing* binary tree. This type of data structure adjusts the tree to keep it balanced after you insert or delete nodes. To see examples, check [AVL tree](../AVL%20Tree) and [red-black tree](../Red-Black%20Tree). ## See also From 499bd86cd7ffab858dac481735b532f1789c0ab9 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Thu, 6 Apr 2017 17:07:38 -0700 Subject: [PATCH 0497/1275] Revisions in README.markdown I have revised your document to be more concise. Some words and phrases are removed or replaced due to redundancy. --- Queue/README.markdown | 52 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Queue/README.markdown b/Queue/README.markdown index 9efce66b9..8938e0cf1 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -2,11 +2,11 @@ A queue is a list where you can only insert new items at the back and remove items from the front. This ensures that the first item you enqueue is also the first item you dequeue. First come, first serve! -Why would you need this? Well, in many algorithms you want to add objects to a temporary list at some point and then pull them off this list again at a later time. Often the order in which you add and remove these objects matters. +Why would you need this? Well, in many algorithms you want to add objects to a temporary list and pull them off this list later. Often the order in which you add and remove these objects matters. -A queue gives you a FIFO or first-in, first-out order. The element you inserted first is also the first one to come out again. It's only fair! (A very similar data structure, the [stack](../Stack/), is LIFO or last-in first-out.) +A queue gives you a FIFO or first-in, first-out order. The element you inserted first is the first one to come out. It is only fair! (A similar data structure, the [stack](../Stack/), is LIFO or last-in first-out.) -For example, let's enqueue a number: +Here is an example to enqueue a number: ```swift queue.enqueue(10) @@ -38,11 +38,11 @@ queue.dequeue() This returns `3`, the next dequeue returns `57`, and so on. If the queue is empty, dequeuing returns `nil` or in some implementations it gives an error message. -> **Note:** A queue is not always the best choice. If the order in which the items are added and removed from the list isn't important, you might as well use a [stack](../Stack/) instead of a queue. Stacks are simpler and faster. +> **Note:** A queue is not always the best choice. If the order in which the items are added and removed from the list is not important, you can use a [stack](../Stack/) instead of a queue. Stacks are simpler and faster. ## The code -Here is a very simplistic implementation of a queue in Swift. It's just a wrapper around an array that lets you enqueue, dequeue, and peek at the front-most item: +Here is a simplistic implementation of a queue in Swift. It is a wrapper around an array to enqueue, dequeue, and peek at the front-most item: ```swift public struct Queue { @@ -74,11 +74,11 @@ public struct Queue { } ``` -This queue works just fine but it is not optimal. +This queue works well, but it is not optimal. -Enqueuing is an **O(1)** operation because adding to the end of an array always takes the same amount of time, regardless of the size of the array. So that's great. +Enqueuing is an **O(1)** operation because adding to the end of an array always takes the same amount of time regardless of the size of the array. -You might be wondering why appending items to an array is **O(1)**, or a constant-time operation. That is so because an array in Swift always has some empty space at the end. If we do the following: +You might be wondering why appending items to an array is **O(1)** or a constant-time operation. That is because an array in Swift always has some empty space at the end. If we do the following: ```swift var queue = Queue() @@ -95,13 +95,13 @@ where `xxx` is memory that is reserved but not filled in yet. Adding a new eleme [ "Ada", "Steve", "Tim", "Grace", xxx, xxx ] -This is simply matter of copying memory from one place to another, a constant-time operation. +This results by copying memory from one place to another which is a constant-time operation. -Of course, there are only a limited number of such unused spots at the end of the array. When the last `xxx` gets used and you want to add another item, the array needs to resize to make more room. +There are only a limited number of unused spots at the end of the array. When the last `xxx` gets used, and you want to add another item, the array needs to resize to make more room. -Resizing includes allocating new memory and copying all the existing data over to the new array. This is an **O(n)** process, so it's relatively slow. But since it happens only every so often, the time for appending a new element to the end of the array is still **O(1)** on average, or **O(1)** "amortized". +Resizing includes allocating new memory and copying all the existing data over to the new array. This is an **O(n)** process which is relatively slow. Since it happens occasionally, the time for appending a new element to the end of the array is still **O(1)** on average or **O(1)** "amortized". -The story for dequeueing is slightly different. To dequeue we remove the element from the *beginning* of the array, not the end. This is always an **O(n)** operation because it requires all remaining array elements to be shifted in memory. +The story for dequeueing is different. To dequeue, we remove the element from the *beginning* of the array. This is always an **O(n)** operation because it requires all remaining array elements to be shifted in memory. In our example, dequeuing the first element `"Ada"` copies `"Steve"` in the place of `"Ada"`, `"Tim"` in the place of `"Steve"`, and `"Grace"` in the place of `"Tim"`: @@ -112,13 +112,13 @@ In our example, dequeuing the first element `"Ada"` copies `"Steve"` in the plac / / / after [ "Steve", "Tim", "Grace", xxx, xxx, xxx ] -Moving all these elements in memory is always an **O(n)** operation. So with our simple implementation of a queue, enqueuing is efficient but dequeueing leaves something to be desired... +Moving all these elements in memory is always an **O(n)** operation. So with our simple implementation of a queue, enqueuing is efficient, but dequeueing leaves something to be desired... ## A more efficient queue -To make dequeuing more efficient, we can use the same trick of reserving some extra free space, but this time do it at the front of the array. We're going to have to write this code ourselves as the built-in Swift array doesn't support this out of the box. +To make dequeuing efficient, we can also reserve some extra free space but this time at the front of the array. We must write this code ourselves because the built-in Swift array does not support it. -The idea is as follows: whenever we dequeue an item, we don't shift the contents of the array to the front (slow) but mark the item's position in the array as empty (fast). After dequeuing `"Ada"`, the array is: +The main idea is whenever we dequeue an item, we do not shift the contents of the array to the front (slow) but mark the item's position in the array as empty (fast). After dequeuing `"Ada"`, the array is: [ xxx, "Steve", "Tim", "Grace", xxx, xxx ] @@ -126,13 +126,13 @@ After dequeuing `"Steve"`, the array is: [ xxx, xxx, "Tim", "Grace", xxx, xxx ] -These empty spots at the front never get reused for anything, so they're wasting space. Every so often you can trim the array by moving the remaining elements to the front again: +Because these empty spots at the front never get reused, you can periodically trim the array by moving the remaining elements to the front: [ "Tim", "Grace", xxx, xxx, xxx, xxx ] -This trimming procedure involves shifting memory so it's an **O(n)** operation. But because it only happens once in a while, dequeuing is now **O(1)** on average. +This trimming procedure involves shifting memory which is an **O(n)** operation. Because this only happens once in a while, dequeuing is **O(1)** on average. -Here is how you could implement this version of `Queue`: +Here is how you can implement this version of `Queue`: ```swift public struct Queue { @@ -176,9 +176,9 @@ public struct Queue { } ``` -The array now stores objects of type `T?` instead of just `T` because we need some way to mark array elements as being empty. The `head` variable is the index in the array of the front-most object. +The array now stores objects of type `T?` instead of just `T` because we need to mark array elements as being empty. The `head` variable is the index in the array of the front-most object. -Most of the new functionality sits in `dequeue()`. When we dequeue an item, we first set `array[head]` to `nil` to remove the object from the array. Then we increment `head` because now the next item has become the front one. +Most of the new functionality sits in `dequeue()`. When we dequeue an item, we first set `array[head]` to `nil` to remove the object from the array. Then, we increment `head` because the next item has become the front one. We go from this: @@ -190,9 +190,9 @@ to this: [ xxx, "Steve", "Tim", "Grace", xxx, xxx ] head -It's like some weird supermarket where the people in the checkout lane don't shuffle forward towards the cash register, but the cash register moves up the queue. +It is like if in a supermarket the people in the checkout lane do not shuffle forward towards the cash register, but the cash register moves up the queue. -Of course, if we never remove those empty spots at the front then the array will keep growing as we enqueue and dequeue elements. To periodically trim down the array, we do the following: +If we never remove those empty spots at the front then the array will keep growing as we enqueue and dequeue elements. To periodically trim down the array, we do the following: ```swift let percentage = Double(head)/Double(array.count) @@ -202,11 +202,11 @@ Of course, if we never remove those empty spots at the front then the array will } ``` -This calculates the percentage of empty spots at the beginning as a ratio of the total array size. If more than 25% of the array is unused, we chop off that wasted space. However, if the array is small we don't want to resize it all the time, so there must be at least 50 elements in the array before we try to trim it. +This calculates the percentage of empty spots at the beginning as a ratio of the total array size. If more than 25% of the array is unused, we chop off that wasted space. However, if the array is small we do not resize it all the time, so there must be at least 50 elements in the array before we try to trim it. > **Note:** I just pulled these numbers out of thin air -- you may need to tweak them based on the behavior of your app in a production environment. -To test this in a playground, do: +To test this in a playground, do the following: ```swift var q = Queue() @@ -251,11 +251,11 @@ q.array // [{Some "Grace"}] q.count // 1 ``` -The `nil` objects at the front have been removed and the array is no longer wasting space. This new version of `Queue` isn't much more complicated than the first one but dequeuing is now also an **O(1)** operation, just because we were a bit smarter about how we used the array. +The `nil` objects at the front have been removed, and the array is no longer wasting space. This new version of `Queue` is not more complicated than the first one but dequeuing is now also an **O(1)** operation, just because we were aware about how we used the array. ## See also -There are many other ways to create a queue. Alternative implementations use a [linked list](../Linked%20List/), a [circular buffer](../Ring%20Buffer/), or a [heap](../Heap/). +There are many ways to create a queue. Alternative implementations use a [linked list](../Linked%20List/), a [circular buffer](../Ring%20Buffer/), or a [heap](../Heap/). Variations on this theme are [deque](../Deque/), a double-ended queue where you can enqueue and dequeue at both ends, and [priority queue](../Priority%20Queue/), a sorted queue where the "most important" item is always at the front. From 0f4baf57b3485af6391de0bc06f626e8efc88c82 Mon Sep 17 00:00:00 2001 From: Parva9eh Date: Thu, 6 Apr 2017 17:38:53 -0700 Subject: [PATCH 0498/1275] Revisions in README.markdown I have revised your document to be more concise. --- Selection Sort/README.markdown | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index cb8ed59c2..daebc64f4 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -1,6 +1,6 @@ # Selection Sort -Goal: Sort an array from low to high (or high to low). +Goal: To sort an array from low to high (or high to low). You are given an array of numbers and need to put them in the right order. The selection sort algorithm divides the array into two parts: the beginning of the array is sorted, while the rest of the array consists of the numbers that still remain to be sorted. @@ -10,20 +10,20 @@ This is similar to [insertion sort](../Insertion%20Sort/), but the difference is It works as follows: -- Find the lowest number in the array. You start at index 0, loop through all the numbers in the array, and keep track of what the lowest number is. -- Swap the lowest number you've found with the number at index 0. Now the sorted portion consists of just the number at index 0. +- Find the lowest number in the array. You must start at index 0, loop through all the numbers in the array, and keep track of what the lowest number is. +- Swap the lowest number with the number at index 0. Now, the sorted portion consists of just the number at index 0. - Go to index 1. - Find the lowest number in the rest of the array. This time you start looking from index 1. Again you loop until the end of the array and keep track of the lowest number you come across. -- Swap it with the number at index 1. Now the sorted portion contains two numbers and extends from index 0 to index 1. +- Swap the lowest number with the number at index 1. Now, the sorted portion contains two numbers and extends from index 0 to index 1. - Go to index 2. -- Find the lowest number in the rest of the array, starting from index 2, and swap it with the one at index 2. Now the array is sorted from index 0 to 2; this range contains the three lowest numbers in the array. -- And so on... until no numbers remain to be sorted. +- Find the lowest number in the rest of the array, starting from index 2, and swap it with the one at index 2. Now, the array is sorted from index 0 to 2; this range contains the three lowest numbers in the array. +- And continue until no numbers remain to be sorted. -It's called a "selection" sort, because at every step you search through the rest of the array to select the next lowest number. +It nis called a "selection" sort because at every step you search through the rest of the array to select the next lowest number. ## An example -Let's say the numbers to sort are `[ 5, 8, 3, 4, 6 ]`. We also keep track of where the sorted portion of the array ends, denoted by the `|` symbol. +Suppose the numbers to sort are `[ 5, 8, 3, 4, 6 ]`. We also keep track of where the sorted portion of the array ends, denoted by the `|` symbol. Initially, the sorted portion is empty: @@ -43,7 +43,7 @@ Again, we look for the lowest number, starting from the `|` bar. We find `4` and [ 3, 4 | 5, 8, 6 ] * * -With every step, the `|` bar moves one position to the right. We again look through the rest of the array and find `5` as the lowest number. There's no need to swap `5` with itself and we simply move forward: +With every step, the `|` bar moves one position to the right. We again look through the rest of the array and find `5` as the lowest number. There is no need to swap `5` with itself, and we simply move forward: [ 3, 4, 5 | 8, 6 ] * @@ -52,7 +52,7 @@ This process repeats until the array is sorted. Note that everything to the left [ 3, 4, 5, 6, 8 |] -As you can see, selection sort is an *in-place* sort because everything happens in the same array; no additional memory is necessary. You can also implement this as a *stable* sort so that identical elements do not get swapped around relative to each other (note that the version given below isn't stable). +The selection sort is an *in-place* sort because everything happens in the same array without using additional memory. You can also implement this as a *stable* sort so that identical elements do not get swapped around relative to each other (note that the version given below is not stable). ## The code @@ -90,9 +90,9 @@ selectionSort(list) A step-by-step explanation of how the code works: -1. If the array is empty or only contains a single element, then there's not much point to sorting it. +1. If the array is empty or only contains a single element, then there is no need to sort. -2. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly in Swift. Like Swift's own `sort()`, the `selectionSort()` function will return a sorted *copy* of the original array. +2. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly in Swift. Like the Swift's `sort()` function, the `selectionSort()` function will return a sorted *copy* of the original array. 3. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what moves the `|` bar forward. @@ -100,17 +100,17 @@ A step-by-step explanation of how the code works: 5. Swap the lowest number with the current array index. The `if` check is necessary because you can't `swap()` an element with itself in Swift. -In summary: For each element of the array, selection sort swaps positions with the lowest value from the rest of the array. As a result, the array gets sorted from the left to the right. (You can also do it right-to-left, in which case you always look for the largest number in the array. Give that a try!) +In summary: For each element of the array, the selection sort swaps positions with the lowest value from the rest of the array. As a result, the array gets sorted from the left to the right. (You can also do it right-to-left, in which case you always look for the largest number in the array. Give that a try!) -> **Note:** The outer loop ends at index `a.count - 2`. The very last element will automatically always be in the correct position because at that point there are no other smaller elements left. +> **Note:** The outer loop ends at index `a.count - 2`. The very last element will automatically be in the correct position because at that point there are no other smaller elements left. -The source file [SelectionSort.swift](SelectionSort.swift) has a version of this function that uses generics, so you can also use it to sort strings and other types. +The source file [SelectionSort.swift](SelectionSort.swift) has a version of this function that uses generics, so you can also use it to sort strings and other data types. ## Performance -Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than [insertion sort](../Insertion%20Sort/) but better than [bubble sort](../Bubble%20Sort/). The killer is finding the lowest element in the rest of the array. This takes up a lot of time, especially since the inner loop will be performed over and over. +The selection sort is easy to understand but it performs slow as **O(n^2)**. It is worse than [insertion sort](../Insertion%20Sort/) but better than [bubble sort](../Bubble%20Sort/). Finding the lowest element in the rest of the array is slow, especially since the inner loop will be performed repeatedly . -[Heap sort](../Heap%20Sort/) uses the same principle as selection sort but has a really fast method for finding the minimum value in the rest of the array. Its performance is **O(n log n)**. +The [Heap sort](../Heap%20Sort/) uses the same principle as selection sort but has a fast method for finding the minimum value in the rest of the array. The heap sort' performance is **O(n log n)**. ## See also From 8d84f6fdb9996e0a8b84360fd54eeb9892965e04 Mon Sep 17 00:00:00 2001 From: vincentngo Date: Thu, 6 Apr 2017 22:25:17 -0400 Subject: [PATCH 0499/1275] Spelling 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 14ef931b9..80c2df7df 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -2,7 +2,7 @@ A binary search tree is a special kind of [binary tree](../Binary%20Tree/) (a tree in which each node has at most two children) that performs insertions and deletions such that the tree is always sorted. -For more iformation about a tree, [read this first](../Tree/). +For more information about a tree, [read this first](../Tree/). ## "Always sorted" property From 8080f271109d494eed485137392363bed2d462f4 Mon Sep 17 00:00:00 2001 From: Jacopo Mangiavacchi Date: Fri, 7 Apr 2017 19:18:26 +0200 Subject: [PATCH 0500/1275] Fix and optimizations --- .../Sources/MinimumCoinChange.swift | 89 +++++++++++-------- .../MinimumCoinChangeTests.swift | 20 +++-- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/MinimumCoinChange/Sources/MinimumCoinChange.swift b/MinimumCoinChange/Sources/MinimumCoinChange.swift index db7edecbe..c995063ab 100644 --- a/MinimumCoinChange/Sources/MinimumCoinChange.swift +++ b/MinimumCoinChange/Sources/MinimumCoinChange.swift @@ -1,5 +1,5 @@ // -// Minimum Coin Change Problem +// Minimum Coin Change Problem Playground // Compare Greedy Algorithm and Dynamic Programming Algorithm in Swift // // Created by Jacopo Mangiavacchi on 04/03/17. @@ -7,70 +7,85 @@ import Foundation +public enum MinimumCoinChangeError: Error { + case noRestPossibleForTheGivenValue +} + public struct MinimumCoinChange { - private let sortedCoinSet: [Int] - private var cache: [Int : [Int]] + internal let sortedCoinSet: [Int] public init(coinSet: [Int]) { self.sortedCoinSet = coinSet.sorted(by: { $0 > $1} ) - self.cache = [:] } //Greedy Algorithm - public func changeGreedy(_ value: Int) -> [Int] { + public func changeGreedy(_ value: Int) throws -> [Int] { + guard value > 0 else { return [] } + var change: [Int] = [] var newValue = value - + for coin in sortedCoinSet { while newValue - coin >= 0 { change.append(coin) newValue -= coin } - if newValue == 0 { + if newValue == 0 { break } } + if newValue > 0 { + throw MinimumCoinChangeError.noRestPossibleForTheGivenValue + } + return change } //Dynamic Programming Algorithm - public mutating func changeDynamic(_ value: Int) -> [Int] { - if value <= 0 { - return [] - } + public func changeDynamic(_ value: Int) throws -> [Int] { + guard value > 0 else { return [] } - if let cached = cache[value] { - return cached - } - - var change: [Int] = [] - - var potentialChangeArray: [[Int]] = [] - - for coin in sortedCoinSet { - if value - coin >= 0 { - var potentialChange: [Int] = [] - potentialChange.append(coin) - let newPotentialValue = value - coin + var cache: [Int : [Int]] = [:] - if value > 0 { - potentialChange.append(contentsOf: changeDynamic(newPotentialValue)) - } + func _changeDynamic(_ value: Int) -> [Int] { + guard value > 0 else { return [] } - //print("value: \(value) coin: \(coin) potentialChange: \(potentialChange)") - potentialChangeArray.append(potentialChange) + if let cached = cache[value] { + return cached } + + var change: [Int] = [] + + var potentialChangeArray: [[Int]] = [] + + for coin in sortedCoinSet { + if value - coin >= 0 { + var potentialChange: [Int] = [coin] + potentialChange.append(contentsOf: _changeDynamic(value - coin)) + potentialChangeArray.append(potentialChange) + } + } + + if potentialChangeArray.count > 0 { + let sortedPotentialChangeArray = potentialChangeArray.sorted(by: { $0.count < $1.count }) + change = sortedPotentialChangeArray[0] + } + + if change.reduce(0, +) == value { + cache[value] = change + } + + return change } - - if potentialChangeArray.count > 0 { - let sortedPotentialChangeArray = potentialChangeArray.sorted(by: { $0.count < $1.count }) - change = sortedPotentialChangeArray[0] - } - - cache[value] = change + + let change: [Int] = _changeDynamic(value) + + if change.reduce(0, +) != value { + throw MinimumCoinChangeError.noRestPossibleForTheGivenValue + } + return change } } - diff --git a/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift b/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift index 86c9007ba..705113e92 100644 --- a/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift +++ b/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift @@ -3,16 +3,24 @@ import XCTest class MinimumCoinChangeTests: XCTestCase { func testExample() { - var mcc = MinimumCoinChange(coinSet: [1, 2, 5, 10, 20, 25]) + let mcc = MinimumCoinChange(coinSet: [1, 2, 5, 10, 20, 25]) + print("Coin set: \(mcc.sortedCoinSet)") - for i in 0..<100 { - let greedy = mcc.changeGreedy(i) - let dynamic = mcc.changeDynamic(i) + do { + for i in 0..<100 { + let greedy = try mcc.changeGreedy(i) + let dynamic = try mcc.changeDynamic(i) - if greedy.count != dynamic.count { - print("\(i): greedy = \(greedy) dynamic = \(dynamic)") + XCTAssertEqual(greedy.reduce(0, +), dynamic.reduce(0, +), "Greedy and Dynamic return two different changes") + + if greedy.count != dynamic.count { + print("\(i): greedy = \(greedy) dynamic = \(dynamic)") + } } } + catch { + XCTFail("Test Failed: impossible to change with the given coin set") + } } static var allTests = [ From 7abd8765deff7437e591730ea5c4cbf263ec9fc6 Mon Sep 17 00:00:00 2001 From: Ievgen Pavliuk Date: Sat, 8 Apr 2017 14:30:42 +0200 Subject: [PATCH 0501/1275] Fixed typo in AVL --- 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 c8d8d4628..e7515d99f 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -48,7 +48,7 @@ Each tree node keeps track of its current balance factor in a variable. After in ![Rotation0](Images/RotationStep0.jpg) For the rotation we're using the terminology: -* *Root* - the parent not of the subtrees that will be rotated; +* *Root* - the parent node of the subtrees that will be rotated; * *Pivot* - the node that will become parent (basically will be on the *Root*'s position) after rotation; * *RotationSubtree* - subtree of the *Pivot* upon the side of rotation * *OppositeSubtree* - subtree of the *Pivot* opposite the side of rotation From 3e62df6cff7e3408647b8da016ca4230fb2a191c Mon Sep 17 00:00:00 2001 From: Ute Schiehlen Date: Mon, 10 Apr 2017 11:18:34 +0200 Subject: [PATCH 0502/1275] Silenced warnings in print statements --- .../RedBlackTree.playground/Sources/RedBlackTree.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index 6f3b16b86..351f89a9d 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -638,11 +638,11 @@ extension RedBlackTree { if let leftChild = node.leftChild, let rightChild = node.rightChild { if node.color == .red { if !leftChild.isNullLeaf && leftChild.color == .red { - print("Property-Error: Red node with key \(node.key ?? nil) has red left child") + print("Property-Error: Red node with key \(String(describing: node.key)) has red left child") return false } if !rightChild.isNullLeaf && rightChild.color == .red { - print("Property-Error: Red node with key \(node.key ?? nil) has red right child") + print("Property-Error: Red node with key \(String(describing: node.key)) has red right child") return false } } @@ -677,7 +677,7 @@ extension RedBlackTree { let addedHeight = node.color == .black ? 1 : 0 return left + addedHeight } else { - print("Property-Error: Black height violated at node with key \(node.key ?? nil)") + print("Property-Error: Black height violated at node with key \(String(describing: node.key))") return -1 } } @@ -697,7 +697,7 @@ extension RBTreeNode: CustomDebugStringConvertible { s = "key: nil" } if let parent = parent { - s += ", parent: \(parent.key)" + s += ", parent: \(String(describing: parent.key))" } if let left = leftChild { s += ", left = [" + left.debugDescription + "]" From 51d36815aaf49d23cc0630ed36459141acbdab9e Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Mon, 10 Apr 2017 15:38:52 -0400 Subject: [PATCH 0503/1275] Updated a comment about nested class declarations for Swift 3. Formatted the signature at the bottom --- Linked List/README.markdown | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 1884aeb23..c5a752e13 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -79,18 +79,18 @@ public class LinkedList { public typealias Node = LinkedListNode private var head: Node? - + public var isEmpty: Bool { return head == nil } - + public var first: Node? { return head } } ``` -Ideally, I'd like to put the `LinkedListNode` class inside `LinkedList` but Swift currently doesn't allow generic types to have nested types. Instead we're using a typealias so inside `LinkedList` we can write the shorter `Node` instead of `LinkedListNode`. +Ideally, we would want a class name to be as descriptive as possible, yet, we don't want to type a long name every time we want to use the class, therefore, we're using a typealias so inside `LinkedList` we can write the shorter `Node` instead of `LinkedListNode`. This linked list only has a `head` pointer, not a tail. Adding a tail pointer is left as an exercise for the reader. (I'll point out which functions would be different if we also had a tail pointer.) @@ -267,7 +267,7 @@ Let's write a method that lets you insert a new node at any index in the list. F ```swift private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { assert(index >= 0) - + var i = index var next = head var prev: Node? @@ -283,13 +283,13 @@ Let's write a method that lets you insert a new node at any index in the list. F } ``` -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. +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. +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 @@ -320,7 +320,7 @@ Now that we have this helper function, we can write the method for inserting nod ```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 @@ -364,20 +364,20 @@ What else do we need? Removing nodes, of course! First we'll do `removeAll()`, w If you had a tail pointer, you'd set it to `nil` here too. -Next we'll add some functions that let you remove individual nodes. If you already have a reference to the node, then using `removeNode()` is the most optimal because you don't need to iterate through the list to find the node first. +Next we'll add some functions that let you remove individual nodes. If you already have a reference to the node, then using `removeNode()` is the most optimal because you don't need to iterate through the list to find the node first. ```swift 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 @@ -412,7 +412,7 @@ If you don't have a reference to the node, you can use `removeLast()` or `remove } ``` -All these removal functions also return the value from the removed element. +All these removal functions also return the value from the removed element. ```swift list.removeLast() // "World" @@ -543,4 +543,4 @@ When performing operations on a linked list, you always need to be careful to up When processing lists, you can often use recursion: process the first element and then recursively call the function again on the rest of the list. You’re done when there is no next element. This is why linked lists are the foundation of functional programming languages such as LISP. -*Written for Swift Algorithm Club by Matthijs Hollemans* +*Originally written by Matthijs Hollemans for Ray Wenderlich's Swift Algorithm Club* From a613ca599c03a98e588e32982d57097d5b388909 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Mon, 10 Apr 2017 16:39:50 -0400 Subject: [PATCH 0504/1275] Updated the Playground file with more comments and added an overloadded implementations of 'insert' & 'append' to accept a whole list as an argument --- .../LinkedList.playground/Contents.swift | 96 +++++++++++++++---- .../contents.xcplayground | 2 +- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index abbb90467..93ed4246d 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -1,30 +1,41 @@ -//: Playground - noun: a place where people can play +//: # Linked Lists -public class LinkedListNode { - var value: T - var next: LinkedListNode? - weak var previous: LinkedListNode? - - public init(value: T) { - self.value = value - } -} +// For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu +//: Linked List Class Declaration: 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 + // 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? { if var node = head { while case let next? = node.next { @@ -36,6 +47,7 @@ public final class LinkedList { } } + // 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 @@ -49,6 +61,7 @@ public final class LinkedList { } } + // Function to return the node at a specific index public func node(atIndex index: Int) -> Node? { if index >= 0 { var node = head @@ -62,17 +75,20 @@ public final class LinkedList { return nil } + // Subscript function to return the node at a specific index public subscript(index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) return node!.value } + // Append a value public func append(_ value: T) { let newNode = Node(value: value) self.append(newNode) } + // Append a node without taking ownership (appends a copy) public func append(_ node: Node) { let newNode = LinkedListNode(value: node.value) if let lastNode = last { @@ -83,6 +99,16 @@ public final class LinkedList { } } + // Append a whole linked list without taking ownership (appends a copy) + public func append(_ list: LinkedList) { + var nodeToCopy = list.head + while let node = nodeToCopy { + self.append(node.value) + nodeToCopy = node.next + } + } + + // Private helper function to return the nodes (in a tuple) before and after a specific index private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { assert(index >= 0) @@ -100,11 +126,13 @@ public final class LinkedList { return (prev, next) } + // Insert a value at a specific index public func insert(_ value: T, atIndex index: Int) { let newNode = Node(value: value) self.insert(newNode, atIndex: index) } + // Insert a node at a specific index without taking ownership (inserts a copy) public func insert(_ node: Node, atIndex index: Int) { let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = LinkedListNode(value: node.value) @@ -118,10 +146,33 @@ public final class LinkedList { } } + // Insert a whole linked list at a specific index without taking ownership (inserts a copy) + 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 + } + prev?.next = next + next?.previous = prev + } + + // Function to remove all nodes from the list public func removeAll() { head = nil } + // Function to remove a specific node from the list and return its value @discardableResult public func remove(node: Node) -> T { let prev = node.previous let next = node.next @@ -138,11 +189,13 @@ public final class LinkedList { return node.value } + // Function to remove the last node in the list @discardableResult public func removeLast() -> T { assert(!isEmpty) return remove(node: last!) } + // Function to remove the node at a specific index from the list @discardableResult public func remove(atIndex index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) @@ -150,6 +203,7 @@ public final class LinkedList { } } +//: End of the base class declarations & beginning of extensions' declarations: extension LinkedList: CustomStringConvertible { public var description: String { var s = "[" @@ -218,6 +272,8 @@ extension LinkedList: ExpressibleByArrayLiteral { } } + +//: Ok, now that the declarations are done, let's see our Linked List in action: let list = LinkedList() list.isEmpty // true list.first // nil @@ -247,10 +303,20 @@ list[0] // "Hello" list[1] // "World" //list[2] // crash! +let list2 = LinkedList() +list2.append("Goodbye") +list2.append("World") +list.append(list2) // [Hello, World, Goodbye, World] +list2.removeAll() // [ ] +list2.isEmpty // true +list.removeLast() // "World" +list.remove(atIndex: 2) // "Goodbye" + + list.insert("Swift", atIndex: 1) -list[0] -list[1] -list[2] +list[0] // "Hello" +list[1] // "Swift" +list[2] // "World" print(list) list.reverse() // [World, Swift, Hello] @@ -262,9 +328,6 @@ m // [8, 6, 5] let f = list.filter { s in s.characters.count > 5 } f // [Universe, Swifty] -//list.removeAll() -//list.isEmpty - list.remove(node: list.first!) // "Universe" list.count // 2 list[0] // "Swifty" @@ -286,3 +349,4 @@ let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] listArrayLiteral2.count // 3 listArrayLiteral2[0] // "Swift" listArrayLiteral2.removeLast() // "Club" + diff --git a/Linked List/LinkedList.playground/contents.xcplayground b/Linked List/LinkedList.playground/contents.xcplayground index 06828af92..3de2b51ba 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 45ef5cc2e0fb0f340744812a43b0fa329b20f867 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Mon, 10 Apr 2017 16:57:12 -0400 Subject: [PATCH 0505/1275] Added 2 overloaded 'insert' & 'append' funcs that take a List as an argument to LinkedList.swift. Added 5 tests to LinkedListTests.swift to check the added 2 functions --- Linked List/LinkedList.swift | 51 ++++++++++++++++----- Linked List/Tests/LinkedListTests.swift | 60 +++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 11 deletions(-) diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 55593cdc9..a7ef9bf5e 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,14 +1,15 @@ -public class LinkedListNode { - var value: T - var next: LinkedListNode? - weak var previous: LinkedListNode? +public final class LinkedList { - public init(value: T) { - self.value = value + public class LinkedListNode { + var value: T + var next: LinkedListNode? + weak var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } } -} - -public final class LinkedList { + public typealias Node = LinkedListNode fileprivate var head: Node? @@ -72,7 +73,7 @@ public final class LinkedList { } public func append(_ node: Node) { - let newNode = Node(value: node.value) + let newNode = LinkedListNode(value: node.value) if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -81,6 +82,14 @@ public final class LinkedList { } } + public func append(_ list: LinkedList) { + var nodeToCopy = list.head + while let node = nodeToCopy { + self.append(node.value) + nodeToCopy = node.next + } + } + private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { assert(index >= 0) @@ -105,7 +114,7 @@ public final class LinkedList { public func insert(_ node: Node, atIndex index: Int) { let (prev, next) = nodesBeforeAndAfter(index: index) - let newNode = Node(value: node.value) + let newNode = LinkedListNode(value: node.value) newNode.previous = prev newNode.next = next prev?.next = newNode @@ -116,6 +125,26 @@ public final class LinkedList { } } + 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 + } + prev?.next = next + next?.previous = prev + } + public func removeAll() { head = nil } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 6f58d9775..ea063cacb 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -165,7 +165,67 @@ class LinkedListTest: XCTestCase { 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, atIndex: 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) + } + func testInsertListAtFirstIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, atIndex: 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) + } + + func testInsertListAtLastIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, atIndex: 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) + } + + func testAppendList() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + 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) + } + + func testAppendListToEmptyList() { + let list = LinkedList() + let list2 = LinkedList() + list2.append(5) + list2.append(10) + list.append(list2) + XCTAssertTrue(list.count == 2) + XCTAssertEqual(list.node(atIndex: 0)?.value, 5) + XCTAssertEqual(list.node(atIndex: 1)?.value, 10) + } + func testRemoveAtIndexOnListWithOneElement() { let list = LinkedList() list.append(123) From c74bec1667b6be79b6a8dd56dd09b9c0076c1ef7 Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Mon, 10 Apr 2017 19:24:50 -0400 Subject: [PATCH 0506/1275] Updated the xcode version in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b6ff6190c..d413140fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode8 +osx_image: xcode8.3 # sudo: false install: From 84009ae732937157fd3f071b78430895968d500b Mon Sep 17 00:00:00 2001 From: Marwan Alani Date: Tue, 11 Apr 2017 19:33:40 -0400 Subject: [PATCH 0507/1275] Added proper annotation to the Linked List playground files --- .../LinkedList.playground/Contents.swift | 82 ++++++++++++++----- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 93ed4246d..b86fbf0b4 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -5,7 +5,7 @@ //: Linked List Class Declaration: public final class LinkedList { - // Linked List's Node Class Declaration + /// Linked List's Node Class Declaration public class LinkedListNode { var value: T var next: LinkedListNode? @@ -16,26 +16,26 @@ public final class LinkedList { } } - // Typealiasing the node class to increase readability of code + /// Typealiasing the node class to increase readability of code public typealias Node = LinkedListNode - // The head of the Linked List + /// The head of the Linked List fileprivate var head: Node? - // Default initializer + /// Default initializer public init() {} - // Computed property to check if the linked list is empty + /// 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) + /// 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) + /// 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 { @@ -47,7 +47,7 @@ public final class LinkedList { } } - // Computed property to iterate through the linked list and return the total number of nodes + /// 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 @@ -61,7 +61,10 @@ public final class LinkedList { } } - // Function to return the node at a specific index + /// 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 @@ -75,20 +78,26 @@ public final class LinkedList { return nil } - // Subscript function to return the node at a specific index + /// 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(atIndex: index) assert(node != nil) return node!.value } - // Append a 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 node without taking ownership (appends a copy) + /// 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 = LinkedListNode(value: node.value) if let lastNode = last { @@ -99,7 +108,9 @@ public final class LinkedList { } } - // Append a whole linked list without taking ownership (appends a copy) + /// 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 { @@ -108,7 +119,10 @@ public final class LinkedList { } } - // Private helper function to return the nodes (in a tuple) before and after a specific index + /// 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) @@ -126,13 +140,21 @@ public final class LinkedList { return (prev, next) } - // Insert a value at a specific index + /// 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, atIndex index: Int) { let newNode = Node(value: value) self.insert(newNode, atIndex: index) } - // Insert a node at a specific index without taking ownership (inserts a copy) + /// 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(_ node: Node, atIndex index: Int) { let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = LinkedListNode(value: node.value) @@ -146,7 +168,11 @@ public final class LinkedList { } } - // Insert a whole linked list at a specific index without taking ownership (inserts a copy) + /// 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, atIndex index: Int) { if list.isEmpty { return } var (prev, next) = nodesBeforeAndAfter(index: index) @@ -167,12 +193,15 @@ public final class LinkedList { next?.previous = prev } - // Function to remove all nodes from the list + /// Function to remove all nodes/value from the list public func removeAll() { head = nil } - // Function to remove a specific node from the list and return its value + /// 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 @@ -189,13 +218,18 @@ public final class LinkedList { return node.value } - // Function to remove the last node in the list + /// 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 the node at a specific index from the list + /// 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(atIndex index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) @@ -204,6 +238,8 @@ public final class LinkedList { } //: 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 = "[" @@ -217,6 +253,7 @@ extension LinkedList: CustomStringConvertible { } } +// MARK: - Extension to add a 'reverse' function to the list extension LinkedList { public func reverse() { var node = head @@ -228,6 +265,7 @@ extension LinkedList { } } +// MARK: - An extension with an implementation of 'map' & 'filter' functions extension LinkedList { public func map(transform: (T) -> U) -> LinkedList { let result = LinkedList() @@ -252,6 +290,7 @@ extension LinkedList { } } +// MARK: - Extension to enable initialization from an Array extension LinkedList { convenience init(array: Array) { self.init() @@ -262,6 +301,7 @@ extension LinkedList { } } +// MARK: - Extension to enable initialization from an Array Literal extension LinkedList: ExpressibleByArrayLiteral { public convenience init(arrayLiteral elements: T...) { self.init() From 621a28da46cebf8bcd003ef6e80afb7e63b01136 Mon Sep 17 00:00:00 2001 From: vincentngo Date: Thu, 13 Apr 2017 21:07:51 -0400 Subject: [PATCH 0508/1275] Update README.markdown --- Hash Table/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index 958c3595a..bc9636195 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -103,7 +103,7 @@ it first hashes the key `"lastName"` to calculate the array index, which is 3. S Common ways to implement this chaining mechanism are to use a linked list or another array. Since the order of the items in the chain does not matter, you can think of it as a set instead of a list. (Now you can also imagine where the term "bucket" comes from; we just dump all the objects together into the bucket.) -Chains should not become long becasuse the slow process of looking up items in the hash table. Ideally, we would have no chains at all, but in practice it is impossible to avoid collisions. You can improve the odds by giving the hash table enough buckets using high-quality hash functions. +Chains should not become long because the slow process of looking up items in the hash table. Ideally, we would have no chains at all, but in practice it is impossible to avoid collisions. You can improve the odds by giving the hash table enough buckets using high-quality hash functions. > **Note:** An alternative to chaining is "open addressing". The idea is this: if an array index is already taken, we put the element in the next unused bucket. This approach has its own upsides and downsides. @@ -127,7 +127,7 @@ public struct HashTable { } ``` -The `HashTable` is a generic container, and the two generic types are named `Key` (which must be `Hashable`) and `Value`. We also define two other types: `Element` is a key/value pair for useing in a chain, and `Bucket` is an array of such `Elements`. +The `HashTable` is a generic container, and the two generic types are named `Key` (which must be `Hashable`) and `Value`. We also define two other types: `Element` is a key/value pair for using in a chain, and `Bucket` is an array of such `Elements`. The main array is named `buckets`. It has a fixed size, the so-called capacity, provided by the `init(capacity)` method. We are also keeping track of how many items have been added to the hash table using the `count` variable. From 55c11cadd38ee59e89a3128860b53f63e8b0457d Mon Sep 17 00:00:00 2001 From: ph1ps Date: Fri, 14 Apr 2017 21:37:24 +0200 Subject: [PATCH 0509/1275] Claim Naive Bayes Classifier --- Naive Bayes Classifier/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Naive Bayes Classifier/README.md diff --git a/Naive Bayes Classifier/README.md b/Naive Bayes Classifier/README.md new file mode 100644 index 000000000..e69de29bb From 85f8085de5131657a9f8f5e7ab8f8d3e42f39edf Mon Sep 17 00:00:00 2001 From: ph1ps Date: Fri, 14 Apr 2017 21:38:44 +0200 Subject: [PATCH 0510/1275] Add initial version of NB --- Naive Bayes Classifier/NaiveBayes.swift | 141 ++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Naive Bayes Classifier/NaiveBayes.swift diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift new file mode 100644 index 000000000..c988cacbe --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.swift @@ -0,0 +1,141 @@ +// +// main.swift +// NaiveBayes +// +// Created by Philipp Gabriel on 14.04.17. +// Copyright © 2017 ph1ps. All rights reserved. +// + +//TODO naming +import Foundation + +extension Array where Element == Double { + + func mean() -> Double { + return self.reduce(0, +) / Double(count) + } + + func standardDeviation() -> Double { + let calculatedMean = mean() + + let sum = self.reduce(0.0) { (previous, next) in + return previous + pow(next - calculatedMean, 2) + } + + return sqrt(sum / Double(count - 1)) + } +} + +extension Array where Element == Int { + + //Is this the best way?! + func uniques() -> [Int] { + return Array(Set(self)) + } + +} + +class NaiveBayes { + + var data: [[Double]] + var classes: [Int] + var variables: [Int: [(feature: Int, mean: Double, stDev: Double)]] + + init(data: [[Double]], classes: [Int]) { + self.data = data + self.classes = classes + self.variables = [Int: [(feature: Int, mean: Double, stDev: Double)]]() + } + + //TODO + //init(dataAndClasses: [[Double]], index ofClassRow: Int) {} + + //TODO: Does it really need to be n^2 runtime? + func train() { + + for `class` in 0.. Int { + let likelihoods = predictLikelihood(input: input).max { (first, second) -> Bool in + return first.1 < second.1 + } + + guard let `class` = likelihoods?.0 else { + return -1 + } + + return `class` + } + + func predictLikelihood(input: [Double]) -> [(Int, Double)] { + + var probabilityOfClasses = [Int: Double]() + let amount = classes.uniques().count + + classes.forEach { `class` in + let individual = classes.filter { $0 == `class` }.count + probabilityOfClasses[`class`] = Double(amount) / Double(individual) + } + + let probaClass = variables.map { (key, value) -> (Int, [Double]) in + let probaFeature = value.map { (feature, mean, stDev) -> Double in + let featureValue = input[feature] + let eulerPart = pow(M_E, -1 * pow(featureValue - mean, 2) / (2 * pow(stDev, 2))) + let distribution = eulerPart / sqrt(2 * .pi) / stDev + return distribution + } + return (key, probaFeature) + } + + let likelihoods = probaClass.map { (key, probaFeature) in + return (key, probaFeature.reduce(1, *) * (probabilityOfClasses[key] ?? 1.0)) + } + + let sum = likelihoods.map { $0.1 }.reduce(0, +) + let normalized = likelihoods.map { (`class`, likelihood) in + return (`class`, likelihood / sum) + } + + return normalized + } +} + +let data: [[Double]] = [ + [6,180,12], + [5.92,190,11], + [5.58,170,12], + [5.92,165,10], + [5,100,6], + [5.5,150,8], + [5.42,130,7], + [5.75,150,9] +] + +let classes = [0,0,0,0,1,1,1,1] + +let naive = NaiveBayes(data: data, classes: classes) +naive.train() +let result = naive.predictLikelihood(input: [6,130,8]) +print(result) + + + + + + + + From be4ac46a126d4f1b744bb84216ab0ef68686e2e7 Mon Sep 17 00:00:00 2001 From: Philipp Gabriel Date: Fri, 14 Apr 2017 21:40:52 +0200 Subject: [PATCH 0511/1275] Add NB to README --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 29fc9d748..7df847960 100644 --- a/README.markdown +++ b/README.markdown @@ -116,6 +116,7 @@ Bad sorting algorithms (don't use these!): - Logistic Regression - Neural Networks - PageRank +- [Naive Bayes Classifier](Naive%20Bayes%20Classifier/) ## Data structures From f536ff10804f32066a5fdea1becfc6b80ebbf25f Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 02:06:55 +0600 Subject: [PATCH 0512/1275] Bugs fied. Readme added. --- .../EggDrop.playground/Contents.swift | 5 +++ .../EggDrop.playground/Sources/EggDrop.swift | 41 +++++++++++++++++ .../EggDrop.playground/contents.xcplayground | 4 ++ Egg Drop Problem/EggDrop.swift | 36 +++++++++------ Egg Drop Problem/README.markdown | 44 +++++++++++++++++++ .../contents.xcworkspacedata | 6 +++ 6 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 Egg Drop Problem/EggDrop.playground/Contents.swift create mode 100644 Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift create mode 100644 Egg Drop Problem/EggDrop.playground/contents.xcplayground create mode 100644 Egg Drop Problem/README.markdown diff --git a/Egg Drop Problem/EggDrop.playground/Contents.swift b/Egg Drop Problem/EggDrop.playground/Contents.swift new file mode 100644 index 000000000..4ddb936b3 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/Contents.swift @@ -0,0 +1,5 @@ + //: Playground - noun: a place where people can play + +import Cocoa + +eggDrop(numberOfEggs: 2, numberOfFloors: 4) diff --git a/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift new file mode 100644 index 000000000..f69284491 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift @@ -0,0 +1,41 @@ +public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { + if numberOfEggs == 0 || numberOfFloors == 0{ + return 0 + } + if numberOfEggs == 1 || numberOfFloors == 1{ + return 1 + } + + var eggFloor = [[Int]](repeating: [Int](repeating: 0, count: numberOfFloors+1), count: numberOfEggs+1) //egg(rows) floor(cols) array to store the solutions + var attempts: Int = 0 + + for var floorNumber in (0..<(numberOfFloors+1)){ + eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts + for var eggNumber in (2..<(numberOfEggs+1)){ + eggFloor[eggNumber][floorNumber] = 0 + } + } + eggFloor[2][1] = 1 //base case: if there's are two eggs and one floor, it takes one attempt + + for var eggNumber in (2..<(numberOfEggs+1)){ + for var floorNumber in (2..<(numberOfFloors+1)){ + eggFloor[eggNumber][floorNumber] = 1000000 + for var visitingFloor in (1..<(floorNumber+1)){ + //there are two cases + //case 1: egg breaks. meaning we'll have one less egg, and we'll have to go downstairs -> visitingFloor-1 + //case 2: egg doesn't break. meaning we'll still have 'eggs' number of eggs, and we'll go upstairs -> floorNumber-visitingFloor + attempts = 1 + max(eggFloor[eggNumber-1][visitingFloor-1], eggFloor[eggNumber][floorNumber-visitingFloor])//we add one taking into account the attempt we're taking at the moment + + if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min + eggFloor[eggNumber][floorNumber] = attempts; + } + } + } + } + + return eggFloor[numberOfEggs][numberOfFloors] +} + +public func max(_ x1: Int, _ x2: Int) -> Int{ + return x1 > x2 ? x1 : x2 +} diff --git a/Egg Drop Problem/EggDrop.playground/contents.xcplayground b/Egg Drop Problem/EggDrop.playground/contents.xcplayground new file mode 100644 index 000000000..63b6dd8df --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift index 6d0aab2a1..a525793db 100644 --- a/Egg Drop Problem/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.swift @@ -1,23 +1,33 @@ -func eggDrop(_ numberOfEggs: Int, numberOfFloors: Int) -> Int { - var eggFloor: [[Int]] = [] //egg(rows) floor(cols) array to store the solutions +public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { + if numberOfEggs == 0 || numberOfFloors == 0{ + return 0 + } + if numberOfEggs == 1 || numberOfFloors == 1{ + return 1 + } + + var eggFloor = [[Int]](repeating: [Int](repeating: 0, count: numberOfFloors+1), count: numberOfEggs+1) //egg(rows) floor(cols) array to store the solutions var attempts: Int = 0 - for var i in (0.. k-1 - //case 2: egg doesn't break. meaning we'll still have 'i' number of eggs, and we'll go upstairs -> j-k - attempts = 1 + max(eggFloor[i-1][k-1], eggFloor[i][j-k])//we add one taking into account the attempt we're taking at the moment + //case 2: egg doesn't break. meaning we'll still have 'eggs' number of eggs, and we'll go upstairs -> floors-k + attempts = 1 + max(eggFloor[eggNumber-1][floors-1], eggFloor[eggNumber][floorNumber-floors])//we add one taking into account the attempt we're taking at the moment - if attempts < eggFloor[i][j]{ //finding the min - eggFloor[i][j] = attempts; + if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min + eggFloor[eggNumber][floorNumber] = attempts; } } } @@ -26,6 +36,6 @@ func eggDrop(_ numberOfEggs: Int, numberOfFloors: Int) -> Int { return eggFloor[numberOfEggs][numberOfFloors] } -func max(_ x1: Int, _ x2: Int){ +public func max(_ x1: Int, _ x2: Int) -> Int{ return x1 > x2 ? x1 : x2 } diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown new file mode 100644 index 000000000..a58827ba3 --- /dev/null +++ b/Egg Drop Problem/README.markdown @@ -0,0 +1,44 @@ +#Egg Drop Dynamic Problem + +#Problem Description + +Given some number of floors and some number of eggs, what is the minimum number of attempts it will take to find out from which floor egg will break. + +Suppose that we wish to know which stories in a 36-story building are safe to drop eggs from, and which will cause the eggs to break on landing. We make a few assumptions: + +- An egg that survives a fall can be used again. +- A broken egg must be discarded. +- The effect of a fall is the same for all eggs. +- If an egg breaks when dropped, then it would break if dropped from a higher floor. +- If an egg survives a fall then it would survive a shorter fall. + +If only one egg is available and we wish to be sure of obtaining the right result, the experiment can be carried out in only one way. Drop the egg from the first-floor window; if it survives, drop it from the second floor window. Continue upward until it breaks. In the worst case, this method may require 36 droppings. Suppose 2 eggs are available. What is the least number of egg-droppings that is guaranteed to work in all cases? +The problem is not actually to find the critical floor, but merely to decide floors from which eggs should be dropped so that total number of trials are minimized. + +#Solution +We store all the solutions in a 2D array. Where rows represents number of eggs and columns represent number of floors. + +First, we set base cases: +1) If there's only one egg, it takes as many attempts as number of floors +2) If there's are two eggs and one floor, it takes one attempt + +eggNumber ==> Number of eggs at the moment +floorNumber ==> Floor number at the moment +visitingFloor ==> Floor being visited at the moment +attempts ==> Minimum number of attempts it will take to find out from which floor egg will break + +When we drop an egg from a floor 'floorNumber', there can be two cases (1) The egg breaks (2) The egg doesn’t break. + +1) If the egg breaks after dropping from 'floorNumberth' floor, then we only need to check for floors lower than 'floorNumber' with remaining eggs; so the problem reduces to 'floorNumber'-1 floors and 'eggNumber'-1 eggs +2) If the egg doesn’t break after dropping from the xth floor, then we only need to check for floors higher than 'floorNumber'; so the problem reduces to floors-'floorNumber' floors and 'eggNumber' eggs. + +Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We consider the max of above two cases for every floor and choose the floor which yields minimum number of trials. + +```swift + +attempts = 1 + max(eggFloor[eggNumber-1][floors-1], eggFloor[eggNumber][floorNumber-floors])//we add one taking into account the attempt we're taking at the moment + +if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min + eggFloor[eggNumber][floorNumber] = attempts; +} +``` diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5ac8577f5..1c6b407c3 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -7,6 +7,12 @@ + + + + From 75d3b5b59977a1cc54bcac2ce42e2c884eab5e69 Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 02:12:30 +0600 Subject: [PATCH 0513/1275] Bugs fixed --- Egg Drop Problem/README.markdown | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index a58827ba3..44af8174a 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -23,19 +23,21 @@ First, we set base cases: 2) If there's are two eggs and one floor, it takes one attempt eggNumber ==> Number of eggs at the moment + floorNumber ==> Floor number at the moment + visitingFloor ==> Floor being visited at the moment + attempts ==> Minimum number of attempts it will take to find out from which floor egg will break When we drop an egg from a floor 'floorNumber', there can be two cases (1) The egg breaks (2) The egg doesn’t break. -1) If the egg breaks after dropping from 'floorNumberth' floor, then we only need to check for floors lower than 'floorNumber' with remaining eggs; so the problem reduces to 'floorNumber'-1 floors and 'eggNumber'-1 eggs -2) If the egg doesn’t break after dropping from the xth floor, then we only need to check for floors higher than 'floorNumber'; so the problem reduces to floors-'floorNumber' floors and 'eggNumber' eggs. +1) If the egg breaks after dropping from 'visitingFloorth' floor, then we only need to check for floors lower than 'visitingFloor' with remaining eggs; so the problem reduces to 'visitingFloor'-1 floors and 'eggNumber'-1 eggs. +2) If the egg doesn’t break after dropping from the 'visitingFloorth' floor, then we only need to check for floors higher than 'visitingFloor'; so the problem reduces to floors-'visitingFloor' floors and 'eggNumber' eggs. Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We consider the max of above two cases for every floor and choose the floor which yields minimum number of trials. ```swift - attempts = 1 + max(eggFloor[eggNumber-1][floors-1], eggFloor[eggNumber][floorNumber-floors])//we add one taking into account the attempt we're taking at the moment if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min From 61949ab24314ee060f888642c59d6d20bcfa4841 Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 11:09:53 +0600 Subject: [PATCH 0514/1275] Minor changes in README --- .../EggDrop.playground/Sources/EggDrop.swift | 9 +++------ Egg Drop Problem/EggDrop.swift | 16 ++++++++-------- Egg Drop Problem/README.markdown | 19 ++++++++++++------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift index f69284491..897ba2dee 100644 --- a/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift @@ -1,5 +1,5 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { - if numberOfEggs == 0 || numberOfFloors == 0{ + if numberOfEggs == 0 || numberOfFloors == 0{ //edge case: When either number of eggs or number of floors is 0, answer is 0 return 0 } if numberOfEggs == 1 || numberOfFloors == 1{ @@ -11,15 +11,12 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { for var floorNumber in (0..<(numberOfFloors+1)){ eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts - for var eggNumber in (2..<(numberOfEggs+1)){ - eggFloor[eggNumber][floorNumber] = 0 - } } - eggFloor[2][1] = 1 //base case: if there's are two eggs and one floor, it takes one attempt + eggFloor[2][1] = 1 //base case: if there are two eggs and one floor, it takes one attempt for var eggNumber in (2..<(numberOfEggs+1)){ for var floorNumber in (2..<(numberOfFloors+1)){ - eggFloor[eggNumber][floorNumber] = 1000000 + eggFloor[eggNumber][floorNumber] = Int.max //setting the final result a high number to find out minimum for var visitingFloor in (1..<(floorNumber+1)){ //there are two cases //case 1: egg breaks. meaning we'll have one less egg, and we'll have to go downstairs -> visitingFloor-1 diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift index a525793db..7be691f57 100644 --- a/Egg Drop Problem/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.swift @@ -1,5 +1,5 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { - if numberOfEggs == 0 || numberOfFloors == 0{ + if numberOfEggs == 0 || numberOfFloors == 0{ //edge case: When either number of eggs or number of floors is 0, answer is 0 return 0 } if numberOfEggs == 1 || numberOfFloors == 1{ @@ -10,21 +10,21 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { var attempts: Int = 0 for var floorNumber in (0..<(numberOfFloors+1)){ - eggFloor[1][floorNumber] = floorNumber + eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts for var eggNumber in (2..<(numberOfEggs+1)){ eggFloor[eggNumber][floorNumber] = 0 } } - eggFloor[2][1] = 1 + eggFloor[2][1] = 1 //base case: if there are two eggs and one floor, it takes one attempt for var eggNumber in (2..<(numberOfEggs+1)){ for var floorNumber in (2..<(numberOfFloors+1)){ - eggFloor[eggNumber][floorNumber] = 1000000 - for var floors in (1..<(floorNumber+1)){ + eggFloor[eggNumber][floorNumber] = Int.max //setting the final result a high number to find out minimum + for var visitingFloor in (1..<(floorNumber+1)){ //there are two cases - //case 1: egg breaks. meaning we'll have one less egg, and we'll have to go downstairs -> k-1 - //case 2: egg doesn't break. meaning we'll still have 'eggs' number of eggs, and we'll go upstairs -> floors-k - attempts = 1 + max(eggFloor[eggNumber-1][floors-1], eggFloor[eggNumber][floorNumber-floors])//we add one taking into account the attempt we're taking at the moment + //case 1: egg breaks. meaning we'll have one less egg, and we'll have to go downstairs -> visitingFloor-1 + //case 2: egg doesn't break. meaning we'll still have 'eggs' number of eggs, and we'll go upstairs -> floorNumber-visitingFloor + attempts = 1 + max(eggFloor[eggNumber-1][visitingFloor-1], eggFloor[eggNumber][floorNumber-visitingFloor])//we add one taking into account the attempt we're taking at the moment if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min eggFloor[eggNumber][floorNumber] = attempts; diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index 44af8174a..2df3088b5 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -22,19 +22,24 @@ First, we set base cases: 1) If there's only one egg, it takes as many attempts as number of floors 2) If there's are two eggs and one floor, it takes one attempt -eggNumber ==> Number of eggs at the moment - -floorNumber ==> Floor number at the moment - -visitingFloor ==> Floor being visited at the moment - -attempts ==> Minimum number of attempts it will take to find out from which floor egg will break +- eggNumber ==> Number of eggs at the moment +- floorNumber ==> Floor number at the moment +- visitingFloor ==> Floor being visited at the moment +- attempts ==> Minimum number of attempts it will take to find out from which floor egg will break When we drop an egg from a floor 'floorNumber', there can be two cases (1) The egg breaks (2) The egg doesn’t break. 1) If the egg breaks after dropping from 'visitingFloorth' floor, then we only need to check for floors lower than 'visitingFloor' with remaining eggs; so the problem reduces to 'visitingFloor'-1 floors and 'eggNumber'-1 eggs. 2) If the egg doesn’t break after dropping from the 'visitingFloorth' floor, then we only need to check for floors higher than 'visitingFloor'; so the problem reduces to floors-'visitingFloor' floors and 'eggNumber' eggs. +```swift +for var floorNumber in (0..<(numberOfFloors+1)){ + eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts +} + +eggFloor[2][1] = 1 //base case: if there are two eggs and one floor, it takes one attempt +``` + Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We consider the max of above two cases for every floor and choose the floor which yields minimum number of trials. ```swift From 4ab987c592763cd13719411b829d8d513a64707b Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 11:14:18 +0600 Subject: [PATCH 0515/1275] Minor changes in README --- Egg Drop Problem/README.markdown | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index 2df3088b5..eda28fa6f 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -16,32 +16,33 @@ If only one egg is available and we wish to be sure of obtaining the right resul The problem is not actually to find the critical floor, but merely to decide floors from which eggs should be dropped so that total number of trials are minimized. #Solution +- eggNumber -> Number of eggs at the moment +- floorNumber -> Floor number at the moment +- visitingFloor -> Floor being visited at the moment +- attempts -> Minimum number of attempts it will take to find out from which floor egg will break + We store all the solutions in a 2D array. Where rows represents number of eggs and columns represent number of floors. First, we set base cases: 1) If there's only one egg, it takes as many attempts as number of floors 2) If there's are two eggs and one floor, it takes one attempt -- eggNumber ==> Number of eggs at the moment -- floorNumber ==> Floor number at the moment -- visitingFloor ==> Floor being visited at the moment -- attempts ==> Minimum number of attempts it will take to find out from which floor egg will break - -When we drop an egg from a floor 'floorNumber', there can be two cases (1) The egg breaks (2) The egg doesn’t break. - -1) If the egg breaks after dropping from 'visitingFloorth' floor, then we only need to check for floors lower than 'visitingFloor' with remaining eggs; so the problem reduces to 'visitingFloor'-1 floors and 'eggNumber'-1 eggs. -2) If the egg doesn’t break after dropping from the 'visitingFloorth' floor, then we only need to check for floors higher than 'visitingFloor'; so the problem reduces to floors-'visitingFloor' floors and 'eggNumber' eggs. - ```swift for var floorNumber in (0..<(numberOfFloors+1)){ - eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts +eggFloor[1][floorNumber] = floorNumber //base case 1: if there's only one egg, it takes 'numberOfFloors' attempts } -eggFloor[2][1] = 1 //base case: if there are two eggs and one floor, it takes one attempt +eggFloor[2][1] = 1 //base case 2: if there are two eggs and one floor, it takes one attempt ``` +When we drop an egg from a floor 'floorNumber', there can be two cases (1) The egg breaks (2) The egg doesn’t break. + +1) If the egg breaks after dropping from 'visitingFloorth' floor, then we only need to check for floors lower than 'visitingFloor' with remaining eggs; so the problem reduces to 'visitingFloor'-1 floors and 'eggNumber'-1 eggs. +2) If the egg doesn’t break after dropping from the 'visitingFloorth' floor, then we only need to check for floors higher than 'visitingFloor'; so the problem reduces to floors-'visitingFloor' floors and 'eggNumber' eggs. + Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We consider the max of above two cases for every floor and choose the floor which yields minimum number of trials. +We find the answer based on the base cases and previously found answers as follows. ```swift attempts = 1 + max(eggFloor[eggNumber-1][floors-1], eggFloor[eggNumber][floorNumber-floors])//we add one taking into account the attempt we're taking at the moment From 1fbb40efe14b80d6187a9ebd698960ba3520fe3b Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 11:35:40 +0600 Subject: [PATCH 0516/1275] Example added --- Egg Drop Problem/EggDrop.playground/Contents.swift | 6 +++++- Egg Drop Problem/EggDrop.swift | 3 --- Egg Drop Problem/README.markdown | 14 +++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Egg Drop Problem/EggDrop.playground/Contents.swift b/Egg Drop Problem/EggDrop.playground/Contents.swift index 4ddb936b3..d452e7f9f 100644 --- a/Egg Drop Problem/EggDrop.playground/Contents.swift +++ b/Egg Drop Problem/EggDrop.playground/Contents.swift @@ -2,4 +2,8 @@ import Cocoa -eggDrop(numberOfEggs: 2, numberOfFloors: 4) +eggDrop(numberOfEggs: 2, numberOfFloors: 2) //expected answer: 2 +eggDrop(numberOfEggs: 2, numberOfFloors: 4) //expected answer: 3 +eggDrop(numberOfEggs: 2, numberOfFloors: 6) //expected answer: 3 +eggDrop(numberOfEggs: 5, numberOfFloors: 5) //expected answer: 2 +eggDrop(numberOfEggs: 5, numberOfFloors: 20) //expected answer: 4 \ No newline at end of file diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift index 7be691f57..897ba2dee 100644 --- a/Egg Drop Problem/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.swift @@ -11,9 +11,6 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { for var floorNumber in (0..<(numberOfFloors+1)){ eggFloor[1][floorNumber] = floorNumber //base case: if there's only one egg, it takes 'numberOfFloors' attempts - for var eggNumber in (2..<(numberOfEggs+1)){ - eggFloor[eggNumber][floorNumber] = 0 - } } eggFloor[2][1] = 1 //base case: if there are two eggs and one floor, it takes one attempt diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index eda28fa6f..1a436c374 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -25,7 +25,7 @@ We store all the solutions in a 2D array. Where rows represents number of eggs a First, we set base cases: 1) If there's only one egg, it takes as many attempts as number of floors -2) If there's are two eggs and one floor, it takes one attempt +2) If there are two eggs and one floor, it takes one attempt ```swift for var floorNumber in (0..<(numberOfFloors+1)){ @@ -50,3 +50,15 @@ if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min eggFloor[eggNumber][floorNumber] = attempts; } ``` +Example: +Let's assume we have 2 eggs and 2 floors. +1) We drop one egg from the first floor. If it breaks, then we get the answer. If it doesn't we'll have 2 eggs and 1 floors to work with. + attempts = 1 + maximum of 0(got the answer) and eggFloor[2][1] (base case 2 which gives us 1) + attempts = 1 + 1 = 2 +2) We drop one egg from the second floor. If it breaks, we'll have 1 egg and 1 floors to work with. If it doesn't, we'll get the answer. + attempts = 1 + maximum of eggFloor[1][1](base case 1 which gives us 1) and 0(got the answer) + attempts = 1 + 1 = 2 +3) Finding the minimum of 2 and 2 gives us 2, so the answer is 2. + 2 is the minimum number of attempts it will take to find out from which floor egg will break. + + From 082385a5ac58967b8eaf565654f1620444383ebf Mon Sep 17 00:00:00 2001 From: Arkalyk Akash Date: Sat, 15 Apr 2017 11:37:09 +0600 Subject: [PATCH 0517/1275] Update README.markdown --- Egg Drop Problem/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index 1a436c374..5ff6ebb1d 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -1,6 +1,6 @@ -#Egg Drop Dynamic Problem +# Egg Drop Dynamic Problem -#Problem Description +# Problem Description Given some number of floors and some number of eggs, what is the minimum number of attempts it will take to find out from which floor egg will break. @@ -15,7 +15,7 @@ Suppose that we wish to know which stories in a 36-story building are safe to dr If only one egg is available and we wish to be sure of obtaining the right result, the experiment can be carried out in only one way. Drop the egg from the first-floor window; if it survives, drop it from the second floor window. Continue upward until it breaks. In the worst case, this method may require 36 droppings. Suppose 2 eggs are available. What is the least number of egg-droppings that is guaranteed to work in all cases? The problem is not actually to find the critical floor, but merely to decide floors from which eggs should be dropped so that total number of trials are minimized. -#Solution +# Solution - eggNumber -> Number of eggs at the moment - floorNumber -> Floor number at the moment - visitingFloor -> Floor being visited at the moment From ffea424eec7b80d010d731f6f1b44c442c26cab8 Mon Sep 17 00:00:00 2001 From: Arkalyk Akash Date: Sat, 15 Apr 2017 11:37:55 +0600 Subject: [PATCH 0518/1275] Update README.markdown --- Egg Drop Problem/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index 5ff6ebb1d..82543502d 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -1,6 +1,6 @@ # Egg Drop Dynamic Problem -# Problem Description +## Problem Description Given some number of floors and some number of eggs, what is the minimum number of attempts it will take to find out from which floor egg will break. @@ -15,7 +15,7 @@ Suppose that we wish to know which stories in a 36-story building are safe to dr If only one egg is available and we wish to be sure of obtaining the right result, the experiment can be carried out in only one way. Drop the egg from the first-floor window; if it survives, drop it from the second floor window. Continue upward until it breaks. In the worst case, this method may require 36 droppings. Suppose 2 eggs are available. What is the least number of egg-droppings that is guaranteed to work in all cases? The problem is not actually to find the critical floor, but merely to decide floors from which eggs should be dropped so that total number of trials are minimized. -# Solution +## Solution - eggNumber -> Number of eggs at the moment - floorNumber -> Floor number at the moment - visitingFloor -> Floor being visited at the moment @@ -50,7 +50,7 @@ if attempts < eggFloor[eggNumber][floorNumber]{ //finding the min eggFloor[eggNumber][floorNumber] = attempts; } ``` -Example: +## Example Let's assume we have 2 eggs and 2 floors. 1) We drop one egg from the first floor. If it breaks, then we get the answer. If it doesn't we'll have 2 eggs and 1 floors to work with. attempts = 1 + maximum of 0(got the answer) and eggFloor[2][1] (base case 2 which gives us 1) From 260948a2b7af625ea0fe6590e3cf966975c420dd Mon Sep 17 00:00:00 2001 From: ARKALYK AKASH Date: Sat, 15 Apr 2017 11:41:32 +0600 Subject: [PATCH 0519/1275] Comments added --- Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift | 3 ++- Egg Drop Problem/EggDrop.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift index 897ba2dee..db1e48b95 100644 --- a/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.playground/Sources/EggDrop.swift @@ -2,7 +2,7 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { if numberOfEggs == 0 || numberOfFloors == 0{ //edge case: When either number of eggs or number of floors is 0, answer is 0 return 0 } - if numberOfEggs == 1 || numberOfFloors == 1{ + if numberOfEggs == 1 || numberOfFloors == 1{ //edge case: When either number of eggs or number of floors is 1, answer is 1 return 1 } @@ -33,6 +33,7 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { return eggFloor[numberOfEggs][numberOfFloors] } +//Helper function to find max of two integers public func max(_ x1: Int, _ x2: Int) -> Int{ return x1 > x2 ? x1 : x2 } diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift index 897ba2dee..db1e48b95 100644 --- a/Egg Drop Problem/EggDrop.swift +++ b/Egg Drop Problem/EggDrop.swift @@ -2,7 +2,7 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { if numberOfEggs == 0 || numberOfFloors == 0{ //edge case: When either number of eggs or number of floors is 0, answer is 0 return 0 } - if numberOfEggs == 1 || numberOfFloors == 1{ + if numberOfEggs == 1 || numberOfFloors == 1{ //edge case: When either number of eggs or number of floors is 1, answer is 1 return 1 } @@ -33,6 +33,7 @@ public func eggDrop(numberOfEggs: Int, numberOfFloors: Int) -> Int { return eggFloor[numberOfEggs][numberOfFloors] } +//Helper function to find max of two integers public func max(_ x1: Int, _ x2: Int) -> Int{ return x1 > x2 ? x1 : x2 } From 903ce26995d275e858dc535726df8a649260a4cd Mon Sep 17 00:00:00 2001 From: ph1ps Date: Sun, 16 Apr 2017 14:37:34 +0200 Subject: [PATCH 0520/1275] Add fully functional gaussian NB & examples --- Naive Bayes Classifier/NaiveBayes.swift | 122 ++++++++++++++---------- 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift index c988cacbe..63edd9981 100644 --- a/Naive Bayes Classifier/NaiveBayes.swift +++ b/Naive Bayes Classifier/NaiveBayes.swift @@ -1,16 +1,15 @@ // -// main.swift +// NaiveBayes.swift // NaiveBayes // // Created by Philipp Gabriel on 14.04.17. // Copyright © 2017 ph1ps. All rights reserved. // -//TODO naming import Foundation extension Array where Element == Double { - + func mean() -> Double { return self.reduce(0, +) / Double(count) } @@ -28,18 +27,17 @@ extension Array where Element == Double { extension Array where Element == Int { - //Is this the best way?! - func uniques() -> [Int] { - return Array(Set(self)) + func uniques() -> Set { + return Set(self) } } class NaiveBayes { - - var data: [[Double]] - var classes: [Int] - var variables: [Int: [(feature: Int, mean: Double, stDev: Double)]] + + private var data: [[Double]] + private var classes: [Int] + private var variables: [Int: [(feature: Int, mean: Double, stDev: Double)]] init(data: [[Double]], classes: [Int]) { self.data = data @@ -47,30 +45,37 @@ class NaiveBayes { self.variables = [Int: [(feature: Int, mean: Double, stDev: Double)]]() } - //TODO - //init(dataAndClasses: [[Double]], index ofClassRow: Int) {} - - //TODO: Does it really need to be n^2 runtime? + convenience init(dataAndClasses: [[Double]], rowOfClass: Int) { + let classes = dataAndClasses.map { Int($0[rowOfClass]) } + let data = dataAndClasses.map { row in + return row.enumerated().filter { $0.offset != rowOfClass }.map { $0.element } + } + + self.init(data: data, classes: classes) + } + func train() { - - for `class` in 0.. Int { - let likelihoods = predictLikelihood(input: input).max { (first, second) -> Bool in + func classify(with input: [Double]) -> Int { + let likelihoods = calcLikelihoods(with: input).max { (first, second) -> Bool in return first.1 < second.1 } @@ -81,30 +86,30 @@ class NaiveBayes { return `class` } - func predictLikelihood(input: [Double]) -> [(Int, Double)] { - - var probabilityOfClasses = [Int: Double]() - let amount = classes.uniques().count + func calcLikelihoods(with input: [Double]) -> [(Int, Double)] { + + var probaClass = [Int: Double]() + let amount = classes.count classes.forEach { `class` in let individual = classes.filter { $0 == `class` }.count - probabilityOfClasses[`class`] = Double(amount) / Double(individual) + probaClass[`class`] = Double(individual) / Double(amount) } - let probaClass = variables.map { (key, value) -> (Int, [Double]) in - let probaFeature = value.map { (feature, mean, stDev) -> Double in + let classesAndFeatures = variables.map { (key, value) -> (Int, [Double]) in + let distributions = value.map { (feature, mean, stDev) -> Double in let featureValue = input[feature] let eulerPart = pow(M_E, -1 * pow(featureValue - mean, 2) / (2 * pow(stDev, 2))) let distribution = eulerPart / sqrt(2 * .pi) / stDev return distribution } - return (key, probaFeature) + return (key, distributions) } - let likelihoods = probaClass.map { (key, probaFeature) in - return (key, probaFeature.reduce(1, *) * (probabilityOfClasses[key] ?? 1.0)) + let likelihoods = classesAndFeatures.map { (key, probaFeature) in + return (key, probaFeature.reduce(1, *) * (probaClass[key] ?? 1.0)) } - + let sum = likelihoods.map { $0.1 }.reduce(0, +) let normalized = likelihoods.map { (`class`, likelihood) in return (`class`, likelihood / sum) @@ -115,27 +120,48 @@ class NaiveBayes { } let data: [[Double]] = [ - [6,180,12], - [5.92,190,11], - [5.58,170,12], - [5.92,165,10], - [5,100,6], - [5.5,150,8], - [5.42,130,7], - [5.75,150,9] + [6, 180, 12], + [5.92, 190, 11], + [5.58, 170, 12], + [5.92, 165, 10], + [5, 100, 6], + [5.5, 150, 8], + [5.42, 130, 7], + [5.75, 150, 9] ] -let classes = [0,0,0,0,1,1,1,1] +let classes = [0, 0, 0, 0, 1, 1, 1, 1] let naive = NaiveBayes(data: data, classes: classes) naive.train() -let result = naive.predictLikelihood(input: [6,130,8]) -print(result) - - - - +print(naive.classify(with: [6, 130, 8])) + +let otherData: [[Double]] = [ + [6, 180, 12, 0], + [5.92, 190, 11, 0], + [5.58, 170, 12, 0], + [5.92, 165, 10, 0], + [5, 100, 6, 1], + [5.5, 150, 8, 1], + [5.42, 130, 7, 1], + [5.75, 150, 9, 1] +] +let otherNaive = NaiveBayes(dataAndClasses: otherData, rowOfClass: 3) +otherNaive.train() +print(otherNaive.calcLikelihoods(with: [6, 130, 8])) +guard let csv = try? String(contentsOfFile: "/Users/ph1ps/Desktop/wine.csv") else { + print("file not found") + exit(0) +} +let rows = csv.characters.split(separator: "\r\n").map { String($0) } +let wineData = rows.map { row -> [Double] in + let split = row.characters.split(separator: ";") + return split.map { Double(String($0))! } +} +let wineNaive = NaiveBayes(dataAndClasses: wineData, rowOfClass: 0) +wineNaive.train() +print(wineNaive.calcLikelihoods(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015])) From b6d40144c5ac91bd3155036fbcefca231a6dba0d Mon Sep 17 00:00:00 2001 From: ph1ps Date: Sun, 16 Apr 2017 23:52:57 +0200 Subject: [PATCH 0521/1275] Split into seperate types of NB classifier, implement strategy pattern --- Naive Bayes Classifier/NaiveBayes.swift | 209 +++++++++++++++++------- 1 file changed, 146 insertions(+), 63 deletions(-) diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift index 63edd9981..dbbf3cd9f 100644 --- a/Naive Bayes Classifier/NaiveBayes.swift +++ b/Naive Bayes Classifier/NaiveBayes.swift @@ -33,49 +33,143 @@ extension Array where Element == Int { } +enum NBType { + + case gaussian(data: [[Double]], classes: [Int]) + case multinomial(data: [[Int]], classes: [Int]) + //case bernoulli(data: [[Bool]], classes: [Int]) --> TODO + + var classes: [Int] { + if case .gaussian(_, let classes) = self { + return classes + } else if case .multinomial(_, let classes) = self { + return classes + } + + return [] + } + + var data: [[Any]] { + if case .gaussian(let data, _) = self { + return data + } else if case .multinomial(let data, _) = self { + return data + } + + return [] + } + + func calcLikelihood(variables: [Any], input: Any) -> Double? { + + if case .gaussian = self { + + guard let input = input as? Double else { + return nil + } + + guard let mean = variables[0] as? Double else { + return nil + } + + guard let stDev = variables[1] as? Double else { + return nil + } + + let eulerPart = pow(M_E, -1 * pow(input - mean, 2) / (2 * pow(stDev, 2))) + let distribution = eulerPart / sqrt(2 * .pi) / stDev + + return distribution + + } else if case .multinomial = self { + + guard let variables = variables as? [(category: Int, probability: Double)] else { + return nil + } + + guard let input = input as? Double else { + return nil + } + + return variables.first { variable in + return variable.category == Int(input) + }?.probability + + } + + return nil + } + + func train(values: [Any]) -> [Any]? { + + if case .gaussian = self { + + guard let values = values as? [Double] else { + return nil + } + + return [values.mean(), values.standardDeviation()] + + } else if case .multinomial = self { + + guard let values = values as? [Int] else { + return nil + } + + let count = values.count + let categoryProba = values.uniques().map { value -> (Int, Double) in + return (value, Double(values.filter { $0 == value }.count) / Double(count)) + } + return categoryProba + } + + return nil + } +} + class NaiveBayes { - private var data: [[Double]] - private var classes: [Int] - private var variables: [Int: [(feature: Int, mean: Double, stDev: Double)]] + private var variables: [Int: [(feature: Int, variables: [Any])]] + private var type: NBType - init(data: [[Double]], classes: [Int]) { - self.data = data - self.classes = classes - self.variables = [Int: [(feature: Int, mean: Double, stDev: Double)]]() + init(type: NBType) { + self.type = type + self.variables = [Int: [(Int, [Any])]]() } - convenience init(dataAndClasses: [[Double]], rowOfClass: Int) { - let classes = dataAndClasses.map { Int($0[rowOfClass]) } + static func convert(dataAndClasses: [[T]], rowOfClasses: Int) -> (data: [[T]], classes: [Int]) { + let classes = dataAndClasses.map { Int($0[rowOfClasses] as! Double) } //TODO + let data = dataAndClasses.map { row in - return row.enumerated().filter { $0.offset != rowOfClass }.map { $0.element } + return row.enumerated().filter { $0.offset != rowOfClasses }.map { $0.element } } - self.init(data: data, classes: classes) + return (data, classes) } + //TODO remake pliss, i dont like this at all func train() { + var classes = type.classes + for `class` in classes.uniques() { - variables[`class`] = [(feature: Int, mean: Double, stDev: Double)]() + variables[`class`] = [(Int, [Any])]() - for feature in 0.. Int { - let likelihoods = calcLikelihoods(with: input).max { (first, second) -> Bool in + let likelihoods = classifyProba(with: input).max { (first, second) -> Bool in return first.1 < second.1 } @@ -86,8 +180,10 @@ class NaiveBayes { return `class` } - func calcLikelihoods(with input: [Double]) -> [(Int, Double)] { + //TODO fix this doesnt have to be a double + func classifyProba(with input: [Double]) -> [(Int, Double)] { + let classes = type.classes var probaClass = [Int: Double]() let amount = classes.count @@ -96,18 +192,15 @@ class NaiveBayes { probaClass[`class`] = Double(individual) / Double(amount) } - let classesAndFeatures = variables.map { (key, value) -> (Int, [Double]) in - let distributions = value.map { (feature, mean, stDev) -> Double in - let featureValue = input[feature] - let eulerPart = pow(M_E, -1 * pow(featureValue - mean, 2) / (2 * pow(stDev, 2))) - let distribution = eulerPart / sqrt(2 * .pi) / stDev - return distribution + let classesAndFeatures = variables.map { (`class`, value) -> (Int, [Double]) in + let distribution = value.map { (feature, variables) -> Double in + return type.calcLikelihood(variables: variables, input: input[feature]) ?? 0.0 } - return (key, distributions) + return (`class`, distribution) } - let likelihoods = classesAndFeatures.map { (key, probaFeature) in - return (key, probaFeature.reduce(1, *) * (probaClass[key] ?? 1.0)) + let likelihoods = classesAndFeatures.map { (`class`, distribution) in + return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 1.0)) } let sum = likelihoods.map { $0.1 }.reduce(0, +) @@ -119,38 +212,6 @@ class NaiveBayes { } } -let data: [[Double]] = [ - [6, 180, 12], - [5.92, 190, 11], - [5.58, 170, 12], - [5.92, 165, 10], - [5, 100, 6], - [5.5, 150, 8], - [5.42, 130, 7], - [5.75, 150, 9] -] - -let classes = [0, 0, 0, 0, 1, 1, 1, 1] - -let naive = NaiveBayes(data: data, classes: classes) -naive.train() -print(naive.classify(with: [6, 130, 8])) - -let otherData: [[Double]] = [ - [6, 180, 12, 0], - [5.92, 190, 11, 0], - [5.58, 170, 12, 0], - [5.92, 165, 10, 0], - [5, 100, 6, 1], - [5.5, 150, 8, 1], - [5.42, 130, 7, 1], - [5.75, 150, 9, 1] -] - -let otherNaive = NaiveBayes(dataAndClasses: otherData, rowOfClass: 3) -otherNaive.train() -print(otherNaive.calcLikelihoods(with: [6, 130, 8])) - guard let csv = try? String(contentsOfFile: "/Users/ph1ps/Desktop/wine.csv") else { print("file not found") exit(0) @@ -162,6 +223,28 @@ let wineData = rows.map { row -> [Double] in return split.map { Double(String($0))! } } -let wineNaive = NaiveBayes(dataAndClasses: wineData, rowOfClass: 0) +let convertedWine = NaiveBayes.convert(dataAndClasses: wineData, rowOfClasses: 0) +let wineNaive = NaiveBayes(type: .gaussian(data: convertedWine.data, classes: convertedWine.classes)) wineNaive.train() -print(wineNaive.calcLikelihoods(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015])) +print(wineNaive.classifyProba(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015])) + +let golfData = [ + [0, 0, 0, 0], + [0, 0, 0, 1], + [1, 0, 0, 0], + [2, 1, 0, 0], + [2, 2, 1, 0], + [2, 2, 1, 1], + [1, 2, 1, 1], + [0, 1, 0, 0], + [0, 2, 1, 0], + [2, 1, 1, 0], + [0, 1, 1, 1], + [1, 1, 0, 1], + [1, 0, 1, 0], + [2, 1, 0, 1] +] +let golfClasses = [0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0] +let golfNaive = NaiveBayes(type: .multinomial(data: golfData, classes: golfClasses)) +golfNaive.train() +print(golfNaive.classifyProba(with: [0, 2, 0, 1])) From 42db9a9d9a823a5bd0f2acf5f629881265ba7a83 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:12:10 +0300 Subject: [PATCH 0522/1275] Removed extra screenshots --- Dijkstra Algorithm/README.md | 4 ---- .../Screenshots/screenshot1.jpg | Bin 214771 -> 224243 bytes .../Screenshots/screenshot2.jpg | Bin 225916 -> 0 bytes .../Screenshots/screenshot3.jpg | Bin 224243 -> 0 bytes 4 files changed, 4 deletions(-) delete mode 100644 Dijkstra Algorithm/Screenshots/screenshot2.jpg delete mode 100644 Dijkstra Algorithm/Screenshots/screenshot3.jpg diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 872e9f851..10166a63f 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -17,7 +17,3 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Screenshots - - - - diff --git a/Dijkstra Algorithm/Screenshots/screenshot1.jpg b/Dijkstra Algorithm/Screenshots/screenshot1.jpg index 390bc658224310c7720678cffd68bf1654b5c045..e9f7a1207f315e8f5aa20c72f3264c65edafd3a8 100644 GIT binary patch literal 224243 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 literal 214771 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

@lrF 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 Ag8%>k diff --git a/Dijkstra Algorithm/Screenshots/screenshot2.jpg b/Dijkstra Algorithm/Screenshots/screenshot2.jpg deleted file mode 100644 index bc51046fb36bd2c77b11cf8f6bc28afd0a2faff8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225916 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 diff --git a/Dijkstra Algorithm/Screenshots/screenshot3.jpg b/Dijkstra Algorithm/Screenshots/screenshot3.jpg deleted file mode 100644 index e9f7a1207f315e8f5aa20c72f3264c65edafd3a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224243 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 From a6020a54187ff8f473b1bccae3229846b7716258 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:13:19 +0300 Subject: [PATCH 0523/1275] Credits to the bottom --- Dijkstra Algorithm/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 10166a63f..bf158def9 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,6 +1,4 @@ # Dijkstra-algorithm -WWDC 2017 Scholarship Project -Created by [Taras Nikulin](https://github.com/crabman448) ## About Dijkstra's algorithm is used for finding shortest paths from start vertex in graph(with weighted vertices) to all other vertices. @@ -17,3 +15,7 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Screenshots + +## Credits +WWDC 2017 Scholarship Project +Created by [Taras Nikulin](https://github.com/crabman448) From a76764eaa0907a8ec455f911af14a0ad27087a95 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:16:05 +0300 Subject: [PATCH 0524/1275] Moved Vertex and Dijkstra classes to sources --- .../Dijkstra.playground/Contents.swift | 69 ------------------- .../Sources/Dijkstra.swift | 40 +++++++++++ .../Dijkstra.playground/Sources/Vertex.swift | 29 ++++++++ 3 files changed, 69 insertions(+), 69 deletions(-) create mode 100644 Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift create mode 100644 Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index 13087a8f9..cd08e26fb 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -1,74 +1,5 @@ //: Playground - noun: a place where people can play - import Foundation -import UIKit - -open class Vertex: Hashable, Equatable { - - open var identifier: String! - open var neighbors: [(Vertex, Double)] = [] - open var pathLengthFromStart: Double = Double.infinity - open var pathVerticesFromStart: [Vertex] = [] - - public init(identifier: String) { - self.identifier = identifier - } - - open var hashValue: Int { - return self.identifier.hashValue - } - - public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { - if lhs.hashValue == rhs.hashValue { - return true - } - return false - } - - open func clearCache() { - self.pathLengthFromStart = Double.infinity - self.pathVerticesFromStart = [] - } -} - -public class Dijkstra { - private var totalVertices: Set - - public init(vertices: Set) { - self.totalVertices = vertices - } - - private func clearCache() { - self.totalVertices.forEach { $0.clearCache() } - } - - public func findShortestPaths(from startVertex: Vertex) { - self.clearCache() - startVertex.pathLengthFromStart = 0 - startVertex.pathVerticesFromStart.append(startVertex) - var currentVertex: Vertex! = startVertex - while currentVertex != nil { - totalVertices.remove(currentVertex) - let filteredNeighbors = currentVertex.neighbors.filter { totalVertices.contains($0.0) } - for neighbor in filteredNeighbors { - let neighborVertex = neighbor.0 - let weight = neighbor.1 - - let theoreticNewWeight = currentVertex.pathLengthFromStart + weight - if theoreticNewWeight < neighborVertex.pathLengthFromStart { - neighborVertex.pathLengthFromStart = theoreticNewWeight - neighborVertex.pathVerticesFromStart = currentVertex.pathVerticesFromStart - neighborVertex.pathVerticesFromStart.append(neighborVertex) - } - } - if totalVertices.isEmpty { - currentVertex = nil - break - } - currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } - } - } -} var _vertices: Set = Set() diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift new file mode 100644 index 000000000..0ae83589e --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift @@ -0,0 +1,40 @@ +import Foundation + +public class Dijkstra { + private var totalVertices: Set + + public init(vertices: Set) { + self.totalVertices = vertices + } + + private func clearCache() { + self.totalVertices.forEach { $0.clearCache() } + } + + public func findShortestPaths(from startVertex: Vertex) { + self.clearCache() + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) + var currentVertex: Vertex! = startVertex + while currentVertex != nil { + totalVertices.remove(currentVertex) + let filteredNeighbors = currentVertex.neighbors.filter { totalVertices.contains($0.0) } + for neighbor in filteredNeighbors { + let neighborVertex = neighbor.0 + let weight = neighbor.1 + + let theoreticNewWeight = currentVertex.pathLengthFromStart + weight + if theoreticNewWeight < neighborVertex.pathLengthFromStart { + neighborVertex.pathLengthFromStart = theoreticNewWeight + neighborVertex.pathVerticesFromStart = currentVertex.pathVerticesFromStart + neighborVertex.pathVerticesFromStart.append(neighborVertex) + } + } + if totalVertices.isEmpty { + currentVertex = nil + break + } + currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } + } + } +} diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift new file mode 100644 index 000000000..035db2713 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -0,0 +1,29 @@ +import Foundation + +open class Vertex: Hashable, Equatable { + + open var identifier: String! + open var neighbors: [(Vertex, Double)] = [] + open var pathLengthFromStart: Double = Double.infinity + open var pathVerticesFromStart: [Vertex] = [] + + public init(identifier: String) { + self.identifier = identifier + } + + open var hashValue: Int { + return self.identifier.hashValue + } + + public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { + if lhs.hashValue == rhs.hashValue { + return true + } + return false + } + + open func clearCache() { + self.pathLengthFromStart = Double.infinity + self.pathVerticesFromStart = [] + } +} From 3bdb63de34cba4abcc581980c83da650bc8d3ba4 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:17:45 +0300 Subject: [PATCH 0525/1275] Hashable, Equatable to Extensions --- .../Dijkstra.playground/Sources/Vertex.swift | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift index 035db2713..67ba3791e 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -1,6 +1,6 @@ import Foundation -open class Vertex: Hashable, Equatable { +open class Vertex { open var identifier: String! open var neighbors: [(Vertex, Double)] = [] @@ -11,19 +11,23 @@ open class Vertex: Hashable, Equatable { self.identifier = identifier } + open func clearCache() { + self.pathLengthFromStart = Double.infinity + self.pathVerticesFromStart = [] + } +} + +extension Vertex: Hashable { open var hashValue: Int { return self.identifier.hashValue } +} +extension Vertex: Equatable { public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { if lhs.hashValue == rhs.hashValue { return true } return false } - - open func clearCache() { - self.pathLengthFromStart = Double.infinity - self.pathVerticesFromStart = [] - } } From b2c5674b0c7d818cf061309e1cb7988e808d294b Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:18:44 +0300 Subject: [PATCH 0526/1275] Removed simplicity unwrapped for initialized variable --- Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift index 67ba3791e..22c04a0e1 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -2,7 +2,7 @@ import Foundation open class Vertex { - open var identifier: String! + open var identifier: String open var neighbors: [(Vertex, Double)] = [] open var pathLengthFromStart: Double = Double.infinity open var pathVerticesFromStart: [Vertex] = [] From f0d057b89058c10cfe749990d5bdc3c669696610 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:19:34 +0300 Subject: [PATCH 0527/1275] Removed unnecessary explicit typing --- Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift index 22c04a0e1..dcdc64691 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -4,7 +4,7 @@ open class Vertex { open var identifier: String open var neighbors: [(Vertex, Double)] = [] - open var pathLengthFromStart: Double = Double.infinity + open var pathLengthFromStart = Double.infinity open var pathVerticesFromStart: [Vertex] = [] public init(identifier: String) { From d0c68887780424e343f6663391eb5d70998fe166 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:20:05 +0300 Subject: [PATCH 0528/1275] Refactor Equatable extension --- Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift index dcdc64691..89e66c68d 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -25,9 +25,6 @@ extension Vertex: Hashable { extension Vertex: Equatable { public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { - if lhs.hashValue == rhs.hashValue { - return true - } - return false + return lhs.hashValue == rhs.hashValue } } From 222e96d2f221c2f0549b5292be8b60adee93e1de Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:23:14 +0300 Subject: [PATCH 0529/1275] Made vertex optional --- .../Dijkstra.playground/Sources/Dijkstra.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift index 0ae83589e..f0a9386b4 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift @@ -15,18 +15,18 @@ public class Dijkstra { self.clearCache() startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) - var currentVertex: Vertex! = startVertex - while currentVertex != nil { - totalVertices.remove(currentVertex) - let filteredNeighbors = currentVertex.neighbors.filter { totalVertices.contains($0.0) } + var currentVertex: Vertex? = startVertex + while let vertex = currentVertex { + totalVertices.remove(vertex) + let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } for neighbor in filteredNeighbors { let neighborVertex = neighbor.0 let weight = neighbor.1 - let theoreticNewWeight = currentVertex.pathLengthFromStart + weight + let theoreticNewWeight = vertex.pathLengthFromStart + weight if theoreticNewWeight < neighborVertex.pathLengthFromStart { neighborVertex.pathLengthFromStart = theoreticNewWeight - neighborVertex.pathVerticesFromStart = currentVertex.pathVerticesFromStart + neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart neighborVertex.pathVerticesFromStart.append(neighborVertex) } } From e2561032e31912df5dab472f7d63a3900d05ac70 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:26:57 +0300 Subject: [PATCH 0530/1275] Removed unnecessary self --- .../Dijkstra.playground/Sources/Dijkstra.swift | 6 +++--- Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift index f0a9386b4..f4cd8503a 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift @@ -4,15 +4,15 @@ public class Dijkstra { private var totalVertices: Set public init(vertices: Set) { - self.totalVertices = vertices + totalVertices = vertices } private func clearCache() { - self.totalVertices.forEach { $0.clearCache() } + totalVertices.forEach { $0.clearCache() } } public func findShortestPaths(from startVertex: Vertex) { - self.clearCache() + clearCache() startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) var currentVertex: Vertex? = startVertex diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift index 89e66c68d..a3587e04e 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -12,14 +12,14 @@ open class Vertex { } open func clearCache() { - self.pathLengthFromStart = Double.infinity - self.pathVerticesFromStart = [] + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] } } extension Vertex: Hashable { open var hashValue: Int { - return self.identifier.hashValue + return identifier.hashValue } } From 5060d788da63363809c93996aa9851751131e2d2 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:53:05 +0300 Subject: [PATCH 0531/1275] Removed self, unnecessary imports --- .../Sources/CustomUI/EdgeRepresentation.swift | 24 +- .../Sources/CustomUI/ErrorView.swift | 23 +- .../Sources/CustomUI/MyShapeLayer.swift | 1 - .../Sources/CustomUI/RoundedButton.swift | 8 +- .../Sources/CustomUI/VertexView.swift | 48 ++-- .../Sources/Graph.swift | 84 +++--- .../Sources/GraphView.swift | 62 ++-- .../Sources/SimpleObjects/Vertex.swift | 59 ++-- .../Sources/Window.swift | 272 +++++++++--------- 9 files changed, 291 insertions(+), 290 deletions(-) diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift index 5ff656dab..d827d3924 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift @@ -1,6 +1,6 @@ import UIKit -public class EdgeRepresentation: Equatable { +public class EdgeRepresentation { private var graphColors: GraphColors = GraphColors.sharedInstance public private(set)var label: UILabel! @@ -67,7 +67,7 @@ public class EdgeRepresentation: Equatable { let label = UILabel(frame: CGRect(origin: circleOrigin, size: CGSize(width: arcDiameter, height: arcDiameter))) label.textAlignment = .center - label.backgroundColor = self.graphColors.defaultEdgeColor + label.backgroundColor = graphColors.defaultEdgeColor label.clipsToBounds = true label.adjustsFontSizeToFitWidth = true label.layer.cornerRadius = arcDiameter / 2 @@ -75,35 +75,35 @@ public class EdgeRepresentation: Equatable { let shapeLayer = MyShapeLayer() shapeLayer.path = path.cgPath - shapeLayer.strokeColor = self.graphColors.defaultEdgeColor.cgColor + shapeLayer.strokeColor = graphColors.defaultEdgeColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.lineWidth = 2.0 shapeLayer.startPoint = startPoint shapeLayer.endPoint = endPoint shapeLayer.actions = ["position" : NSNull(), "bounds" : NSNull(), "path" : NSNull()] + self.layer = shapeLayer self.label = label self.label.text = "\(weight)" } public func setCheckingColor() { - self.layer.strokeColor = self.graphColors.checkingColor.cgColor - self.label.backgroundColor = self.graphColors.checkingColor + layer.strokeColor = graphColors.checkingColor.cgColor + label.backgroundColor = graphColors.checkingColor } public func setDefaultColor() { - self.layer.strokeColor = self.graphColors.defaultEdgeColor.cgColor - self.label.backgroundColor = self.graphColors.defaultEdgeColor + layer.strokeColor = graphColors.defaultEdgeColor.cgColor + label.backgroundColor = graphColors.defaultEdgeColor } public func setText(text: String) { - self.label.text = text + label.text = text } +} +extension EdgeRepresentation: Equatable { public static func ==(lhs: EdgeRepresentation, rhs: EdgeRepresentation) -> Bool { - if lhs.label.hashValue == rhs.label.hashValue && lhs.layer.hashValue == rhs.layer.hashValue { - return true - } - return false + return lhs.label.hashValue == rhs.label.hashValue && lhs.layer.hashValue == rhs.layer.hashValue } } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift index 69874e5d7..a63655dd9 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift @@ -2,9 +2,10 @@ import UIKit public class ErrorView: UIView { private var label: UILabel! + public override init(frame: CGRect) { super.init(frame: frame) - self.commonInit() + commonInit() } public required init?(coder aDecoder: NSCoder) { @@ -12,19 +13,19 @@ public class ErrorView: UIView { } private func commonInit() { - self.backgroundColor = UIColor(red: 242/255, green: 156/255, blue: 84/255, alpha: 1) - self.layer.cornerRadius = 10 + backgroundColor = UIColor(red: 242/255, green: 156/255, blue: 84/255, alpha: 1) + layer.cornerRadius = 10 - let labelFrame = CGRect(x: 10, y: 10, width: self.frame.width - 20, height: self.frame.height - 20) - self.label = UILabel(frame: labelFrame) - self.label.numberOfLines = 0 - self.label.adjustsFontSizeToFitWidth = true - self.label.textAlignment = .center - self.label.textColor = UIColor.white - self.addSubview(self.label) + let labelFrame = CGRect(x: 10, y: 10, width: frame.width - 20, height: frame.height - 20) + label = UILabel(frame: labelFrame) + label.numberOfLines = 0 + label.adjustsFontSizeToFitWidth = true + label.textAlignment = .center + label.textColor = UIColor.white + addSubview(label) } public func setText(text: String) { - self.label.text = text + label.text = text } } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift index 54147f5e1..33bf4a515 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift @@ -1,4 +1,3 @@ -import Foundation import UIKit public class MyShapeLayer: CAShapeLayer { diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift index 2647c4525..819fcfc5c 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/RoundedButton.swift @@ -5,7 +5,7 @@ public class RoundedButton: UIButton { public override init(frame: CGRect) { super.init(frame: frame) - self.commonInit() + commonInit() } public required init?(coder aDecoder: NSCoder) { @@ -13,8 +13,8 @@ public class RoundedButton: UIButton { } private func commonInit() { - self.backgroundColor = self.graphColors.buttonsBackgroundColor - self.titleLabel?.adjustsFontSizeToFitWidth = true - self.layer.cornerRadius = 7 + backgroundColor = graphColors.buttonsBackgroundColor + titleLabel?.adjustsFontSizeToFitWidth = true + layer.cornerRadius = 7 } } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift index 29c971411..e785e120b 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/VertexView.swift @@ -15,49 +15,49 @@ public class VertexView: UIButton { precondition(frame.height == frame.width) precondition(frame.height >= 30) super.init(frame: frame) - self.backgroundColor = self.graphColors.defaultVertexColor - self.layer.cornerRadius = frame.width / 2 - self.clipsToBounds = true - self.setupIdLabel() - self.setupPathLengthFromStartLabel() + backgroundColor = graphColors.defaultVertexColor + layer.cornerRadius = frame.width / 2 + clipsToBounds = true + setupIdLabel() + setupPathLengthFromStartLabel() } private func setupIdLabel() { - let x: CGFloat = self.frame.width * 0.2 + let x: CGFloat = frame.width * 0.2 let y: CGFloat = 0 - let width: CGFloat = self.frame.width * 0.6 - let height: CGFloat = self.frame.height / 2 + let width: CGFloat = frame.width * 0.6 + let height: CGFloat = frame.height / 2 let idLabelFrame = CGRect(x: x, y: y, width: width, height: height) - self.idLabel = UILabel(frame: idLabelFrame) - self.idLabel.textAlignment = .center - self.idLabel.adjustsFontSizeToFitWidth = true - self.addSubview(self.idLabel) + idLabel = UILabel(frame: idLabelFrame) + idLabel.textAlignment = .center + idLabel.adjustsFontSizeToFitWidth = true + addSubview(idLabel) } private func setupPathLengthFromStartLabel() { - let x: CGFloat = self.frame.width * 0.2 - let y: CGFloat = self.frame.height / 2 - let width: CGFloat = self.frame.width * 0.6 - let height: CGFloat = self.frame.height / 2 + let x: CGFloat = frame.width * 0.2 + let y: CGFloat = frame.height / 2 + let width: CGFloat = frame.width * 0.6 + let height: CGFloat = frame.height / 2 let pathLengthLabelFrame = CGRect(x: x, y: y, width: width, height: height) - self.pathLengthLabel = UILabel(frame: pathLengthLabelFrame) - self.pathLengthLabel.textAlignment = .center - self.pathLengthLabel.adjustsFontSizeToFitWidth = true - self.addSubview(self.pathLengthLabel) + pathLengthLabel = UILabel(frame: pathLengthLabelFrame) + pathLengthLabel.textAlignment = .center + pathLengthLabel.adjustsFontSizeToFitWidth = true + addSubview(pathLengthLabel) } public func setIdLabel(text: String) { - self.idLabel.text = text + idLabel.text = text } public func setPathLengthLabel(text: String) { - self.pathLengthLabel.text = text + pathLengthLabel.text = text } public func setLabelsTextColor(color: UIColor) { - self.idLabel.textColor = color - self.pathLengthLabel.textColor = color + idLabel.textColor = color + pathLengthLabel.textColor = color } } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift index 0b0b97b92..7c4a8e373 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift @@ -22,20 +22,20 @@ public class Graph { public var startVertex: Vertex! public var interactiveNeighborCheckAnimationDuration: Double = 1.8 { didSet { - self._interactiveOneSleepDuration = UInt32(self.interactiveNeighborCheckAnimationDuration * 1000000.0 / 3.0) + _interactiveOneSleepDuration = UInt32(interactiveNeighborCheckAnimationDuration * 1000000.0 / 3.0) } } private var _interactiveOneSleepDuration: UInt32 = 600000 public var visualizationNeighborCheckAnimationDuration: Double = 2.25 { didSet { - self._visualizationOneSleepDuration = UInt32(self.visualizationNeighborCheckAnimationDuration * 1000000.0 / 3.0) + _visualizationOneSleepDuration = UInt32(visualizationNeighborCheckAnimationDuration * 1000000.0 / 3.0) } } private var _visualizationOneSleepDuration: UInt32 = 750000 public var vertices: Set { - return self._vertices + return _vertices } public init(verticesCount: UInt) { @@ -43,46 +43,46 @@ public class Graph { } public func removeGraph() { - self._vertices.removeAll() - self.startVertex = nil + _vertices.removeAll() + startVertex = nil } public func createNewGraph() { - guard self._vertices.isEmpty, self.startVertex == nil else { + guard _vertices.isEmpty, startVertex == nil else { assertionFailure("Clear graph before creating new one") return } - self.createNotConnectedVertices() - self.setupConnections() - let offset = Int(arc4random_uniform(UInt32(self._vertices.count))) - let index = self._vertices.index(self._vertices.startIndex, offsetBy: offset) - self.startVertex = self._vertices[index] - self.setVertexLevels() + createNotConnectedVertices() + setupConnections() + let offset = Int(arc4random_uniform(UInt32(_vertices.count))) + let index = _vertices.index(_vertices.startIndex, offsetBy: offset) + startVertex = _vertices[index] + setVertexLevels() } private func clearCache() { - self._vertices.forEach { $0.clearCache() } + _vertices.forEach { $0.clearCache() } } public func reset() { - for vertex in self._vertices { + for vertex in _vertices { vertex.clearCache() } } private func createNotConnectedVertices() { - for i in 0.. Vertex { - var newSet = self._vertices + var newSet = _vertices newSet.remove(vertex) let offset = Int(arc4random_uniform(UInt32(newSet.count))) let index = newSet.index(newSet.startIndex, offsetBy: offset) @@ -103,8 +103,8 @@ public class Graph { } private func setVertexLevels() { - self._vertices.forEach { $0.clearLevelInfo() } - guard let startVertex = self.startVertex else { + _vertices.forEach { $0.clearLevelInfo() } + guard let startVertex = startVertex else { assertionFailure() return } @@ -127,21 +127,21 @@ public class Graph { } public func findShortestPathsWithVisualization(completion: () -> Void) { - self.clearCache() + clearCache() startVertex.pathLengthFromStart = 0 - startVertex.pathVerticesFromStart.append(self.startVertex) - var currentVertex: Vertex! = self.startVertex + startVertex.pathVerticesFromStart.append(startVertex) + var currentVertex: Vertex! = startVertex - var totalVertices = self._vertices + var totalVertices = _vertices breakableLoop: while currentVertex != nil { totalVertices.remove(currentVertex) - while self.pauseVisualization == true { - if self.stopVisualization == true { + while pauseVisualization == true { + if stopVisualization == true { break breakableLoop } } - if self.stopVisualization == true { + if stopVisualization == true { break breakableLoop } DispatchQueue.main.async { @@ -155,12 +155,12 @@ public class Graph { let weight = edge.weight let edgeRepresentation = edge.edgeRepresentation - while self.pauseVisualization == true { - if self.stopVisualization == true { + while pauseVisualization == true { + if stopVisualization == true { break breakableLoop } } - if self.stopVisualization == true { + if stopVisualization == true { break breakableLoop } DispatchQueue.main.async { @@ -170,32 +170,32 @@ public class Graph { edgePathLength: weight, endVertexPathLength: neighbor.pathLengthFromStart) } - usleep(self._visualizationOneSleepDuration) + usleep(_visualizationOneSleepDuration) let theoreticNewWeight = currentVertex.pathLengthFromStart + weight if theoreticNewWeight < neighbor.pathLengthFromStart { - while self.pauseVisualization == true { - if self.stopVisualization == true { + while pauseVisualization == true { + if stopVisualization == true { break breakableLoop } } - if self.stopVisualization == true { + if stopVisualization == true { break breakableLoop } neighbor.pathLengthFromStart = theoreticNewWeight neighbor.pathVerticesFromStart = currentVertex.pathVerticesFromStart neighbor.pathVerticesFromStart.append(neighbor) } - usleep(self._visualizationOneSleepDuration) + usleep(_visualizationOneSleepDuration) DispatchQueue.main.async { self.delegate?.didFinishCompare() edge.edgeRepresentation?.setDefaultColor() edge.neighbor.setDefaultColor() } - usleep(self._visualizationOneSleepDuration) + usleep(_visualizationOneSleepDuration) } if totalVertices.isEmpty { currentVertex = nil @@ -203,7 +203,7 @@ public class Graph { } currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } } - if self.stopVisualization == true { + if stopVisualization == true { DispatchQueue.main.async { self.delegate?.didStop() } @@ -294,10 +294,10 @@ public class Graph { } public func didTapVertex(vertex: Vertex) { - if self.nextVertices.contains(vertex) { - self.delegate?.willStartVertexNeighborsChecking() - self.state = .parsing - self.parseNeighborsFor(vertex: vertex) { + if nextVertices.contains(vertex) { + delegate?.willStartVertexNeighborsChecking() + state = .parsing + parseNeighborsFor(vertex: vertex) { self.state = .interactiveVisualization self.delegate?.didFinishVertexNeighborsChecking() } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift index 49bc6853f..bdeab7669 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift @@ -7,7 +7,7 @@ public class GraphView: UIView { public override init(frame: CGRect) { super.init(frame: frame) - self.backgroundColor = self.graphColors.graphBackgroundColor + backgroundColor = graphColors.graphBackgroundColor } public required init?(coder aDecoder: NSCoder) { @@ -20,13 +20,13 @@ public class GraphView: UIView { } public func removeGraph() { - for vertex in self.graph.vertices { + for vertex in graph.vertices { if let view = vertex.view { view.removeFromSuperview() vertex.view = nil } } - for vertex in self.graph.vertices { + for vertex in graph.vertices { for edge in vertex.edges { if let edgeRepresentation = edge.edgeRepresentation { edgeRepresentation.layer.removeFromSuperlayer() @@ -38,41 +38,41 @@ public class GraphView: UIView { } public func createNewGraph() { - self.setupVertexViews() - self.setupEdgeRepresentations() - self.addGraph() + setupVertexViews() + setupEdgeRepresentations() + addGraph() } public func reset() { - for vertex in self.graph.vertices { + for vertex in graph.vertices { vertex.edges.forEach { $0.edgeRepresentation?.setDefaultColor() } vertex.setDefaultColor() } } private func addGraph() { - for vertex in self.graph.vertices { + for vertex in graph.vertices { for edge in vertex.edges { if let edgeRepresentation = edge.edgeRepresentation { - self.layer.addSublayer(edgeRepresentation.layer) - self.addSubview(edgeRepresentation.label) + layer.addSublayer(edgeRepresentation.layer) + addSubview(edgeRepresentation.label) } } } - for vertex in self.graph.vertices { + for vertex in graph.vertices { if let view = vertex.view { - self.addSubview(view) + addSubview(view) } } } private func setupVertexViews() { var level = 0 - var buildViewQueue = [self.graph.startVertex!] + var buildViewQueue = [graph.startVertex!] let itemWidth: CGFloat = 40 while !buildViewQueue.isEmpty { let levelItemsCount = CGFloat(buildViewQueue.count) - let xStep = (self.frame.width - levelItemsCount * itemWidth) / (levelItemsCount + 1) + let xStep = (frame.width - levelItemsCount * itemWidth) / (levelItemsCount + 1) var previousVertexMaxX: CGFloat = 0.0 for vertex in buildViewQueue { let x: CGFloat = previousVertexMaxX + xStep @@ -84,12 +84,12 @@ public class GraphView: UIView { vertexView.vertex = vertex vertex.view?.setIdLabel(text: vertex.identifier) vertex.view?.setPathLengthLabel(text: "\(vertex.pathLengthFromStart)") - vertex.view?.addTarget(self, action: #selector(self.didTapVertex(sender:)), for: .touchUpInside) - let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(recognizer:))) + vertex.view?.addTarget(self, action: #selector(didTapVertex(sender:)), for: .touchUpInside) + let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(recognizer:))) vertex.view?.addGestureRecognizer(panGesture) } level += 1 - buildViewQueue = self.graph.vertices.filter { $0.level == level } + buildViewQueue = graph.vertices.filter { $0.level == level } } } @@ -100,8 +100,8 @@ public class GraphView: UIView { guard let vertexView = recognizer.view as? VertexView, let vertex = vertexView.vertex else { return } - if self.panningView != nil { - if self.panningView != vertexView { + if panningView != nil { + if panningView != vertexView { return } } @@ -122,39 +122,39 @@ public class GraphView: UIView { } } } - self.panningView = vertexView + panningView = vertexView case .changed: - if self.movingVertexOutputEdges.isEmpty && self.movingVertexInputEdges.isEmpty { + if movingVertexOutputEdges.isEmpty && movingVertexInputEdges.isEmpty { return } let translation = recognizer.translation(in: self) if vertexView.frame.origin.x + translation.x <= 0 || vertexView.frame.origin.y + translation.y <= 0 - || (vertexView.frame.origin.x + vertexView.frame.width + translation.x) >= self.frame.width - || (vertexView.frame.origin.y + vertexView.frame.height + translation.y) >= self.frame.height { + || (vertexView.frame.origin.x + vertexView.frame.width + translation.x) >= frame.width + || (vertexView.frame.origin.y + vertexView.frame.height + translation.y) >= frame.height { break } - self.movingVertexInputEdges.forEach { edgeRepresentation in + movingVertexInputEdges.forEach { edgeRepresentation in let originalLabelCenter = edgeRepresentation.label.center edgeRepresentation.label.center = CGPoint(x: originalLabelCenter.x + translation.x * 0.625, y: originalLabelCenter.y + translation.y * 0.625) CATransaction.begin() CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) - let newPath = self.path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: false) + let newPath = path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: false) edgeRepresentation.layer.path = newPath CATransaction.commit() } - self.movingVertexOutputEdges.forEach { edgeRepresentation in + movingVertexOutputEdges.forEach { edgeRepresentation in let originalLabelCenter = edgeRepresentation.label.center edgeRepresentation.label.center = CGPoint(x: originalLabelCenter.x + translation.x * 0.375, y: originalLabelCenter.y + translation.y * 0.375) CATransaction.begin() CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) - let newPath = self.path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: true) + let newPath = path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: true) edgeRepresentation.layer.path = newPath CATransaction.commit() } @@ -163,9 +163,9 @@ public class GraphView: UIView { y: vertexView.center.y + translation.y) recognizer.setTranslation(CGPoint.zero, in: self) case .ended: - self.movingVertexInputEdges = [] - self.movingVertexOutputEdges = [] - self.panningView = nil + movingVertexInputEdges = [] + movingVertexOutputEdges = [] + panningView = nil default: break } @@ -223,7 +223,7 @@ public class GraphView: UIView { } private func setupEdgeRepresentations() { - var edgeQueue: [Vertex] = [self.graph.startVertex!] + var edgeQueue: [Vertex] = [graph.startVertex!] //BFS while !edgeQueue.isEmpty { diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift index c9270b0df..f18ec3114 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift @@ -1,10 +1,17 @@ import UIKit -public class Vertex: Hashable, Equatable { +public class Vertex { private var graphColors: GraphColors = GraphColors.sharedInstance + public var view: VertexView? + public var identifier: String public var edges: [Edge] = [] + public var pathVerticesFromStart: [Vertex] = [] + public var level: Int = 0 + public var levelChecked: Bool = false + public var haveAllEdges: Bool = false + public var visited: Bool = false public var pathLengthFromStart: Double = Double.infinity { didSet { DispatchQueue.main.async { @@ -12,51 +19,45 @@ public class Vertex: Hashable, Equatable { } } } - public var pathVerticesFromStart: [Vertex] = [] - public var level: Int = 0 - public var levelChecked: Bool = false - public var haveAllEdges: Bool = false - public var visited: Bool = false - - public var view: VertexView? public init(identifier: String) { self.identifier = identifier } - public var hashValue: Int { - return self.identifier.hashValue - } - - public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { - if lhs.hashValue == rhs.hashValue { - return true - } - return false - } - public func clearCache() { - self.pathLengthFromStart = Double.infinity - self.pathVerticesFromStart = [] - self.visited = false + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] + visited = false } public func clearLevelInfo() { - self.level = 0 - self.levelChecked = false + level = 0 + levelChecked = false } public func setVisitedColor() { - self.view?.backgroundColor = self.graphColors.visitedColor - self.view?.setLabelsTextColor(color: UIColor.white) + view?.backgroundColor = graphColors.visitedColor + view?.setLabelsTextColor(color: UIColor.white) } public func setCheckingPathColor() { - self.view?.backgroundColor = self.graphColors.checkingColor + view?.backgroundColor = graphColors.checkingColor } public func setDefaultColor() { - self.view?.backgroundColor = self.graphColors.defaultVertexColor - self.view?.setLabelsTextColor(color: UIColor.black) + view?.backgroundColor = graphColors.defaultVertexColor + view?.setLabelsTextColor(color: UIColor.black) + } +} + +extension Vertex: Hashable { + public var hashValue: Int { + return identifier.hashValue + } +} + +extension Vertex: Equatable { + public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { + return lhs.hashValue == rhs.hashValue } } diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift index e8aabad27..054b804c9 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -30,7 +30,7 @@ public class Window: UIView, GraphDelegate { public override init(frame: CGRect) { super.init(frame: frame) self.frame = frame - self.backgroundColor = self.graphColors.mainWindowBackgroundColor + backgroundColor = graphColors.mainWindowBackgroundColor } public required init?(coder aDecoder: NSCoder) { @@ -39,130 +39,130 @@ public class Window: UIView, GraphDelegate { public func configure(graph: Graph) { self.graph = graph - self.graph.createNewGraph() - self.graph.delegate = self + graph.createNewGraph() + graph.delegate = self let frame = CGRect(x: 10, y: 170, width: self.frame.width - 20, height: self.frame.height - 180) - self.graphView = GraphView(frame: frame) - self.graphView.layer.cornerRadius = 15 - - self.graphView.configure(graph: self.graph) - self.graphView.createNewGraph() - self.addSubview(self.graphView) - - self.configureCreateGraphButton() - self.configureStartVisualizationButton() - self.configureStartInteractiveVisualizationButton() - self.configureStartButton() - self.configurePauseButton() - self.configureStopButton() - self.configureComparisonLabel() - self.configureActivityIndicator() - - self.topView = UIView(frame: CGRect(x: 10, y: 10, width: self.frame.width - 20, height: 150)) - self.topView.backgroundColor = self.graphColors.topViewBackgroundColor - self.topView.layer.cornerRadius = 15 - self.addSubview(self.topView) - - self.topView.addSubview(self.createGraphButton) - self.topView.addSubview(self.startVisualizationButton) - self.topView.addSubview(self.startInteractiveVisualizationButton) - self.topView.addSubview(self.startButton) - self.topView.addSubview(self.pauseButton) - self.topView.addSubview(self.stopButton) - self.topView.addSubview(self.comparisonLabel) - self.topView.addSubview(self.activityIndicator) + graphView = GraphView(frame: frame) + graphView.layer.cornerRadius = 15 + + graphView.configure(graph: graph) + graphView.createNewGraph() + addSubview(graphView) + + configureCreateGraphButton() + configureStartVisualizationButton() + configureStartInteractiveVisualizationButton() + configureStartButton() + configurePauseButton() + configureStopButton() + configureComparisonLabel() + configureActivityIndicator() + + topView = UIView(frame: CGRect(x: 10, y: 10, width: frame.width - 20, height: 150)) + topView.backgroundColor = graphColors.topViewBackgroundColor + topView.layer.cornerRadius = 15 + addSubview(topView) + + topView.addSubview(createGraphButton) + topView.addSubview(startVisualizationButton) + topView.addSubview(startInteractiveVisualizationButton) + topView.addSubview(startButton) + topView.addSubview(pauseButton) + topView.addSubview(stopButton) + topView.addSubview(comparisonLabel) + topView.addSubview(activityIndicator) } private func configureCreateGraphButton() { - let frame = CGRect(x: self.center.x - 200, y: 12, width: 100, height: 34) - self.createGraphButton = RoundedButton(frame: frame) - self.createGraphButton.setTitle("New graph", for: .normal) - self.createGraphButton.addTarget(self, action: #selector(self.createGraphButtonTap), for: .touchUpInside) + let frame = CGRect(x: center.x - 200, y: 12, width: 100, height: 34) + createGraphButton = RoundedButton(frame: frame) + createGraphButton.setTitle("New graph", for: .normal) + createGraphButton.addTarget(self, action: #selector(createGraphButtonTap), for: .touchUpInside) } private func configureStartVisualizationButton() { - let frame = CGRect(x: self.center.x - 50, y: 12, width: 100, height: 34) - self.startVisualizationButton = RoundedButton(frame: frame) - self.startVisualizationButton.setTitle("Auto", for: .normal) - self.startVisualizationButton.addTarget(self, action: #selector(self.startVisualizationButtonDidTap), for: .touchUpInside) + let frame = CGRect(x: center.x - 50, y: 12, width: 100, height: 34) + startVisualizationButton = RoundedButton(frame: frame) + startVisualizationButton.setTitle("Auto", for: .normal) + startVisualizationButton.addTarget(self, action: #selector(startVisualizationButtonDidTap), for: .touchUpInside) } private func configureStartInteractiveVisualizationButton() { - let frame = CGRect(x: self.center.x + 100, y: 12, width: 100, height: 34) - self.startInteractiveVisualizationButton = RoundedButton(frame: frame) - self.startInteractiveVisualizationButton.setTitle("Interactive", for: .normal) - self.startInteractiveVisualizationButton.addTarget(self, action: #selector(self.startInteractiveVisualizationButtonDidTap), for: .touchUpInside) + let frame = CGRect(x: center.x + 100, y: 12, width: 100, height: 34) + startInteractiveVisualizationButton = RoundedButton(frame: frame) + startInteractiveVisualizationButton.setTitle("Interactive", for: .normal) + startInteractiveVisualizationButton.addTarget(self, action: #selector(startInteractiveVisualizationButtonDidTap), for: .touchUpInside) } private func configureStartButton() { - let frame = CGRect(x: self.center.x - 65, y: 56, width: 30, height: 30) - self.startButton = UIButton(frame: frame) + let frame = CGRect(x: center.x - 65, y: 56, width: 30, height: 30) + startButton = UIButton(frame: frame) let playImage = UIImage(named: "Start.png") - self.startButton.setImage(playImage, for: .normal) - self.startButton.isEnabled = false - self.startButton.addTarget(self, action: #selector(self.didTapStartButton), for: .touchUpInside) + startButton.setImage(playImage, for: .normal) + startButton.isEnabled = false + startButton.addTarget(self, action: #selector(didTapStartButton), for: .touchUpInside) } private func configurePauseButton() { - let frame = CGRect(x: self.center.x - 15, y: 56, width: 30, height: 30) - self.pauseButton = UIButton(frame: frame) + let frame = CGRect(x: center.x - 15, y: 56, width: 30, height: 30) + pauseButton = UIButton(frame: frame) let pauseImage = UIImage(named: "Pause.png") - self.pauseButton.setImage(pauseImage, for: .normal) - self.pauseButton.isEnabled = false - self.pauseButton.addTarget(self, action: #selector(self.didTapPauseButton), for: .touchUpInside) + pauseButton.setImage(pauseImage, for: .normal) + pauseButton.isEnabled = false + pauseButton.addTarget(self, action: #selector(didTapPauseButton), for: .touchUpInside) } private func configureStopButton() { - let frame = CGRect(x: self.center.x + 35, y: 56, width: 30, height: 30) - self.stopButton = UIButton(frame: frame) + let frame = CGRect(x: center.x + 35, y: 56, width: 30, height: 30) + stopButton = UIButton(frame: frame) let stopImage = UIImage(named: "Stop.png") - self.stopButton.setImage(stopImage, for: .normal) - self.stopButton.isEnabled = false - self.stopButton.addTarget(self, action: #selector(self.didTapStopButton), for: .touchUpInside) + stopButton.setImage(stopImage, for: .normal) + stopButton.isEnabled = false + stopButton.addTarget(self, action: #selector(didTapStopButton), for: .touchUpInside) } private func configureComparisonLabel() { let size = CGSize(width: 250, height: 42) - let origin = CGPoint(x: self.center.x - 125, y: 96) + let origin = CGPoint(x: center.x - 125, y: 96) let frame = CGRect(origin: origin, size: size) - self.comparisonLabel = UILabel(frame: frame) - self.comparisonLabel.textAlignment = .center - self.comparisonLabel.text = "Have fun!" + comparisonLabel = UILabel(frame: frame) + comparisonLabel.textAlignment = .center + comparisonLabel.text = "Have fun!" } private func configureActivityIndicator() { let size = CGSize(width: 50, height: 42) - let origin = CGPoint(x: self.center.x - 25, y: 100) + let origin = CGPoint(x: center.x - 25, y: 100) let activityIndicatorFrame = CGRect(origin: origin, size: size) - self.activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) - self.activityIndicator.activityIndicatorViewStyle = .whiteLarge + activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) + activityIndicator.activityIndicatorViewStyle = .whiteLarge } @objc private func createGraphButtonTap() { - self.comparisonLabel.text = "" - self.graphView.removeGraph() - self.graph.removeGraph() - self.graph.createNewGraph() - self.graphView.createNewGraph() - self.graph.state = .initial + comparisonLabel.text = "" + graphView.removeGraph() + graph.removeGraph() + graph.createNewGraph() + graphView.createNewGraph() + graph.state = .initial } @objc private func startVisualizationButtonDidTap() { - self.comparisonLabel.text = "" - self.pauseButton.isEnabled = true - self.stopButton.isEnabled = true - self.createGraphButton.isEnabled = false - self.startVisualizationButton.isEnabled = false - self.startInteractiveVisualizationButton.isEnabled = false - self.createGraphButton.alpha = 0.5 - self.startVisualizationButton.alpha = 0.5 - self.startInteractiveVisualizationButton.alpha = 0.5 - - if self.graph.state == .completed { - self.graphView.reset() - self.graph.reset() + comparisonLabel.text = "" + pauseButton.isEnabled = true + stopButton.isEnabled = true + createGraphButton.isEnabled = false + startVisualizationButton.isEnabled = false + startInteractiveVisualizationButton.isEnabled = false + createGraphButton.alpha = 0.5 + startVisualizationButton.alpha = 0.5 + startInteractiveVisualizationButton.alpha = 0.5 + + if graph.state == .completed { + graphView.reset() + graph.reset() } - self.graph.state = .autoVisualization + graph.state = .autoVisualization DispatchQueue.global(qos: .background).async { self.graph.findShortestPathsWithVisualization { self.graph.state = .completed @@ -184,25 +184,25 @@ public class Window: UIView, GraphDelegate { } @objc private func startInteractiveVisualizationButtonDidTap() { - self.comparisonLabel.text = "" - self.pauseButton.isEnabled = true - self.stopButton.isEnabled = true - self.createGraphButton.isEnabled = false - self.startVisualizationButton.isEnabled = false - self.startInteractiveVisualizationButton.isEnabled = false - self.createGraphButton.alpha = 0.5 - self.startVisualizationButton.alpha = 0.5 - self.startInteractiveVisualizationButton.alpha = 0.5 - - if self.graph.state == .completed { - self.graphView.reset() - self.graph.reset() + comparisonLabel.text = "" + pauseButton.isEnabled = true + stopButton.isEnabled = true + createGraphButton.isEnabled = false + startVisualizationButton.isEnabled = false + startInteractiveVisualizationButton.isEnabled = false + createGraphButton.alpha = 0.5 + startVisualizationButton.alpha = 0.5 + startInteractiveVisualizationButton.alpha = 0.5 + + if graph.state == .completed { + graphView.reset() + graph.reset() } - self.graph.startVertex.pathLengthFromStart = 0 - self.graph.startVertex.pathVerticesFromStart.append(self.graph.startVertex) - self.graph.state = .parsing - self.graph.parseNeighborsFor(vertex: self.graph.startVertex) { + graph.startVertex.pathLengthFromStart = 0 + graph.startVertex.pathVerticesFromStart.append(graph.startVertex) + graph.state = .parsing + graph.parseNeighborsFor(vertex: graph.startVertex) { self.graph.state = .interactiveVisualization DispatchQueue.main.async { self.comparisonLabel.text = "Pick next vertex" @@ -211,43 +211,43 @@ public class Window: UIView, GraphDelegate { } @objc private func didTapStartButton() { - self.startButton.isEnabled = false - self.pauseButton.isEnabled = true + startButton.isEnabled = false + pauseButton.isEnabled = true DispatchQueue.global(qos: .utility).async { self.graph.pauseVisualization = false } } @objc private func didTapPauseButton() { - self.startButton.isEnabled = true - self.pauseButton.isEnabled = false + startButton.isEnabled = true + pauseButton.isEnabled = false DispatchQueue.global(qos: .utility).async { self.graph.pauseVisualization = true } } @objc private func didTapStopButton() { - self.startButton.isEnabled = false - self.pauseButton.isEnabled = false - self.comparisonLabel.text = "" - self.activityIndicator.startAnimating() - if self.graph.state == .parsing || self.graph.state == .autoVisualization { - self.graph.stopVisualization = true - } else if self.graph.state == .interactiveVisualization { - self.didStop() + startButton.isEnabled = false + pauseButton.isEnabled = false + comparisonLabel.text = "" + activityIndicator.startAnimating() + if graph.state == .parsing || graph.state == .autoVisualization { + graph.stopVisualization = true + } else if graph.state == .interactiveVisualization { + didStop() } } private func setButtonsToInitialState() { - self.createGraphButton.isEnabled = true - self.startVisualizationButton.isEnabled = true - self.startInteractiveVisualizationButton.isEnabled = true - self.startButton.isEnabled = false - self.pauseButton.isEnabled = false - self.stopButton.isEnabled = false - self.createGraphButton.alpha = 1 - self.startVisualizationButton.alpha = 1 - self.startInteractiveVisualizationButton.alpha = 1 + createGraphButton.isEnabled = true + startVisualizationButton.isEnabled = true + startInteractiveVisualizationButton.isEnabled = true + startButton.isEnabled = false + pauseButton.isEnabled = false + stopButton.isEnabled = false + createGraphButton.alpha = 1 + startVisualizationButton.alpha = 1 + startInteractiveVisualizationButton.alpha = 1 } private func showError(error: String) { @@ -268,14 +268,14 @@ public class Window: UIView, GraphDelegate { // MARK: GraphDelegate public func didCompleteGraphParsing() { - self.graph.state = .completed - self.setButtonsToInitialState() - self.comparisonLabel.text = "Completed!" + graph.state = .completed + setButtonsToInitialState() + comparisonLabel.text = "Completed!" } public func didTapWrongVertex() { - if !self.subviews.contains { $0 is ErrorView } { - self.showError(error: "You have picked wrong next vertex") + if !subviews.contains { $0 is ErrorView } { + showError(error: "You have picked wrong next vertex") } } @@ -296,13 +296,13 @@ public class Window: UIView, GraphDelegate { } public func didStop() { - self.graph.state = .initial - self.graph.stopVisualization = false - self.graph.pauseVisualization = false - self.graphView.reset() - self.graph.reset() - self.setButtonsToInitialState() - self.activityIndicator.stopAnimating() + graph.state = .initial + graph.stopVisualization = false + graph.pauseVisualization = false + graphView.reset() + graph.reset() + setButtonsToInitialState() + activityIndicator.stopAnimating() } public func willStartVertexNeighborsChecking() { From 900b7caf229697f5666627bd7cdc34c6f1143702 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 12:56:12 +0300 Subject: [PATCH 0532/1275] Replaced with optional --- .../Sources/Graph.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift index 7c4a8e373..8bf2452cc 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift @@ -130,12 +130,12 @@ public class Graph { clearCache() startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) - var currentVertex: Vertex! = startVertex + var currentVertex: Vertex? = startVertex var totalVertices = _vertices - breakableLoop: while currentVertex != nil { - totalVertices.remove(currentVertex) + breakableLoop: while let vertex = currentVertex { + totalVertices.remove(vertex) while pauseVisualization == true { if stopVisualization == true { break breakableLoop @@ -145,11 +145,11 @@ public class Graph { break breakableLoop } DispatchQueue.main.async { - currentVertex.setVisitedColor() + vertex.setVisitedColor() } usleep(750000) - currentVertex.visited = true - let filteredEdges = currentVertex.edges.filter { !$0.neighbor.visited } + vertex.visited = true + let filteredEdges = vertex.edges.filter { !$0.neighbor.visited } for edge in filteredEdges { let neighbor = edge.neighbor let weight = edge.weight @@ -166,14 +166,14 @@ public class Graph { DispatchQueue.main.async { edgeRepresentation?.setCheckingColor() neighbor.setCheckingPathColor() - self.delegate?.willCompareVertices(startVertexPathLength: currentVertex.pathLengthFromStart, + self.delegate?.willCompareVertices(startVertexPathLength: vertex.pathLengthFromStart, edgePathLength: weight, endVertexPathLength: neighbor.pathLengthFromStart) } usleep(_visualizationOneSleepDuration) - let theoreticNewWeight = currentVertex.pathLengthFromStart + weight + let theoreticNewWeight = vertex.pathLengthFromStart + weight if theoreticNewWeight < neighbor.pathLengthFromStart { while pauseVisualization == true { @@ -185,7 +185,7 @@ public class Graph { break breakableLoop } neighbor.pathLengthFromStart = theoreticNewWeight - neighbor.pathVerticesFromStart = currentVertex.pathVerticesFromStart + neighbor.pathVerticesFromStart = vertex.pathVerticesFromStart neighbor.pathVerticesFromStart.append(neighbor) } usleep(_visualizationOneSleepDuration) From 2a1a2a1a7bbdf738b8643d49775ccf7895d476b6 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 13:27:18 +0300 Subject: [PATCH 0533/1275] Refactored a bit --- .../Sources/Graph.swift | 14 ++++++++------ .../Sources/GraphView.swift | 12 +++++------- .../Sources/Window.swift | 19 +++++++++++-------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift index 8bf2452cc..447b3dbe1 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift @@ -10,16 +10,14 @@ public enum GraphState { } public class Graph { - private init() { } - - private var verticesCount: UInt! + private var verticesCount: UInt private var _vertices: Set = Set() public weak var delegate: GraphDelegate? public var nextVertices: [Vertex] = [] public var state: GraphState = .initial - public var pauseVisualization: Bool = false - public var stopVisualization: Bool = false - public var startVertex: Vertex! + public var pauseVisualization = false + public var stopVisualization = false + public var startVertex: Vertex? public var interactiveNeighborCheckAnimationDuration: Double = 1.8 { didSet { _interactiveOneSleepDuration = UInt32(interactiveNeighborCheckAnimationDuration * 1000000.0 / 3.0) @@ -127,6 +125,10 @@ public class Graph { } public func findShortestPathsWithVisualization(completion: () -> Void) { + guard let startVertex = self.startVertex else { + assertionFailure("start vertex is nil") + return + } clearCache() startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift index bdeab7669..ec4f74705 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift @@ -1,13 +1,15 @@ import UIKit public class GraphView: UIView { - private var graph: Graph! + private var graph: Graph private var panningView: VertexView? = nil - private var graphColors: GraphColors = GraphColors.sharedInstance + private var graphColors = GraphColors.sharedInstance - public override init(frame: CGRect) { + public init(frame: CGRect, graph: Graph) { + self.graph = graph super.init(frame: frame) backgroundColor = graphColors.graphBackgroundColor + layer.cornerRadius = 15 } public required init?(coder aDecoder: NSCoder) { @@ -15,10 +17,6 @@ public class GraphView: UIView { } - public func configure(graph: Graph) { - self.graph = graph - } - public func removeGraph() { for vertex in graph.vertices { if let view = vertex.view { diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift index 054b804c9..73c512e6b 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -25,7 +25,7 @@ public class Window: UIView, GraphDelegate { private var activityIndicator: UIActivityIndicatorView! private var graph: Graph! private var numberOfVertices: UInt! - private var graphColors: GraphColors = GraphColors.sharedInstance + private var graphColors = GraphColors.sharedInstance public override init(frame: CGRect) { super.init(frame: frame) @@ -42,10 +42,9 @@ public class Window: UIView, GraphDelegate { graph.createNewGraph() graph.delegate = self let frame = CGRect(x: 10, y: 170, width: self.frame.width - 20, height: self.frame.height - 180) - graphView = GraphView(frame: frame) - graphView.layer.cornerRadius = 15 + graphView = GraphView(frame: frame, graph: graph) + - graphView.configure(graph: graph) graphView.createNewGraph() addSubview(graphView) @@ -198,11 +197,15 @@ public class Window: UIView, GraphDelegate { graphView.reset() graph.reset() } - - graph.startVertex.pathLengthFromStart = 0 - graph.startVertex.pathVerticesFromStart.append(graph.startVertex) + + guard let startVertex = graph.startVertex else { + assertionFailure("startVertex is nil") + return + } + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) graph.state = .parsing - graph.parseNeighborsFor(vertex: graph.startVertex) { + graph.parseNeighborsFor(vertex: startVertex) { self.graph.state = .interactiveVisualization DispatchQueue.main.async { self.comparisonLabel.text = "Pick next vertex" From 846101720981de86abf8fe8f372715fa50f12dcb Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:02:43 +0300 Subject: [PATCH 0534/1275] Updated description --- Dijkstra Algorithm/README.md | 38 ++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index bf158def9..2bbf74b87 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,21 +1,39 @@ # Dijkstra-algorithm -## About -Dijkstra's algorithm is used for finding shortest paths from start vertex in graph(with weighted vertices) to all other vertices. -More algorithm's description can be found in playground or on wikipedia: -[Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) - -To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. - -If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. +## About this repository +This repository contains to playgrounds: +* To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. +* If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. ## Demo video Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Screenshots - +## Dijkstra's algorithm explanation + +Wikipedia's explanation: +Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. + +1. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all other nodes. +2. Set the initial node as current. Mark all other nodes unvisited. Create a set of all the unvisited nodes called the unvisited set. +3. For the current node, consider all of its unvisited neighbors and calculate their tentative distances. Compare the newly calculated tentative distance to the current assigned value and assign the smaller one. For example, if the current node A is marked with a distance of 6, and the edge connecting it with a neighbor B has length 2, then the distance to B (through A) will be 6 + 2 = 8. If B was previously marked with a distance greater than 8 then change it to 8. Otherwise, keep the current value. +4. When we are done considering all of the neighbors of the current node, mark the current node as visited and remove it from the unvisited set. A visited node will never be checked again. +5. If the destination node has been marked visited (when planning a route between two specific nodes) or if the smallest tentative distance among the nodes in the unvisited set is infinity (when planning a complete traversal; occurs when there is no connection between the initial node and remaining unvisited nodes), then stop. The algorithm has finished. +6. Otherwise, select the unvisited node that is marked with the smallest tentative distance, set it as the new "current node", and go back to step 3. + +Explanation, that can be found in the **VisualizedDijkstra.playground** +Algorithm's flow: +First of all, this program randomly decides which vertex will be the start one, then the program assigns a zero value to the start vertex path length from the start. + +Then the algorithm repeats following cycle until all vertices are marked as visited. +Cycle: +1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) +2. The algorithm marks picked vertex as visited. +3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. +When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. + ## Credits -WWDC 2017 Scholarship Project +WWDC 2017 Scholarship Project Created by [Taras Nikulin](https://github.com/crabman448) From f7793cc6b6692000e4fd878afce62fd67d5b5f00 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:38:47 +0300 Subject: [PATCH 0535/1275] Added gif --- Dijkstra Algorithm/Images/Dijkstra_Animation.gif | Bin 0 -> 8561 bytes .../{Screenshots => Images}/screenshot1.jpg | Bin Dijkstra Algorithm/README.md | 8 +++++++- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Dijkstra Algorithm/Images/Dijkstra_Animation.gif rename Dijkstra Algorithm/{Screenshots => Images}/screenshot1.jpg (100%) diff --git a/Dijkstra Algorithm/Images/Dijkstra_Animation.gif b/Dijkstra Algorithm/Images/Dijkstra_Animation.gif new file mode 100644 index 0000000000000000000000000000000000000000..3b1a2ef434107efb104a9bc1a6a714af37367529 GIT binary patch literal 8561 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Screenshots/screenshot1.jpg b/Dijkstra Algorithm/Images/screenshot1.jpg similarity index 100% rename from Dijkstra Algorithm/Screenshots/screenshot1.jpg rename to Dijkstra Algorithm/Images/screenshot1.jpg diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 2bbf74b87..0ac4bc17e 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -9,10 +9,12 @@ This repository contains to playgrounds: Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Screenshots - + ## Dijkstra's algorithm explanation + + Wikipedia's explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. @@ -34,6 +36,10 @@ Cycle: 3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. +## Usage + + + ## Credits WWDC 2017 Scholarship Project Created by [Taras Nikulin](https://github.com/crabman448) From 3f6be33a1750d6f9122ca8ab38b70c3a9e4d123b Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:40:34 +0300 Subject: [PATCH 0536/1275] Added link --- Dijkstra Algorithm/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 0ac4bc17e..b2606f0f9 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -13,7 +13,8 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Dijkstra's algorithm explanation - +GIF from Wikipedia + Wikipedia's explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. From a153067e60fcd90d8a8b6448fbc5d9e0c5753076 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:41:35 +0300 Subject: [PATCH 0537/1275] Updated link --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index b2606f0f9..cf939c7cc 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -14,7 +14,7 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Dijkstra's algorithm explanation GIF from Wikipedia - + Wikipedia's explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. From b59ffa53930e3021a22bee31923965a12f7031a3 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:42:10 +0300 Subject: [PATCH 0538/1275] Revert "Updated link" This reverts commit a153067e60fcd90d8a8b6448fbc5d9e0c5753076. --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index cf939c7cc..b2606f0f9 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -14,7 +14,7 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Dijkstra's algorithm explanation GIF from Wikipedia - + Wikipedia's explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. From ef13b5076e1741023c6d014e32266044d8d63d7b Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:42:40 +0300 Subject: [PATCH 0539/1275] Revert "Added link" This reverts commit 3f6be33a1750d6f9122ca8ab38b70c3a9e4d123b. --- Dijkstra Algorithm/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index b2606f0f9..0ac4bc17e 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -13,8 +13,7 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Dijkstra's algorithm explanation -GIF from Wikipedia - + Wikipedia's explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. From aea01e8b68d7fefd06ccae2d3afeb253a43abba0 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Mon, 17 Apr 2017 14:44:39 +0300 Subject: [PATCH 0540/1275] Added link to Wikipedia This reverts commit a153067e60fcd90d8a8b6448fbc5d9e0c5753076. --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 0ac4bc17e..325bab40f 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -15,7 +15,7 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) -Wikipedia's explanation: +[Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)'s explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. 1. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all other nodes. From edafd431fab46087ff805f6ad419b076a076bf82 Mon Sep 17 00:00:00 2001 From: ph1ps Date: Mon, 17 Apr 2017 21:15:01 +0200 Subject: [PATCH 0541/1275] Add playground --- .../NaiveBayes.playground/Contents.swift | 60 ++++++ .../NaiveBayes.playground/Resources/wine.csv | 177 ++++++++++++++++ .../Sources/NaiveBayes.swift | 196 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + Naive Bayes Classifier/NaiveBayes.swift | 124 ++++------- 6 files changed, 479 insertions(+), 89 deletions(-) create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/Contents.swift create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/Resources/wine.csv create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift new file mode 100644 index 000000000..cb820272e --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift @@ -0,0 +1,60 @@ +import Foundation + +/*: + ## Naive Bayes Classifier + + This playground uses the given algorithm and utilizes its features with some example datasets + + ### Gaussian Naive Bayes + - Note: + When using Gaussian NB you have to have continuous features (Double). + + For this example we are going to use a famous dataset with different types of wine. The labels of the features can be viewed [here](https://gist.github.com/tijptjik/9408623) + */ +guard let wineCSV = Bundle.main.path(forResource: "wine", ofType: "csv") else { + print("Resource could not be found!") + exit(0) +} + +guard let csv = try? String(contentsOfFile: wineCSV) else { + print("File could not be read!") + exit(0) +} + +/*: + Reading the .csv file line per line + */ +let rows = csv.characters.split(separator: "\r\n").map { String($0) } +/*: + Splitting on the ; sign and converting the value to a Double + + - Important: + Do not force unwrap the mapped values in your real application. Carefully convert them! This is just for the sake of showing how the algorithm works. + */ +let wineData = rows.map { row -> [Double] in + let split = row.characters.split(separator: ";") + return split.map { Double(String($0))! } +} + +/*: + The algorithm wants the classes and the data seperated since this gives a huge performance boost. Also I haven't implemented this in the NB class itself since it is not in the scope of it. + */ +let rowOfClasses = 0 +let classes = wineData.map { Int($0[rowOfClasses]) } +let data = wineData.map { row in + return row.enumerated().filter { $0.offset != rowOfClasses }.map { $0.element } +} + +/*: + Again use `guard` on the result of a `try?` or simply `do-try-catch` because this would crash your application if an error occured. + + The array in the `classifyProba` method I passed is a former entry in the .csv file which I removed in order to classify it. + */ +let wineBayes = try! NaiveBayes(type: .gaussian, data: data, classes: classes).train() +let result = wineBayes.classifyProba(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015]) +print(result) +/*: + I can assure you that this is the correct result and as you can see the classifier thinks that its ***99.99%*** correct too. + + ### Multinomial Naive Bayes + */ diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Resources/wine.csv b/Naive Bayes Classifier/NaiveBayes.playground/Resources/wine.csv new file mode 100644 index 000000000..89e14fd02 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/Resources/wine.csv @@ -0,0 +1,177 @@ +1;14.23;1.71;2.43;15.6;127;2.8;3.06;.28;2.29;5.64;1.04;3.92;1065 +1;13.2;1.78;2.14;11.2;100;2.65;2.76;.26;1.28;4.38;1.05;3.4;1050 +1;13.16;2.36;2.67;18.6;101;2.8;3.24;.3;2.81;5.68;1.03;3.17;1185 +1;14.37;1.95;2.5;16.8;113;3.85;3.49;.24;2.18;7.8;.86;3.45;1480 +1;13.24;2.59;2.87;21;118;2.8;2.69;.39;1.82;4.32;1.04;2.93;735 +1;14.2;1.76;2.45;15.2;112;3.27;3.39;.34;1.97;6.75;1.05;2.85;1450 +1;14.39;1.87;2.45;14.6;96;2.5;2.52;.3;1.98;5.25;1.02;3.58;1290 +1;14.06;2.15;2.61;17.6;121;2.6;2.51;.31;1.25;5.05;1.06;3.58;1295 +1;14.83;1.64;2.17;14;97;2.8;2.98;.29;1.98;5.2;1.08;2.85;1045 +1;13.86;1.35;2.27;16;98;2.98;3.15;.22;1.85;7.22;1.01;3.55;1045 +1;14.1;2.16;2.3;18;105;2.95;3.32;.22;2.38;5.75;1.25;3.17;1510 +1;14.12;1.48;2.32;16.8;95;2.2;2.43;.26;1.57;5;1.17;2.82;1280 +1;13.75;1.73;2.41;16;89;2.6;2.76;.29;1.81;5.6;1.15;2.9;1320 +1;14.75;1.73;2.39;11.4;91;3.1;3.69;.43;2.81;5.4;1.25;2.73;1150 +1;14.38;1.87;2.38;12;102;3.3;3.64;.29;2.96;7.5;1.2;3;1547 +1;13.63;1.81;2.7;17.2;112;2.85;2.91;.3;1.46;7.3;1.28;2.88;1310 +1;14.3;1.92;2.72;20;120;2.8;3.14;.33;1.97;6.2;1.07;2.65;1280 +1;13.83;1.57;2.62;20;115;2.95;3.4;.4;1.72;6.6;1.13;2.57;1130 +1;14.19;1.59;2.48;16.5;108;3.3;3.93;.32;1.86;8.7;1.23;2.82;1680 +1;13.64;3.1;2.56;15.2;116;2.7;3.03;.17;1.66;5.1;.96;3.36;845 +1;14.06;1.63;2.28;16;126;3;3.17;.24;2.1;5.65;1.09;3.71;780 +1;12.93;3.8;2.65;18.6;102;2.41;2.41;.25;1.98;4.5;1.03;3.52;770 +1;13.71;1.86;2.36;16.6;101;2.61;2.88;.27;1.69;3.8;1.11;4;1035 +1;13.5;1.81;2.61;20;96;2.53;2.61;.28;1.66;3.52;1.12;3.82;845 +1;13.05;2.05;3.22;25;124;2.63;2.68;.47;1.92;3.58;1.13;3.2;830 +1;13.39;1.77;2.62;16.1;93;2.85;2.94;.34;1.45;4.8;.92;3.22;1195 +1;13.3;1.72;2.14;17;94;2.4;2.19;.27;1.35;3.95;1.02;2.77;1285 +1;13.87;1.9;2.8;19.4;107;2.95;2.97;.37;1.76;4.5;1.25;3.4;915 +1;14.02;1.68;2.21;16;96;2.65;2.33;.26;1.98;4.7;1.04;3.59;1035 +1;13.73;1.5;2.7;22.5;101;3;3.25;.29;2.38;5.7;1.19;2.71;1285 +1;13.58;1.66;2.36;19.1;106;2.86;3.19;.22;1.95;6.9;1.09;2.88;1515 +1;13.68;1.83;2.36;17.2;104;2.42;2.69;.42;1.97;3.84;1.23;2.87;990 +1;13.76;1.53;2.7;19.5;132;2.95;2.74;.5;1.35;5.4;1.25;3;1235 +1;13.51;1.8;2.65;19;110;2.35;2.53;.29;1.54;4.2;1.1;2.87;1095 +1;13.48;1.81;2.41;20.5;100;2.7;2.98;.26;1.86;5.1;1.04;3.47;920 +1;13.28;1.64;2.84;15.5;110;2.6;2.68;.34;1.36;4.6;1.09;2.78;880 +1;13.05;1.65;2.55;18;98;2.45;2.43;.29;1.44;4.25;1.12;2.51;1105 +1;13.07;1.5;2.1;15.5;98;2.4;2.64;.28;1.37;3.7;1.18;2.69;1020 +1;14.22;3.99;2.51;13.2;128;3;3.04;.2;2.08;5.1;.89;3.53;760 +1;13.56;1.71;2.31;16.2;117;3.15;3.29;.34;2.34;6.13;.95;3.38;795 +1;13.41;3.84;2.12;18.8;90;2.45;2.68;.27;1.48;4.28;.91;3;1035 +1;13.88;1.89;2.59;15;101;3.25;3.56;.17;1.7;5.43;.88;3.56;1095 +1;13.24;3.98;2.29;17.5;103;2.64;2.63;.32;1.66;4.36;.82;3;680 +1;13.05;1.77;2.1;17;107;3;3;.28;2.03;5.04;.88;3.35;885 +1;14.21;4.04;2.44;18.9;111;2.85;2.65;.3;1.25;5.24;.87;3.33;1080 +1;14.38;3.59;2.28;16;102;3.25;3.17;.27;2.19;4.9;1.04;3.44;1065 +1;13.9;1.68;2.12;16;101;3.1;3.39;.21;2.14;6.1;.91;3.33;985 +1;14.1;2.02;2.4;18.8;103;2.75;2.92;.32;2.38;6.2;1.07;2.75;1060 +1;13.94;1.73;2.27;17.4;108;2.88;3.54;.32;2.08;8.90;1.12;3.1;1260 +1;13.05;1.73;2.04;12.4;92;2.72;3.27;.17;2.91;7.2;1.12;2.91;1150 +1;13.83;1.65;2.6;17.2;94;2.45;2.99;.22;2.29;5.6;1.24;3.37;1265 +1;13.82;1.75;2.42;14;111;3.88;3.74;.32;1.87;7.05;1.01;3.26;1190 +1;13.77;1.9;2.68;17.1;115;3;2.79;.39;1.68;6.3;1.13;2.93;1375 +1;13.74;1.67;2.25;16.4;118;2.6;2.9;.21;1.62;5.85;.92;3.2;1060 +1;13.56;1.73;2.46;20.5;116;2.96;2.78;.2;2.45;6.25;.98;3.03;1120 +1;14.22;1.7;2.3;16.3;118;3.2;3;.26;2.03;6.38;.94;3.31;970 +1;13.29;1.97;2.68;16.8;102;3;3.23;.31;1.66;6;1.07;2.84;1270 +1;13.72;1.43;2.5;16.7;108;3.4;3.67;.19;2.04;6.8;.89;2.87;1285 +2;12.37;.94;1.36;10.6;88;1.98;.57;.28;.42;1.95;1.05;1.82;520 +2;12.33;1.1;2.28;16;101;2.05;1.09;.63;.41;3.27;1.25;1.67;680 +2;12.64;1.36;2.02;16.8;100;2.02;1.41;.53;.62;5.75;.98;1.59;450 +2;13.67;1.25;1.92;18;94;2.1;1.79;.32;.73;3.8;1.23;2.46;630 +2;12.37;1.13;2.16;19;87;3.5;3.1;.19;1.87;4.45;1.22;2.87;420 +2;12.17;1.45;2.53;19;104;1.89;1.75;.45;1.03;2.95;1.45;2.23;355 +2;12.37;1.21;2.56;18.1;98;2.42;2.65;.37;2.08;4.6;1.19;2.3;678 +2;13.11;1.01;1.7;15;78;2.98;3.18;.26;2.28;5.3;1.12;3.18;502 +2;12.37;1.17;1.92;19.6;78;2.11;2;.27;1.04;4.68;1.12;3.48;510 +2;13.34;.94;2.36;17;110;2.53;1.3;.55;.42;3.17;1.02;1.93;750 +2;12.21;1.19;1.75;16.8;151;1.85;1.28;.14;2.5;2.85;1.28;3.07;718 +2;12.29;1.61;2.21;20.4;103;1.1;1.02;.37;1.46;3.05;906;1.82;870 +2;13.86;1.51;2.67;25;86;2.95;2.86;.21;1.87;3.38;1.36;3.16;410 +2;13.49;1.66;2.24;24;87;1.88;1.84;.27;1.03;3.74;.98;2.78;472 +2;12.99;1.67;2.6;30;139;3.3;2.89;.21;1.96;3.35;1.31;3.5;985 +2;11.96;1.09;2.3;21;101;3.38;2.14;.13;1.65;3.21;.99;3.13;886 +2;11.66;1.88;1.92;16;97;1.61;1.57;.34;1.15;3.8;1.23;2.14;428 +2;13.03;.9;1.71;16;86;1.95;2.03;.24;1.46;4.6;1.19;2.48;392 +2;11.84;2.89;2.23;18;112;1.72;1.32;.43;.95;2.65;.96;2.52;500 +2;12.33;.99;1.95;14.8;136;1.9;1.85;.35;2.76;3.4;1.06;2.31;750 +2;12.7;3.87;2.4;23;101;2.83;2.55;.43;1.95;2.57;1.19;3.13;463 +2;12;.92;2;19;86;2.42;2.26;.3;1.43;2.5;1.38;3.12;278 +2;12.72;1.81;2.2;18.8;86;2.2;2.53;.26;1.77;3.9;1.16;3.14;714 +2;12.08;1.13;2.51;24;78;2;1.58;.4;1.4;2.2;1.31;2.72;630 +2;13.05;3.86;2.32;22.5;85;1.65;1.59;.61;1.62;4.8;.84;2.01;515 +2;11.84;.89;2.58;18;94;2.2;2.21;.22;2.35;3.05;.79;3.08;520 +2;12.67;.98;2.24;18;99;2.2;1.94;.3;1.46;2.62;1.23;3.16;450 +2;12.16;1.61;2.31;22.8;90;1.78;1.69;.43;1.56;2.45;1.33;2.26;495 +2;11.65;1.67;2.62;26;88;1.92;1.61;.4;1.34;2.6;1.36;3.21;562 +2;11.64;2.06;2.46;21.6;84;1.95;1.69;.48;1.35;2.8;1;2.75;680 +2;12.08;1.33;2.3;23.6;70;2.2;1.59;.42;1.38;1.74;1.07;3.21;625 +2;12.08;1.83;2.32;18.5;81;1.6;1.5;.52;1.64;2.4;1.08;2.27;480 +2;12;1.51;2.42;22;86;1.45;1.25;.5;1.63;3.6;1.05;2.65;450 +2;12.69;1.53;2.26;20.7;80;1.38;1.46;.58;1.62;3.05;.96;2.06;495 +2;12.29;2.83;2.22;18;88;2.45;2.25;.25;1.99;2.15;1.15;3.3;290 +2;11.62;1.99;2.28;18;98;3.02;2.26;.17;1.35;3.25;1.16;2.96;345 +2;12.47;1.52;2.2;19;162;2.5;2.27;.32;3.28;2.6;1.16;2.63;937 +2;11.81;2.12;2.74;21.5;134;1.6;.99;.14;1.56;2.5;.95;2.26;625 +2;12.29;1.41;1.98;16;85;2.55;2.5;.29;1.77;2.9;1.23;2.74;428 +2;12.37;1.07;2.1;18.5;88;3.52;3.75;.24;1.95;4.5;1.04;2.77;660 +2;12.29;3.17;2.21;18;88;2.85;2.99;.45;2.81;2.3;1.42;2.83;406 +2;12.08;2.08;1.7;17.5;97;2.23;2.17;.26;1.4;3.3;1.27;2.96;710 +2;12.6;1.34;1.9;18.5;88;1.45;1.36;.29;1.35;2.45;1.04;2.77;562 +2;12.34;2.45;2.46;21;98;2.56;2.11;.34;1.31;2.8;.8;3.38;438 +2;11.82;1.72;1.88;19.5;86;2.5;1.64;.37;1.42;2.06;.94;2.44;415 +2;12.51;1.73;1.98;20.5;85;2.2;1.92;.32;1.48;2.94;1.04;3.57;672 +2;12.42;2.55;2.27;22;90;1.68;1.84;.66;1.42;2.7;.86;3.3;315 +2;12.25;1.73;2.12;19;80;1.65;2.03;.37;1.63;3.4;1;3.17;510 +2;12.72;1.75;2.28;22.5;84;1.38;1.76;.48;1.63;3.3;.88;2.42;488 +2;12.22;1.29;1.94;19;92;2.36;2.04;.39;2.08;2.7;.86;3.02;312 +2;11.61;1.35;2.7;20;94;2.74;2.92;.29;2.49;2.65;.96;3.26;680 +2;11.46;3.74;1.82;19.5;107;3.18;2.58;.24;3.58;2.9;.75;2.81;562 +2;12.52;2.43;2.17;21;88;2.55;2.27;.26;1.22;2;.9;2.78;325 +2;11.76;2.68;2.92;20;103;1.75;2.03;.6;1.05;3.8;1.23;2.5;607 +2;11.41;.74;2.5;21;88;2.48;2.01;.42;1.44;3.08;1.1;2.31;434 +2;12.08;1.39;2.5;22.5;84;2.56;2.29;.43;1.04;2.9;.93;3.19;385 +2;11.03;1.51;2.2;21.5;85;2.46;2.17;.52;2.01;1.9;1.71;2.87;407 +2;11.82;1.47;1.99;20.8;86;1.98;1.6;.3;1.53;1.95;.95;3.33;495 +2;12.42;1.61;2.19;22.5;108;2;2.09;.34;1.61;2.06;1.06;2.96;345 +2;12.77;3.43;1.98;16;80;1.63;1.25;.43;.83;3.4;.7;2.12;372 +2;12;3.43;2;19;87;2;1.64;.37;1.87;1.28;.93;3.05;564 +2;11.45;2.4;2.42;20;96;2.9;2.79;.32;1.83;3.25;.8;3.39;625 +2;11.56;2.05;3.23;28.5;119;3.18;5.08;.47;1.87;6;.93;3.69;465 +2;12.42;4.43;2.73;26.5;102;2.2;2.13;.43;1.71;2.08;.92;3.12;365 +2;13.05;5.8;2.13;21.5;86;2.62;2.65;.3;2.01;2.6;.73;3.1;380 +2;11.87;4.31;2.39;21;82;2.86;3.03;.21;2.91;2.8;.75;3.64;380 +2;12.07;2.16;2.17;21;85;2.6;2.65;.37;1.35;2.76;.86;3.28;378 +2;12.43;1.53;2.29;21.5;86;2.74;3.15;.39;1.77;3.94;.69;2.84;352 +2;11.79;2.13;2.78;28.5;92;2.13;2.24;.58;1.76;3;.97;2.44;466 +2;12.37;1.63;2.3;24.5;88;2.22;2.45;.4;1.9;2.12;.89;2.78;342 +2;12.04;4.3;2.38;22;80;2.1;1.75;.42;1.35;2.6;.79;2.57;580 +3;12.86;1.35;2.32;18;122;1.51;1.25;.21;.94;4.1;.76;1.29;630 +3;12.88;2.99;2.4;20;104;1.3;1.22;.24;.83;5.4;.74;1.42;530 +3;12.81;2.31;2.4;24;98;1.15;1.09;.27;.83;5.7;.66;1.36;560 +3;12.7;3.55;2.36;21.5;106;1.7;1.2;.17;.84;5;.78;1.29;600 +3;12.51;1.24;2.25;17.5;85;2;.58;.6;1.25;5.45;.75;1.51;650 +3;12.6;2.46;2.2;18.5;94;1.62;.66;.63;.94;7.1;.73;1.58;695 +3;12.25;4.72;2.54;21;89;1.38;.47;.53;.8;3.85;.75;1.27;720 +3;12.53;5.51;2.64;25;96;1.79;.6;.63;1.1;5;.82;1.69;515 +3;13.49;3.59;2.19;19.5;88;1.62;.48;.58;.88;5.7;.81;1.82;580 +3;12.84;2.96;2.61;24;101;2.32;.6;.53;.81;4.92;.89;2.15;590 +3;12.93;2.81;2.7;21;96;1.54;.5;.53;.75;4.6;.77;2.31;600 +3;13.36;2.56;2.35;20;89;1.4;.5;.37;.64;5.6;.7;2.47;780 +3;13.52;3.17;2.72;23.5;97;1.55;.52;.5;.55;4.35;.89;2.06;520 +3;13.62;4.95;2.35;20;92;2;.8;.47;1.02;4.4;.91;2.05;550 +3;12.25;3.88;2.2;18.5;112;1.38;.78;.29;1.14;8.21;.65;2;855 +3;13.16;3.57;2.15;21;102;1.5;.55;.43;1.3;4;.6;1.68;830 +3;13.88;5.04;2.23;20;80;.98;.34;.4;.68;4.9;.58;1.33;415 +3;12.87;4.61;2.48;21.5;86;1.7;.65;.47;.86;7.65;.54;1.86;625 +3;13.32;3.24;2.38;21.5;92;1.93;.76;.45;1.25;8.42;.55;1.62;650 +3;13.08;3.9;2.36;21.5;113;1.41;1.39;.34;1.14;9.40;.57;1.33;550 +3;13.5;3.12;2.62;24;123;1.4;1.57;.22;1.25;8.60;.59;1.3;500 +3;12.79;2.67;2.48;22;112;1.48;1.36;.24;1.26;10.8;.48;1.47;480 +3;13.11;1.9;2.75;25.5;116;2.2;1.28;.26;1.56;7.1;.61;1.33;425 +3;13.23;3.3;2.28;18.5;98;1.8;.83;.61;1.87;10.52;.56;1.51;675 +3;12.58;1.29;2.1;20;103;1.48;.58;.53;1.4;7.6;.58;1.55;640 +3;13.17;5.19;2.32;22;93;1.74;.63;.61;1.55;7.9;.6;1.48;725 +3;13.84;4.12;2.38;19.5;89;1.8;.83;.48;1.56;9.01;.57;1.64;480 +3;12.45;3.03;2.64;27;97;1.9;.58;.63;1.14;7.5;.67;1.73;880 +3;14.34;1.68;2.7;25;98;2.8;1.31;.53;2.7;13;.57;1.96;660 +3;13.48;1.67;2.64;22.5;89;2.6;1.1;.52;2.29;11.75;.57;1.78;620 +3;12.36;3.83;2.38;21;88;2.3;.92;.5;1.04;7.65;.56;1.58;520 +3;13.69;3.26;2.54;20;107;1.83;.56;.5;.8;5.88;.96;1.82;680 +3;12.85;3.27;2.58;22;106;1.65;.6;.6;.96;5.58;.87;2.11;570 +3;12.96;3.45;2.35;18.5;106;1.39;.7;.4;.94;5.28;.68;1.75;675 +3;13.78;2.76;2.3;22;90;1.35;.68;.41;1.03;9.58;.7;1.68;615 +3;13.73;4.36;2.26;22.5;88;1.28;.47;.52;1.15;6.62;.78;1.75;520 +3;13.45;3.7;2.6;23;111;1.7;.92;.43;1.46;10.68;.85;1.56;695 +3;12.82;3.37;2.3;19.5;88;1.48;.66;.4;.97;10.26;.72;1.75;685 +3;13.58;2.58;2.69;24.5;105;1.55;.84;.39;1.54;8.66;.74;1.8;750 +3;13.4;4.6;2.86;25;112;1.98;.96;.27;1.11;8.5;.67;1.92;630 +3;12.2;3.03;2.32;19;96;1.25;.49;.4;.73;5.5;.66;1.83;510 +3;12.77;2.39;2.28;19.5;86;1.39;.51;.48;.64;9.899999;.57;1.63;470 +3;14.16;2.51;2.48;20;91;1.68;.7;.44;1.24;9.7;.62;1.71;660 +3;13.71;5.65;2.45;20.5;95;1.68;.61;.52;1.06;7.7;.64;1.74;740 +3;13.4;3.91;2.48;23;102;1.8;.75;.43;1.41;7.3;.7;1.56;750 +3;13.27;4.28;2.26;20;120;1.59;.69;.43;1.35;10.2;.59;1.56;835 +3;13.17;2.59;2.37;20;120;1.65;.68;.53;1.46;9.3;.6;1.62;840 +3;14.13;4.1;2.74;24.5;96;2.05;.76;.56;1.35;9.2;.61;1.6;560 \ No newline at end of file diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift new file mode 100644 index 000000000..3af8102c7 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift @@ -0,0 +1,196 @@ +// +// NaiveBayes.swift +// NaiveBayes +// +// Created by Philipp Gabriel on 14.04.17. +// Copyright © 2017 ph1ps. All rights reserved. +// + +import Foundation + +extension String: Error {} + +extension Array where Element == Double { + + func mean() -> Double { + return self.reduce(0, +) / Double(count) + } + + func standardDeviation() -> Double { + let calculatedMean = mean() + + let sum = self.reduce(0.0) { (previous, next) in + return previous + pow(next - calculatedMean, 2) + } + + return sqrt(sum / Double(count - 1)) + } +} + +extension Array where Element == Int { + + func uniques() -> Set { + return Set(self) + } + +} + +public enum NBType { + + case gaussian + case multinomial + //case bernoulli --> TODO + + func calcLikelihood(variables: [Any], input: Any) -> Double? { + + if case .gaussian = self { + + guard let input = input as? Double else { + return nil + } + + guard let mean = variables[0] as? Double else { + return nil + } + + guard let stDev = variables[1] as? Double else { + return nil + } + + let eulerPart = pow(M_E, -1 * pow(input - mean, 2) / (2 * pow(stDev, 2))) + let distribution = eulerPart / sqrt(2 * .pi) / stDev + + return distribution + + } else if case .multinomial = self { + + guard let variables = variables as? [(category: Int, probability: Double)] else { + return nil + } + + guard let input = input as? Int else { + return nil + } + + return variables.first { variable in + return variable.category == input + }?.probability + + } + + return nil + } + + func train(values: [Any]) -> [Any]? { + + if case .gaussian = self { + + guard let values = values as? [Double] else { + return nil + } + + return [values.mean(), values.standardDeviation()] + + } else if case .multinomial = self { + + guard let values = values as? [Int] else { + return nil + } + + let count = values.count + let categoryProba = values.uniques().map { value -> (Int, Double) in + return (value, Double(values.filter { $0 == value }.count) / Double(count)) + } + return categoryProba + } + + return nil + } +} + +public class NaiveBayes { + + var variables: [Int: [(feature: Int, variables: [Any])]] + var type: NBType + + var data: [[T]] + var classes: [Int] + + public init(type: NBType, data: [[T]], classes: [Int]) throws { + self.type = type + self.data = data + self.classes = classes + self.variables = [Int: [(Int, [Any])]]() + + if case .gaussian = type, T.self != Double.self { + throw "When using Gaussian NB you have to have continuous features (Double)" + } else if case .multinomial = type, T.self != Int.self { + throw "When using Multinomial NB you have to have categorical features (Int)" + } + } + + public func train() throws -> Self { + + for `class` in classes.uniques() { + variables[`class`] = [(Int, [Any])]() + + let classDependent = data.enumerated().filter { (offset, _) in + return classes[offset] == `class` + } + + for feature in 0.. Int { + let likelihoods = classifyProba(with: input).max { (first, second) -> Bool in + return first.1 < second.1 + } + + guard let `class` = likelihoods?.0 else { + return -1 + } + + return `class` + } + + public func classifyProba(with input: [T]) -> [(Int, Double)] { + + var probaClass = [Int: Double]() + let amount = classes.count + + classes.forEach { `class` in + let individual = classes.filter { $0 == `class` }.count + probaClass[`class`] = Double(individual) / Double(amount) + } + + let classesAndFeatures = variables.map { (`class`, value) -> (Int, [Double]) in + let distribution = value.map { (feature, variables) -> Double in + return type.calcLikelihood(variables: variables, input: input[feature]) ?? 0.0 + } + return (`class`, distribution) + } + + let likelihoods = classesAndFeatures.map { (`class`, distribution) in + return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 0.0)) + } + + let sum = likelihoods.map { $0.1 }.reduce(0, +) + let normalized = likelihoods.map { (`class`, likelihood) in + return (`class`, likelihood / sum) + } + + return normalized + } +} diff --git a/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground new file mode 100644 index 000000000..b1148fc50 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Naive Bayes Classifier/NaiveBayes.playground/playground.xcworkspace/contents.xcworkspacedata b/Naive Bayes Classifier/NaiveBayes.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift index dbbf3cd9f..9b9ace86d 100644 --- a/Naive Bayes Classifier/NaiveBayes.swift +++ b/Naive Bayes Classifier/NaiveBayes.swift @@ -8,6 +8,8 @@ import Foundation +extension String: Error {} + extension Array where Element == Double { func mean() -> Double { @@ -35,29 +37,9 @@ extension Array where Element == Int { enum NBType { - case gaussian(data: [[Double]], classes: [Int]) - case multinomial(data: [[Int]], classes: [Int]) - //case bernoulli(data: [[Bool]], classes: [Int]) --> TODO - - var classes: [Int] { - if case .gaussian(_, let classes) = self { - return classes - } else if case .multinomial(_, let classes) = self { - return classes - } - - return [] - } - - var data: [[Any]] { - if case .gaussian(let data, _) = self { - return data - } else if case .multinomial(let data, _) = self { - return data - } - - return [] - } + case gaussian + case multinomial + //case bernoulli --> TODO func calcLikelihood(variables: [Any], input: Any) -> Double? { @@ -86,12 +68,12 @@ enum NBType { return nil } - guard let input = input as? Double else { + guard let input = input as? Int else { return nil } return variables.first { variable in - return variable.category == Int(input) + return variable.category == input }?.probability } @@ -126,49 +108,52 @@ enum NBType { } } -class NaiveBayes { +class NaiveBayes { - private var variables: [Int: [(feature: Int, variables: [Any])]] - private var type: NBType + var variables: [Int: [(feature: Int, variables: [Any])]] + var type: NBType - init(type: NBType) { + var data: [[T]] + var classes: [Int] + + init(type: NBType, data: [[T]], classes: [Int]) throws { self.type = type + self.data = data + self.classes = classes self.variables = [Int: [(Int, [Any])]]() - } - - static func convert(dataAndClasses: [[T]], rowOfClasses: Int) -> (data: [[T]], classes: [Int]) { - let classes = dataAndClasses.map { Int($0[rowOfClasses] as! Double) } //TODO - let data = dataAndClasses.map { row in - return row.enumerated().filter { $0.offset != rowOfClasses }.map { $0.element } + if case .gaussian = type, T.self != Double.self { + throw "When using Gaussian NB you have to have continuous features (Double)" + } else if case .multinomial = type, T.self != Int.self { + throw "When using Multinomial NB you have to have categorical features (Int)" } - - return (data, classes) } - //TODO remake pliss, i dont like this at all - func train() { - - var classes = type.classes + func train() throws -> Self { for `class` in classes.uniques() { - variables[`class`] = [(Int, [Any])]() - for feature in 0.. Int { + func classify(with input: [T]) -> Int { let likelihoods = classifyProba(with: input).max { (first, second) -> Bool in return first.1 < second.1 } @@ -180,10 +165,8 @@ class NaiveBayes { return `class` } - //TODO fix this doesnt have to be a double - func classifyProba(with input: [Double]) -> [(Int, Double)] { + func classifyProba(with input: [T]) -> [(Int, Double)] { - let classes = type.classes var probaClass = [Int: Double]() let amount = classes.count @@ -200,7 +183,7 @@ class NaiveBayes { } let likelihoods = classesAndFeatures.map { (`class`, distribution) in - return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 1.0)) + return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 0.0)) } let sum = likelihoods.map { $0.1 }.reduce(0, +) @@ -211,40 +194,3 @@ class NaiveBayes { return normalized } } - -guard let csv = try? String(contentsOfFile: "/Users/ph1ps/Desktop/wine.csv") else { - print("file not found") - exit(0) -} - -let rows = csv.characters.split(separator: "\r\n").map { String($0) } -let wineData = rows.map { row -> [Double] in - let split = row.characters.split(separator: ";") - return split.map { Double(String($0))! } -} - -let convertedWine = NaiveBayes.convert(dataAndClasses: wineData, rowOfClasses: 0) -let wineNaive = NaiveBayes(type: .gaussian(data: convertedWine.data, classes: convertedWine.classes)) -wineNaive.train() -print(wineNaive.classifyProba(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015])) - -let golfData = [ - [0, 0, 0, 0], - [0, 0, 0, 1], - [1, 0, 0, 0], - [2, 1, 0, 0], - [2, 2, 1, 0], - [2, 2, 1, 1], - [1, 2, 1, 1], - [0, 1, 0, 0], - [0, 2, 1, 0], - [2, 1, 1, 0], - [0, 1, 1, 1], - [1, 1, 0, 1], - [1, 0, 1, 0], - [2, 1, 0, 1] -] -let golfClasses = [0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0] -let golfNaive = NaiveBayes(type: .multinomial(data: golfData, classes: golfClasses)) -golfNaive.train() -print(golfNaive.classifyProba(with: [0, 2, 0, 1])) From 8ac88ae7fe6134885956502bd9551e7b6cd0a083 Mon Sep 17 00:00:00 2001 From: ph1ps Date: Mon, 17 Apr 2017 21:29:43 +0200 Subject: [PATCH 0542/1275] Change macOS playground to iOS --- .../NaiveBayes.playground/Contents.swift | 51 +++++++++++++++++-- .../contents.xcplayground | 2 +- .../NaiveBayes.playground/timeline.xctimeline | 21 ++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift index cb820272e..321e7a04a 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift +++ b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift @@ -7,7 +7,7 @@ import Foundation ### Gaussian Naive Bayes - Note: - When using Gaussian NB you have to have continuous features (Double). + When using Gaussian NB you have to have continuous features (Double). For this example we are going to use a famous dataset with different types of wine. The labels of the features can be viewed [here](https://gist.github.com/tijptjik/9408623) */ @@ -52,9 +52,54 @@ let data = wineData.map { row in */ let wineBayes = try! NaiveBayes(type: .gaussian, data: data, classes: classes).train() let result = wineBayes.classifyProba(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015]) -print(result) /*: - I can assure you that this is the correct result and as you can see the classifier thinks that its ***99.99%*** correct too. + I can assure you that ***class 1*** is the correct result and as you can see the classifier thinks that its ***99.99%*** likely too. ### Multinomial Naive Bayes + + - Note: + When using Multinomial NB you have to have categorical features (Int). + + Now this dataset is commonly used to describe the classification problem and it is categorical which means you don't have real values you just have categorical data as stated before. The structure of this dataset is as follows. + + Outlook,Temperature,Humidity,Windy + + ***Outlook***: 0 = rainy, 1 = overcast, 2 = sunny + + ***Temperature***: 0 = hot, 1 = mild, 2 = cool + + ***Humidity***: 0 = high, 1 = normal + + ***Windy***: 0 = false, 1 = true + + The classes are either he will play golf or not depending on the weather conditions. (0 = won't play, 1 = will play) + */ + +let golfData = [ + [0, 0, 0, 0], + [0, 0, 0, 1], + [1, 0, 0, 0], + [2, 1, 0, 0], + [2, 2, 1, 0], + [2, 2, 1, 1], + [1, 2, 1, 1], + [0, 1, 0, 0], + [0, 2, 1, 0], + [2, 1, 1, 0], + [0, 1, 1, 1], + [1, 1, 0, 1], + [1, 0, 1, 0], + [2, 1, 0, 1] +] +let golfClasses = [0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0] + +let golfNaive = try! NaiveBayes(type: .multinomial, data: golfData, classes: golfClasses).train() + +/*: + The weather conditions is as follows now: Outlook=rainy, Temperature=cool, Humidity=high, Windy=true + */ +let golfResult = golfNaive.classifyProba(with: [0, 2, 0, 1]) + +/*: + Naive Bayes tells us that the golf player will ***not*** play with a likelihood of almost ***80%***. Which is true of course. */ diff --git a/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground index b1148fc50..35968656f 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground +++ b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline new file mode 100644 index 000000000..b15fdda55 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + From d9e36fa2800c2c67e07df17048424903ab5a7eb6 Mon Sep 17 00:00:00 2001 From: Matthijs Hollemans Date: Tue, 18 Apr 2017 13:43:41 +0200 Subject: [PATCH 0543/1275] Missing word --- Huffman Coding/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 69e105c87..7058096d0 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -1,6 +1,6 @@ # Huffman Coding -The idea: To encode objects that occur with a smaller number of bits than objects that occur less frequently. +The idea: To encode objects that occur often with a smaller number of bits than objects that occur less frequently. Although any type of objects can be encoded with this scheme, it is common to compress a stream of bytes. Suppose you have the following text, where each character is one byte: From 6c7e9de65cb84da86bb0a5de554f5d13fa6412e6 Mon Sep 17 00:00:00 2001 From: Matthijs Hollemans Date: Tue, 18 Apr 2017 13:45:16 +0200 Subject: [PATCH 0544/1275] Fix alignment --- Huffman Coding/README.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 7058096d0..d1181d215 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -9,13 +9,13 @@ Although any type of objects can be encoded with this scheme, it is common to co If you count how often each byte appears, you can see some bytes occur more than others: space: 5 u: 1 - o: 5 h: 1 - s: 4 d: 1 - m: 3 a: 1 - w: 3 y: 1 - c: 2 p: 1 - r: 2 e: 1 - n: 2 i: 1 + o: 5 h: 1 + s: 4 d: 1 + m: 3 a: 1 + w: 3 y: 1 + c: 2 p: 1 + r: 2 e: 1 + n: 2 i: 1 We can assign bit strings to each of these bytes. The more common a byte is, the fewer bits we assign to it. We might get something like this: @@ -23,10 +23,10 @@ We can assign bit strings to each of these bytes. The more common a byte is, the o: 5 000 h: 1 10001 s: 4 101 d: 1 11010 m: 3 111 a: 1 11011 - w: 3 0010 y: 1 01111 - c: 2 0011 p: 1 11000 - r: 2 1001 e: 1 01110 - n: 2 0110 i: 1 10000 + w: 3 0010 y: 1 01111 + c: 2 0011 p: 1 11000 + r: 2 1001 e: 1 01110 + n: 2 0110 i: 1 10000 Now if we replace the original bytes with these bit strings, the compressed output becomes: From 9fafc9278d72240fda1117d010b1544ff106dccb Mon Sep 17 00:00:00 2001 From: ph1ps Date: Tue, 18 Apr 2017 13:47:17 +0200 Subject: [PATCH 0545/1275] Add README with explanation --- .../NaiveBayes.playground/Contents.swift | 28 ++--- .../Sources/NaiveBayes.swift | 100 +++++++++--------- .../contents.xcplayground | 2 +- .../NaiveBayes.playground/timeline.xctimeline | 10 ++ Naive Bayes Classifier/NaiveBayes.swift | 100 +++++++++--------- Naive Bayes Classifier/README.md | 99 +++++++++++++++++ Naive Bayes Classifier/images/bayes.gif | Bin 0 -> 1095 bytes .../images/code_example.png | Bin 0 -> 122044 bytes Naive Bayes Classifier/images/mean.gif | Bin 0 -> 590 bytes Naive Bayes Classifier/images/multinomial.gif | Bin 0 -> 703 bytes .../images/normal_distribution.gif | Bin 0 -> 925 bytes .../images/standard_deviation.gif | Bin 0 -> 1125 bytes .../images/tennis_dataset.png | Bin 0 -> 61477 bytes 13 files changed, 224 insertions(+), 115 deletions(-) create mode 100644 Naive Bayes Classifier/images/bayes.gif create mode 100644 Naive Bayes Classifier/images/code_example.png create mode 100644 Naive Bayes Classifier/images/mean.gif create mode 100644 Naive Bayes Classifier/images/multinomial.gif create mode 100644 Naive Bayes Classifier/images/normal_distribution.gif create mode 100644 Naive Bayes Classifier/images/standard_deviation.gif create mode 100644 Naive Bayes Classifier/images/tennis_dataset.png diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift index 321e7a04a..66aefaa32 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift +++ b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift @@ -2,13 +2,13 @@ import Foundation /*: ## Naive Bayes Classifier - + This playground uses the given algorithm and utilizes its features with some example datasets - + ### Gaussian Naive Bayes - Note: When using Gaussian NB you have to have continuous features (Double). - + For this example we are going to use a famous dataset with different types of wine. The labels of the features can be viewed [here](https://gist.github.com/tijptjik/9408623) */ guard let wineCSV = Bundle.main.path(forResource: "wine", ofType: "csv") else { @@ -27,7 +27,7 @@ guard let csv = try? String(contentsOfFile: wineCSV) else { let rows = csv.characters.split(separator: "\r\n").map { String($0) } /*: Splitting on the ; sign and converting the value to a Double - + - Important: Do not force unwrap the mapped values in your real application. Carefully convert them! This is just for the sake of showing how the algorithm works. */ @@ -47,31 +47,31 @@ let data = wineData.map { row in /*: Again use `guard` on the result of a `try?` or simply `do-try-catch` because this would crash your application if an error occured. - + The array in the `classifyProba` method I passed is a former entry in the .csv file which I removed in order to classify it. */ let wineBayes = try! NaiveBayes(type: .gaussian, data: data, classes: classes).train() let result = wineBayes.classifyProba(with: [12.85, 1.6, 2.52, 17.8, 95, 2.48, 2.37, 0.26, 1.46, 3.93, 1.09, 3.63, 1015]) /*: I can assure you that ***class 1*** is the correct result and as you can see the classifier thinks that its ***99.99%*** likely too. - + ### Multinomial Naive Bayes - + - Note: When using Multinomial NB you have to have categorical features (Int). - + Now this dataset is commonly used to describe the classification problem and it is categorical which means you don't have real values you just have categorical data as stated before. The structure of this dataset is as follows. - + Outlook,Temperature,Humidity,Windy - + ***Outlook***: 0 = rainy, 1 = overcast, 2 = sunny - + ***Temperature***: 0 = hot, 1 = mild, 2 = cool - + ***Humidity***: 0 = high, 1 = normal - + ***Windy***: 0 = false, 1 = true - + The classes are either he will play golf or not depending on the weather conditions. (0 = won't play, 1 = will play) */ diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift index 3af8102c7..6e6d7b4c0 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift +++ b/Naive Bayes Classifier/NaiveBayes.playground/Sources/NaiveBayes.swift @@ -11,186 +11,186 @@ import Foundation extension String: Error {} extension Array where Element == Double { - + func mean() -> Double { return self.reduce(0, +) / Double(count) } - + func standardDeviation() -> Double { let calculatedMean = mean() - + let sum = self.reduce(0.0) { (previous, next) in return previous + pow(next - calculatedMean, 2) } - + return sqrt(sum / Double(count - 1)) } } extension Array where Element == Int { - + func uniques() -> Set { return Set(self) } - + } public enum NBType { - + case gaussian case multinomial //case bernoulli --> TODO - + func calcLikelihood(variables: [Any], input: Any) -> Double? { - + if case .gaussian = self { - + guard let input = input as? Double else { return nil } - + guard let mean = variables[0] as? Double else { return nil } - + guard let stDev = variables[1] as? Double else { return nil } - + let eulerPart = pow(M_E, -1 * pow(input - mean, 2) / (2 * pow(stDev, 2))) let distribution = eulerPart / sqrt(2 * .pi) / stDev - + return distribution - + } else if case .multinomial = self { - + guard let variables = variables as? [(category: Int, probability: Double)] else { return nil } - + guard let input = input as? Int else { return nil } - + return variables.first { variable in return variable.category == input }?.probability - + } - + return nil } - + func train(values: [Any]) -> [Any]? { - + if case .gaussian = self { - + guard let values = values as? [Double] else { return nil } - + return [values.mean(), values.standardDeviation()] - + } else if case .multinomial = self { - + guard let values = values as? [Int] else { return nil } - + let count = values.count let categoryProba = values.uniques().map { value -> (Int, Double) in return (value, Double(values.filter { $0 == value }.count) / Double(count)) } return categoryProba } - + return nil } } public class NaiveBayes { - + var variables: [Int: [(feature: Int, variables: [Any])]] var type: NBType - + var data: [[T]] var classes: [Int] - + public init(type: NBType, data: [[T]], classes: [Int]) throws { self.type = type self.data = data self.classes = classes self.variables = [Int: [(Int, [Any])]]() - + if case .gaussian = type, T.self != Double.self { throw "When using Gaussian NB you have to have continuous features (Double)" } else if case .multinomial = type, T.self != Int.self { throw "When using Multinomial NB you have to have categorical features (Int)" } } - + public func train() throws -> Self { - + for `class` in classes.uniques() { variables[`class`] = [(Int, [Any])]() - + let classDependent = data.enumerated().filter { (offset, _) in return classes[offset] == `class` } - + for feature in 0.. Int { let likelihoods = classifyProba(with: input).max { (first, second) -> Bool in return first.1 < second.1 } - + guard let `class` = likelihoods?.0 else { return -1 } - + return `class` } - + public func classifyProba(with input: [T]) -> [(Int, Double)] { - + var probaClass = [Int: Double]() let amount = classes.count - + classes.forEach { `class` in let individual = classes.filter { $0 == `class` }.count probaClass[`class`] = Double(individual) / Double(amount) } - + let classesAndFeatures = variables.map { (`class`, value) -> (Int, [Double]) in let distribution = value.map { (feature, variables) -> Double in return type.calcLikelihood(variables: variables, input: input[feature]) ?? 0.0 } return (`class`, distribution) } - + let likelihoods = classesAndFeatures.map { (`class`, distribution) in return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 0.0)) } - + let sum = likelihoods.map { $0.1 }.reduce(0, +) let normalized = likelihoods.map { (`class`, likelihood) in return (`class`, likelihood / sum) } - + return normalized } } diff --git a/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground index 35968656f..89da2d470 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground +++ b/Naive Bayes Classifier/NaiveBayes.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline index b15fdda55..7bc414f58 100644 --- a/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline +++ b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline @@ -17,5 +17,15 @@ selectedRepresentationIndex = "0" shouldTrackSuperviewWidth = "NO"> + + + + diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift index 9b9ace86d..46a0bb4f5 100644 --- a/Naive Bayes Classifier/NaiveBayes.swift +++ b/Naive Bayes Classifier/NaiveBayes.swift @@ -11,186 +11,186 @@ import Foundation extension String: Error {} extension Array where Element == Double { - + func mean() -> Double { return self.reduce(0, +) / Double(count) } - + func standardDeviation() -> Double { let calculatedMean = mean() - + let sum = self.reduce(0.0) { (previous, next) in return previous + pow(next - calculatedMean, 2) } - + return sqrt(sum / Double(count - 1)) } } extension Array where Element == Int { - + func uniques() -> Set { return Set(self) } - + } enum NBType { - + case gaussian case multinomial //case bernoulli --> TODO - + func calcLikelihood(variables: [Any], input: Any) -> Double? { - + if case .gaussian = self { - + guard let input = input as? Double else { return nil } - + guard let mean = variables[0] as? Double else { return nil } - + guard let stDev = variables[1] as? Double else { return nil } - + let eulerPart = pow(M_E, -1 * pow(input - mean, 2) / (2 * pow(stDev, 2))) let distribution = eulerPart / sqrt(2 * .pi) / stDev - + return distribution - + } else if case .multinomial = self { - + guard let variables = variables as? [(category: Int, probability: Double)] else { return nil } - + guard let input = input as? Int else { return nil } - + return variables.first { variable in return variable.category == input }?.probability - + } - + return nil } - + func train(values: [Any]) -> [Any]? { - + if case .gaussian = self { - + guard let values = values as? [Double] else { return nil } - + return [values.mean(), values.standardDeviation()] - + } else if case .multinomial = self { - + guard let values = values as? [Int] else { return nil } - + let count = values.count let categoryProba = values.uniques().map { value -> (Int, Double) in return (value, Double(values.filter { $0 == value }.count) / Double(count)) } return categoryProba } - + return nil } } class NaiveBayes { - + var variables: [Int: [(feature: Int, variables: [Any])]] var type: NBType - + var data: [[T]] var classes: [Int] - + init(type: NBType, data: [[T]], classes: [Int]) throws { self.type = type self.data = data self.classes = classes self.variables = [Int: [(Int, [Any])]]() - + if case .gaussian = type, T.self != Double.self { throw "When using Gaussian NB you have to have continuous features (Double)" } else if case .multinomial = type, T.self != Int.self { throw "When using Multinomial NB you have to have categorical features (Int)" } } - + func train() throws -> Self { - + for `class` in classes.uniques() { variables[`class`] = [(Int, [Any])]() - + let classDependent = data.enumerated().filter { (offset, _) in return classes[offset] == `class` } - + for feature in 0.. Int { let likelihoods = classifyProba(with: input).max { (first, second) -> Bool in return first.1 < second.1 } - + guard let `class` = likelihoods?.0 else { return -1 } - + return `class` } - + func classifyProba(with input: [T]) -> [(Int, Double)] { - + var probaClass = [Int: Double]() let amount = classes.count - + classes.forEach { `class` in let individual = classes.filter { $0 == `class` }.count probaClass[`class`] = Double(individual) / Double(amount) } - + let classesAndFeatures = variables.map { (`class`, value) -> (Int, [Double]) in let distribution = value.map { (feature, variables) -> Double in return type.calcLikelihood(variables: variables, input: input[feature]) ?? 0.0 } return (`class`, distribution) } - + let likelihoods = classesAndFeatures.map { (`class`, distribution) in return (`class`, distribution.reduce(1, *) * (probaClass[`class`] ?? 0.0)) } - + let sum = likelihoods.map { $0.1 }.reduce(0, +) let normalized = likelihoods.map { (`class`, likelihood) in return (`class`, likelihood / sum) } - + return normalized } } diff --git a/Naive Bayes Classifier/README.md b/Naive Bayes Classifier/README.md index e69de29bb..9c0f0082a 100644 --- a/Naive Bayes Classifier/README.md +++ b/Naive Bayes Classifier/README.md @@ -0,0 +1,99 @@ +# Naive Bayes Classifier + +> ***Disclaimer:*** Do not get scared of complicated formulas or terms, I will describe them right after I use them. Also the math skills you need to understand this are very basic. + +The goal of a classifier is to predict the class of a given data entry based on previously fed data and its features. + +Now what is a class or a feature? The best I can do is to describe it with a table. +This is a dataset that uses height, weight and foot size of a person to illustrate the relationship between those values and the sex. + +| Sex | height (feet) | weight(lbs) | foot size (inches) | +| ------------- |:-------------:|:-----:|:---:| +| male | 6 | 180 | 12 | +| male | 5.92 | 190 | 11 | +| male | 5.58 | 170 | 12 | +| male | 5.92 | 165 | 10 | +| female | 5 | 100 | 6 | +| female | 5.5 | 150 | 8 | +| female | 5.42 | 130 | 7 | +| female | 5.75 | 150 | 9 | + +The ***classes*** of this table is the data in the sex column (male/female). You "classify" the rest of the data and bind them to a sex. + +The ***features*** of this table are the labels of the other columns (height, weight, foot size) and the numbers right under the labels. + +Now that I've told you what a classifier is I will tell you what exactly a ***Naive Bayes classifier*** is. There are a lot of other classifiers out there but what's so special about this specific is that it only needs a very small dataset to get good results. The others like Random Forests normally need a very large dataset. + +Why isn't this algorithm used more you might ask (or not). Because it is normally ***outperformed*** in accuracy by ***Random Forests*** or ***Boosted Trees***. + +## Theory + +The Naive Bayes classifier utilizes the ***Bayes Theorem*** (as its name suggests) which looks like this. + +![](images/bayes.gif) + +***P*** always means the probability of something. + +***A*** is the class, ***B*** is the data depending on a feature and the ***pipe*** symbol means given. + +P(A | B) therefore is: probability of the class given the data (which is dependent on the feature). + +This is all you have to know about the Bayes Theorem. The important thing for us is now how to calculate all those variables, plug them into this formula and you are ready to classify data. + +### **P(A)** +This is the probability of the class. To get back to the example I gave before: Let's say we want to classify this data entry: + +| height (feet) | weight(lbs) | foot size (inches) | +|:-------------:|:-----:|:---:| +| 6 | 130 | 8 | + +What Naive Bayes classifier now does: it checks the probability for every class possible which is in our case either male or female. Look back at the original table and count the male and the female entries. Then divide them by the overall count of data entries. + +P(male) = 4 / 8 = 0.5 + +P(female) = 4 / 8 = 0.5 + +This should be a very easy task to do. Basically just the probability of all classes. + +### **P(B)** +This variable is not needed in a Naive Bayes classifier. It is the probability of the data. It does not change, therefore it is a constant. And what can you do with a constant? Exactly! Discard it. This saves time and code. + +### **P(B | A)** +This is the probability of the data given the class. To calculate this I have to introduce you to the subtypes of NB. You have to decide which you use depending on your data which you want to classify. + +### **Gaussian Naive Bayes** +If you have a dataset like the one I showed you before (continuous features -> `Double`s) you have to use this subtype. There are 3 formulas you need for Gaussian NB to calculate P(B | A). + +![mean](images/mean.gif) + +![standard deviation](images/standard_deviation.gif) + +![normal distribution](images/normal_distribution.gif) + +and **P(x | y) = P(B | A)** + +Again, very complicated looking formulas but they are very easy. The first formula with µ is just the mean of the data (adding all data points and dividing them by the count). The second with σ is the standard deviation. You might have heard of it somewhen in school. It is just the sum of all values minus the mean, squared and that divided by the count of the data minus 1 and a sqaure root around it. The third equation is the Gaussian or normal distribution if you want to read more about it I suggest reading [this](https://en.wikipedia.org/wiki/Normal_distribution). + +Why the Gaussian distribution? Because we assume that the continuous values associated with each class are distributed according to the Gaussian distribution. Simple as that. + +### **Multinomial Naive Bayes** + +What do we do if we have this for examples: + +![tennis or golf](images/tennis_dataset.png) + +We can't just calculate the mean of sunny, overcast and rainy. This is why we need the categorical model which is the multinomial NB. This is the last formula, I promise! + +![multinomial](images/multinomial.gif) + +Now this is the number of times feature **i** appears in a sample **N** of class **y** in the data set divided by the count of the sample just depending on the class **y**. That θ is also just a fancy way of writing P(B | A). + +You might have noticed that there is still the α in this formula. This solves a problem called "zero-frequency-problem". Because what happens if there is no sample with feature **i** and class **y**? The whole equation would result in 0 (because 0 / something is always 0). This is a huge problem but there is a simple solution to this. Just add 1 to any count of the sample (α = 1). + +## Those formulas in action + +Enough talking! This is the code. If you want a deeper explanation of how the code works just look at the Playground I provided. + +![code example](images/code_example.png) + +*Written for Swift Algorithm Club by Philipp Gabriel* \ No newline at end of file diff --git a/Naive Bayes Classifier/images/bayes.gif b/Naive Bayes Classifier/images/bayes.gif new file mode 100644 index 0000000000000000000000000000000000000000..363ff3425836342c4e354a74454b4828c1fab6d3 GIT binary patch literal 1095 zcmV-N1i1T0Nk%w1Vb1_70OJ4v|Ns90004G&b|NAoW@ctYL`2NY%v4lVy1KgD+}xO$ znC|ZGh=_;~5D+plGODVoA^8LW00000EC2ui0M7s`000F35XecZy*TU5yI+boEg}$> z=mm;r>b`KC5oB4E3n8PlnD4+KOfU!tj)a1N!a!JvMr5IN(-54KM=J(B3X;o7b91F= zh3GV=aG)RpiHQSK&`lD7hop*mZvk^aY;JIJ8-5jmYKx2j0b2_J3=(G-c@;)`8VZsX z41X_=6p@nvl^L9+VxWz!FmG`a1_4+Fu@$p5l!X9%79j(6vc4Ar9IzC#wYL|*!V(6= zuG1+34HX26*B14m3J zr&6dow5$Yn85Xz%Ab=QCO%+xGKt^HhHvn@6oh{f}N{a#~oxTwKL7l82;k1`DtadXy zH#FNEdWZmy;fERl4mzfGy#;vys9z2UZz>_dfdCOHT_2!|!SYcVoEP{mK|u@a*mXVF z-hFu&DMmxifc>P1mn2(G30**(P6}_0@cvg%27^p67=RWaLY->Q;2{@+8VSHv2mNVf z+Hn&ea-k?AbYjYd<#`AfCY@!nN@34H&HgXjZ=;<(sbh*I2MFv7(!Rh^AJAzXi(8b3sPW@KMcL-NS0`( zDM3dd$+uHaas5PrG?R%z)?r0jG}E4ZCZy({L2Q+QS4TnDmROJ(h$sMWjg@C80Yob4 zq?A@_>7|%vs_CYjcG~F#XccFdV2=^g7Hg_B3FxZyAhrQ#l9faZV-z@cBLH?0&}W}~ zvFfW2zR_``Y^<&1OC&nIX2FlY_cptTc;uOI-gViT!rq9^L8t3$tbi!2 zXaR)ZrogReW~wP+xh@c!Zg}>=#{_0<)%(R1S%jNqyZ)gNWsL0Z8nS-t9B!@uGKiq*>E?O+<2Qbmz=iJ73p2veB)qlB7Fz$!MjWQE4bhQtC0BN Nhc~=Il0roQ06YAH(zpNs literal 0 HcmV?d00001 diff --git a/Naive Bayes Classifier/images/code_example.png b/Naive Bayes Classifier/images/code_example.png new file mode 100644 index 0000000000000000000000000000000000000000..a147ecdd6d5a9b542ac02cc1b778e279e183b229 GIT binary patch literal 122044 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%0AqlP%v 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 literal 0 HcmV?d00001 diff --git a/Naive Bayes Classifier/images/mean.gif b/Naive Bayes Classifier/images/mean.gif new file mode 100644 index 0000000000000000000000000000000000000000..7518c9995f8b5d2a33b4268aebfe9d8c9d90868f GIT binary patch literal 590 zcmV-U0hZ;sgm(P!LiW?r0MiU?!oEECS8T_EArNc1 zo1rg}gaRXCD4?~V0RsmPtT>=_swa&C3-P7X@Kx6@D%(%=F0vZiyQX43783hUy3kL~<76Sx%d?-p21_23@D-Q&n z1PThC1auS(k_rQC7F|7)DVhupY>-z)v~Z3VX*UyqycbY)u7wo?OcGWLKnj@v%D5T= z0Tm6T!#e_+2x=jT0Cx%A8ip7PzXsL9*EtUi3z{=dO#*=c4w@I_7YX+V1qcZU3 z)t+@Y9GGxGM;X2f2M!(?U?Lns9SI&3SRh5#uZ#W$Vn~>F5yzN2B`qu%lO|=01Pkz3 za|ytJxB@6?rU0W#X9EQc9V`&1vnUM)dtzm9gMpK%r!$Qr*)~BM!3tN61lY>8tJkk! z!-^eC_5(^zQq!(L5VH;gUbh_B5_!StQ%_OV?zlrhO0s3mp6N~dWq>0D-oOzZ%oxBI z0Q9arY@Al1y@m)T@8IBJj|dWeC|Ah1vEzV`WM0sf5RZioohM87_z{GLK7=r3f?UGp ziS1k$d6qnbMGKDG7rum%SU7WmzLd|TS#un?g*g)JAgf~_&6xv>)%pP>s5%^?iyGB* z+!nxqdV?!TxYSIA-A|$LS};Wcl`8BK2yWCEEV5`Jl3dVaunPsglrjh=0~T`(9?k%k zpdKXkVoggt#AF?8+HjLyVugG-fjO3>0|g=zVAoSo?Ytuc1&>8`AqM;u;156oL2*x2 l_hcp71eP&`LPSHlL>fm)iWXawjpbHAUQkLUoL&(C06Px_310vJ literal 0 HcmV?d00001 diff --git a/Naive Bayes Classifier/images/normal_distribution.gif b/Naive Bayes Classifier/images/normal_distribution.gif new file mode 100644 index 0000000000000000000000000000000000000000..b2f35e8ebf9e6e92c985176a946e5dbcce14a9a4 GIT binary patch literal 925 zcmV;O17iF~Nk%w1VZHz=0OJ4v|Ns90004G&b|NAoW@ctYL`2NY%v4lVy1KgD+}xO$ znC|ZGh=_;~5D+plGODVoA^8LW00000EC2ui0KNb!000F35XecZy*TU5yI+Ojjbzy= z4}q9$>%LYZD8UNfIAAb9GUUKuuqG^;5C@}j*&#AF29ax_pezWBr*;c)axFX<;vq>? zZQt||tp+d>I6|*67$n*L8VdqFVE_VId5brDYIh3@336Ev440QSC~jyB zQjDN1j%j@WRAg`&2XFU2JWK9g`LY zWI0$S1szwhgarW(0-tJ8BM;LP#T^0z0RrpViaR5+5j(@N*`MKMG*IC@GHu5)uxUGH}4F=|VUO z8jxuKZUVhxWF;IZdu8gdRAJi$Ro3oi#u+iHQiTMdd^!Wg{*0S{;`>};^EF_jGlOJ4?1 zRKPM*3LfGU;xk%8yr>CMw~xcD8@`o*J1UE0;e&8 znO*=|AV_QkJRpq#51^4iPlr(uRaCRVli?PM={68HGyE3e1;e3pk4zFUfFp@t98lqm zTzu2PW64O=7*ot3@SGM2;0Pos=-9HLDSZeq43&5g@Z*zPoa532f6SmEeoNF?AOr4H z#icCBDI=60iYT_?nsk0)<^Z1@kXoI528l)k$q0~QpM;jlBL#Yv;lMy%DWDEO))iW3 zHWe^1rzrtULjW8+JkZhsSb*T3qqNNyIqFNSL zrbU>OwAN`_a~N1+)Rbj-MZl=RP4YPaJsVb_xPtpKKss^Zlz!;@C zU_$`lq;|li+|t=VApJ2V5G1J;z=o*`c+xJd40N;azd2|WFTezspk~1rL;wIghTUnw literal 0 HcmV?d00001 diff --git a/Naive Bayes Classifier/images/standard_deviation.gif b/Naive Bayes Classifier/images/standard_deviation.gif new file mode 100644 index 0000000000000000000000000000000000000000..b917d9922e589300b796ba8cd32d2b6251d26089 GIT binary patch literal 1125 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
PPPq>4m!%z#o!=8IENk;buccYO#mSK|v> z^)!t(Sy#pK*{N_p{r17%L}5%r)45FT#yf5nJ=V#5G(KzLNmb8aCtScY7i$OftVL+DJ zS9d>jIRMUXq-KH|KELvJ%4rZ>KYODMWPAZ}JGbE8{;jAD^LD*iHYIrZ` ziD(&tDg8|Pm>SMyO?H-bZAQgfwtaaw%6AkfPar9?!bp4xWM72`xs>VtY0epp87w9> z223Uj#)#_Sy4E_9YB5JQhgF9($BdiQoAleX8%^kDXi-QUlu9&re9pE|1ugkr)mkMB z;Sl9T%}RM6=^2HS8i_|8GUv!a`w3@j>^oU>Evs!aZgOs|o^8+VcZv^Fu+IoaIO}*8sE^FOBo3sU6v<3B+&exBNB-eP zZHc<(${3GnTA^rlwgr zD|kvg7EGnM&YZ1;O{vY8rR%9)D~m_*dF33B*3-+ILkHX2J#O^l5WF~CuTaF4Nl2*Z zoi0>IncK%()TZ0ynplF8qRX7==7dk|CpxpE$z#v@I?y5Vn`tRsYXqERLDl9Kb=RGb zt`2W&Z>PeS(2Lkf%t8(vpQZ|iDv_$D%94-y=jii7lc-jmI#&y8vrJ=U3vQQ>v$sp2 zX`gw%-rmmOpzX=lW|!=z&;8p|(S6a>Vd=zY#k1JU=%^JQ9)bWC!1(jwA)5ez9Vmd+ zzO7BAvaO9xrbu`c0{~~BYv-9&4$C}1qOG?iP|T`N;rr9u=oirE)ldaS13$=j?;y)u zNzF-3T8h)q)|yt|$kxD^*3H`PyPW_4!0pEQy|gxV(#LnRwz6^LbmJlXmj~zf`Y$sb zA^yKyoGf_=)uiR{g=`&+@mXk@Y3T`hq44qXxgCs5I2D9N|0n$Wjfc?8$;pnBj?UH9 zmDZJs*4Dw4j)8-NgN~k&j**e(+k?i@-Ns4ZjmE~2=-(j!!4WogG;}bxb27KJ!T$?a z-@w+{iHDHzuS9=8|30U&oB4k;**N}BS>FZH{k22KKub^eH}-cZ_g_{{IdeB-D>Y$r zYhxS7?;O0Wj2ztm^8a5u|IPT1NcI0lGBYy%Gx8rh{}ahg_g4Y`DCpm}^)Ku9b@4)R z)BSz*yijHcG$sH5`~W|N1(e(X&$D2)5|vlKd@l^}l}hr{_-jcqP}FvX+RV-Z=`2@j zU)3_+X`GCkmK#!(rBrJ2V4toeRm3$KmuV~Ge8wZA4%Ek#zo?V%kHd?UxWP1ux626P z;piCOcD}ftc>2Zxm|*&@3AKt-Tdo{)n%+D&mN=GLCR>L7P*PE4;0r)N021JX1o$v@aAPWK$)7 z(87$9ovN{|GKrJ+4Dxtv72(}2JyYipzYzQj;NNK15P%G)+yU}Xh(Lc^`KOQ&@+(bW zB>%rVy1HM$iV{V>Gda6UEBOCa-M>zCa|_o-)fs{> z<&F<{R~)=LF!pl_fqY^s9F6TTudL-2zn}Yt{ZJNj1AFhhTg?UG%9jBfUJ45~qCL>0 zc>AD5f3lXN!-RS>_&E^=A}uRi+3{`9(V+j4DF3Np z@{XqV7(j40w#9;!nStep{y@7@BFKd3;h5tCJG_#1yEmvptt3K1Eyi8n`-LR)l6uw2 zF8TTHU44G^gRR0thFrTVStm>@Jd>d2ejQz*Y!*gDQ=RTe2!RCyE3u3pnnktqNd9nP zHmJ1h;8;xL-iHdlwE!WMMc?&!UDKW`l`B4Z$j8ci^n+<3N2&NEW$$^S)HrOLU}D2i zp>=;HikFO}73S_)#P8{x?b3d5gyV^`Q;rbR`(Z+&jMa4bjW~Bl6L4@??4?6{Ez2$| zA~+jw$TP=?aS{xKjC&Z|Fc>GfTF)69_fx5;l!sLq{jlh0Q6*srIpyf}$R7oViLFaW zBL@sXg>6gtD^}AYQZYT}C-T>z2Xzb>R4yn@x-q5bQ=}C`o1>yM)^+UKGdKh8wM$&Xd0zLet_!261-^^6_T#)=Lz(#C37BLJ8x-ScG$t6=DpVXdtbX9C< z`D7UZ6(#Dp1Og-%^&prlHnnj{VphmwpXJyyZ2A;(uelf;_~GXQ76xOp;e`vyLqjEx zta9jA0fv)31y;4SCTYB(nBGupiro6P1W9G_$viz0vpF0tlc$yxisy}y0a$qLr(d3@ z3c6e8GfuT2I*X2_x;(0}3>RZB%+Vj3>;`ws;ZmKeRH6JXMYi94qRAvA8 zj1T!n#pD#hf?s6>AU835!5I2r9ulrZ?gv{44zk3Z6JG$q?bs-9 zj$Xd}h>W$jCAtD(+VwE-kyw>u3`c~QX+Qk>Ry^e{E&0c%Qs#uP${8xy+o9v`RSM=AjLQLfM{+~)wZN0hvid2?$><{2m4qAy@aP3V(k_7?;*gjZ%sOh& z4IO%KDYxt#o1F1Y?>zGYf!mxn*)q$DVRR)W2_Gavg_uyubKf$yiv`8EpeeEg^KEA6 zW*Incp7ChPzi5pEw%ON&{+6-MUgsh7iCFJM>j0E>g= zGci&N(+Sv|KnxT{*nI@I{Z)s-rg_9~b=84#icEt+Ipzq+~cJaFd6}C)^3%}xUjhUE;2!)Co~(D znJ8>@F!OuQi)vUdBEFrP`z7N->wcS1>=Vob`k8<38X}LatgId2ECE;S6XRk3w5Rxn z*rkwHY_AZz*%Q~KLCc_)_`Gim7S-0Z4o+FGuUBc}H}tPCzuYpAv{Gmmo1#JJbNtb` zl&q*aBA{iIg*?3>(ef$Ipp4!UCyAU{zUgO6heG>Q=|DJrf_4=Vcxxn=B+Lfm`+n!q z-%R)cn-67qTEui4tC>~d&ZxD>N`bokb}XN^7Re^lBGYx~{N`wfHvN@(wwgS6UzJ=# zjF$GN0iWxs=aXl4;qXH4KM`R$d4Hh$cT2X|%}49d-QME3@v@+lp4uvdfx}qZl`B3R zhrygpdWYQJ5@zPxuqIxJ?s^zc0}>z-#iq0kSyWe_I+97qIqYIf>2#(yNm#-f`xM!; zgUOSMcsj`EaRb8YZcn+BlvH4a$9a$Zp0io@(;Tww*eF)=uxv_`}J$v6@~Yu z7OGg1cTPbxBqpG=6-eaZfSjY4uL?~jY0k1f)Nock2voi;@v`tsnTa*LkuL@Y)5&7@ z2j?-fM52TE_g_oWNzEHr7S4FS(XjT8-Gr^nZN~M!#&|fNKY0$z)#}W_T6Q3dd0ciz zy<7t~m7$83#RKlqr4dGr>BKv(CW%8et`pUj#InpMs|;Qf|HtS6mNgdUw2czFa^!tDXFr}SGe6xpj8T#;x=$)RcS#Bg$_K3mx*pMakSMcghmHrZ>g%yk#r}w&e;iAC zxgQf#wXoELL)*PDhA1yy~m`65O zOS)x@FFu>M9&pI1H7 zBr`0-ga^qubZTTqjy#-{UfC?F8@euXPaEpo=YJ0iQ~(V2xZV~>L~*cV>))>Ahi4t= z?DcUzy**z_?+{-tebnc6)$lY6ERte`hXa$! zL=VuS{UA4-k;O6!*$&Blt+ky_%}A4_0dGPqo7x4+f7`{M8{BC9p{$wu>zO07C#}yt zLgB`1ThANh3G?^ZRS3c98c0MzL-bf?RnPhy3})UH0md*%D_s|Rl{U@tFzg=I1mw%Z zf_lD5|DV)td7+n+fiFzC#~JW*FX#su32iI5=$x2CVjB1WLi^B0-Y?tY3;y5UXj`?Z zxO`7p(e+z&etAKXVsY(uIHm`cO=U!k^O6h3Joh02tEE%1XE-V*H|`}#NGLXM^32s_ z(4csDzl)V~tfbQlLTWnEVAwWBeCXgwTJCA@9${v3(RsayFZ2A9#lQ|ulg*De_NS?k zqV+Cj+Q9lk>8&|bY1n_xMjiU2n_V(i;r;Zclne0>iblQ`>A$Cd&&6dSXF-h1 zPqH`a0$4L{6zXeQb;~E^JVTwVVeOhU$)R5LfupAM=|j+l2Y)T~X?Sql#__=0?Y)f~ z@FrbJOO{~;`I(`R(Zr1&@s*(o>V?sSoeP&EW_icyG0!1s;m6`BJ)^rKr~L7NzN;NF z@uy{6i0k>+!Wg~&bg`Smj)#PTt z)DJSLV!nYmI!pUGYqptIR!@$M;3CD^%yeDNS|Qg9er*@hgzU2DqOGW{Ju?w_b0tAa zA6yRf;$|u5@Y(h#B5g+$lOBu+$L7+Mw}@VY7Abn@1umb!`E`dj&h+AvR#^QGlgc?v zeb4=idYncI&x0ETKA79bU0iGwu*RJT!+NHyS_tW}DQoz{t45;|+O%=3y9|_YU^!2H zzZRdX?O&;v8NocBjIp_l_P5w8s$^3kGZ3m^*xn$NkulgKvcQ+^fkoLX5KO|s7CO1C zkeFbOQ^nrs-JKJ)$OE@wy5);+OmB$}hnW5Z&sCsz6P|0>2gibIJ)RIYMhyoLLJF&U z&A&Xo;Bj8a-fi3aPHC*}II0^PI?#-yv<^EAC#M+9Fv$iRzWTq;w;}@Kk*u~91H|v% zz;%E_Z-V34BQFSxZO`P_RzF>0M)|~t;*sms{!leY-%tt(_i}?|@bFmpZUi%t)!bFU zOcb#woe8z6ZiDorGfs$x(B+Y}J~Cllu!#Q_q^B z=-a~^G8gI?;Zi@^dLsu8>h6o`WdN?N2P$944yBJd-bA!j=yim|4B~LpY&)FQSw=R` zy)j*8De;&yUqWK}kKPE}!zCJSb9 z=r)so>O%=W$SbsM;_&YMU{7C_> zk$*nYb!aHx>$B~zj_^o%9MNsrm-sr?Wt#6F^DCG@wyS7V!wb5WPjBnh(C$D?8u|*c ziV!HKWH?EonHn-=3Nc4KXz}fT6hO8ol&n&WFj`HX3)bIqT!;H`hU<9Oc^RP{_j;>H zH)ZHvoi9}>U5lYoRmUU~1-cK?-*@YRZz2SonEl$_>Bg-PKL>&XG6r z6gs1>TA&S^ag(#yGxn20^^gR(_wu?Bu=te__!2!oCbh|nFEdLy+eLD(k3-;;-;B5d zp+Qyl!E~yK;BgY{e0gq_YtEnW&0E3vp4nBwdd5tJc4`%Fb${dxED~;Kulu88rH!xm zN7qzr+Jtfe{`Q2u;+jPi>XHH(4(Wby$dn7A`2#L*fV|rKa|}Ia*czb3@hPT@wPWMe z>$=~Xn92^&m9lS3^-H`M-1@5G5sTlaB1*G*b*4&*$C!Kv!w(_&ZiNHq8>m6w0TFru zj@rd4p~qkVyDy5eTVCNbQf6N%Z+>l4h*!vZp32uWFAqQd?Rw#IP3{bBthAIL>9Cxg zplQ{Z6kc5N!PV+_2%>58x1h=8IAjg=lsb+@udsbtUeifl(0uPuTMfgSZRlZSY{W$2 zK*|{rj?iW>w}3L6iN9&`qdoUI`o$C-Eh1ti1Ea6H2u!80zRft6ElmbV>dqqUl_YEyZ#Yn1OVg9gH|J+`~})K~wDUlXv3iG+hI8 zxh^ncpJOn1fLOnW-4`b39zEV9^rj=6+sF(oi_Z8ChLD9z=4qLgjm!zkK(N`oofz$G z(KwG+mg1@C#3+XzC-k2cybjG@6!nYkLE-F7FT?$!`p5X?ybJ#puA-Y z%d4S}VWd&O;B>F0SuF)c+X_Cgihr^tR+rjZ-RYT6V z1|-@MQ}Vz`1pocwD<;oP^{&99?pdS4ghqXUDeD}vF8jM`_K+@bwE;Ac7e-|j9gYCP zU3Su0TE@^2N3!SHGuli=FdMX>e@TF%k?1p^B95YK-M$mu`=GvjnrtvnE*O7eb8a+^ zW@&KaVoAqr;f`~7y*1i)JH3WmMK92{W$B*Z)bZ92U+0}KJ1y=oO>snNmE4$eJ{;FG zHMOfuR~~O!bPp59&5S1CMr~;Kp?Hqlt*|%TfGsS<7lz<{qPw|9N8QHYmj){*`+>3h zqF^_#@9NNg7o|9z)_+JXqg5JN-5Ow6*B2h#?NC>Em%gfttO8T?yl#+}os+ zL=+0rzOx1S&Fw5I_AMS1S#&aCNu;#}&Jx?Bf2mMC1; z%GKlxSK%eD>VsI88L#B0Gv|8Gb7URM|6HW3UMbdlExz%@(t=H^Y;FHs>v?HD_Rl!$ zxtY2NyYzpv_yh6aBCgPjKd;4;*hTYW#Fwz3LJ5iNTi4|R5#6Z!F``w`R*Lt*B!6jl z`sV&l&v60?;^To0Ka9p%CMOVG!iWewb}m&z5mi$o$$WZ-qx6g zdE)Ow{Ez(VPfLU^s-2RX6cGF$6ClB~H%NcU8SkP(!rvk-K1ge%AG))4hzb70N+W;+x+!0z-kUHxi()k@ zvk#?Wmn1I&vKhZAj}29C(o!sowO_3r#SzuYT6IzeIxfNm$#B{M<5$a=TA4gIg|DdFWO6H7^|(G?RHp)g?x~AM0;6? zvd8j0haRN%MrSlQ)Fl1&^`YzTApS)oL3L}6&Q@_?S?JStRM7;;B2l8zG3eMgX?6t_ zGQ-zyB%`7)<+E$dC{uamMDVL);sVlv+)8q^uCL!e{F_4Z8;P;NshmK|IX?lREXB5? z_4piLZWrRa`QeyaG#d@hRPMGOE0$ZDuu)T_5nuu9Jq5Zzydek7+@a)QC= zQALb%CI_SfoGxQ(54ASGcsIMz1&N6PfDSPOSDwzn%b#%}esQp1b}k3XF0|i|n-6CD?8hE zp3jl5vBVVR+3CTc@*q**s-oqTiIxo%yvP#pmZM_%woUk8Bpa6;T=YMzpfh_iELKPk zYA<-QQ;c?FppB&%sr>a_{JI2O4Vu~vj4C9fTYvE{uPcj7%JAPy^Xpu~mCH)+cDACh zo7EldTZCFO;J=i%Kw$B}-60wHQPOgi{H|x*g(RMg6gJzJqRzUE7_HmtrJ_e-=;WW| zbqR+Ft-WK%$@bSeFO{|cAI7D_Wd2-{c=U7tm0cy3DNuwfPz zXl2<^po^AWZ2|iquX`~f>M$GCHmThg$&A#Yi0()#!Lub|IUR#X9*W2 zuoIB>>oAL4@(D`Gmddlruh}_xLEqd_dAx!Vos%0^O9a^}(<+~!0B)}c>`w{3JsFJ{ zsBJ+;z~+XF=}47&bbtOm+)7sKJLmXuS)rsoMMUAr1ekz`f`Ufxw9d?3^x5oYSM=Xgi50RgMeE4T zzgGzo_HnR$=;Sb+&W{uNJf!P}q0hRi+UgA%&!@Kt8GYZ0xaVFnCUdf^t%5UmC}qqpYZ@yRq#@wMWAIE9 zwp-MMoP#5xOwb|tRrt!m7kRYr`0({(m(^yJZJi1HbI^Ae{b{f?De{?zbpYHxCqIP` zY|$sc_-=8qkCnR44>~7f< z2QA=94RCuoYH(K5!V{*J;pEBrn92eW+4%3YT5!#;`lvCynJ_pT6=_qE`!mZZ)SFZa z=EmiIy9#CQW~W2TqE;-Ti9yy4u#a?Y*-bA`hq}fJn1wIaoHUs|CR|p}p|xp-KRbFf z0@0j;dhDHe*8G=$s`C7*q$9Bksm7%FQhSZnJGF#`Y**PaJ$wLHQA4Vqo!#Cpnrfna z)36lcm~DY7DK~->BYB#sctJB5o4!>}MP~RvohrG!`PDXe7Q)l2DeoFSVwhy+)({|5 zYC-70Df)_wxj~!O59fbw3LbNc&mYN8_u}uJS&y|i-=ifeue@nQuWfGmxC7EdFtNSvVpe$*53!t%VClYUQb(djLET9p zer4r32TdG|2n<2Eg>LKEz^^8Jig|!Oa|N148(4}0A|QzyW@zJiww8@1lvJx7;ZSKS zxB>%qO_yRn|G75MfE%4mBrxs6Ok7)B3yD4n3A85UxFq-2Bs_sX_|yv$Hb`{WIpL!O z63`IPZ)Ot4@aVHQ{c+Tk=G(giMf9ny7#>NcSWUZ!S7NKwsiYf;;mHK!Bf6jQCTa~- zUJj=VY@_$pN^j1|)fTm^Q_v+`ghGdhgTEaUn*DP+xsfJK)XtVwg0UunZ)twI8*Sk8 znv#Va1liUmdqg9C)RhZ_(;CdR)z1Z!JcUa_j~!Q17BJfvQTwC zjkHD?Ba=n&pczxTs>;gCtuPq`Uu=l)S%HdWa~9M0E4}8s$Y;8BhR4R>H))dk=KU}| zJl{Wfn2;$q8-OT$A;k`pTh>QrpM*?}_n>mYE_8u!0&;RXuB8%j+S`p07g54!W}QOU z=cm95D?SjIQh4&yzjvrK^s;-@1<2pej&7M$L~C1Y9}73fu4GV1}@1lLkLd z_9`i6xaetAv|*eO?`HnNhU4ei-@t$b+eqJM)#@ew^$**0+xLwuwH**u{I{kcKgsVx z9U&8lziH)v27~yoNWV$pRdP(d%-;>G`A>&W;fg&mr_Sr%EPJrMab z5Q@bTapQjh`BMe?l?t5QVHV7_34)ML+%p5RMR6jByLS15Iv(mpziP&Yzt3XIHc5{< zru<*TDKB!?A-uoYF{PO7?t2zzCo`DcqMokaZ3$^yy%~ol?*jSeTx!NtI=fc6n$sS6x@%;Ay4*`iI{N+!L(1{GT?O$zl zdWH_1qed?C(6}jJ``kGJ-2M0@*2o8SkfpNyzwxP1u;5f40v>-NuM+>inbYg=f0)xM zAP~w6RyFSv^KQbD{@mfja8jF`UC`F zy7e$jf*XZP zKi0dVc(WY=X4XOgRpINi)61$|$Nmg2D;5j{4{-YzAIkQ2In2gZ7&s`#aayq`m_#-n z#^u`(Y)jc}WxgZ4VTR%}&ijSb2CB80@PxC+K!vA9pH2CMWFV{T>MZar`uO8iReTSX zr*JlEE!Ehx`15M~d{8xRud|E9L4&DSy36q+Q?$4)M*b|Jndqrfd^B_AwGGD8`3k1< zdD;ck;%mkXK0ieIYfPlp^=9_fs@gKpcG!v9+XAo`MhEVVr{c^Be-B)+aLe)~wX`LM zfEYqVoht6@gN@$Y%~B|Lcl(jmc)FIF!&Ro6Mpk<}s738_nE1|WF6jMf)0id~eb(T& zgHD6i1t!pESTh-jvge|Gnkl5tS}Qbo#3;SZrJ27 z#eBqr1JL0QQf!Jp2@KwPkc@L*Wi%)(m{WOW;#VSY9aFK|u=rf-MB#dJU}so!4rR*D6L7_}ANf277Yi-{f@^ShcXxMpcX!v|!QDMraJS$tO>l?C-JPGT zwZ3=d+eiB!WAD=%PuHBY54!7m?z(GY^P_#GnP4YEcP6s4P^}hmp$)v-RdYW>{gMkj zFr^aKLP2Olu8(h{LyJ%4-xVp-0WcbX;Aoo6*M8}TP#Bs&;F@o&I$tRcm-7u^PYV~Z zW0jQk25-NP+n$|ZzF1s^X|cOep^1#zy#36>_-^OHswd#73IppqXzVu50+H>H5y5f* zIiVNrdYs^>ev4m3H{OG_=P-B9nd-PbK6#NhFfFb z9oF}kIh~Lg{BTbgMgi5r93@NBepHDptcdC1bPcXGjAZlfP;~Sa zl0wuW-$dg;u(y*CJh_3+qFW3ekEyua?cnsVt-0EK+-hP3%|Zy>dCu><)UDF^J;fW; zdQA{;Xu-E8@!{78XW;O_#rI~!>SFoKPqB@t4)v<{%;eU2`bt_n!}5h0owT=^3d7o& z0>i$d`D{#B&SY92#Pfi!N`+e|5Baf%wpdU-^f2n9wIZwOVSY=ABsd%@>f|FD$+`nby5&y))&YNj<5?q!r@h0uEa0WUcDY0C_wQ z4poE0n6u!zM2Xiv_QQBNt6Zk3x?y{v_FG0IQ(9QqR-pJC0WZI5v4{V4)M9*mtfV5n zaS~N^)67dr)3-Q#Az()CLGV zQ$_sInAN-IsLjP8?$BqzyIkHw z|6MZgx5>@)!o>{5o>PH9mZow8T-zU1@&&()vf-Na#CzynsEEo`=}UllCo))0Y?U)? zo9yfj2zUTow+WctJY$F#$NQ7dXRMkrtSi@wYL1X-#o?FB%QEQ9V)w(AYJKV)o`XD@ zb@9E>XK-SYWNufbLD<+239|%x#Wz9>mwS7fDiwPT)H`aNB)_D32#|Oadr0l99mFB$ zSDj3x^KMo8@2oP15I8dYCEAseQv-K-q>0WHhgU-!?UF1g1-p0!|2G8DF;P$<%1@O7 z2QKPEEJ#dk`U{Uje}0FCa2&qGk?1XtA5a6R7=2Js?ehPkAQ51~v>}+zYHDmTnE5{JC|)>$fKqvDStoVABmE?W z?#eSD5X#<7!7Z@6Lr>T~uDg3@sZ96DO)k>CN?=s~SA44}T{G$Z>$K)li%^;1^MXLf z=Ds;S52`5?y*&=`ujE;h7@}!BCuM$|q^3LJahP{&EG4>t&*Rt|KdE#}T%t%iTSF$9{f(r^jmiNsgta#&9dWj^QSodC_m! zw()VU+cWx-H(SqlS7!UW|8NgTXtwrI$Coz=a0cGTazDdq*8sWF1TSX?OKBlJ#L(sP zBa-@3Xosj^_Rjf{>sUe}BM4Zya=fp#X@rp3rO@1T;cZ*{3j7^5`Ykr9VMp}3XDFhB zRS%v-1;R`hBB8!N;XkT+qkJtIdv{*fH7Dy5Y~0Cb?j!geMoS%oW|buzs#YQs0FJI3+!I1>IqIb0*A%g*TopMOpXEqG_@*5T!zOQsKxW9h5Rpn8%G&({s=O86+B zer5MinCb=Ag)xG7z?`-j$_FM`kZqdwv`7L7+wn6aZaTr^9XAp!30jDo*Zoex?`fL} z{{k02(GTq5Bb95#`Y-l$|M3lUOX;0y{{sjI%6}+Ic{?fdzXpRR>OT}!u?y__FGYQ% zdzMV(a}{@D{s%$=J|Bcb^eZnQh0-KUj)XqgdgekN~s`{m0STQk&<<{@E{d zAl=tL0-M39X{cTsgwBt1)0l+4|H^VXB-5OQcJIeMs_KXS^?D#bWOHmXlYVQ0K{XxJ zwccrME(i83>Vp-tTzHvo)?ZIj_e31&Epbh;9pRb^b}p&e=-XVPk6JS!I6NPynHQgf zYr|@bN{gtYItbc9sVRlMIHSuXwI8v=J@?h0!H1C7C|Z&wTFR9-P9Md&PS&g(M3SC? zm@ds27%dSs$0`8;sdm6>mjJ0^54V2@hC~Mz1bN?-;@QQU%E6IkP`f2~XNsYu zmIkI{OknFj*h_5!34m{mOR29W-;7)h@*n5B6x_EhFTy9nZmA;RIi8gCcso*Ooo8Yv zJ041{Qe4dHK^=T|NRus!3ODaI_~l@bG&~_{G;dOP4z=ykW>C*s?Zi*sj0Dci4vG}2 zwF4|uhFE1kdO3$!=N1BDBEau$L|Yi-9#xXua0J#k2RzV>76wU)5F0X7g%~Ey{AgZc z(Lz1Ph2kqwx4}1;Ovy9LHy%1#4;}^Yp~0`vEU$7uM=|e6+y|v6Ia*kM$M(n_?35~f zLum%N{ULxIb3W~C9g*7z_Mp`cl4XpQQdg7l3D*E?z-H){MMXv9r|9z$fIuIA=X3(X z&epK=HJeG>C*1Ei1Abg*D8aM#>PRI4ud|wp2UEDFBE1}+I9FFTPq%euQ%)NECG41X zr1k*B^$?G5C$XGeCMZGv=D0kmVm5wcF3x!l3nqtHVT6x?bgHYvnT05&_I>3QLUlxt zV88O5ig)~~%zd=v`N_AwS$ATRq(Qz1%HxR^k>BO*L|soQmOW7UQTC$+O`kI!3T+Rq znn80gL48;^NEz%5$CcQ>$B{B97y;^#mO3!h6ZhoYSu0)Vgbd986`WeC7(kvU8k&_| zB7PjU@Vg_an2XYRSW76hFk$V6G}#uV+fz?bEW0ot|EkigbZbml03RWah7NedFNBZ1>7I)woYroBI3oULu8Nm-0MNz{Pi}9GwLv|lm zp<7XtTcV^ZLoUR7@%-szc+Msi*712&_OSR%UKX6Xqr*156;r2})yQipzX4C5 zw~7L56v7+jaXOp~=BK$@+UEKlZr5}S8J_(G@>~$}#lyEfUBVlRR20j~GKOSGU5fy} zRdfE4O$W$xI_!sUFA-1+y5eM-Pk0riOY9g|9<-f&NQaKndin5!V7ZCs-}9rRio$gu zQSs#5ecK3|Bkz~eEH($3Z?>lu#y+OMD2_zgD4_@9gfcg5Fu;mfk6fom0F$yLgmo0l20w9f-kQ)+qx=Gbf z*3~~+;YTq`G=HO{DN^tX^9@ZthVxuqeVm z9XGS#H=JDF9`GQ!;b>>k{j^kYQEfw2zj{p8Q&knyxUk(T+NVv(;HLBG$2bDZnIHBj zF0TI_X95(xIElkJr%cVgM~(=f_JXY$r5scuh!||c(WTeYhmzn$->#ml_09X~($qQ$ z_m(j5*aFw|rP(ZesgY<0D@ROOkYn*-+DpNBl96hzfalEmfm7as$LCkg4Y7c7;#+A7 z?z(gl`)LQ?bG8c{D#OorKv0clFP$TLd(hx&s`srNW4FxIhKG(kdy4H-+SIt;WYIgp z7~dq8JwEsH0&Ht;5M+VX0w!X#FRx1KkvqrWNp{2Px%h5AJQ!Ti@$d)=qSD5f+^??7 zQfy?Ow5x~R-H{zc?ZOXzwZ~zi(93kdC&G_x)q$iL62f^w8&WBPW`d~z<*JS^A75y? zW$U{uD?(Ff)U6}{aDNPxi3Wx^BJ-|!vf$4Z0VE0Ts}j2^3MA-j0$!I(EJigCi$V}l z8L}C<(aF;4x#Go%U4fzQhckZ4{#eeAXbgVIt|x~Mz*piv_tkb;Eqg2^=kL`dn^v1Z zQyMcehcScu$V8nS(hFs5L#yC~S>QR_22B|o8^Cet z(15QjRGRlY(dtu!n0wp}VYjsT$U}8~L&wZ)7n)Cd)Ft^d_f?$qQ%^PzR}}U!JYC{% z6M;N@1vUxq!Hm&y+Y5-MNtp-zCNC;pP)fO`B%M532I3U?-Y^Z+?0oIqoY11{GRRbG zo0n8a@}%AVF4R-y++SIC`FY2Uaduvz5qb|I+V0!E&&%TG#nylD!!`b<5A~zRlznI@M;>L?R?A5Sm%s~eGiAW#H6Fc~69;LY$xe=shRw)XNy&woea|)G0>%Xd~R3K5+KR&tb-?hPLES-(tzvaS87^1e7+~ z*o}z;)!s8gmdD&=qtYwX>JpKXr=mQ4mNn6tX2yzmq!uXTb7iNmn5(O-R;-kH#}scH zm9u3Lc)bpgmm1umY)1nsBYx<%HmJMtcdpYqJwLc^+HZj8bgGwjB&;9#)9kZ_g+Ecc zF4(tg?;2amWj+l=O+L{{ulqf$0qYz|kXYH$mNAW=^5L`A>O}dnafEzv;g=_^Qmogc z^NMSMR;Sf_%3&IC-f|VcG~b%49~(?xTbCF4GOB6iMvu@`I<+^0De}J1)t z+~qot=n9<^O_%u9M#OG=s~S>rmU*5(V>onH@oDtIp)h}n;M9uQBsfgoL&`EMluD%acM12XNq-HhRi zss1YYp#$Cih$?hMl7xTN{Oj@`#IR0JY?=R81Kl#|2MDx(Bl)lMnGnK@|Id2e(M6$u zL5M|az}-&YX-NXaU%}5{of#iZbzY4gMUH=k9by9RxLvcK%*%8t#FbhFd#x*}^Jp;2F5ejcWy5HkUMQsC7n`r`(_CRCx6`ipaT|3F<15&bRf ze>tZo_=DiC31$9&f3SyHEW7**rZ?Kps+Q6-;Uing&1{iPs?q*4dm2-fMJChZYjEoH zIDeG3Zvw0gQFZArQpZGqyKL##_m%JnX6=aAo1gcRnRK%4Z6!l`pi*SoJuK7aQfatx@^jgHLNF5C@XCS^dUDT$N9XQkAqc_SDK&^t zH7KkbnBs{VG&Oq|$_brA@2@Iquzuu6o9*X$PsQ$_ku??jDOP5|VYaO7UTmn9% znH?BDY~$dVVkxxCY}w9<#riF7mI{v9m7#iPMo12MPhbuko}Ul<=g%O~xFhy&qVi@% zg7$i^3q6sZPbZQSeCl1`)97=R(G4s;_8dr@ec9tID+gbdER)!`K@gB&vWYK#J39Mm zxtSkW)`z&yr^gip5*{URZAfc+DNfZ{$iD1jzIsi;${Q|%zY22c@HO1a+_B8w9 ztnx0Mx_J`-tYGA^On9c3gXo*L3%A|0Sr;F4lmOXWb=DzoEHGlpj_?o!OhV;F@thMU zEh+H7AV$Iz$)+CJ{|eOcig!fe5!>{m;0N%@w`+)EosGDyychRQed4YmpX916F9fOkA11n{;(6p=kTpa+le10zQ%8)Q-qUuHAi^P5abY+%J5a`Yb75y20`%~;K3ZN( zNNy0pGQKt-7k6-S5q7II$f zUJ_<7m4jF7inS^(_&tFSzCvC1gEtzs`Ct;~S3su$OLi|5*<8bJb=>hTBvbVAnOdmV z_Ze$8Ji_#FvBA?>V9!*8`QB$+Pm(4gYLIx5mN-x7Dc?6_{)coZ@hN?0SRmZdggF^7cZpBesVhbLf!$l zsK4H$8u4%ZS!F(g<-DLFI^b|q(mvqa+=bk#spE&+)C-MA{E={AN9>S=C-1@K@Ul=@ zm%}_K9vFI(=lA-3zB~VoC-r(U!gP0u-4fHgg+A#kd$6AR9`$BGa)vz{=3@D&!PBDp z$@Q=%6pX{5WH|0!DA;>}qQe6iRM!11Xz2+b*BZwr4M87ckqSM#2lU0EA-*!1!BEMs z_eZ2x?W$B~lnNxXJ&MO8A~3Vo&U-fbw$hT}2WVz=R?k->o_YzSlstos9)*sB7c zcLGQZV=)O*EHir$-b&5Q{A^y~mP1o)&O8~m{Sg;;qd*C-4AQUdTAtFa zQXbJ6sY^_mJ-O3r!dD%>HDUuzY@{s+3Lh%-JQfJG83S#ZGf)=D1Ni9_P1@(?BpJRE zv@{uEx#O{dLrMmBtJ~Z|dYx}FtBIoGPO6zPCyWa#`%eht>vjd37=Y5XzNa0Fo-SPL6mwxch;6aOU-cP5;IhUJaKB`e@Cdfj{? z$6)eU1V3gj8DqUz{8<)JoYX{b0Aob$aBLT^rgdZ2VXCbCe&H$1ppo+7oli<*ChNn{ zAdSG}eRxSeq#{Ud3{nu*q$p$5(>|v#TT@qcOUk+zWSZc3O@~ zX?H^Bl^Mw>1>wP5o(Thr%JX_GtO6$-7@lTH2Ic7Y=pR@A{smEJ2KT1a!5tg1SGIU5{|I-Wm{wU;mWIWH zme*m}r2zwZN74Y!`vhO?6}KRkD6d3eV4GTvJdllV1juYE6%B+!VpzryMgy0(g(sT3lFkS@cUXSWP_cjv)u0bF^(b zy_mbigiWQ$jhGtfX8r6EtJ%Cm#}CE2fuyis3)ipDH3~0c13_wu#PL(FLp344r!CB2 z-$mN@b71{8^SQwz^z9aHYUxoCiqs`2fbAPVLpk{2w(us1t+U9PRwWGARTAMrG%A{W(+an0hJnYB{8D*hc@sMpJIhp!O8X z#x^6lvM{96VHT5AsSSogvlvtN5u9*!acc6DY2Jc-sMuS!ij(pnci%99l{4kbz4=qC zPn+DP{wSw_ux6EjMi8-QbdGQh#ZX@P9R2Oxapmo*@_oZ1Ho6^R*MFMtj6#CPP}UMZ zW-0Amu?a5>hu4o=AyNg?(go*q0H|xus*`28d5)6B1G5X_>flLTLIj$JPj?m`_pa^( z%+G&kHYMQa`qPvOzA1=jEYkzrqI_sf=oRBSmZynnb6yK#)(l5xbGzGh*kX4Tr)o$0 zYmcz8DzbR}(I1D)Hlvkty9V*4d3e-ILVSyykADZ@h^$HFL%DWe#hM@Hv`rmmf1hrL z=3qj>9k{Qazweyq*ghkkcNGtz71I^BkktCaBLdzKLKqIluO3~#)hUy$C--*{UA5%k z%HE5+Z66SlP5uEN`&d#i|6&JkFwoV^;(x$KU|&D!U~o`M^)Ima3}%b^p^wLjYQb z@v@|N)FMmQGT4^A2upk%*$C#w6 z^nJKg`lnZsLVS!kgPZ18^v7?d)nlKfd;i+t0pA~0hrqgA@-N!a75ktaI$`QhaQ~&9 zyyrivj&Ef#*z*l|wuL=bnc=pFObzhtEx9@4%^pD!b)S&e9vqNA&Iev=^ z%w{UY|76Pk`l0lkWux^h*6wvz1ZdW{m(V6GBtoo9LR1&XoV-y~*oK}iI2n*$U&;$% zpp-%CJ&-aO5IUST_6Uqx0l5RpQB~)ao21tDqe2&9BIW94A96&yuA3H1A2XcVt(an* zpAYExQ9V}($zDd1WaY|PtDlT@3G|u|uW1~iCN%-AUM5CMQr)oS?I>Jgc`n*3Cvs^! z&1mkGJd&s1{}3l)4OeFm6t^qu#UdXe7f4wZ5QKHk60vnr7s3L|rvYEW1I~jkBMfXR zx#)T}ARGgPISzb*!&3SpF3?Ax9A;N(A6mr;1h$CB3`~49U?mJh-)DGa2EL~oM@6nskTe3y?^>B~wNfP4x4(ru@NAIo%8s_?18W>{5^s0L z<|%CCHeq)BImXFm2m0#u84NiXtbRsek!Ugp&fJ4L@@W6W;&{X1ZFAy(?g(Epwf#UF zTRAGIY~szX(&{#7j^5EBcrZGhO?Qag`}l0@nBBY2f%PD^TrUrHgaMHE5~HL6{xgYK zmea>&@7NlQ^0~a_OXl^d-Jk|4m~&F-I)M3-UC^&k4V#m@zb1O+9`*SYmfH< z(4zz4gMts8J!dML(%6VpD)`f#LQ-tTl)*+g=RMEpo)^pX`ptA}=(8=*xy!GEq3hdS z@0ufg@(4#TFWzD6oYEXJrcs$?@>#ee69v-rX}kwZ{=Z$Vqpl*Uu>jWIK~HyMwNI@H z)cZ!uL)`Qlw=U@F;xsuL@y()ORo&Fi0Uyxw;QSnDire7EZ#YlSY(3DG^qPYXy@q@~ z+b4qzPLX+bd{4RpOKYCi?Kr^OsJ#z0^R7v+MY z?<>W+Z>#2FsWMr+YbS*wSpH;4qBq&?VEU?!t0g(`wpO!Q!1pDKN!hgQjfJ_pyjgM6nXXeEDEu zo9$*Sh5fq5^vz^+|Add%pDH)l@5^dx%qJzhTwSNQ68MBd*AIJ#BU#+e9Q*h#hg*uV zMoEr%j53NA^3P$Yqr9EK>?JKK=^xlKnAn^b6r{BjN%+*c*(3(YO5stQMpz6KsH7NU z8(MBo7{3KXL`ThsZaC3^L}*37R!1mJDHS2{(PAYV5EZffsG?vqF>4Sgo-F;}T(sHH z3m?BF#!_Zy)y_vY&)8THyvn2k$#S%XK)EG;?pXhrt~uRl{)15|nN*5cpJ0AW6$(-8 zNMTK*FX86@;z-EEZb@4NUt;?z~F18shlV-=+MXLm_ls+`Ta&;yE>JBAdC)qOX z?34}ps;p-x#4)wa@{==PlQc$)iR{Vv5_zQzrX4{g`;~F9N^;3_&R@zi&z3pMd0rc_ zT$86|V`V;V?3OFnDaN(JE_9)WC9BCAsSa<*dTK(F@JjKye!QS8 z%T}|4FngZJocGbw5z-nXjqv)nez4QtDwQ{qygj9PJla$JM_N_$EF+)g>%{>IyzIZoMJz^#v;t<2?@mr5z>ls)Fe-HJeH7j3e`1YyU$14pawcFjP+!h8{$W}%N zRC+9u*%VjgQGc#{Xe6w$ZGCi>ls}x+I{Pqk$&%kwu5Gu%rpg^@Yx?<=`suyEbQ2UI z{wNlpyB@5W-=WP-uaw`l%{P3#+nP_PplghXrdc)>`5MQ1kS9QF(oe9EyBF8BthY-|3{Khux~lx zwdRp8XoY&THApKF;YpoF4?J%`Te4e?SZM9yo$A;ZE-oP|?}S}w#4THX1W=wIvjR#~MW$1B=DMjHC7eF{V*=AUOd3pbiN>WTXa`^=&2D))dDzs^rtw?R5 zShD%RGRe;LlEJINPtPxF1NSiLt^5KB(F4Z)r}kO}j?1HITMpX~7kJ|($oS^TUw79> z#~hxzmFMJsPkyhX{Tgn*Q5<~0TKyNa9gcD(Hs>eg?DF~d_ z)Q3p1fTJBTU1PdTNKLZV{Yw_I1cEtIaVKjUpzBerXex~!+n6V^>B378oT~%7DK2Z6 zFLm4>@NiTIi;Dxo9OL$xOYBzVTfPdqNyQ0KBCUL$j5tm*jQ-jVMH$6jrvG~`AC+aY z0Dl)Zr41O}{4YikKw9&S7#A0=O?o7Ci4M4fWUOBuH`jub+jY#T)45~lES<~koogOB z+30~ufY^ta!Dp@sVClWscU?KZ4p;J{mm49y~=O2 z#8ER#QW0~x_uYQoxBytZx~}}JL}A^?sB_n#MZx*vrfs(jN5%GxtBR1~t7T7##qjad zSi*fmPn%zCSKeumf}wMyk&;j~D|m|%HY+>koG{MoX$5$A?4q{+&}A0U(_H(S&g(n! z66~4zba(MZwO^&o{mVXycX%qErph!)VywO2R4LanqRtPY@%8zHWCja+I-IYTpud{% z4bj8cqWm1*r*dU5>WAJ>$t|onTDVAN-@+a{`K>4v;r@>{Gh|tuq|0i`u3@tOB{4V( zKVFuXm(f+nuO+4acN34zk$%QS!BB50P;~Sx;UF7)h9lUQY~aq4BD$ zlr~EqQAvMhW{rpd?yI=dk$49!h0f!d(-KF5IPWv}t#*ZxIR{#zC?BmjTxq(Nt_pbU zB1F|s9W3M|JX;tTUI~F$zU=zIWkYf@uZ3VG>u#%XCu@G|OiCVIz0BmBJ_&Ihyn%aR zku|Te*p_FGW0Lm9P<0X0v(xf+B0E{^ziRowH{p+3`;FMTRr!CaVWB*vKX`!zr*0?v zPf>or|EGZFuS?^VW zTcP-0Gj%~&B>zsoF7-$Ip~A9E{Y(4d68H!r_9PVjv*bs6Th*V_Rwcx{{oPjv{wD}R z^M8}FryfFv0XxRRg2A&%gHjgyMjfmKQnys3_~{sR`uu#wws2A-B@XS6>*lT*%v;*} ziFbS*wC9^HHH}m4qux)5cEnuE<_J-Hnx3qM*rrT56qhgoggZOg;xnF*hX;@G%=^#i z)k~p~koRLO==K9ypR^5Kx}ir7qXmTH=QoPa=o+O}JFH>$Xja!xS4G#|j5Z^Xp_1iz zS>zYW!}kmXkK8Kcu%v5WV>-Vp{vd5W){Q9+&&IH!kZz)P{mJa#(g@0VrZ{hta7vn=JDvvRw{nXkd9OCVHd$7|y!UR3X4F z=Z7n)EY_yoxNDsnfXqpaFDhoo`(dV0^k*~fI~u@LYyppm(suDWO)*Ur@FcUcodizr zKpbfrDeg&q%u{d#*R2MB@Nb5SZ^pZdd_mC2_0|HE%VxS}!_tn5ZC|(NE3jrg`46uv z!w|IVIL%f;jMm5J81qve%|AU$nl67B^=7U zZqph!XjpOor`hF7i>DaKTS8;_p${@zJG49>1EL)-%LMJ=1{A^o=P(uM_B?MmR_{7C z{QC^*Pa9W+`Lm7yY23gU#n4V|J<-7&qEj!8aa0ehHS(J#^;qR4>p!q*2OeAr}*Uq(M)-s|t_HdR&4-`+8BNVd?w z!U78v7dzOtKT|@Np~Y`dhyk2MXx%TDjHKXc4$P3uz4!LeB6fQ?Mg7(K-=A- zPub-_j+o34O^sGN0MM@Y3s6H~Hmg*rD}`WnCa|5s>R~j=itDQznJvoYZ|H0@X3KhN zK4PC@X!1x$!p^k4smoqlEX3u)n#OF8Xa{$0k9)qX7nDmvMl_Ec^wCjm2v7%nPs0qq zxY8+lDGwmi2-)W(PT*#PwARy!f@PEv?l{TL|6zE2lj`9Pd9o8NAx$1`6k z*|R%(|GmKj+@x0ObfBJMYD$D)h>3(YO3?L_surEl-6r7Q}W@5jGf z7mALH)$`(_t-=_c=@YU1SGSHwg*gZ87o*-xJywfKo|tR79`aJePR-3?ANUtXFg4%B} zhIW>%!@e3Nuz1|{b(^?B4b|yyRbTEfxW4f_=zOd8DdzfY$5pk#t(!I^KCjp^Xg$yD z!GDcX(*KSbt`(GcwEU-Pb$W4zE&`KU>>sjRtyGe z?dBOp)}$YjC4JSeDGa^<^}AtcJ^ocLH;(X4qKi&P;Y$Q!V@#ABuP;b^P6Sy#2cnB$ zG^OAiR&x+MZ|x9Hll|?FHpl%q5nf=@h2(~-MHW21?)pjDudo~)PWzq!q7HbhmnbUcClwQ-gpc`3Sg>&t-9A02T z!r}&Qt5X&bj~qu+Qs;ZsDpSpA0r0N(o!p@I-LGux60*B3-$ULo`F@?q2#M>2)4xBP z^7NN3ht|Fa6*cJG$!(V}ATjAJ@b@!yyt`schgVnUio|J28o11T$$RF~DSYdLF{6d}X>F-5CG1 zI`!?=^^3plq03UcUFiYNTs^5?(f%b+>-a}i_;#E5PM$)D&J)DgVHVF%hp(lmfM_6! zx|Wsp`_ZKS+vBW}iY_z$J@1orQQexfv~K7pMZ@9M?_ie`@Fl5M6SNQy6!5hrDg9Yb zave*&fG=}6!7;ffEVCc4jd>Ev2>T+M(J(^=OTs0ffL=1Yo~)waS*i4V(IIlb?2U%5 z^AFUAsagUA)kaHLE|k*5yuWT{D(@GYpJUi;Z0T764%~=8J2fs{+`!<(l`izp#xI8I z+w+*r>HoZ4SWLo;CQq0rvW3Ix>2F^eTjZ7Qlde2A!p@mCCV;-da=>#=Hqejd^)p6y zdYd+jEhF3NyLx9Of}G>D6ZoC39Ni91j37zPI}g+!+;B3n&1OFxue;@*h7h{ktjQJF zNYM4L^!_T|wFYD_SwYyV|ANZeP#iXN=45j2G{Y^idVxrC zI}oX8nL%C58&fE=Q*3=hQ!sQMm(dB~{EGu2vjs8~nvv{Ht57fwY7rhJH>>S}+pphf zL-=UYN5?HkeBS>hQ2zT4V4JNQ$@MBUJQm&n<%Ltn%elA0WcQG&&t{xQRM(bmvy+vi z@G}Y~7hbo{XS;bye1Tktnzmbe3vPtCDr)#V3 z*^S>dGZj`DOrSY7v^)HZQ;_j%dtsf^WHC zC+T}$o26?z)+q)bs`IaA*YrQ zVWgfium+Fr0npR+jRLKIp6q8%rvfgqJ5aw%LVAkS23H2Y0E2ube8zMLmXjde@YkB6 z1#0T*m==B--nN~m0FzX3X*v97BK-1SZxEhSl&u{{KMYwomcH|)BN-2=3sc<4b2Yj9 zUcbql4kcuy)L%T!M)^COzNwh9x+-j2@1Ga zmr$Lzu_n%pSr&HW@x`nY>(#j|S#;kbXEMEorwpEo$=zNu%^r4)$2;bn53$Xhc6bVo zl$JG)oD+LJ7KUAiUx8~hc;KN|`hwSsvoxsFo4V9mbT?Y|p4%ov(o)orlh)o^-mTlB zz~W>~PoH^$vp=@C4@kP9{LmeuqQrAW#lArfZ=azy2}e81J!I3W6oU*2a9{JG=9>mS zx}oWkq%MBpj|tBsBQOYlx)Da*)94=N1D_^;=Ov*T7gU*J*xkFbmkOirnX@~Z{{4Pw z>pn+?uzbeU<}$L(>|*(Nvz;7(q5vk9_X-o;v!kuV2<$O@c^#8Zd+H0nvh)wxv{I!jsjh{b*E%|*Eo6g&X*>s)vS+Dza< zQsDhW)2)D>X=z7WkNy|`eXFCH%#W;J8;a3ZK>Wu`$rk3Glf1qKE=WriosJjF!2ymj z{3F|LGYqq;{R?8^RL&s-%BQ^KGmj8>?tVN6j%bSETyxlc*G5|TE--^$Z#!x`-LB|2t>PQJp&0DuvHi$nMjM+n9W*d_+!v5zRFL(JH35mZ4pc{c z^2;aZH(9qZkob9SY9V(Hkwt2=@8N}dN;S2!b#MR`{en2XzNmWsq;;wdLt}_T&gPo` ztDzhr3X8mev18)3YPG3ZP7KKVVm%%gh{>dJlYt|$#D~bjGfqa0=3$Y=t#|)IwArrg zE)3z|{pIt(seVGhHxq*)`PVkg30y+3(#3BBc3^iYv)|0Xf}a3O_~4a3nP|I?A}7!e z4!q*H4@o9a=JA}{RPsuu&zwZP$Qs5Z^TsYUk;H<`2Q<}sRyixau!|Gq`jX_i#fS6C zjM;;>6>FEyxu7RAh0Zj6bnOc|2K-|bo38Nbwt6E(DKl%rPfmo)8IyO2%Tov^CS~&d zyaJG?2M~BrFkz7B>R6!k7aqUXWKV7Oa)^;zUFe9+EK5yM;9uM|`NmAVF@~m`akK0D z@?B4UJ_t}x)vvo)TX3(u+bkvt?cAFN$)?Y zEvxwR;YP}y7WXj(-X%}69UC@9dAgj;ES4%;dEH)v+gfeJ6f-(J_%NwV3!zj zH^z94QB-B=cdqE3%e7}0+N~_cP8jgwzjbjN%5T6y=B&xQ**xFHvqlCW+f?)eR$i3P zePer)X4JJ)Z}CsOxs>d?yDKZlf$GC@Zml4x6%F$>AEHb$ga}UVjbuy-nWQ>81tTS5 zDmCX2a8%MT!^1s;Wu$LMDhHK!2T*3o2w>{$kLnOtns7#jp<9^8qg&vk47O}GtLMST zc^*&fy{_vHHbo6*5I8r(hA9zJP!9@6UEppS(L4cZGO7k=y<^(*6arBG+FRvn3)<@ z&aIb@kov~0G|tWtYP5sfMUFh7u%TComX5`bsr=4BUuDL|;R3Y;@=UhUEm*K7zVCP& z;M@j*Sp|3z=kT5T4Wd^$zs9f}S8d3D=%HXIbI4P&6u`21&2mVBo8Tm~7=<|x4ORtZ zi?Q;XSGmmg7BQ~7UD)iCL}Y)*b1Ry?SfoI&f9bS2_>o>7bT0vhGmYt{vhC4d{|3z! zG1SlSxYT=PU3DzQZI(KB*vx0GEK6s^%qhzvQ$VojxtKpc>ikfa&YnEvHf#nC!{$Rb zhJNo<(Mt`Q>zas?=s_?v!}Fh@-N#)s_T4wgNoY30C`H*s@{cCdl!*?3S|f~^9EEGh>ykF!Bwwxql_$}Z)rmEp zMuSsNd!o8fV3%Sg+cig=NaHxJ-9EqK*?_lOUTEWN8P%h^X;}+Lt=gOJd z)#669f8U~%Q!N5<4|8Y>QvQ-x9ZZVAFKqJ7hlD>XY}m}_3d}j9Jj_}>4ewrVGZn3X zGum(80kOvUhY@-yu@L0XEaV<4Irs7Hq~vk=Dh{v^$F`%C-mD)UFln5Lm*f-2kx5={ zo(}UF{Qrlxw~T7@+t;;mDORMoYbjP7g0{GYQd%hPPH@-a6qgovcXxMp4MB>#yK~a@ z-+Qg@@qXE7jQ4zfm?O+Q86>&p^}BB>co*i-Hk;EeTVHIe<|N)_zTBQ|HfVA@r{b%Tn=@) z>#&J=bChB*(;)FLT=#}F>o-wfEw{^aaTz|4*7<3GWv&pPLyd+*VH1CNuv5k#FoFvQ z9m9`cc|UuHx=XfwvJGl+sLF+Z3V6dEm2zmKOL9YMIdX3!H;LrtAe=l8TdyT|9OTN1 zL}-=1kr~*5UBJjr=JTT^l5Xklb-U?n)XJa!mFk#{@KD?$mAG0gR)r?`XVD4E5K4I4u?S4DOTX~kF8 zkfCt=lXr`|B_m&J6pXw54}7{kCStB)ocP`*dCvo~SOUK_kHG=%EaCHQh0>9rAFU=M z$hWS_rCbV^{I#2n_mLfJJu+-Ldf#9(lA~ev4gAgyVc% zda|*@Hy%^W8|jH_Z^!l5M%c-6^XlhoW<{@fNG!Sqj+_UHR@m`H0yL)Ik=IC6EM z&#UMzS}llS=jgCEC|P0Rn|T~NScs9-X`3F`DK}YS>{7($bmcGAtY#2p5W_+yvk7wb5hcYJCjO7{zW_-FbZc>QHAx2Tsy^c14=N8SE3s97N4 zBMv+i?;>nd10E+XrE>nzsbR2gnw@&?A*u)UlN(h>Ufi5>)f!;;4M-qy$6rWB5=c4Ukw}euRys6gc zudyUev&IW4=eG{iuP42bCRdCnBs-94F%)p4T)(CJR-W=gG;h|FVUr5^;jT$t?e~a< zbOvgXuh%UMM#9vOYUkp?L}89Xn#k*SF~f*u*k>d0`lSNwb3CVrDC1Fdq2G?!TlwOY zN2@iN@cXYsojl;?#|J;EN;b3FU<8y%RE-Zp0BRJr@^gjKE&TwFaW}wPn+{|^zYy=d zihqDdZO&XR)AvA1kXyP!n+~yZ66tE~iK?S_zG0E5QocZA z5<@T%NPMns)?Mj`Sxm`Aj3gviKTg%6G`V_ydch(x@+`&Qpz1n$&*&+;(#Ug;k@LgN z{k0Ye7G__o;#^uv%N2i?hPj{9=Q&FY)1Ti<711)j-MR9%d;Gmiz_2Osu!Lj z*DBz7DRA!QQG_I{_7T&D#(}e|13+7ys(1MKK<8%3yWjT#4Zf#81rn{E4mk^C4Mbb*7=M*Ig`y9Yj5YDgxN+8#twi%IHrfs*E_y&T4^HlQwtZe?py<*O5F2(!9sOhn%w{# z{?=x;Kz^RY>C^tOD_Rzo57XSVt4G4t!1}?C#wG@u_i<)oHYf6-P8O-h)~S@zgX9CyU{H~=KJjR&ldhg zj}DG-PzIcRGjs5t-|`a%mC!qXto$WVmc5P$_M!dhlP3hdavZUkM>zXnBCJRwXx+Nb zZZ=;{oGebXcJKWqOA&ZZN@`!-Uk;b?4-5aZy9|3=C^p(3WUJ=?^}O)0p%*0*xT62& zWZplVTrceA_!o(qVnZ*g`^)^VAF|1qdS@%N!R3rPMeE}Hs_5T%?xXVhbfJ(*_!NLI zbP7WrH6B||*{-P-q+(;en6ra+Iuwhwni)_T93I{)He-4;=HYk@iE|5;ZP%=su1cI& z(q;?7Mb=guu^*>=p|)Z7rn%u=7o5gxX(J5f*`AjJk!p_h$Ie_|dC25uDxgMPts~=a zyste&M?4YyfsEgd`eW>O0}57)9r)t%%>x0Nc0YWmHt&>Q&}tF%32U63%1c zg4I;o?y(g{J2aJ)PQI#}UUgRdmcpjHoCw3FU}rFe(CKFK)q;B^V|wvq7!vf%ya{^b zQfEa#-%qzzJ3pu2$(<;DKQFRT_3;P+fz@Eg8YlV(zqDqutmo(G%N|lgYuT<))3KhTdg?1^YwKWYJ9Q969dc9Bn`I)H z*1<|p`Pd8IJM&)(6seOVXgzuAYC2#Oslqy@S@mugjL>qA)H%y=sN_SF301&IllLH^ zbEMk^y1(9C&i7(zEq4-_(;@YyaF6shqixXi=qQ~=BQfJuB<3-8v5yz-)~E|-v0ME1 z6mwP3i{LA%yYE8D+iyoWM$r$g@x;dEM5J59N}^dG8@CNc+HTk|#&^d?Uh(L(+yKY5 zo^JazMJrd96EHu-OturO2pU2%&b-;wR2_tWOJ9uiiLFpHsC%3V(PRof_yYKi1{w_*^?lu{k2y*0QEi zi6q`J4)&F?QAahrgLMwVqh{F}m-JJ0KVu%c;GFEQM3))X|CHK}_Hu27ExCl_BNwn} zn=xaisd*Re9PMsKXhlM2AWuxp@H!#^QR%J6fv3f*YYyS1v>#^|_}`5YBTzeB*GOO4 zk8=-bhY-ZK`akMjMAguv{#J@FgH5j!LeErhp3><*DA!2m)#;xTawukLFT01f%<~Pe z46B9J4$sZ*aqS)4L~DH32NO;t6C_$Me52k*&kt|ag?wAo_H0yV~wJgfFYIB?`fQ8yce9W%U)TW<>L|LVob%)1GY|C8Iy2;PM$8{M?Bx zwUulaMD;khrl<;a#iEGgxIR~E`AQhLFwK}C6hDvB9*U?oU{uz#g{8k#VC%A}`a^JP zA`KxV(ksk2Qlzi{5pUBoOy9k4ya8ppx%u1eycAx)c=ls7KIq zenF_VYDJn4ON&S!K@}TprkI*+z(?DNU+eA9X5UY;VE4E*1q5`&pTm%fn>q?TFAc0=Tt7FES+qe(N1A&I+hxPKodmgQ;!&Dq&!`JY1}@ za?px|Gc7Shsk4*P^L3TWT@{fVXP(WZ#>!;(+wrY}2@z?5c`V$!)5iUFds`-gt)Qn< zSbyzD65(wKU*ce}=XiEjwB`;WUPzQ&y6#;U_f_1u43kM94iI%{MYSMHTZ}}$SL27n z#xI!EjR~1sg+mu+xraAZea|IjPdKsr0%yiERJpjIYo4^$sCnNje`KFx!E22cCJRYy z9=!Q){P$t^b!W8dF6yoO_+pmD{sbbOQ$})?#lfW!*!Q}-4STl?iEQH{{fv~HbSMmfFVr-a$s;l-3O7nwEdV32Vbq>I;#8QnKynvP9 z@J2G^aSn&}Erh^z_lWn0Zg)n87qvf7vqu@Gt(S#kr>o4s;!-DNs1BF+7*c#_WE9Ov zf24HXY3#K=P8>^0h_=KDrERx+0%>yaObv_61BN~A(rI%z@(Sa(3&=ZhTWOlLHxbNc zr$0Ih7UbSDgiTlcuxN-iQ%$?`k5{i#(O&9u$|nqkZza?_=Uen1{rkq%3x)}Quw z=h^_qH#*`l4oAA#kLWFe^O1cIxkUIK&`DD`U6`m~1+efkF69}|8)2>j>iM?bGrY?5 zMA9W><2iUDO=*`uTDkSB#LPXu_jK)M;=-BKEJ#UJ3qD2U#6WH@6I?b+fl2kNfF3lo z{)}8YfB$InioxEJLDY_G{r44#P`HXpMEvi8F4u?wa>#vMS&>DGRZ!m_LrCV$?^W-_ z5HgNuuoKEQGhc{J!bui{*?P#Tb2l2xNAC8+rkg>p=1P+Y02um~FUyPh8#Vsf>}?xo zz<9mci;q|?!CCuGXvNyjk8jm$G&3_p-^_Kw!dp=Fo>-}e%}K(Mbu0VZ^ls@F=X-~b zjSX&aR%S%#HaCQD|K%X_>W<(7Z9zP*rYo*KF|z8g_NRG!C*tP_TS;sg{C5{Xz-T_V zM*7lf<}`)W;~?6%dUM7)lG*^h59`&0+3;MYdcP&jg4WM|im&pvcjr0&02|J7*vX=& zdHSajbc^)zS6Ft--4Y~vp~Op;BRqX{VUixF4wV-4b6h%=Ec9MNR(=^@mLB%Tx>>?L zPSm&|d5yBqvcWxvXWp*Cp4`BLD7B%oXDuk@gJ2_e?b)a6s*fH=s|E=O=OQ%~Yeu@- z)pN(rh>J_HN+$Hl*U=38H9W7oFwXmf?UM*s4Ld&Nc7CS_oSuO-r!l(ZvTLzBartjk zd6L1PC5r}?VST|X+lbex8iCw$2BWXKv!YHH8wp9(Bly=AEA{q1TCOHmoGI_B{G>dY z9>;zHaTeY>Wya!D^Xv=d(1H3!>PP9Mx7D7mB}FB(dZGVJ~rWkf@9P ziSy-SH-U#t*O77$EvssJ7t&k^=)ZgG+UUuUkSnnc~cNKmpoeb}%rM$8%+(+q5f+}7oiRO>qgJk z0-DQ11n>4OsL#eSgm>qqN{27JEU-Z6>As#S?Ou>N*DCA5w$ex)XV9l~uaq$h8ONkN z8kAsR%Vc6KL2P1_Gq4XGi~MFf8q6`!rAUg;Asikw{>_QcXQE7qt&w4N)&%C>W(J_A zhnbZXNW~jJhusFFJezs&#rXpT05hCBa%Ej$w%2(&R4Kj7Tkpwk|FK+KZucCajUByu zLw^+|Id~73c#PBWPA6YP6!lhA7lHhDOb8<~=EjMRcGnDraM+0g;dBA~n%G*B#2<=W z{RNeS+LOCK@Ud6ZVG|rw9YSNwsp%#RP!Iz2x-OgFXZAnpK4n5N$pPt)hlCKZYL}M3&^JV*Gen6{h3C!-L$_rtcm##UzRwyt^LJe zHn{JfZz~=?-Ta$5{~%ryH7r@-K}gXaH`8Cl2MfD#GIMwT`xEzDIV^bjj%RC;FX=FT z7^1dC3NVyTqS!?m$fDK~zls!@bZhND&*r82)K>vCD98#e==c=M{=&pDX(;}V6@+NV z{+m!F1FwaK#kx zZb1q6{-4sJwlRMk5stetZ!CXC?9xvkSMAP*mZ$c8t5=fpOzAv2VCO1(@lpEfT2%g) zvtV?L+F6rsQNZj*J68+b8L{X+7GZWbH&~V1q6sMroWp(#nc`~}Wb%^xa4tOQYTY+lE-pP)r)ooVM@rREcY9I4`hOT+Ukrj&l+0Uo4#Qv_m(bFL%orO;td%iHJcLitc3wzVU>iBSPOJ zVer~y*8G0fr#h@)j|2skcc&A4&Mn7x5*$$=YK5 zxCKbUYhT02Fwsrmxq>mkPnH9pcfnd&@JhW5^U@JG3r{hGs%!@?yiz*xWjk-DK3)u( zBcd9&>dM2x*o9MTKr+>Q#x%=!WfBcw4Psz12>j=~F^KYZO z$MD0Mja%0UC*2^i1F)U~{N~HfSza=D34OmI$%(27^iu7b0(6fxsO%Tab7h_?EoL_# zE(aBl^2zYVUz9p`8BMSr~2UU${PsRr-tx6RxX4m$tH<&I3&ut0{VJuEdYK z+09RI`9NnxR1dll85qHnFnE;GJVrBRFx(f>I}!ulC{dF^z-OUCPR(4hbkPFqc`l{ zEbbNjN(sX~R`|In{Z)u%$a&fFx+ZlBT{-8Rn58G$fcU7-Dmf+xM00{B zZva+J3i9mb)z?XDQOm0dN1fSWUgQ}}?|H~TM*Lk{N%i$&g^m}QTiPZ8J@Qk1-sSuI zch_vaCJQGyiLU#Pn9Z8YuV6JO27m|fz0rMiNf=9r$0r%mcCm{{v-fb^QZxvb(Zu|- zRRyF@eAR106=$H)kVpc~lTO__mn zo9mGTtGlCWp4r2<{$`koZfIFSqsmh=>aLg++!uN0V9W)5_sx@c+~Y@EDt@YP!Uyzp zAJ4{q10;wLPwc}#XCxCNUeK8-dgz6`O9DLye4yNVU^8=s5Cp3l z4{I^V8mR2aTajLL_lj^pQJp$gsX7ti0W8`C#t(cUN=!aorTCKWmoFqN? z^+xM+txRTi{)@p|CWd3qg;f1B8Oa*uXf;YJfR_M{jPl}Px z5i4E3)BBisTc#z}eP^p@UQ=(92VjX9kv=e=B`Vv==XG%>w>UE!;m#qPd>+=WE|e&O z4<<;SnJ|YNIh^})!ZX+zC|tLvQ@ zF9u4*jW!VWUVY*_Hl&-x%F~vO`1SR;h^XPoGj%pWV6;KlE{B0-|LD zF@`(C8WS`rjb8p+39jF1Z%TLZAkXC4+z3$}G62}RRKngVs#xS)dGe9O9yWmCibHWO zSqP_aAVjW0YTo7Y)SXN32LRJQn(Z6Nr_!WYjSZ-VV9ojoT_%K}uq39{?Vj zl3tynV-J!#G(@l)@}{d>=6HUc3Oon%023ASed=cMPR50Gwc~6BkXgNIe%|fA#bs048kGCqHhA?~kyIU>cNo1*bM8%7SzmMaZzp(jo-fCa4cJ|VCM!`xt5d#q-JH&Bb=4%>~0OyYZ5 z?-Y8O(q6wKy|dGdglX%)zuLn<=P>i@eY_E}j@Q<`UP308{{189w4;an!|aP&EyBNT z(;pWG1D#W3{rT`&{s=drlbFPqra9 zqLEnsB7TrVX1mw|K~u&MOdOE07wU7UpTR})je`uVx-DGp4wCOc^{BuMUX*{%6|LOu z7~fXw=nhRf@sM0bGaR+vusH1Oolnu->HeMGSnq>h6aAx-KH*2UkFMAClvmfobX*;r zvXvzQL`@eyn?dLI0Dt(ax3DHZ3K!|kf9|Yxl0AK&^$2o9tf|{Z6S$+A7KayuG_P;7 zm3Dtl5j-io|6jmTf-qbpeya*WK$WM*C(nd>oBz;~b3QN)7_Qt`rFL>@@MY1O8FJ~j19s>|McNd}D>+UO#%3DOAa#8ZXBe8j zfx$C!b0TqMeO#&IHjz2OcKg~~WQu~iCx#91WY}axpYOa=a+OD{BdM#1lzU}26|u$$ z*M3iM)zh|V8d#1Nl;1%-TM06&<@RlR8qWjeUciE-9|*}LAd3dk+h+#l>etfQOU4JI z96Q4BU>f^I2YQ;@j6C7gQh#?1$wk=_2a4g9M$ZmAh*BSJ91#CNx{9qT^^)F&fJ~pt z9)`VExw(+-3fy(hRr4Ljddh@xsc@CGvfJ+a@1F2#OxAaZg3z?>PQK@N-rK=a&xDuMt_r;J>0K4_$NdX3Svbi z*wjiEE@}X50_tTsEPfcA$`xY78+d+=1sFTSV;Uz>j*uEF+=*shn{}}WdfS(Pai1;& zQ4jj**7@!D-$zUXxgYq}@7CCaq)1{YQ=dHm$dfgxDCS(jslz&^8dNn*lj8Rg!O=6( zWRIFWVH#?ZbAsDyUAR+|!BUw}mrR-~>4JCrh8s*I*PJDpF*@P#{=oQ{JSSWMxvh6h zPO{HH_PfS&`CiIGT@532M*Wm3l;>Stuf9!~`jCyqrg%hO+sJjy9dC=oGEu8QG_mpt z89%gJHwbnGcl>xg&hh2f-H!W6)O!^_iB(?91H(LO79{YPlYCck4L>ccbA=G6gWJ^9 z9-mZqI38j>sw3^#r?{21D(np;=$_6)xK9zueI1LOKbe8W{qW`s zF6`##rWY+<^+GVwMhxulQZVLNNQJiEJ9CgUqH)l5Vy>C(I~>-NViUu7Txc9y zynCWJ7U1ihNFQ54Udpd)Wa7u+!fZ%9Ahi*oeSix#$LtHHdtRM8cu0Ug*kW zqcE&bv`ovz^(nvA6LGW>p^!F{a(_vrNpII91u;aYcXsc6Q--e?#bbalS(_(xK5h}E zWF{fzd@kNO(L=&uVGt$rQt0Q4#d=rFac5&6hE+6E$|$reOlUza{4B88EMdtu=sg1S zV`ep=dx~bbFt1zTznzp6OE03l6X!XYHi{Tn34L36O1!%5;N$o4oa#hS#I{kjn5@3GF?*iT@1dMn z+iFtN(?l474abp3Ex_PBCIZlV5Ywc7VNLLXhR5NM&oHUBXrM$7@9OUI^-UovxI*T( z|0GGnc1&dFm}_r@tA+&@u#h#1XHJ83=77V!G0-W+FG%n0YP_5vqk)@RvdZN~OZgM< zgN2T*!t%#Tw{|59xm*Fj3J`eX)i20;>#q@!a%0lw>F~)|!mcNdY+)7q5Zx7{`kPL! zqqqNbAa??SZ}<1&;oUE>S|i4Qeg|sv-5HEchVTggu&L3U(WB)-&vS|qVMc!n+o|_4 z>GUr1KNI|LNmSU$y1zN*DZDOyB)5;e6UCF-IrggaId_Uy6>3r@Hxy^6^skuT~1HE72mOi`yg((L=seNR2%)w@0v9g~REft)q5j%(SAG7AKX zQ8pO)Nhj4%TN9TM30~{9t*Nubl8W9HH++-qq|UTQNbQQjfN9UrCnTnyvb(0EiiLpR zpNyr@_m<36K6|6Z9(8`os7mXRk!IJ_yGubf;%Z_TStn6tx$>umA$d z2lqE1?wX|U7hwy=qsit*ppTL2#7p}kaP2OB%Su#<)Ab1rQ>U#OTGm)YtLe%+%(Z}D zlU9Zs3mv8F%9H#6g7YRj=F}gpmL6O+Sg@1gfUreLXn8KOzCE-Fk)1qj1Xu4cc(*4t zE1TDd|KX=uO75z1Y?!2c)1VNJE?b9)d&&YeA2s_xw&pU3+b0GqF@TJZ?!#{Q_Lm+2 zvXrN>-7+x?zCh#yw!^hA|3_Ls`1+uWVqTF%(fbcPmPVQc{L%fGv;KGx!IT_a zT?>ORl0nSj0ONDrF-Dcj=3)z;}w!&oh zO$6koejK9=G`_%NIYQwCqt7Sl66fC?BXTjw^~jMaUipUM-G7z(erSmI54U;Pq`HzB z3|I-*f~8a66$b6n#b=(;P!h?rVN}aw`*NvEcZ@AS9WF0C8uk5sFV<`zv53kTJBKW zDL*q)0yyrSQS-KCU3KF+zByzB8vxlCvz(hR1M(o<^wv zVUa-u%STf`;z!CTnpE~w?!B;}Z&+f5?Yxb|)|_LUamZ9JxR^aQfUA?eHSU zdM`LxG?Kc_XqfWZhqm=JytC)7(Xg($(!)?zI)L()oE|X4IV*ak0WqKCOsJFV4*A9O z)AkmA|BeQxuMrq7zi%Nuh)`=vd?0lpWcI{ctigk9Qrle*B@ae=TSmmmG4d{%-QL_z zEAdZF5W}U1lAU#m8wVV&DnznlO?YRdj;zC%wmbox$)rltXOW4LljHx}n{~IOT+=ia z#hfk>A|7Ptl;bI;3xfC6e~LnJ6je(|Qdy|yNikgEfgh4TuTgH`z#RIldSiWpNZ zJt1Qo`{mup3aArjJ7BQ_aWXbPHr3Z9;mK@Z2#aEdK)PuBycH$DRpMW)wkeVioyp=o z?i5-zqyN6H^`@h$=5L&O>w^gmx@jT%%$xsvz7Ce|wKP;FA;#pz<^Ba(|1TEmKAx>% z7HJfJ{SOy?$3b}wbx~-qrCB8ZqA@a=j#~;k$aZ_?{y_Sy(0<)NiMYK&h=Z_#x}8Lk zhTL06P2$=74KS~2wfQt@W`vOSK{kyeS+U>T-zMt&YbaDw64t){8!G>ZGC*AW|L+UE z7w5H=5x<;e|I6u3;G*zZjPR8AE#P{UK12bMUDb}1tdwQp=3uX8q6pY{Ze_x?8P9~U2 zt~)Ezqedb(A*$%w_?B2p0p&4cjkw{uan8*@kvKsE$KP0R&-{)%Z+k)-J4(bUjjJ4q zJOD$B3Jj4EJpd>9ji7s5*Q8lqIPMO8z>H2VOzs=eUNv0{oYPahRVZMcm%@#1VfiHC zb^!6Cpg2a;0W{GsQ9JLM6n!t^UhQ-GEPAb?I}{#1BMahv?{FPjvXmbgF>>1>?fPGXWbVtP$f)rTe+kbA6)hhQE8M>SAWa9s!+C#m&tZV2LrN!+ z;Jr~;qZWlkrZK#p-2jpatpF{?k$eX6t^d~usJ@~=KySiq5P_A>G;rR7Bm1Fg-ov2Y ztb?<$Z$x&o9Xv60)v+J29XlIl@?AEuFC+Vwkn9#Tqb12?xM|Iu>WsQK!bBtYFL~9J z9(ClhoP+=*uarJS7>g<a5d13s^`Y%=iL1iO$^T$T_N!wqob>5=8ypJ*tJM<|6UC* zKNPVIlKQDf4T$tOjIr)&N9U6Fwx`ICq8l{e&x|*_n!nxPC(^H9+hS3K z?7o-RrT7Uv#+qI^-v!HP)F#WPQyKX2Iu`QpSY3!mUizsN)+kyZrR5Y0bTZUDR%}~V z)w#-h>ByW@&9GsKyRfMLkK|f-GgC9ML{M5C(V$5*gO9mCE?79p8c#DjaBRm8LYSsK zs*Pyg>0<-&DB~g@b$$%PD^x0JjVkT?I-3v-o}1#>91ggP3{QsWMeGHCU4@zDAb0 zAhMc>52cap>EN&w#q5=Z5$nY`C58>>)91IwWRpvg3qx>64}PxAN~dxZ$?cudM~bz` z2_HFl*9)~6j|$3C<+91$2fo}Y7aPp5{E5$bYAPS4l`0@PvU61rotDgR;56Nr=|BiY z(scc+{cb#byJy58T+K(J`S^}b-Pe;9BoGpCJDxIHb8GeDNEs$q$Gr6c{K6TNp&Uau zP!^#8O)xm$1$DXEp!}f`RAUgjX@ACVIY2r!aY{3m%D09yWlHM^B#cxx)s>XebNu9p zNrWMD9)i60_o;e=JR)3IA!}bmw`Aq4E0h%~3N?9Ef(B$KRbpzyejqVS62% zNT{*DT?Ia2xzYvo(k+tl599Q+1*)4ur@((Z8k{*oqMG?sWo9zx>>7Gm#T6GZH_Z?2 zr)+a4^}f$44e~#HyYBtgQz%#Iz>@pC`b5d|W#qwt?Vw=$1L8>lLLZ5ny^f{waikUA zE=QI{NMr-eJw%4-CO^4%(DOG6Q;^T;j|W^1bg>$?cQ0FxwfYeN$c) ztykPTV3y~X@oo?mXHvle^Fu%$&ZIU+qN|tj9sEE>TAasfk@X}Bi=^5RVp&3N!rL$4 zSng+5_6`xR`K6)9rJbeJzCBS4ko*;lj2-n8u+ zBAS#o;>xC0@xl(Gl{kI2jOv#WjQixcRMYIvlFWSTAAMmaHc}rs-BQg5g)%`5a@dk} z?h$>@Uvp2`!aZ-Z`n|uVt=DjI6N@*i-yzLoQ*h=FnuwSKgUDZ^g4bQrNSafVMP_@h z3rl{;BUxpXNoEM^*fQLjpB!mVxN`2b&U9h!4ErR;1v;fz9pDn$M^?T=vptMGhGyne zS)Q;>vHaXGgm+AW<%c7i9|)L%BvkYVt1WA;k*EjEq9z8KCYGy zf_}?Xo*E>iip)pVP{Mk!m2Fj zK7njV765nVKA1>`_+Tks@j>8>-ML^PShsDdYRnJ>B{LqkK1_l9?Cq|nK^6D`QesH3 zsKSrJQSs2LRIEzsN}q5063Fr?h^X)nNg8*;qCx1GPAc&u@oIS&or5TE@-P5>2|<6c z*>azwr2BX9S5cM9FbkO4md4Tn6sfHx}8qFyjBj=bX4BIR--_y0IbgLbtj# z_Us+uH7uxKbrLiln&17l#AVR@?a<6H<`MjBP)%1jL1Dv97-I#MZ#)4s*HWlLEPU(H zwfvLxf;|2~Q~T9o<ntdZ{@88_N5`Sx zfteyq_R-pKCwd@S09n94QIv{IP$N|ESn5-#Zk2JnRfOBkHZZR-SmRl+8&0^Ecn=im z8$=8V?2vH+)bU7SI1FrlV2nk!r#}nDgkxYnolD=fte$6l?VfETGhS_ zmn*`?x%SMggV+h>16K+H@g%eDK*KNIJDw3PDPkb`4nL2tq;5a7QK-wcU0=+l@36(o zn*Zc0!-!I7B~3{U)uCxa@?aphdiocZx8c_4Qi*j`alAe2iTCcY-hq5}7xMXl7u;(p zk!)Px9FF0PK!T-n)S0Fe;O9I#bLdf4AP+rd-P&CT&Fu06SGy_AhV^EgZ(CG1?@tE1 z%fPV!e}o7=LB+)(t#Lp86dn%!Ql&b+o8W`r1y>&CEFUBhI2*M@Vy1n>6duqiC{4bR zlVLoD1F1oLi&Y96{$6WiMh;bX8N^Iv?Qf_DZV5q52@vs$BMqR&o>;hVp^QdJy|aoRdC4of#*u-iE(hXF)Y!k#SVXVyLiFz(>2P!3tcVx1zk8h)H8}e`%I& zm3|fdqTqW(`jPK)TTe_f^SoUifm8T3lAV?3}oAP37slEE;U>x#=C-&>^Y#3}gF(6t0aij>sE)(L?RD zm7~BtvXj`iB69ogG@fLy=C?s#Nrv+IB-`D@Ra9!$BIs!@kDq$wP}0HPE-F(5Bnll# zsS}1Uxk$`l0E4HuOEJ)beJZdu`8qTy@VfI$$=4?wZ&Rt7%y(N5;Pf@fMc5{`T=ABV zoO%<Ae3PP7%z7KOvOL;JO8NEPAe_ShdZAS?r6H=UI$E zNZkeuG7!`o^`NHZ4a^mDD~A5s(Dp?{xp(6$LBDFxD#jE%D}bN;W)9xMekIOhTG zZ%I=43q)lzVqZ^0Hvy^rwFCc}WqhRiFI)J|+kCEN6z8AD7PT)&X`;1e&YQ4>pB&Lp z`goYcugo}Wya-Alx8W5EXcbqJ(M>$PB>{g=U3#KG8*7A9YVrRf)EY)8p+fM=@&88I zYbq$ZKiJHv|0Odg^8SoUDz~UN{Ixkq5cJ+0b*owYb;m@L|Fpm;oH@mG6&HOkN&?!k zyAl1lcRoC{tA-j3AnovK45rDfU!ps-uL<+5e!rr$YkeR941YJ-hHG_8Ojo^W9^cb` zzy_yVom0GrA${c*lM8m54Q42kx(D7AYL6XO6LPPcctH}JM8x=Dt8V(PVsDC`@6R? zzV;E8f}N`lKNzh8LRz9$YQj~`q*R2a*h)|NFdeSc)12WXG>F@GE=q0#dA3?F=~yB2?^ah?*hVSRz-r07wLQf{7uKqW2$l-I$~52nrft zQdkhSNs+tq;fzvGQU6`+a&0i9#66n=<5YDnZ>~JvZ=BB=og|aMM~t#iM%OAh>HUK0b0-T{{ghvzTq@a=8A9zUh)(^Z&=+%wJa8dg=vM*#s3G; z0zvSBf4RkvL3$2w7$J(q-3zAS&B@`Eik|n4Is`?D8Xs2iNGib!4k)r_;)j+TVJqgLAY-DH?OiYg_k-{nIa`DjC?$k%!tIrop$I2a6 z!gmmwD!J*>eEk*pMV00asP{`LVz&VFa~xK=pZWZ|2_{Xahoi}zPv%)N18Bm`YS#h^ zC&EBZ)i9^;ci*i+oV-{RU;dYooHmy8T6~VR<*H!cr~Gybv9ez`h$F*TqFzasx@7{f zJo89?%CEKX@e&)2bp%Yt)t!;2e`v;LXgkHd@PKwbSehUmZIFT_{k#z(yoVltXI6W_ zlUYKaIIrH=hm#%%m7J8}CsiLWNqd01`f

D73NrvdrmS(1$?q|n9 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/image3.png b/Dijkstra Algorithm/Images/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..493048ab7b37f907f7b1a89aeee868a543d00e91 GIT binary patch literal 65232 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�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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/image4.png b/Dijkstra Algorithm/Images/image4.png new file mode 100644 index 0000000000000000000000000000000000000000..9c47aaaaffabcd49f10fe5cda5aedf33431ce1a3 GIT binary patch literal 65286 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 )oiImBH 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 DI2Sh? literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/image5.png b/Dijkstra Algorithm/Images/image5.png new file mode 100644 index 0000000000000000000000000000000000000000..2494654449417fd46572395eafcdc21a10c1c812 GIT binary patch literal 66333 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/image7.png b/Dijkstra Algorithm/Images/image7.png new file mode 100644 index 0000000000000000000000000000000000000000..dd91cab0b84515792f0002c8c9fb360a78098357 GIT binary patch literal 66716 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 - ## Credits WWDC 2017 Scholarship Project Created by [Taras Nikulin](https://github.com/crabman448) From fb4c63bc92ac909159528e2e1c3f16d99eb9665a Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:32:05 +0300 Subject: [PATCH 0557/1275] Tables fix --- Dijkstra Algorithm/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 9a48bbeb3..132f4e5bd 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -12,6 +12,7 @@ When the algorithm starts to work initial graph looks like this: [image1.png] The table below will represent graph state + | | A | B | C | D | E | | ------------------------- | --- | --- | --- | --- | --- | | Visited | F | F | F | F | F | @@ -61,6 +62,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | [image4.jpg] + | | A | B | C | D | E | | ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | | Visited | T | F | F | T | F | @@ -68,6 +70,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | [image5.jpg] + | | A | B | C | D | E | | ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | | Visited | T | F | F | T | T | @@ -75,6 +78,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | [image6.jpg] + | | A | B | C | D | E | | ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | | Visited | T | T | F | T | T | @@ -82,6 +86,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | [image7.jpg] + | | A | B | C | D | E | | ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | | Visited | T | T | T | T | T | From cce96e2694e71e473f30817a535a97a6d59591f3 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:34:16 +0300 Subject: [PATCH 0558/1275] Updating --- Dijkstra Algorithm/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 132f4e5bd..cb0683e5d 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -9,12 +9,12 @@ The best example is road network. If you wnat to find the shortest path from you I have a gif example, which will show you how algorithm works. If this is not enough, then you can play with my **VisualizedDijkstra.playground**. So let's image, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. When the algorithm starts to work initial graph looks like this: -[image1.png] +[images/image1.png] The table below will represent graph state | | A | B | C | D | E | -| ------------------------- | --- | --- | --- | --- | --- | +|:------------------------- |:---:|:---:|:---:|:---:|:---:| | Visited | F | F | F | F | F | | Path Length From Start | inf | inf | inf | inf | inf | | Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | @@ -44,51 +44,51 @@ var checkingVertex = nonVisitedVertices.smallestPathLengthFromStartVertex() Then we set this vertex as visited | | A | B | C | D | E | -| ------------------------- | --- | --- | --- | --- | --- | +|:------------------------- |:---:|:---:|:---:|:---:|:---:| | Visited | T | F | F | F | F | | Path Length From Start | 0 | inf | inf | inf | inf | | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | checkingVertex.visited = true -[image2.jpg] +[images/image2.jpg] Then we check all of its neighbors. If neighbor's path length from start is bigger than checking vertex path length from start + edge weigth, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. -[image3.jpg] +[images/image3.jpg] | | A | B | C | D | E | -| ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | F | F | F | F | | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | -[image4.jpg] +[images/image4.jpg] | | A | B | C | D | E | -| ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | F | F | T | F | | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | -[image5.jpg] +[images/image5.jpg] | | A | B | C | D | E | -| ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | F | F | T | T | | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | -[image6.jpg] +[images/image6.jpg] | | A | B | C | D | E | -| ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | T | F | T | T | | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -[image7.jpg] +[images/image7.jpg] | | A | B | C | D | E | -| ------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | T | T | T | T | | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | From 142ff2e866c89259c576b03b025b500e655cf028 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:35:00 +0300 Subject: [PATCH 0559/1275] Fix folder references --- Dijkstra Algorithm/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index cb0683e5d..677c97447 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -9,7 +9,7 @@ The best example is road network. If you wnat to find the shortest path from you I have a gif example, which will show you how algorithm works. If this is not enough, then you can play with my **VisualizedDijkstra.playground**. So let's image, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. When the algorithm starts to work initial graph looks like this: -[images/image1.png] +[Images/image1.png] The table below will represent graph state @@ -50,10 +50,10 @@ Then we set this vertex as visited | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | checkingVertex.visited = true -[images/image2.jpg] +[Images/image2.jpg] Then we check all of its neighbors. If neighbor's path length from start is bigger than checking vertex path length from start + edge weigth, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. -[images/image3.jpg] +[Images/image3.jpg] | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -61,7 +61,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | -[images/image4.jpg] +[Images/image4.jpg] | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -69,7 +69,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | -[images/image5.jpg] +[Images/image5.jpg] | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -77,7 +77,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | -[images/image6.jpg] +[Images/image6.jpg] | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -85,7 +85,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -[images/image7.jpg] +[Images/image7.jpg] | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| From 8e0d77ff9f99812bb8de307b66f1d211ef4ea785 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:37:15 +0300 Subject: [PATCH 0560/1275] Images --- Dijkstra Algorithm/README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 677c97447..490b4de1d 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -9,7 +9,8 @@ The best example is road network. If you wnat to find the shortest path from you I have a gif example, which will show you how algorithm works. If this is not enough, then you can play with my **VisualizedDijkstra.playground**. So let's image, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. When the algorithm starts to work initial graph looks like this: -[Images/image1.png] + + The table below will represent graph state @@ -50,10 +51,13 @@ Then we set this vertex as visited | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | checkingVertex.visited = true -[Images/image2.jpg] + + + Then we check all of its neighbors. If neighbor's path length from start is bigger than checking vertex path length from start + edge weigth, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. -[Images/image3.jpg] + + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -61,7 +65,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | -[Images/image4.jpg] + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -69,7 +73,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | -[Images/image5.jpg] + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -77,7 +81,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | -[Images/image6.jpg] + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| @@ -85,7 +89,7 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -[Images/image7.jpg] + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| From 37550365f6db8b980cfe1792a3122efe24a1ed91 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:55:29 +0300 Subject: [PATCH 0561/1275] Still improving description --- Dijkstra Algorithm/README.md | 73 ++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 490b4de1d..5541276fc 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,4 +1,4 @@ -# Dijkstra-algorithm +# Dijkstra's algorithm This algorithm was invented in 1956 by Edsger W. Dijkstra. @@ -6,13 +6,17 @@ This algorithm can be used, when you have one source vertex and want to find the The best example is road network. If you wnat to find the shortest path from your house to your job, then it is time for the Dijkstra's algorithm. -I have a gif example, which will show you how algorithm works. If this is not enough, then you can play with my **VisualizedDijkstra.playground**. -So let's image, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. +I have created **VisualizedDijkstra.playground** to help you to understand, how this algorithm works. Besides, I have described below step by step how does it works. + +So let's imagine, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. + +> Initialization + When the algorithm starts to work initial graph looks like this: -The table below will represent graph state +The table below represents graph state: | | A | B | C | D | E | |:------------------------- |:---:|:---:|:---:|:---:|:---:| @@ -20,11 +24,17 @@ The table below will represent graph state | Path Length From Start | inf | inf | inf | inf | inf | | Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | -Graph's array contains 5 vertices [A, B, C, D, E]. -Let's assume, that edge weight it is path length in kilometers between vertices. -A vertex has neighbors: B(path from A: 5.0), C(path from A: 0.0), D(path from A: 0.0) -And because algorithm has done nothing, then all vertices' path length from source vertex values are infinity (think about infinity as "I don't know, how long will it takes to get this vertex from source one") -Finally we have to set source vertex path length from source vertex to 0. +_inf is equal infinity, which basically means, that algorithm doesn't know how far away is this vertex from start one._ +_F states for False_ +_T states for True_ + +To initialize out graph we have to set source vertex path length from source vertex to 0. + +| | A | B | C | D | E | +|:------------------------- |:---:|:---:|:---:|:---:|:---:| +| Visited | F | F | F | F | F | +| Path Length From Start | 0 | inf | inf | inf | inf | +| Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm. @@ -37,12 +47,15 @@ Cycle: When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. Okay, let's start! -From now we will keep array which contains non visited vertices. Here they are: -var nonVisitedVertices = [A, B, C, D, E] -Let's follow the algorithm and pick the first vertex, which neighbors we want to check. -Imagine that we have function, that returns vertex with smallest path length from start. -var checkingVertex = nonVisitedVertices.smallestPathLengthFromStartVertex() -Then we set this vertex as visited +Let's follow the algorithm's cycle and pick the first vertex, which neighbors we want to check. +All our vertices are not visited, but there is only one have the smallest path length from start - A. This vertex is th first one, which neighbors we will check. +First of all, set this vertex as visited + +A.visited = true + + + +After this step graph has this state: | | A | B | C | D | E | |:------------------------- |:---:|:---:|:---:|:---:|:---:| @@ -50,21 +63,35 @@ Then we set this vertex as visited | Path Length From Start | 0 | inf | inf | inf | inf | | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | -checkingVertex.visited = true - - +> Step 1 Then we check all of its neighbors. -If neighbor's path length from start is bigger than checking vertex path length from start + edge weigth, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. +If checking vertex path length from start + edge weigth is smaller than neighbor's path length from start, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. + +for clarity: +```swift +if (A.pathLengthFromStart + AB.weight) < B.pathLengthFromStart { + B.pathLengthFromStart = A.pathLengthFromStart + AB.weight + B.pathVerticesFromStart = A.pathVerticesFromStart + B.pathVerticesFromStart.append(B) +} +``` +And now our graph looks like this one: +And its state is here: + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | F | F | F | F | | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | +> Step 2 + +From now we repeat all actions again and fill our table with new info! + | | A | B | C | D | E | @@ -73,6 +100,8 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | +> Step 3 + | | A | B | C | D | E | @@ -81,6 +110,8 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | +> Step 4 + | | A | B | C | D | E | @@ -89,8 +120,12 @@ If neighbor's path length from start is bigger than checking vertex path length | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | +> Step 5 + +> Step 6 + | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | T | T | T | T | From 5e5e7a93188b79ee6693b19fd03d387635b87dbf Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:57:33 +0300 Subject: [PATCH 0562/1275] Description --- Dijkstra Algorithm/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 5541276fc..206507b7b 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -63,7 +63,7 @@ After this step graph has this state: | Path Length From Start | 0 | inf | inf | inf | inf | | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | -> Step 1 +## Step 1 Then we check all of its neighbors. If checking vertex path length from start + edge weigth is smaller than neighbor's path length from start, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. @@ -88,7 +88,7 @@ And its state is here: | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | -> Step 2 +## Step 2 From now we repeat all actions again and fill our table with new info! @@ -100,7 +100,7 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | -> Step 3 +## Step 3 @@ -110,7 +110,7 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | -> Step 4 +## Step 4 @@ -120,23 +120,23 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -> Step 5 +## Step 5 -> Step 6 - | | A | B | C | D | E | |:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| | Visited | T | T | T | T | T | | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | +## About + This repository contains to playgrounds: * To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. * If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. -## Dijkstra's algorithm explanation + From 2e7c34c8d59c003dffe5f51a5f035a8c9b1141ba Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:58:50 +0300 Subject: [PATCH 0563/1275] Probably final updates --- Dijkstra Algorithm/README.md | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 206507b7b..e73f95393 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -10,7 +10,7 @@ I have created **VisualizedDijkstra.playground** to help you to understand, how So let's imagine, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. -> Initialization +## Initialization When the algorithm starts to work initial graph looks like this: @@ -130,43 +130,17 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -## About +## About this repository This repository contains to playgrounds: * To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. * If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. - - - - -[Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)'s explanation: -Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. - -1. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all other nodes. -2. Set the initial node as current. Mark all other nodes unvisited. Create a set of all the unvisited nodes called the unvisited set. -3. For the current node, consider all of its unvisited neighbors and calculate their tentative distances. Compare the newly calculated tentative distance to the current assigned value and assign the smaller one. For example, if the current node A is marked with a distance of 6, and the edge connecting it with a neighbor B has length 2, then the distance to B (through A) will be 6 + 2 = 8. If B was previously marked with a distance greater than 8 then change it to 8. Otherwise, keep the current value. -4. When we are done considering all of the neighbors of the current node, mark the current node as visited and remove it from the unvisited set. A visited node will never be checked again. -5. If the destination node has been marked visited (when planning a route between two specific nodes) or if the smallest tentative distance among the nodes in the unvisited set is infinity (when planning a complete traversal; occurs when there is no connection between the initial node and remaining unvisited nodes), then stop. The algorithm has finished. -6. Otherwise, select the unvisited node that is marked with the smallest tentative distance, set it as the new "current node", and go back to step 3. - -Explanation, that can be found in the **VisualizedDijkstra.playground** -Algorithm's flow: -First of all, this program randomly decides which vertex will be the start one, then the program assigns a zero value to the start vertex path length from the start. - -Then the algorithm repeats following cycle until all vertices are marked as visited. -Cycle: -1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) -2. The algorithm marks picked vertex as visited. -3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. -When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. - -## Usage -This algorithm is popular in routing. For example, biggest Russian IT company Yandex uses it in [Яндекс.Карты](https://yandex.ru/company/technologies/routes/) - ## Demo video + Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Credits + WWDC 2017 Scholarship Project Created by [Taras Nikulin](https://github.com/crabman448) From dd9e998e4482ff9665e3964829569a0c5489daf4 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 16:01:01 +0300 Subject: [PATCH 0564/1275] Added reference to wikipedia --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index e73f95393..76cc4ca1d 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,6 +1,6 @@ # Dijkstra's algorithm -This algorithm was invented in 1956 by Edsger W. Dijkstra. +This [algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) was invented in 1956 by Edsger W. Dijkstra. This algorithm can be used, when you have one source vertex and want to find the shortest paths to all other vertices in the graph. From e2282045c04aeab0ff7eeb2c1df8edc33c92c76c Mon Sep 17 00:00:00 2001 From: Taras Date: Thu, 20 Apr 2017 16:07:33 +0300 Subject: [PATCH 0565/1275] Update README.md --- Dijkstra Algorithm/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 76cc4ca1d..61b47e97f 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -24,9 +24,11 @@ The table below represents graph state: | Path Length From Start | inf | inf | inf | inf | inf | | Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | -_inf is equal infinity, which basically means, that algorithm doesn't know how far away is this vertex from start one._ -_F states for False_ -_T states for True_ +>inf is equal infinity, which basically means, that algorithm doesn't know how far away is this vertex from start one. + +>F states for False + +>T states for True To initialize out graph we have to set source vertex path length from source vertex to 0. From b95331012e6fa880928b38a7606384e6b7a0db9a Mon Sep 17 00:00:00 2001 From: Taras Date: Thu, 20 Apr 2017 16:09:14 +0300 Subject: [PATCH 0566/1275] Update README.md --- Dijkstra Algorithm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 61b47e97f..9999e224e 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -30,13 +30,13 @@ The table below represents graph state: >T states for True -To initialize out graph we have to set source vertex path length from source vertex to 0. +To initialize out graph we have to set source vertex path length from source vertex to 0, and append itself to path vertices ffrom start. | | A | B | C | D | E | |:------------------------- |:---:|:---:|:---:|:---:|:---:| | Visited | F | F | F | F | F | | Path Length From Start | 0 | inf | inf | inf | inf | -| Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | +| Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm. From a44f84ecad941273df7472ef1c7de7aa93b1d1c8 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 16:26:33 +0300 Subject: [PATCH 0567/1275] Removed unnecessary images --- .../Images/Dijkstra_Animation.gif | Bin 8561 -> 0 bytes Dijkstra Algorithm/Images/screenshot1.jpg | Bin 224243 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Dijkstra Algorithm/Images/Dijkstra_Animation.gif delete mode 100644 Dijkstra Algorithm/Images/screenshot1.jpg diff --git a/Dijkstra Algorithm/Images/Dijkstra_Animation.gif b/Dijkstra Algorithm/Images/Dijkstra_Animation.gif deleted file mode 100644 index 3b1a2ef434107efb104a9bc1a6a714af37367529..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8561 zcmc(Ec{J30-~XgkC?Zr^Daz8O63I@MjI3!C-DOFoy3%sBsHvGTW*Eloj4_z8%^2$} z_MNfsQMT-BLLpJiGj!ee<+|?Ye$Maw&U4Q5{loExb9~;*=e2#zEiY*6+}OSDBY+PA z2tR3QX(c74Q>RV=yaA@BrcO>yUS3|m|NcAR4FDJq^yYZ`<@*8NyaBus9485Y@d9s- z;66{_moIo@2#9|H6aWAMAW-1#E%5Ub{uL+0J3rD7fj}^s%-q~u6dy&dBPX;ZWVC1G zf6Rv!3s8IkzDhu@6T~zM5?TbwZGy~BLHJTIXT%o zCFq;(8=D>Ln-&az6^zXaK7SKTkM_+@jtTnu1Y={KOiv5`FFr+q zgpHY_gNc!?ndY$*>(>eAp}4RC-~kW-G**VQGA6*LoFq2rxDXD4c8Eg)hmzkBFlbe@cP*_x4Qd(Bduc)l5 zuBol7Z)j|4Zh6<*)+FB!Y43Rdu?NxB-`_hlBoFNx8=iPS3L5AP0?f_^&wXBC5Bx;T zX#>{vJ9u1*Ds~?4Rn{;)9&HjJDrI&)@j>)afYd4D*-dX~#UT*G=90wpLy{QSs3M@T zn686A;*L2D()5ylp>-axtygAGt;;FJw!7aOy^4`~NlO$tSta1xEk;VfbHG7IXW)9T zx}7tLKxXswt9#tJ!4{mI-sl!U+ejsO`K+LL?_#XbOO;tM#epFeQ9mX zFcXz>ql``8D7dx$?nF(NuVaPtRz;ih?HMCkVJAKBEzYxJVS~gQ$GUEFTF7|dj{Y6T zo7_Q3?$C~Nc(01u46%F%ZNFz$u`H9Jw#Ykd%dlF#!lZlWC-X*8M1gOLw#W2uoE;zi zV0$_4o?St{Kkskme*ZdvPK_t-Q#1Nr{3YUj!^oJ)Y)Br7 z^s?-}fP^eqmWBFn`S^aPf16)9rh;)IH0Rg{v}mRz29$ylDV> zmXA<+e%T4{eqDon`5@A0-$0+g#Q1XMfZqB=#G&h!YGO#pao(dtA=|7}#XR+1mr0Xc zY(%d4UJkUp8Fukle3YY^*9R}BQ~F3R@{1cI{edRT1(nl|kZfiA$;qn2zI%psXwh@Hxzr(+gGS4r#n}Z79pdKGLUL# zpUEds>XBr)_T^{&yL74<7}t@U zXc!cqS#&KZjs@s=-v9Kqne$!teP7GOtdPa>O3p-%s+~_SR^&kRrcRHp5Qby*#z9yVRSg=h|C zOlKe6e{Ql!lek5qYJ=DOF$b;RHBN*YdQ#Z%v-5t^frjXJ60AWv*R-0gi&g9-pcatW zWPVun%>BM)`BXIphphu`Cx2fWA|%0%K5e~~QTOBoGe?hYUbCzGNZZ$vy`G(Z1`fa9 z*Uiw#Z0XZP&X<9E>MWZf+Y6rdUOG#9#=6q(^}KDjRDNbG&LL$UuMa*pJd07$&x?I8o<3RBvp(hatoY%nO0VkN;7@ZywDsrazbe{nRc=R< zB$sY!yQ|6#hC}P!=Cq%Jel#y%cWBVVP}Q%0FX;(3I9pKi46Hk+HjunL%62;oo^4%T z&Y65Kk?sBM)~7(h@+SR@U8zrwmh7)kdt_)S*Z6kJ`Owd%+l|DOLLqk`+uvz58RBlA zc)W+@5YV5gec9Fhb*jk4O;@2h@)t&TQ~Yi?63B#{81)ed|A>;bmArX!;MTg z8l~7Q1x8T1Dg98}WW9uKWV zNb|PeQcn!s@KiMUeqm_oM5rD%=E=s&i&gofBsgRL%;WIdna}-G5qf!`_jCEB9@m%{<<79{tQ{ z-CGNcPwcSz?pFP!IB$=#ZT*wiO7>e%+D0FE=VpBPd!ncfC(6n=Ds^&K{57{g`d+Tf zveII*wXZs%NpsBdMtJjlFh1^RWd8+E5j)YG7EtsdXN|ir9LzUXtTTM_W{K}%^z`+n zM3CY5GOEb&U=iy1{xjp3{K?CX%z7r{O8L0mf$R#py%R&Rig|@w-O~E%q?whdI)Gn& zIe~bFTJK@&!pLdk@#d2C;yh81JFPhxt*M}L_3aJJLj~};l&5kmJqNk;T#?JHz`9oB z)>-ES6?rGD&%~8ai&rY;&!EW3EZ4}zcJ*-%+hy<3+qw%?Eh?9}5H9|v*|&}+K974& zZ^G-IZu?vQnarH68a__phI|p{Q?z`RU!rPaJNzOyB40|~e5h;0_-tC<`q2mIpsr7v zbDsI4$=kCd_D(II%H!7^em+&&d4M+mj~bf%(q+y^jXg1d*&>Oz`_ya2=7?@;aW`Ix z0^S^CncZ6IZXEl`mFy`M%PN4T6~FA3pnboiUbMk~dflXEUwNc>QL~=YlUM07Qd?S_ z#OjIu^DlQ{jI|}!0p7Trqww{r?iU=_hpgK;{Z>e+>mtv&j!(|rj5EAQ|Eb|yK|L2I zYvL4iP*Qb7-?Qn+U1Ux{uJttQn%&+G-v{RXzNEW(1(nF>wH1LOS_Dd7ZU3`0pV!fs z-aZ>Pd?I)EiT-Hh1M-OWE$ynHxf!E2pUXxD(v6q2W}~^*@%ri=<)N=1A3At+%rckL ztX4*%pUjVoeCVPz^n;UV4ji|SSbUdg!(}?x-7(rEvO@OjJOE&ThB|-;00Q<4$v*xK z_)oHjD}*SZR>&R_LJTDc$(}@siVmd4#Nt2+kc32fTyh{YjY$_v;le>sCX~hD6=Z?a z!~F9LQqn5}%K33Q#r4&-&85{fEh#K`+xsqXXLn0aZ>?DWK*8_`cWAt8>~q}2bo194 z{?OF7sJX>YKgkOneFL!Lz1ffr(lTn=zwIdn2kldvIBY>HN6OCcs@;ikKX3bXRj2&@ z=!Cx<9TWokx1+-)>9H~K2@rZ>QWTTOO2ek4rgIT&4lf6s1r5*T<`)zdOBVW5%aW=B zDyqxs8*-bPd9|%M?>?lx?@aIbnAqJ{(>oZ09^np*k4|8R`^F;BUpnU^zr*Hc8h%dI zEzjLOoEBa1G#a2p@py0}7LF8Ix7y^&l_sAAm;+1zp28+~tvM+K6b#-Px)l^8R8#@M z!J%XFw(u7#tcN866w{)GzjFa%x;`dUR%X=-d3~8Sv!d$8Q@KaPN=r%>#el zK+O%9zG~ttwOxkdePUnviwPxo%jOWeNs!#}V;himu{vmgWyopdr6EhwQIIiA$6;7M zLdIlVBYWnM)qR7v&3kq@?k=PrfA~~`9DLj1>Dtkp1egLWgt{KEX?9J)L0~mWNi~#k ztFR##bwdde6g(OtDIH0V1%nbm;3%eKTnb*eUPmMiE+(aBW7Ab6Riu-1N|5QWg3?O= zat<)upsKMP3@nn?ZERwE=!7+QtrXlYta!EHiO-W$(_g;M%+7tA|Gu#J+L3K$=PpGPKJ(R^E%dYU#KRaczG{BgmiCl;Gztq>}o8xAHV#|@ z?KzC%)EJeE{K~+L#3sqi;@lGIyOg%N`oHb}nst~d8d?}=?_cUe)Qg@bdG9Z>5|Nhi zi9;)9LpBx~UHjf})yRK&i%~TK6U7e*X*N55B;!yHrq|Z$bolh48vkSNJc=03%Ow2F zJxJMehXiw~?xSzA3i#1WQF}00NAg$CrWo5OD?J6moz~b3B(K&NTvgj7hitfSL+|kD@m&`5dh1fF^nGsez(jWM+3c}(50ssmy5^jmGKgK)dcbb3^NTl7#z%`D` zR9+LTDQ}9Amk(QYT-aUmSHM@~cY$dL8kf!xI<71>hn~;Q&lTbWx}-R>ieFoola!pA zUR0P_|NaA!Orb{akhdqdwhs=4n!w-)lb%!T33=n;f4?qi(Z$fs5*=2Rw#4LsHU$xw zg0^g}{;N;cDXzJX1G>9|&OT5pcr&tiMlNf**WQ2qetzuEV?E_WfS~xtPR+QA-w#i5 z&#R_itBcSv`Fh?tW7Is>C_q2Cl0Dwal2(4bRafhC1N&YkpK>*GqK@%OcNvw#d(g~B zAKanQ)%0~3`@&?ZYlr=s+v*E22J8X&3FpxA2CM*80IxbM1J3B`t&F87v}i4nD0|_0Sm7?lwU;y@YDP&6w7CLyi^$5s}xOG`n~Ti%IhwNxJ>Gb(#1jI^#2E-W(} z-XP8%E`o*Sghdbf$Br|Sl4+2Z35d>zFA=jE67lu{;x;aoX)&c5e?6$F@SrbNFNQFR zfUNKbY$b{af?w1{gy0E*0YU;HQt)A*s7RU+KnyO%(3vZ=A<0aKC1=p%fLH@A4VWse zn=6bWa>4%rKK~PNOhop~e_ZJP(Y4em;E2|0ZM#~0cT=)5ix=urdRr>a45cOQVs?u* z>*_BFH(qHM8xyDuloUtWD_5dU0O7K-4jz1hw(D>#19vzkLi5u2 zhVfIQ76j9mDoz~^-Yrp=VlEt2c*3}tQ-` z@EKu-eesuH3jgH&GQo~?pBX-PCyp^zPJH#0cfK?8?#t!C-EI$hataIfEq1zod72#l z_2W^$=Z_j|lQxo$X>I$H16RiI`oA9o2m|^x2K*mmh(ScsgsECkEO5J|l~7$tX;|~S`VaAqV1r}>Xt!if`ydy%O;Q&+ zGBz}sxNX}2G@ z73c#dfqN`7VykdR9GKUtGU94TC)}$kmhAYt2<=DXT~*s-3#e4yx_srwN9dMj!79d! z4!7w*i^z}t8!X4|UR_B(wp8Vmq*z!5$~pF1B-ni_ulNqXdpa ziJC&11B+s*5W!DUxy;;2ff@t zi;qVdu6n({A9-S~wmv;zf9kUzRx=~z*P}x8Jzvg`>)_^>mpxwLdOq>zKfe09gcV@$ zJ-3$DY5l{Syd=H(&lx@i6atP3wG3brcU8^F!{IAx4uuLpqlG%gKa?1N4@Z(H2(s`Z zMd4#2>DYJzF(HHm#-y+UQ$kadGGK9Glq_Z(FB7`T^TBo}Avy9z#o#~aJ-Mck2K|HC zdF^SmLc$moL9OSGj8lSx-lSt{DoZOWB@Vug29xc0=A43lSl~>eptMcnt-VQ=)+uDOabo?j6{$>0y zVm}hamVQ1F*=gH*2(nRCS|hB{t}tM$qLJy&CfgziKwUhi()M6!h_o)mdb1||0`jn3 z{9|oR&l;SHv*wF2j8}P>=GkG&?Nfs`L3+FUYj@#2?4Tx|`{cqN57~o(uKL}i18cB- zJ7A|!rbr2^W(ccR6oWu?#Qfnws1-Sdf}cZ6SXmuF2B8BX2Q0DRRZ$fqF6JnPrbiw; zM21^RNa&!*EO=yYC^*AWqA(8x(h)C#qb)NEQR$dcYGz$I=ul;lRVBI<8Hf;fgk<#e zu(>**n4Cd)+?IjCyk>Y*IVwEvP%d0CA&6Y(4nsGcbco4Qv_8T(Alz{i9h8N1e_7xv zwm%#w50Nvtzh#X(TRFXpFrNTyTKtO|1Pk3q2x{fM2Z;$M2^Sadh z(4@tJR+uS*i5B`aHYg{LTU4x)pH^B}T*;}ZsH&sXq}4Z*8Z+BgJZdz&wNoe%GP|3~ z`u}IMzD6MYlbQC#2X-F2S;q4|Xl}MI^~n~-9U05}!8XRsSeYGhMDQ^N$1G!eE#cq; zzV-8#*!oDF8;kFB9FH_m&4VF7!yOqHVlReo^j{o1+?e1f1=a0D_qED{xgrqZHA!(j2hJev^9 z10pFw94uwksUf2L*|_*$CXE9j!D-x5qP#5z;hH2RLrf-5p?=E48gqw{j%ROd4&Sxmsd`L_f174xgy_Qq=a6!T-B^UC z{_>DbpWfn!?s=$&1gyP>Dnh^g3*SNi1HKddF_BboKuk22F4P+#;R#eyR1%HBNMo~; zxM|Fsxa8bmNFIV%l*q&JIjPx*h?7E@5sOgus>^OxEU%DWZXS8lLZwOYc`-XjmY-auvT45XOJxp^o$I29tLoL|m|>X(8GYosa~axLf|<4k!PW}KV(i9h)6<}jsIf1DmE?H8>bxVI(fYs(Mj}qK zYoyHI7vz_eSt9`CR|LTS!h&e569%BAfK-6}YRde_ld`{T00{Am7C^RpWMz*-PY_O^ zf}jLQBnE{ekRai*5tKke6k@lmt*z`aP`Hs10|`R}#ej~P(I9CV9G+}ePHtgfUTVSa z-01pu4ZDp>sg2Rid7V*hAVb;azP|p}$U-MWyxbX9a^1iXE4r|tr`3#5G7{7FT%mH* zQuGCU(eC?*`acf7vXvAmHpfKgT^`$zO$SUVoimbFwazowJZNMpr?z>!DWkK1RHt@h zH__LVNDRzFK1$qtLG%dB`%q0>b!?GwF=t`JIg7*$S}Sc_S9=N{e;dB-PK~kL!3|kW`OR00kjam{r~^~ diff --git a/Dijkstra Algorithm/Images/screenshot1.jpg b/Dijkstra Algorithm/Images/screenshot1.jpg deleted file mode 100644 index e9f7a1207f315e8f5aa20c72f3264c65edafd3a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224243 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 From 3395c01c00c80554be30f91310f2878d7faedcce Mon Sep 17 00:00:00 2001 From: darrellhz Date: Fri, 21 Apr 2017 16:04:19 +0900 Subject: [PATCH 0568/1275] Update README.markdown updated to Swift 3 syntax --- 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 c5a752e13..c03023c42 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -364,7 +364,7 @@ What else do we need? Removing nodes, of course! First we'll do `removeAll()`, w If you had a tail pointer, you'd set it to `nil` here too. -Next we'll add some functions that let you remove individual nodes. If you already have a reference to the node, then using `removeNode()` is the most optimal because you don't need to iterate through the list to find the node first. +Next we'll add some functions that let you remove individual nodes. If you already have a reference to the node, then using `remove()` is the most optimal because you don't need to iterate through the list to find the node first. ```swift public func remove(node: Node) -> T { From b66e31825d9025916d9617073830f50284ebd488 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Fri, 21 Apr 2017 19:25:23 +0100 Subject: [PATCH 0569/1275] Filters the potential change arrays for only the ones which add up to the exact value --- MinimumCoinChange/Sources/MinimumCoinChange.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MinimumCoinChange/Sources/MinimumCoinChange.swift b/MinimumCoinChange/Sources/MinimumCoinChange.swift index c995063ab..8b0da80ac 100644 --- a/MinimumCoinChange/Sources/MinimumCoinChange.swift +++ b/MinimumCoinChange/Sources/MinimumCoinChange.swift @@ -64,7 +64,10 @@ public struct MinimumCoinChange { if value - coin >= 0 { var potentialChange: [Int] = [coin] potentialChange.append(contentsOf: _changeDynamic(value - coin)) - potentialChangeArray.append(potentialChange) + + if potentialChange.reduce(0, +) == value { + potentialChangeArray.append(potentialChange) + } } } From d5c9d179f63767cfad7dda48faad914f808ca68b Mon Sep 17 00:00:00 2001 From: Jacopo Date: Fri, 21 Apr 2017 19:38:45 +0100 Subject: [PATCH 0570/1275] Optimisation: removed double check if the winner change is valid --- MinimumCoinChange/Sources/MinimumCoinChange.swift | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/MinimumCoinChange/Sources/MinimumCoinChange.swift b/MinimumCoinChange/Sources/MinimumCoinChange.swift index 8b0da80ac..55629d020 100644 --- a/MinimumCoinChange/Sources/MinimumCoinChange.swift +++ b/MinimumCoinChange/Sources/MinimumCoinChange.swift @@ -56,8 +56,6 @@ public struct MinimumCoinChange { return cached } - var change: [Int] = [] - var potentialChangeArray: [[Int]] = [] for coin in sortedCoinSet { @@ -73,14 +71,11 @@ public struct MinimumCoinChange { if potentialChangeArray.count > 0 { let sortedPotentialChangeArray = potentialChangeArray.sorted(by: { $0.count < $1.count }) - change = sortedPotentialChangeArray[0] + cache[value] = sortedPotentialChangeArray[0] + return sortedPotentialChangeArray[0] } - if change.reduce(0, +) == value { - cache[value] = change - } - - return change + return [] } let change: [Int] = _changeDynamic(value) From 2ff26a1365cce2d47e7cf8cc341eadf3134cfdac Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Fri, 21 Apr 2017 23:07:00 -0700 Subject: [PATCH 0571/1275] prettify some syntax around optionals --- AVL Tree/AVLTree.swift | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/AVL Tree/AVLTree.swift b/AVL Tree/AVLTree.swift index cfcf114c0..4feb691e4 100644 --- a/AVL Tree/AVLTree.swift +++ b/AVL Tree/AVLTree.swift @@ -99,17 +99,11 @@ open class AVLTree { extension TreeNode { public func minimum() -> TreeNode? { - if let leftChild = self.leftChild { - return leftChild.minimum() - } - return self + return leftChild?.minimum() ?? self } public func maximum() -> TreeNode? { - if let rightChild = self.rightChild { - return rightChild.maximum() - } - return self + return rightChild?.maximum() ?? self } } @@ -120,11 +114,7 @@ extension AVLTree { } public func search(input: Key) -> Payload? { - if let result = search(key: input, node: root) { - return result.payload - } else { - return nil - } + return search(key: input, node: root)?.payload } fileprivate func search(key: Key, node: Node?) -> Node? { @@ -385,11 +375,7 @@ extension TreeNode: CustomDebugStringConvertible { extension AVLTree: CustomDebugStringConvertible { public var debugDescription: String { - if let root = root { - return root.debugDescription - } else { - return "[]" - } + return root?.debugDescription ?? "[]" } } @@ -409,10 +395,6 @@ extension TreeNode: CustomStringConvertible { extension AVLTree: CustomStringConvertible { public var description: String { - if let root = root { - return root.description - } else { - return "[]" - } + return root?.description ?? "[]" } } From 7ecbb716fb9bd16f5f89bd491edc1fe81d3c85be Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Fri, 21 Apr 2017 23:15:30 -0700 Subject: [PATCH 0572/1275] prettify some syntax around optionals --- .../AVLTree.playground/Sources/AVLTree.swift | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/AVL Tree/AVLTree.playground/Sources/AVLTree.swift b/AVL Tree/AVLTree.playground/Sources/AVLTree.swift index b4b97f0d6..56ba81608 100644 --- a/AVL Tree/AVLTree.playground/Sources/AVLTree.swift +++ b/AVL Tree/AVLTree.playground/Sources/AVLTree.swift @@ -99,17 +99,11 @@ open class AVLTree { extension TreeNode { public func minimum() -> TreeNode? { - if let leftChild = self.leftChild { - return leftChild.minimum() - } - return self + return leftChild?.minimum() ?? self } public func maximum() -> TreeNode? { - if let rightChild = self.rightChild { - return rightChild.maximum() - } - return self + return rightChild?.maximum() ?? self } } @@ -120,11 +114,7 @@ extension AVLTree { } public func search(input: Key) -> Payload? { - if let result = search(key: input, node: root) { - return result.payload - } else { - return nil - } + return search(key: input, node: root)?.payload } fileprivate func search(key: Key, node: Node?) -> Node? { @@ -385,11 +375,7 @@ extension TreeNode: CustomDebugStringConvertible { extension AVLTree: CustomDebugStringConvertible { public var debugDescription: String { - if let root = root { - return root.debugDescription - } else { - return "[]" - } + return root?.debugDescription ?? "[]" } } @@ -409,10 +395,6 @@ extension TreeNode: CustomStringConvertible { extension AVLTree: CustomStringConvertible { public var description: String { - if let root = root { - return root.description - } else { - return "[]" - } + return root?.description ?? "[]" } } From 3d48ed411d872b5b3f03c114e6b1c074bb4293e8 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Sun, 23 Apr 2017 23:36:55 +0300 Subject: [PATCH 0573/1275] Credits --- Dijkstra Algorithm/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 9999e224e..086e60c55 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -144,5 +144,4 @@ Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) ## Credits -WWDC 2017 Scholarship Project -Created by [Taras Nikulin](https://github.com/crabman448) +WWDC 2017 Scholarship Project (Rejected) created by [Taras Nikulin](https://github.com/crabman448) From 83f7a32ccf0a2fe4b6223305bf89a7724b666a65 Mon Sep 17 00:00:00 2001 From: Antonio081014 Date: Mon, 24 Apr 2017 11:23:09 -0700 Subject: [PATCH 0574/1275] Add variety implementation with complexity analysis. --- Union-Find/README.markdown | 63 ++++++++++---- .../UnionFind.playground/Contents.swift | 82 ++++--------------- .../Sources/UnionFindQuickFind.swift | 50 +++++++++++ .../Sources/UnionFindQuickUnion.swift | 51 ++++++++++++ .../Sources/UnionFindWeightedQuickFind.swift | 59 +++++++++++++ .../Sources/UnionFindWeightedQuickUnion.swift | 56 +++++++++++++ ...indWeightedQuickUnionPathCompression.swift | 53 ++++++++++++ .../UnionFind.playground/timeline.xctimeline | 6 -- Union-Find/UnionFind.swift | 59 ------------- 9 files changed, 330 insertions(+), 149 deletions(-) create mode 100644 Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift create mode 100644 Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift create mode 100644 Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift create mode 100644 Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift create mode 100644 Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift delete mode 100644 Union-Find/UnionFind.playground/timeline.xctimeline delete mode 100644 Union-Find/UnionFind.swift diff --git a/Union-Find/README.markdown b/Union-Find/README.markdown index 5102f6b89..03e082507 100644 --- a/Union-Find/README.markdown +++ b/Union-Find/README.markdown @@ -23,7 +23,8 @@ The most common application of this data structure is keeping track of the conne ## Implementation -Union-Find can be implemented in many ways but we'll look at the most efficient. +Union-Find can be implemented in many ways but we'll look at an efficient and easy to understand implementation: Weighted Quick Union. +> __PS: Variety implementation of Union-Find has been included in playground.__ ```swift public struct UnionFind { @@ -141,24 +142,24 @@ public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool Since this calls `setOf()` it also optimizes the tree. -## Union +## Union (Weighted) The final operation is **Union**, which combines two sets into one larger set. ```swift -public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { // 1 - if firstSet != secondSet { // 2 - if size[firstSet] < size[secondSet] { // 3 - parent[firstSet] = secondSet // 4 - size[secondSet] += size[firstSet] // 5 - } else { - parent[secondSet] = firstSet - size[firstSet] += size[secondSet] - } + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { // 1 + if firstSet != secondSet { // 2 + if size[firstSet] < size[secondSet] { // 3 + parent[firstSet] = secondSet // 4 + size[secondSet] += size[firstSet] // 5 + } else { + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] + } + } + } } - } -} ``` Here is how it works: @@ -167,7 +168,7 @@ Here is how it works: 2. Check that the sets are not equal because if they are it makes no sense to union them. -3. This is where the size optimization comes in. We want to keep the trees as shallow as possible so we always attach the smaller tree to the root of the larger tree. To determine which is the smaller tree we compare trees by their sizes. +3. This is where the size optimization comes in (Weighting). We want to keep the trees as shallow as possible so we always attach the smaller tree to the root of the larger tree. To determine which is the smaller tree we compare trees by their sizes. 4. Here we attach the smaller tree to the root of the larger tree. @@ -185,10 +186,40 @@ Note that, because we call `setOf()` at the start of the method, the larger tree Union with optimizations also takes almost **O(1)** time. +## Path Compression +```swift +private mutating func setByIndex(_ index: Int) -> Int { + if index != parent[index] { + // Updating parent index while looking up the index of parent. + parent[index] = setByIndex(parent[index]) + } + return parent[index] +} +``` +Path Compression helps keep trees very flat, thus find operation could take __ALMOST__ in __O(1)__ + +## Complexity Summary of Variety Implementation + +##### To process N objects +| Data Structure | Union | Find | +|---|---|---| +|Quick Find|N|1| +|Quick Union|Tree height|Tree height| +|Weighted Quick Union|lgN|lgN| +|Weighted Quick Union + Path Compression| very close, but not O(1)| very close, but not O(1) | + +##### To process M union commands on N objects +| Algorithm | Worst-case time| +|---|---| +|Quick Find| M N | +|Quick Union| M N | +|Weighted Quick Union| N + M lgN | +|Weighted Quick Union + Path Compression| (M + N) lgN | + ## See also See the playground for more examples of how to use this handy data structure. [Union-Find at Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) -*Written for Swift Algorithm Club by [Artur Antonov](https://github.com/goingreen)* +*Written for Swift Algorithm Club by [Artur Antonov](https://github.com/goingreen)*, *modified by [Yi Ding](https://github.com/antonio081014).* \ No newline at end of file diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 09649b938..9ad5215b3 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -1,73 +1,19 @@ //: Playground - noun: a place where people can play -public struct UnionFind { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) - } - - private mutating func setByIndex(_ index: Int) -> Int { - if parent[index] == index { - return index - } else { - parent[index] = setByIndex(parent[index]) - return parent[index] - } - } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) - } else { - return nil - } - } - - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - if size[firstSet] < size[secondSet] { - parent[firstSet] = secondSet - size[secondSet] += size[firstSet] - } else { - parent[secondSet] = firstSet - size[firstSet] += size[secondSet] - } - } - } - } - - public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } - } -} - - - - -var dsu = UnionFind() +var dsu = UnionFindQuickUnion() for i in 1...10 { - dsu.addSetWith(i) + dsu.addSetWith(i) } // now our dsu contains 10 independent sets // let's divide our numbers into two sets by divisibility by 2 for i in 3...10 { - if i % 2 == 0 { - dsu.unionSetsContaining(2, and: i) - } else { - dsu.unionSetsContaining(1, and: i) - } + if i % 2 == 0 { + dsu.unionSetsContaining(2, and: i) + } else { + dsu.unionSetsContaining(1, and: i) + } } // check our division @@ -88,7 +34,7 @@ print(dsu.inSameSet(3, and: 6)) -var dsuForStrings = UnionFind() +var dsuForStrings = UnionFindQuickUnion() let words = ["all", "border", "boy", "afternoon", "amazing", "awesome", "best"] dsuForStrings.addSetWith("a") @@ -96,12 +42,12 @@ dsuForStrings.addSetWith("b") // In that example we divide strings by its first letter for word in words { - dsuForStrings.addSetWith(word) - if word.hasPrefix("a") { - dsuForStrings.unionSetsContaining("a", and: word) - } else if word.hasPrefix("b") { - dsuForStrings.unionSetsContaining("b", and: word) - } + dsuForStrings.addSetWith(word) + if word.hasPrefix("a") { + dsuForStrings.unionSetsContaining("a", and: word) + } else if word.hasPrefix("b") { + dsuForStrings.unionSetsContaining("b", and: word) + } } print(dsuForStrings.inSameSet("a", and: "all")) diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift b/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift new file mode 100644 index 000000000..25d7f5b5d --- /dev/null +++ b/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift @@ -0,0 +1,50 @@ +import Foundation + +/// Quick-find algorithm may take ~MN steps +/// to process M union commands on N objects +public struct UnionFindQuickFind { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + for index in 0.. Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift b/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift new file mode 100644 index 000000000..4c848e61d --- /dev/null +++ b/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift @@ -0,0 +1,51 @@ +import Foundation + +/// Quick-Union algorithm may take ~MN steps +/// to process M union commands on N objects +public struct UnionFindQuickUnion { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + if parent[index] == index { + return index + } else { + parent[index] = setByIndex(parent[index]) + return parent[index] + } + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] + } + } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift new file mode 100644 index 000000000..02bec94a8 --- /dev/null +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift @@ -0,0 +1,59 @@ +import Foundation + +/// Quick-find algorithm may take ~MN steps +/// to process M union commands on N objects +public struct UnionFindWeightedQuickFind { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + for index in 0.. Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift new file mode 100644 index 000000000..b3ac7445e --- /dev/null +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift @@ -0,0 +1,56 @@ +import Foundation + +public struct UnionFindWeightedQuickUnion { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + if parent[index] == index { + return index + } else { + parent[index] = setByIndex(parent[index]) + return parent[index] + } + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + /// Weighted, by comparing set size. + /// Merge small set into the large one. + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] + } else { + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] + } + } + } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift new file mode 100644 index 000000000..892f46a3c --- /dev/null +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift @@ -0,0 +1,53 @@ +import Foundation + +public struct UnionFindWeightedQuickUnionPathCompression { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + /// Path Compression. + private mutating func setByIndex(_ index: Int) -> Int { + if index != parent[index] { + parent[index] = setByIndex(parent[index]) + } + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] + } else { + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] + } + } + } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Union-Find/UnionFind.playground/timeline.xctimeline b/Union-Find/UnionFind.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Union-Find/UnionFind.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Union-Find/UnionFind.swift b/Union-Find/UnionFind.swift deleted file mode 100644 index 506cdc1fe..000000000 --- a/Union-Find/UnionFind.swift +++ /dev/null @@ -1,59 +0,0 @@ -/* - Union-Find Data Structure - - Performance: - adding new set is almost O(1) - finding set of element is almost O(1) - union sets is almost O(1) -*/ - -public struct UnionFind { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) - } - - private mutating func setByIndex(_ index: Int) -> Int { - if parent[index] == index { - return index - } else { - parent[index] = setByIndex(parent[index]) - return parent[index] - } - } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) - } else { - return nil - } - } - - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - if size[firstSet] < size[secondSet] { - parent[firstSet] = secondSet - size[secondSet] += size[firstSet] - } else { - parent[secondSet] = firstSet - size[firstSet] += size[secondSet] - } - } - } - } - - public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } - } -} From 0de6055763a91902d3a52ef4857930aec6dbd0d7 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Tue, 25 Apr 2017 17:36:09 +0300 Subject: [PATCH 0575/1275] Added code description --- Dijkstra Algorithm/README.md | 138 +++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 086e60c55..a72843e69 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -132,6 +132,144 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | + +## Code implementation +First of all, lets create class, that will describe any Vertex in the graph. +It is pretty simple +```swift +open class Vertex { + + //Every vertex should be unique, that's why we set up identifier + open var identifier: String + + //For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, + //when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. + //Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. + open var neighbors: [(Vertex, Double)] = [] + + //As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. + //It is var, because we will update it during algorithm execution. + open var pathLengthFromStart = Double.infinity + + //This array containt vertices, which we need to go through to reach this vertex from starting one + //As with path length from start, we will change this array during algorithm execution. + open var pathVerticesFromStart: [Vertex] = [] + + public init(identifier: String) { + self.identifier = identifier + } + + //This function let us use the same array of vertices again and again to calculate paths with different starting vertex. + //When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. + open func clearCache() { + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] + } +} +``` + +Because every vertex should be unique it is usefull to make them Hashable and according Equatable. We use identifier for this purposes. +```swift +extension Vertex: Hashable { + open var hashValue: Int { + return identifier.hashValue + } +} + +extension Vertex: Equatable { + public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { + return lhs.hashValue == rhs.hashValue + } +} +``` + +We've created a base for our algorithm. Now let's create a house :) +Dijkstra's realization is really straightforward. +```swift +public class Dijkstra { + //It is a storage for vertices in the graph. + //Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. + private var totalVertices: Set + + public init(vertices: Set) { + totalVertices = vertices + } + + //Remember clearCache function in the Vertex class implementation? + //This is just a wrapper that cleans cache for all stored vertices. + private func clearCache() { + totalVertices.forEach { $0.clearCache() } + } + + public func findShortestPaths(from startVertex: Vertex) { + //Before we start searching shortes path from startVertex, + //we need to clear vertices cache just to be sure, that out graph is as clean as a baby. + //Remember that every Vertex is a class and classes are passed by reference. + //So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set + clearCache() + //Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. + + //The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) + + //Here starts the main part. We will use while loop to iterate through all vertices in the graph. + //For this purpose we define currentVertex variable, which we will change in the end of each while cycle. + var currentVertex: Vertex? = startVertex + + while let vertex = currentVertex { + + //Nex line of code is an implementation of setting vertex as visited. + //As it has been said, we should check only unvisited vertices in the graph, + //So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* + totalVertices.remove(vertex) + + //filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited + let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } + + //Let's iterate through them + for neighbor in filteredNeighbors { + //These variable are more representative, than neighbor.0 or neighbor.1 + let neighborVertex = neighbor.0 + let weight = neighbor.1 + + //Here we calculate new weight, that we can offer to neighbor. + let theoreticNewWeight = vertex.pathLengthFromStart + weight + + //If it is smaller than neighbor's current pathLengthFromStart + //Then we perform this code + if theoreticNewWeight < neighborVertex.pathLengthFromStart { + + //set new pathLengthFromStart + neighborVertex.pathLengthFromStart = theoreticNewWeight + + //set new pathVerticesFromStart + neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart + + //append current vertex to neighbor's pathVerticesFromStart + neighborVertex.pathVerticesFromStart.append(neighborVertex) + } + } + + //If totalVertices is empty, i.e. all vertices are visited + //Than break the loop + if totalVertices.isEmpty { + currentVertex = nil + break + } + + //If loop is not broken, than pick next vertex for checkin from not visited. + //Next vertex pathLengthFromStart should be the smallest one. + currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } + } + } +} +``` + +That's all! Now you can check this algorithm in the playground. On the main page there is a code for creating random graph. + +Also there is a **VisualizedDijkstra.playground**. Use it to figure out algorithm flow in real (slowed :)) time. + ## About this repository This repository contains to playgrounds: From aac4f8fbf24f6996b70ea5c1f792ba7b81cd9e98 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Tue, 25 Apr 2017 17:54:34 +0300 Subject: [PATCH 0576/1275] Fixed code comments --- Dijkstra Algorithm/README.md | 76 ++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index a72843e69..2b6bc3875 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -139,28 +139,28 @@ It is pretty simple ```swift open class Vertex { - //Every vertex should be unique, that's why we set up identifier +//Every vertex should be unique, that's why we set up identifier open var identifier: String - //For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, - //when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. - //Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. +//For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, +//when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. +//Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. open var neighbors: [(Vertex, Double)] = [] - //As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. - //It is var, because we will update it during algorithm execution. +//As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. +//It is var, because we will update it during algorithm execution. open var pathLengthFromStart = Double.infinity - //This array containt vertices, which we need to go through to reach this vertex from starting one - //As with path length from start, we will change this array during algorithm execution. +//This array containt vertices, which we need to go through to reach this vertex from starting one +//As with path length from start, we will change this array during algorithm execution. open var pathVerticesFromStart: [Vertex] = [] public init(identifier: String) { self.identifier = identifier } - //This function let us use the same array of vertices again and again to calculate paths with different starting vertex. - //When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. +//This function let us use the same array of vertices again and again to calculate paths with different starting vertex. +//When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. open func clearCache() { pathLengthFromStart = Double.infinity pathVerticesFromStart = [] @@ -187,79 +187,79 @@ We've created a base for our algorithm. Now let's create a house :) Dijkstra's realization is really straightforward. ```swift public class Dijkstra { - //It is a storage for vertices in the graph. - //Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. +//It is a storage for vertices in the graph. +//Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. private var totalVertices: Set public init(vertices: Set) { totalVertices = vertices } - //Remember clearCache function in the Vertex class implementation? - //This is just a wrapper that cleans cache for all stored vertices. +//Remember clearCache function in the Vertex class implementation? +//This is just a wrapper that cleans cache for all stored vertices. private func clearCache() { totalVertices.forEach { $0.clearCache() } } public func findShortestPaths(from startVertex: Vertex) { - //Before we start searching shortes path from startVertex, - //we need to clear vertices cache just to be sure, that out graph is as clean as a baby. - //Remember that every Vertex is a class and classes are passed by reference. - //So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set +//Before we start searching shortes path from startVertex, +//we need to clear vertices cache just to be sure, that out graph is as clean as a baby. +//Remember that every Vertex is a class and classes are passed by reference. +//So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set clearCache() - //Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. +//Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. - //The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart +//The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) - //Here starts the main part. We will use while loop to iterate through all vertices in the graph. - //For this purpose we define currentVertex variable, which we will change in the end of each while cycle. +//Here starts the main part. We will use while loop to iterate through all vertices in the graph. +//For this purpose we define currentVertex variable, which we will change in the end of each while cycle. var currentVertex: Vertex? = startVertex while let vertex = currentVertex { - //Nex line of code is an implementation of setting vertex as visited. - //As it has been said, we should check only unvisited vertices in the graph, - //So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* +//Nex line of code is an implementation of setting vertex as visited. +//As it has been said, we should check only unvisited vertices in the graph, +//So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* totalVertices.remove(vertex) - //filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited +//filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } - //Let's iterate through them +//Let's iterate through them for neighbor in filteredNeighbors { - //These variable are more representative, than neighbor.0 or neighbor.1 +//These variable are more representative, than neighbor.0 or neighbor.1 let neighborVertex = neighbor.0 let weight = neighbor.1 - //Here we calculate new weight, that we can offer to neighbor. +//Here we calculate new weight, that we can offer to neighbor. let theoreticNewWeight = vertex.pathLengthFromStart + weight - //If it is smaller than neighbor's current pathLengthFromStart - //Then we perform this code +//If it is smaller than neighbor's current pathLengthFromStart +//Then we perform this code if theoreticNewWeight < neighborVertex.pathLengthFromStart { - //set new pathLengthFromStart +//set new pathLengthFromStart neighborVertex.pathLengthFromStart = theoreticNewWeight - //set new pathVerticesFromStart +//set new pathVerticesFromStart neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart - //append current vertex to neighbor's pathVerticesFromStart +//append current vertex to neighbor's pathVerticesFromStart neighborVertex.pathVerticesFromStart.append(neighborVertex) } } - //If totalVertices is empty, i.e. all vertices are visited - //Than break the loop +//If totalVertices is empty, i.e. all vertices are visited +//Than break the loop if totalVertices.isEmpty { currentVertex = nil break } - //If loop is not broken, than pick next vertex for checkin from not visited. - //Next vertex pathLengthFromStart should be the smallest one. +//If loop is not broken, than pick next vertex for checkin from not visited. +//Next vertex pathLengthFromStart should be the smallest one. currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } } } From edbccd3b4fee79fe55ce2d741833dbef431bf466 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Tue, 25 Apr 2017 17:57:12 +0300 Subject: [PATCH 0577/1275] Fixed comments again --- Dijkstra Algorithm/README.md | 76 ++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 2b6bc3875..a8ed3c827 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -139,28 +139,28 @@ It is pretty simple ```swift open class Vertex { -//Every vertex should be unique, that's why we set up identifier + //Every vertex should be unique, that's why we set up identifier open var identifier: String -//For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, -//when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. -//Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. + //For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, + //when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. + //Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. open var neighbors: [(Vertex, Double)] = [] -//As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. -//It is var, because we will update it during algorithm execution. + //As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. + //It is var, because we will update it during algorithm execution. open var pathLengthFromStart = Double.infinity -//This array containt vertices, which we need to go through to reach this vertex from starting one -//As with path length from start, we will change this array during algorithm execution. + //This array containt vertices, which we need to go through to reach this vertex from starting one + //As with path length from start, we will change this array during algorithm execution. open var pathVerticesFromStart: [Vertex] = [] public init(identifier: String) { self.identifier = identifier } -//This function let us use the same array of vertices again and again to calculate paths with different starting vertex. -//When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. + //This function let us use the same array of vertices again and again to calculate paths with different starting vertex. + //When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. open func clearCache() { pathLengthFromStart = Double.infinity pathVerticesFromStart = [] @@ -187,79 +187,79 @@ We've created a base for our algorithm. Now let's create a house :) Dijkstra's realization is really straightforward. ```swift public class Dijkstra { -//It is a storage for vertices in the graph. -//Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. + //This is a storage for vertices in the graph. + //Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. private var totalVertices: Set public init(vertices: Set) { totalVertices = vertices } -//Remember clearCache function in the Vertex class implementation? -//This is just a wrapper that cleans cache for all stored vertices. + //Remember clearCache function in the Vertex class implementation? + //This is just a wrapper that cleans cache for all stored vertices. private func clearCache() { totalVertices.forEach { $0.clearCache() } } public func findShortestPaths(from startVertex: Vertex) { -//Before we start searching shortes path from startVertex, -//we need to clear vertices cache just to be sure, that out graph is as clean as a baby. -//Remember that every Vertex is a class and classes are passed by reference. -//So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set + //Before we start searching shortes path from startVertex, + //we need to clear vertices cache just to be sure, that out graph is as clean as a baby. + //Remember that every Vertex is a class and classes are passed by reference. + //So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set clearCache() -//Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. + //Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. -//The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart + //The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) -//Here starts the main part. We will use while loop to iterate through all vertices in the graph. -//For this purpose we define currentVertex variable, which we will change in the end of each while cycle. + //Here starts the main part. We will use while loop to iterate through all vertices in the graph. + //For this purpose we define currentVertex variable, which we will change in the end of each while cycle. var currentVertex: Vertex? = startVertex while let vertex = currentVertex { -//Nex line of code is an implementation of setting vertex as visited. -//As it has been said, we should check only unvisited vertices in the graph, -//So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* + //Nex line of code is an implementation of setting vertex as visited. + //As it has been said, we should check only unvisited vertices in the graph, + //So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* totalVertices.remove(vertex) -//filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited + //filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } -//Let's iterate through them + //Let's iterate through them for neighbor in filteredNeighbors { -//These variable are more representative, than neighbor.0 or neighbor.1 + //These variable are more representative, than neighbor.0 or neighbor.1 let neighborVertex = neighbor.0 let weight = neighbor.1 -//Here we calculate new weight, that we can offer to neighbor. + //Here we calculate new weight, that we can offer to neighbor. let theoreticNewWeight = vertex.pathLengthFromStart + weight -//If it is smaller than neighbor's current pathLengthFromStart -//Then we perform this code + //If it is smaller than neighbor's current pathLengthFromStart + //Then we perform this code if theoreticNewWeight < neighborVertex.pathLengthFromStart { -//set new pathLengthFromStart + //set new pathLengthFromStart neighborVertex.pathLengthFromStart = theoreticNewWeight -//set new pathVerticesFromStart + //set new pathVerticesFromStart neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart -//append current vertex to neighbor's pathVerticesFromStart + //append current vertex to neighbor's pathVerticesFromStart neighborVertex.pathVerticesFromStart.append(neighborVertex) } } -//If totalVertices is empty, i.e. all vertices are visited -//Than break the loop + //If totalVertices is empty, i.e. all vertices are visited + //Than break the loop if totalVertices.isEmpty { currentVertex = nil break } -//If loop is not broken, than pick next vertex for checkin from not visited. -//Next vertex pathLengthFromStart should be the smallest one. + //If loop is not broken, than pick next vertex for checkin from not visited. + //Next vertex pathLengthFromStart should be the smallest one. currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } } } From b6c5b820be7506bbbfec04b230bbedcda1b6f5d0 Mon Sep 17 00:00:00 2001 From: Taras Date: Tue, 25 Apr 2017 18:02:52 +0300 Subject: [PATCH 0578/1275] Update README.md --- Dijkstra Algorithm/README.md | 80 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index a8ed3c827..f8ac37cf0 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -139,28 +139,28 @@ It is pretty simple ```swift open class Vertex { - //Every vertex should be unique, that's why we set up identifier + //Every vertex should be unique, that's why we set up identifier open var identifier: String - //For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, - //when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. - //Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. + //For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases, + //when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array. + //Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor. open var neighbors: [(Vertex, Double)] = [] - //As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. - //It is var, because we will update it during algorithm execution. + //As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible. + //It is var, because we will update it during algorithm execution. open var pathLengthFromStart = Double.infinity - - //This array containt vertices, which we need to go through to reach this vertex from starting one - //As with path length from start, we will change this array during algorithm execution. + + //This array containt vertices, which we need to go through to reach this vertex from starting one + //As with path length from start, we will change this array during algorithm execution. open var pathVerticesFromStart: [Vertex] = [] public init(identifier: String) { self.identifier = identifier } - //This function let us use the same array of vertices again and again to calculate paths with different starting vertex. - //When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. + //This function let us use the same array of vertices again and again to calculate paths with different starting vertex. + //When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes. open func clearCache() { pathLengthFromStart = Double.infinity pathVerticesFromStart = [] @@ -187,79 +187,79 @@ We've created a base for our algorithm. Now let's create a house :) Dijkstra's realization is really straightforward. ```swift public class Dijkstra { - //This is a storage for vertices in the graph. - //Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. + //This is a storage for vertices in the graph. + //Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later. private var totalVertices: Set public init(vertices: Set) { totalVertices = vertices } - //Remember clearCache function in the Vertex class implementation? - //This is just a wrapper that cleans cache for all stored vertices. + //Remember clearCache function in the Vertex class implementation? + //This is just a wrapper that cleans cache for all stored vertices. private func clearCache() { totalVertices.forEach { $0.clearCache() } } public func findShortestPaths(from startVertex: Vertex) { - //Before we start searching shortes path from startVertex, - //we need to clear vertices cache just to be sure, that out graph is as clean as a baby. - //Remember that every Vertex is a class and classes are passed by reference. - //So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set + //Before we start searching shortes path from startVertex, + //we need to clear vertices cache just to be sure, that out graph is as clean as a baby. + //Remember that every Vertex is a class and classes are passed by reference. + //So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set clearCache() - //Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. + //Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array. - //The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart + //The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) - //Here starts the main part. We will use while loop to iterate through all vertices in the graph. - //For this purpose we define currentVertex variable, which we will change in the end of each while cycle. + //Here starts the main part. We will use while loop to iterate through all vertices in the graph. + //For this purpose we define currentVertex variable, which we will change in the end of each while cycle. var currentVertex: Vertex? = startVertex while let vertex = currentVertex { - - //Nex line of code is an implementation of setting vertex as visited. - //As it has been said, we should check only unvisited vertices in the graph, - //So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* + + //Nex line of code is an implementation of setting vertex as visited. + //As it has been said, we should check only unvisited vertices in the graph, + //So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"* totalVertices.remove(vertex) - //filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited + //filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } - //Let's iterate through them + //Let's iterate through them for neighbor in filteredNeighbors { - //These variable are more representative, than neighbor.0 or neighbor.1 + //These variable are more representative, than neighbor.0 or neighbor.1 let neighborVertex = neighbor.0 let weight = neighbor.1 - //Here we calculate new weight, that we can offer to neighbor. + //Here we calculate new weight, that we can offer to neighbor. let theoreticNewWeight = vertex.pathLengthFromStart + weight - //If it is smaller than neighbor's current pathLengthFromStart - //Then we perform this code + //If it is smaller than neighbor's current pathLengthFromStart + //Then we perform this code if theoreticNewWeight < neighborVertex.pathLengthFromStart { - //set new pathLengthFromStart + //set new pathLengthFromStart neighborVertex.pathLengthFromStart = theoreticNewWeight - //set new pathVerticesFromStart + //set new pathVerticesFromStart neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart - //append current vertex to neighbor's pathVerticesFromStart + //append current vertex to neighbor's pathVerticesFromStart neighborVertex.pathVerticesFromStart.append(neighborVertex) } } - //If totalVertices is empty, i.e. all vertices are visited - //Than break the loop + //If totalVertices is empty, i.e. all vertices are visited + //Than break the loop if totalVertices.isEmpty { currentVertex = nil break } - //If loop is not broken, than pick next vertex for checkin from not visited. - //Next vertex pathLengthFromStart should be the smallest one. + //If loop is not broken, than pick next vertex for checkin from not visited. + //Next vertex pathLengthFromStart should be the smallest one. currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } } } From 9575a6745caa33bc5d864d6e406682af2f5f9515 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Tue, 25 Apr 2017 18:22:00 +0300 Subject: [PATCH 0579/1275] Added some comments to playground --- Dijkstra Algorithm/Dijkstra.playground/Contents.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index 1c12245bd..7c7f1a4b0 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -14,13 +14,18 @@ func createNotConnectedVertices() { func setupConnections() { for vertex in vertices { + //the amount of edges each vertex can have let randomEdgesCount = arc4random_uniform(4) + 1 for _ in 0.. Date: Wed, 26 Apr 2017 10:31:44 +0300 Subject: [PATCH 0580/1275] Final edits --- Dijkstra Algorithm/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index f8ac37cf0..db1726b1f 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -2,13 +2,13 @@ This [algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) was invented in 1956 by Edsger W. Dijkstra. -This algorithm can be used, when you have one source vertex and want to find the shortest paths to all other vertices in the graph. +It can be used, when you have one source vertex and want to find the shortest paths to all other vertices in the graph. The best example is road network. If you wnat to find the shortest path from your house to your job, then it is time for the Dijkstra's algorithm. -I have created **VisualizedDijkstra.playground** to help you to understand, how this algorithm works. Besides, I have described below step by step how does it works. +I have created **VisualizedDijkstra.playground** to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. -So let's imagine, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. +Let's imagine, you want to go to the shop. Your house is A vertex and there are 4 possible stores around your house. How to find the closest one/ones? Luckily, you have graph, that connects your house with all these stores. So, you know what to do :) ## Initialization @@ -30,7 +30,7 @@ The table below represents graph state: >T states for True -To initialize out graph we have to set source vertex path length from source vertex to 0, and append itself to path vertices ffrom start. +To initialize our graph we have to set source vertex path length from source vertex to 0, and append itself to path vertices from start. | | A | B | C | D | E | |:------------------------- |:---:|:---:|:---:|:---:|:---:| @@ -40,7 +40,7 @@ To initialize out graph we have to set source vertex path length from source ver Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm. -But before we will go through all process side by side let me explain how algorithm works. +But before we will go through all process side by side read this explanation. The algorithm repeats following cycle until all vertices are marked as visited. Cycle: 1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) @@ -50,7 +50,7 @@ When all vertices are marked as visited, the algorithm's job is done. Now, you c Okay, let's start! Let's follow the algorithm's cycle and pick the first vertex, which neighbors we want to check. -All our vertices are not visited, but there is only one have the smallest path length from start - A. This vertex is th first one, which neighbors we will check. +All our vertices are not visited, but there is only one has the smallest path length from start - A. This vertex is the first one, which neighbors we will check. First of all, set this vertex as visited A.visited = true @@ -268,7 +268,9 @@ public class Dijkstra { That's all! Now you can check this algorithm in the playground. On the main page there is a code for creating random graph. -Also there is a **VisualizedDijkstra.playground**. Use it to figure out algorithm flow in real (slowed :)) time. +Also there is a **VisualizedDijkstra.playground**. Use it to figure out algorithm's flow in real (slowed :)) time. + +It is up to you how to implement some specific parts of algorithm, you can use Array instead of Set, add _visited_ property to Vertex or you can create some local totalVertices Array/Set inside _func findShortestPaths(from startVertex: Vertex)_ to keep totalVertices Array/Set unchanged. This is a general explanation with one possible implementation :) ## About this repository From d79a076ea901657161392a4fc3b53b0e2df65cdd Mon Sep 17 00:00:00 2001 From: Lucy Jeong Date: Thu, 27 Apr 2017 11:31:57 +0900 Subject: [PATCH 0581/1275] Update README.markdown changed enumerate() -> enumerated() --- Hash Table/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index bc9636195..8f1eaaf70 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -202,7 +202,7 @@ The code to insert a new element or update an existing element lives in `updateV let index = self.index(forKey: key) // Do we already have this key in the bucket? - for (i, element) in buckets[index].enumerate() { + for (i, element) in buckets[index].enumerated() { if element.key == key { let oldValue = element.value buckets[index][i].value = value From 03393a86a3864221ff1f0b7137eefb619bf19698 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 06:17:13 +0500 Subject: [PATCH 0582/1275] Fix "found unknown escape character" while trying to run swiftlint 0.18.1 Also update the smiley face regex check to have a space before the colon so that it doesn't match: fatalError("init(coder:) has not been implemented") --- .swiftlint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 1434bf637..6cb714110 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -17,8 +17,8 @@ disabled_rules: custom_rules: smiley_face: name: "Smiley Face" - regex: "(\:\))" - match_kinds: + regex: '( :\))' + match_kinds: - comment - string message: "A closing parenthesis smiley :) creates a half-hearted smile, and thus is not preferred. Use :]" From 018ddaccfc0276ac8740c093731b92aeae122a9d Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:42:15 +0500 Subject: [PATCH 0583/1275] [swiftlint] Fix: MARK comment should be in valid format. --- .../TST.playground/Sources/TernarySearchTree.swift | 4 ++-- Ternary Search Tree/TernarySearchTree.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift index fed8f9710..21b8f0dc3 100644 --- a/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift +++ b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift @@ -15,7 +15,7 @@ public class TernarySearchTree { public init() {} - //MARK: - Insertion + // MARK: - Insertion public func insert(data: Element, withKey key: String) -> Bool { return insert(node: &root, withData: data, andKey: key, atIndex: 0) @@ -59,7 +59,7 @@ public class TernarySearchTree { } - //MARK: - Finding + // MARK: - Finding public func find(key: String) -> Element? { diff --git a/Ternary Search Tree/TernarySearchTree.swift b/Ternary Search Tree/TernarySearchTree.swift index 2e2ca2917..0fa6d9634 100644 --- a/Ternary Search Tree/TernarySearchTree.swift +++ b/Ternary Search Tree/TernarySearchTree.swift @@ -23,7 +23,7 @@ public class TernarySearchTree { */ public init() {} - //MARK: - Insertion + // MARK: - Insertion /** Public insertion method. @@ -85,7 +85,7 @@ public class TernarySearchTree { } - //MARK: - Finding + // MARK: - Finding /** Public find method. From 29c5952fadf80e8ac3f0c717d7d7ae08620b0dcb Mon Sep 17 00:00:00 2001 From: Felipe Naranjo Date: Fri, 28 Apr 2017 10:57:48 -0400 Subject: [PATCH 0584/1275] Update README.markdown Though "indexes" is grammatically correct, the word "indices" is used in Apple documentation. --- Union-Find/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Union-Find/README.markdown b/Union-Find/README.markdown index 5102f6b89..68698f39e 100644 --- a/Union-Find/README.markdown +++ b/Union-Find/README.markdown @@ -119,7 +119,7 @@ Here's illustration of what I mean. Let's say the tree looks like this: ![BeforeFind](Images/BeforeFind.png) -We call `setOf(4)`. To find the root node we have to first go to node `2` and then to node `7`. (The indexes of the elements are marked in red.) +We call `setOf(4)`. To find the root node we have to first go to node `2` and then to node `7`. (The indices of the elements are marked in red.) During the call to `setOf(4)`, the tree is reorganized to look like this: From 137c36051dff6a1e3965dad4959ad0a742fc01b4 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:46:49 +0500 Subject: [PATCH 0585/1275] [swiftlint] Fix: Else and catch should be on the same line warning: Statement Position Violation: Else and catch should be on the same line, one space after the previous declaration. --- DiningPhilosophers/Sources/main.swift | 3 +-- Skip-List/SkipList.swift | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DiningPhilosophers/Sources/main.swift b/DiningPhilosophers/Sources/main.swift index 285402d53..338a9074d 100755 --- a/DiningPhilosophers/Sources/main.swift +++ b/DiningPhilosophers/Sources/main.swift @@ -22,8 +22,7 @@ struct ForkPair { if leftIndex > rightIndex { leftFork = ForkPair.forksSemaphore[leftIndex] rightFork = ForkPair.forksSemaphore[rightIndex] - } - else { + } else { leftFork = ForkPair.forksSemaphore[rightIndex] rightFork = ForkPair.forksSemaphore[leftIndex] } diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index 5fc61bf8e..c5fe2b821 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -118,8 +118,7 @@ extension SkipList { if value.key == key { isFound = true break - } - else { + } else { if key < value.key! { currentNode = node.down } else { From c3a05c6bfe865554261fbb0b641651f7dcfffff4 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:49:54 +0500 Subject: [PATCH 0586/1275] [swiftlint] Fix: trailing_semicolon warning: Trailing Semicolon Violation: Lines should not have trailing semicolons. --- Trie/Trie/TrieTests/TrieTests.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index a75c35c62..50a30a552 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -175,21 +175,21 @@ class TrieTests: XCTestCase { trie.insert(word: "another") trie.insert(word: "exam") let wordsAll = trie.findWordsWithPrefix(prefix: "") - XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]); + XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) let words = trie.findWordsWithPrefix(prefix: "ex") - XCTAssertEqual(words, ["exam"]); + XCTAssertEqual(words, ["exam"]) trie.insert(word: "examination") let words2 = trie.findWordsWithPrefix(prefix: "exam") - XCTAssertEqual(words2, ["exam", "examination"]); + XCTAssertEqual(words2, ["exam", "examination"]) let noWords = trie.findWordsWithPrefix(prefix: "tee") - XCTAssertEqual(noWords, []); + XCTAssertEqual(noWords, []) let unicodeWord = "😬😎" trie.insert(word: unicodeWord) let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") - XCTAssertEqual(wordsUnicode, [unicodeWord]); + XCTAssertEqual(wordsUnicode, [unicodeWord]) trie.insert(word: "Team") let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") - XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]); + XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) } } From 4eb7ac1975dfbd2f3d9059d649af3ab6f90d97a2 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:52:12 +0500 Subject: [PATCH 0587/1275] [swiftlint] Fix control_statement (i.e. parens around if statement) warning: Control Statement Violation: if,for,while,do statements shouldn't wrap their conditionals in parentheses. --- Rootish Array Stack/Tests/RootishArrayStackTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rootish Array Stack/Tests/RootishArrayStackTests.swift b/Rootish Array Stack/Tests/RootishArrayStackTests.swift index f73857d0f..9ffc4ebb9 100755 --- a/Rootish Array Stack/Tests/RootishArrayStackTests.swift +++ b/Rootish Array Stack/Tests/RootishArrayStackTests.swift @@ -4,7 +4,7 @@ fileprivate extension RootishArrayStack { func equal(toArray array: Array) -> Bool{ for index in 0.. Date: Fri, 28 Apr 2017 09:53:16 +0500 Subject: [PATCH 0588/1275] [swiftlint] Fix redundant_optional_initialization (i.e. don't need "= nil") warning: Redundant Optional Initialization Violation: Initializing an optional variable with nil is redundant. --- Graph/Graph/AdjacencyListGraph.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graph/Graph/AdjacencyListGraph.swift b/Graph/Graph/AdjacencyListGraph.swift index e5e9fc2db..edb754c97 100644 --- a/Graph/Graph/AdjacencyListGraph.swift +++ b/Graph/Graph/AdjacencyListGraph.swift @@ -12,7 +12,7 @@ import Foundation private class EdgeList where T: Equatable, T: Hashable { var vertex: Vertex - var edges: [Edge]? = nil + var edges: [Edge]? init(vertex: Vertex) { self.vertex = vertex From 55eba6e7d86e468b1cb0f114c25f5439cf2d4702 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:55:51 +0500 Subject: [PATCH 0589/1275] [swiftlint] Fix: closure_parameter_position warning: Closure Parameter Position Violation: Closure parameters should be on the same line as opening brace. --- B-Tree/BTree.playground/Contents.swift | 3 +-- Shunting Yard/ShuntingYard.playground/Sources/Stack.swift | 3 +-- Skip-List/SkipList.swift | 7 +++---- Stack/Stack.swift | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift index 8238fe5a5..710ace701 100644 --- a/B-Tree/BTree.playground/Contents.swift +++ b/B-Tree/BTree.playground/Contents.swift @@ -14,8 +14,7 @@ bTree[3] bTree.remove(2) -bTree.traverseKeysInOrder { - key in +bTree.traverseKeysInOrder { key in print(key) } diff --git a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift index a67bb9d64..27286fdbd 100644 --- a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift +++ b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift @@ -31,8 +31,7 @@ public struct Stack { extension Stack: Sequence { public func makeIterator() -> AnyIterator { var curr = self - return AnyIterator { - _ -> T? in + return AnyIterator { _ -> T? in return curr.pop() } } diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index c5fe2b821..1418656f3 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -52,10 +52,9 @@ public struct Stack { extension Stack: Sequence { public func makeIterator() -> AnyIterator { var curr = self - return AnyIterator { - _ -> T? in - return curr.pop() - } + return AnyIterator { _ -> T? in + return curr.pop() + } } } diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 974d5a443..c3f42ea44 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -30,8 +30,7 @@ public struct Stack { extension Stack: Sequence { public func makeIterator() -> AnyIterator { var curr = self - return AnyIterator { - _ -> T? in + return AnyIterator { _ -> T? in return curr.pop() } } From 6c3dcd4be40058e09875d4bcd3f6086e021380e4 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:57:19 +0500 Subject: [PATCH 0590/1275] [swiftlint] Fix: leading_whitespace warning: Leading Whitespace Violation: File shouldn't start with whitespace. --- HaversineDistance/HaversineDistance.playground/Contents.swift | 1 - QuadTree/QuadTree.playground/Contents.swift | 1 - QuadTree/QuadTree.playground/Sources/QuadTree.swift | 1 - Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift | 1 - 4 files changed, 4 deletions(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index f46d7c394..a6effb7b0 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,4 +1,3 @@ - import UIKit func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { diff --git a/QuadTree/QuadTree.playground/Contents.swift b/QuadTree/QuadTree.playground/Contents.swift index 41e73147f..ad8ee31f8 100644 --- a/QuadTree/QuadTree.playground/Contents.swift +++ b/QuadTree/QuadTree.playground/Contents.swift @@ -1,4 +1,3 @@ - import Foundation let tree = QuadTree(rect: Rect(origin: Point(0, 0), size: Size(xLength: 10, yLength: 10))) diff --git a/QuadTree/QuadTree.playground/Sources/QuadTree.swift b/QuadTree/QuadTree.playground/Sources/QuadTree.swift index 65c55d49e..14d0dbba7 100644 --- a/QuadTree/QuadTree.playground/Sources/QuadTree.swift +++ b/QuadTree/QuadTree.playground/Sources/QuadTree.swift @@ -1,4 +1,3 @@ - public struct Point { let x: Double let y: Double diff --git a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift index 1735798d5..b0f440809 100644 --- a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -1,4 +1,3 @@ - private enum RBTColor { case red case black From 932b453d5b0ce1b5ad058323bed79728f92dfd52 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 09:58:51 +0500 Subject: [PATCH 0591/1275] [swiftlint] Fix rule: trailing_newline warning: Trailing Newline Violation: Files should have a single trailing newline. --- B-Tree/Tests/Tests/BTreeNodeTests.swift | 1 - Comb Sort/Comb Sort.playground/Contents.swift | 2 -- Convex Hull/Convex Hull/AppDelegate.swift | 1 - Fixed Size Array/FixedSizeArray.playground/Contents.swift | 1 - Insertion Sort/InsertionSort.playground/Contents.swift | 2 +- Linked List/LinkedList.playground/Contents.swift | 1 - .../MRPrimality.playground/Contents.swift | 2 +- Run-Length Encoding/RLE.playground/Contents.swift | 2 +- Trie/Trie/Trie/AppDelegate.swift | 1 - Trie/Trie/Trie/ViewController.swift | 1 - 10 files changed, 3 insertions(+), 11 deletions(-) diff --git a/B-Tree/Tests/Tests/BTreeNodeTests.swift b/B-Tree/Tests/Tests/BTreeNodeTests.swift index da6ebe9f6..fd3ba10e8 100644 --- a/B-Tree/Tests/Tests/BTreeNodeTests.swift +++ b/B-Tree/Tests/Tests/BTreeNodeTests.swift @@ -51,4 +51,3 @@ class BTreeNodeTests: XCTestCase { XCTAssertEqual(root.children!.count, 2) } } - diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift index d6add44f5..40176be9f 100644 --- a/Comb Sort/Comb Sort.playground/Contents.swift +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -16,5 +16,3 @@ while i < 1000 { i += 1 } combSort(bigArray) - - diff --git a/Convex Hull/Convex Hull/AppDelegate.swift b/Convex Hull/Convex Hull/AppDelegate.swift index 1901083a8..4f8496cd5 100644 --- a/Convex Hull/Convex Hull/AppDelegate.swift +++ b/Convex Hull/Convex Hull/AppDelegate.swift @@ -54,4 +54,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } - diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index f1bc63315..4bc5d66df 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -53,4 +53,3 @@ array.append(2) array[1] array.removeAt(index: 0) array.removeAll() - diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index b25916b23..df1822b8f 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -16,4 +16,4 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] insertionSort(list, <) -insertionSort(list, >) \ No newline at end of file +insertionSort(list, >) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index b86fbf0b4..10677935a 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -389,4 +389,3 @@ let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] listArrayLiteral2.count // 3 listArrayLiteral2[0] // "Swift" listArrayLiteral2.removeLast() // "Club" - diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift index 8d97dc409..98032bd59 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -21,4 +21,4 @@ mrPrimalityTest(178426363) mrPrimalityTest(32415187747) // With iteration -mrPrimalityTest(32416190071, iteration: 10) \ No newline at end of file +mrPrimalityTest(32416190071, iteration: 10) diff --git a/Run-Length Encoding/RLE.playground/Contents.swift b/Run-Length Encoding/RLE.playground/Contents.swift index 62b4ef437..11e177d0d 100644 --- a/Run-Length Encoding/RLE.playground/Contents.swift +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -113,4 +113,4 @@ func runTests() -> Bool { return result } -runTests() \ No newline at end of file +runTests() diff --git a/Trie/Trie/Trie/AppDelegate.swift b/Trie/Trie/Trie/AppDelegate.swift index 4da9dc345..b2b4c0c5f 100644 --- a/Trie/Trie/Trie/AppDelegate.swift +++ b/Trie/Trie/Trie/AppDelegate.swift @@ -23,4 +23,3 @@ class AppDelegate: NSObject, NSApplicationDelegate { } - diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift index b2e9d9105..e24a812cb 100644 --- a/Trie/Trie/Trie/ViewController.swift +++ b/Trie/Trie/Trie/ViewController.swift @@ -24,4 +24,3 @@ class ViewController: NSViewController { } - From a025c0cc27b3fa4b8bfa2255f59eceb8447ad9b3 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 10:00:27 +0500 Subject: [PATCH 0592/1275] [swiftlint] Fix rule: opening_brace warning: Opening Brace Spacing Violation: Opening braces should be preceded by a single space and on the same line as the declaration. --- .../BruteForceStringSearch.playground/Contents.swift | 2 +- Brute-Force String Search/BruteForceStringSearch.swift | 2 +- .../KaratsubaMultiplication.playground/Contents.swift | 6 +++--- .../Red-Black Tree 2.playground/Sources/RBTree.swift | 2 +- Rootish Array Stack/Tests/RootishArrayStackTests.swift | 2 +- Shell Sort/ShellSortExample.swift | 2 +- Skip-List/SkipList.swift | 2 +- .../Sources/Number.swift | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift index 61064c698..00ac6da97 100644 --- a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift +++ b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift @@ -6,7 +6,7 @@ extension String { for i in self.characters.indices { var j = i var found = true - for p in pattern.characters.indices{ + for p in pattern.characters.indices { if j == self.characters.endIndex || self[j] != pattern[p] { found = false break diff --git a/Brute-Force String Search/BruteForceStringSearch.swift b/Brute-Force String Search/BruteForceStringSearch.swift index 03a2dff13..016292304 100644 --- a/Brute-Force String Search/BruteForceStringSearch.swift +++ b/Brute-Force String Search/BruteForceStringSearch.swift @@ -6,7 +6,7 @@ extension String { for i in self.characters.indices { var j = i var found = true - for p in pattern.characters.indices{ + for p in pattern.characters.indices { if j == self.characters.endIndex || self[j] != pattern[p] { found = false break diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index bde8fd9f9..3ac29301a 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -15,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).characters.reversed().map { Int(String($0))! } + let num2Array = String(num2).characters.reversed().map { Int(String($0))! } var product = Array(repeating: 0, count: num1Array.count + num2Array.count) @@ -30,7 +30,7 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { product[i + num2Array.count] += carry } - return Int(product.reversed().map{ String($0) }.reduce("", +))! + return Int(product.reversed().map { String($0) }.reduce("", +))! } // Karatsuba Multiplication - O(n^log2(3)) diff --git a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift index b0f440809..0038494d3 100644 --- a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -22,7 +22,7 @@ public class RBTNode: CustomStringConvertible { // If the value is encapsulated by double pipes it is double black (This should not occur in a verified RBTree) if self.isRed { nodeValue = "(\(self.value!))" - } else if self.isBlack{ + } else if self.isBlack { nodeValue = "|\(self.value!)|" } else { nodeValue = "||\(self.value!)||" diff --git a/Rootish Array Stack/Tests/RootishArrayStackTests.swift b/Rootish Array Stack/Tests/RootishArrayStackTests.swift index 9ffc4ebb9..f0aaa8bca 100755 --- a/Rootish Array Stack/Tests/RootishArrayStackTests.swift +++ b/Rootish Array Stack/Tests/RootishArrayStackTests.swift @@ -1,7 +1,7 @@ import XCTest fileprivate extension RootishArrayStack { - func equal(toArray array: Array) -> Bool{ + func equal(toArray array: Array) -> Bool { for index in 0.. 0 else { continue } - while list[index - 1] > list[index] && index - 1 > 0 { + while list[index - 1] > list[index] && index - 1 > 0 { swap(&list[index - 1], &list[index]) index -= 1 } diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index 1418656f3..52de1412e 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -283,7 +283,7 @@ extension SkipList { extension SkipList { - public func get(key:Key) -> Payload?{ + public func get(key:Key) -> Payload? { return search(key: key) } } diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift index 7da1eee60..69afe76e4 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift @@ -37,7 +37,7 @@ extension Array where Element: Number { public func dot(_ b: Array) -> Element { let a = self assert(a.count == b.count, "Can only take the dot product of arrays of the same length!") - let c = a.indices.map{ a[$0] * b[$0] } + let c = a.indices.map { a[$0] * b[$0] } return c.reduce(Element.zero, { $0 + $1 }) } } From 44adf5a8f6ac5e14ca74b761fbdd01083100ccf8 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 10:01:33 +0500 Subject: [PATCH 0593/1275] [swiftlint] Fix rule: empty_parentheses_with_trailing_closure warning: Empty Parentheses with Trailing Closure Violation: When using trailing closures, empty parentheses should be avoided after the method call. --- All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift | 2 +- Bloom Filter/BloomFilter.playground/Contents.swift | 4 ++-- Bloom Filter/BloomFilter.swift | 4 ++-- Graph/Graph/AdjacencyListGraph.swift | 2 +- Graph/Graph/AdjacencyMatrixGraph.swift | 2 +- .../SSSP/BellmanFord.swift | 4 ++-- Trie/Trie/TrieTests/TrieTests.swift | 8 ++++---- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift index b1a870f2a..7bc78f326 100644 --- a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift +++ b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift @@ -175,7 +175,7 @@ public struct FloydWarshallResult: APSPResult where T: Hashable { public func path(fromVertex from: Vertex, toVertex to: Vertex, inGraph graph: AbstractGraph) -> [T]? { if let path = recursePathFrom(fromVertex: from, toVertex: to, path: [ to ], inGraph: graph) { - let pathValues = path.map() { vertex in + let pathValues = path.map { vertex in vertex.data } return pathValues diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index d5e7d2dc6..06022c9b3 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -10,7 +10,7 @@ public class BloomFilter { } private func computeHashes(_ value: T) -> [Int] { - return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } + return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } } public func insert(_ element: T) { @@ -29,7 +29,7 @@ public class BloomFilter { let hashValues = computeHashes(value) // Map hashes to indices in the Bloom Filter - let results = hashValues.map() { hashValue in array[hashValue] } + let results = hashValues.map { hashValue in array[hashValue] } // All values must be 'true' for the query to return true diff --git a/Bloom Filter/BloomFilter.swift b/Bloom Filter/BloomFilter.swift index 03b5333f1..56c3be328 100644 --- a/Bloom Filter/BloomFilter.swift +++ b/Bloom Filter/BloomFilter.swift @@ -8,7 +8,7 @@ public class BloomFilter { } private func computeHashes(_ value: T) -> [Int] { - return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } + return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } } public func insert(_ element: T) { @@ -27,7 +27,7 @@ public class BloomFilter { let hashValues = computeHashes(value) // Map hashes to indices in the Bloom Filter - let results = hashValues.map() { hashValue in array[hashValue] } + let results = hashValues.map { hashValue in array[hashValue] } // All values must be 'true' for the query to return true diff --git a/Graph/Graph/AdjacencyListGraph.swift b/Graph/Graph/AdjacencyListGraph.swift index edb754c97..3d86c78f7 100644 --- a/Graph/Graph/AdjacencyListGraph.swift +++ b/Graph/Graph/AdjacencyListGraph.swift @@ -64,7 +64,7 @@ open class AdjacencyListGraph: AbstractGraph where T: Equatable, T: Hashab open override func createVertex(_ data: T) -> Vertex { // check if the vertex already exists - let matchingVertices = vertices.filter() { vertex in + let matchingVertices = vertices.filter { vertex in return vertex.data == data } diff --git a/Graph/Graph/AdjacencyMatrixGraph.swift b/Graph/Graph/AdjacencyMatrixGraph.swift index 8f357bc8c..a9b43fb6d 100644 --- a/Graph/Graph/AdjacencyMatrixGraph.swift +++ b/Graph/Graph/AdjacencyMatrixGraph.swift @@ -46,7 +46,7 @@ open class AdjacencyMatrixGraph: AbstractGraph where T: Equatable, T: Hash // Performance: possibly O(n^2) because of the resizing of the matrix. open override func createVertex(_ data: T) -> Vertex { // check if the vertex already exists - let matchingVertices = vertices.filter() { vertex in + let matchingVertices = vertices.filter { vertex in return vertex.data == data } diff --git a/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift b/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift index 5b6670806..41be9759b 100644 --- a/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift +++ b/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift @@ -41,7 +41,7 @@ extension BellmanFord: SSSPAlgorithm { for _ in 0 ..< vertices.count - 1 { var weightsUpdated = false - edges.forEach() { edge in + edges.forEach { edge in let weight = edge.weight! let relaxedDistance = weights[edge.from.index] + weight let nextVertexIdx = edge.to.index @@ -116,7 +116,7 @@ extension BellmanFordResult: SSSPResult { return nil } - return path.map() { vertex in + return path.map { vertex in return vertex.data } } diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 50a30a552..960b65791 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -101,7 +101,7 @@ class TrieTests: XCTestCase { /// Tests the performance of the insert method. func testInsertPerformance() { - self.measure() { + self.measure { let trie = Trie() for word in self.wordArray! { trie.insert(word: word) @@ -114,7 +114,7 @@ class TrieTests: XCTestCase { /// Tests the performance of the insert method when the words are already /// present. func testInsertAgainPerformance() { - self.measure() { + self.measure { for word in self.wordArray! { self.trie.insert(word: word) } @@ -123,7 +123,7 @@ class TrieTests: XCTestCase { /// Tests the performance of the contains method. func testContainsPerformance() { - self.measure() { + self.measure { for word in self.wordArray! { XCTAssertTrue(self.trie.contains(word: word)) } @@ -136,7 +136,7 @@ class TrieTests: XCTestCase { for word in self.wordArray! { self.trie.remove(word: word) } - self.measure() { + self.measure { self.insertWordsIntoTrie() for word in self.wordArray! { self.trie.remove(word: word) From 71c0e32fbc9794289199c3a8bbe0e1719a9b2ece Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Fri, 28 Apr 2017 10:05:34 +0500 Subject: [PATCH 0594/1275] [swiftlint] Fix rule: colon (i.e. should be next to identifier) warning: Colon Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals. --- .../BucketSort.playground/Sources/BucketSort.swift | 2 +- Bucket Sort/BucketSort.swift | 2 +- Convex Hull/Convex Hull/View.swift | 2 +- Deque/Deque-Optimized.swift | 2 +- Linked List/LinkedList.playground/Contents.swift | 2 +- Linked List/LinkedList.swift | 2 +- .../Red-Black Tree 2.playground/Sources/RBTree.swift | 8 ++++---- Skip-List/SkipList.swift | 2 +- Topological Sort/Graph.swift | 4 ++-- .../Topological Sort.playground/Sources/Graph.swift | 4 ++-- .../Sources/TopologicalSort1.swift | 2 +- Topological Sort/TopologicalSort1.swift | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift index e510e51b4..08962c0e1 100644 --- a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift +++ b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift @@ -122,7 +122,7 @@ public struct InsertionSorter: Sorter { // MARK: Bucket ////////////////////////////////////// -public struct Bucket { +public struct Bucket { var elements: [T] let capacity: Int diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift index ef72c67dc..ff36b372a 100644 --- a/Bucket Sort/BucketSort.swift +++ b/Bucket Sort/BucketSort.swift @@ -173,7 +173,7 @@ public struct InsertionSorter: Sorter { // MARK: Bucket ////////////////////////////////////// -public struct Bucket { +public struct Bucket { var elements: [T] let capacity: Int diff --git a/Convex Hull/Convex Hull/View.swift b/Convex Hull/Convex Hull/View.swift index 2d7157e6f..f9f9f6ef4 100644 --- a/Convex Hull/Convex Hull/View.swift +++ b/Convex Hull/Convex Hull/View.swift @@ -150,7 +150,7 @@ class View: UIView { let context = UIGraphicsGetCurrentContext() // Draw hull - let lineWidth:CGFloat = 2.0 + let lineWidth: CGFloat = 2.0 context!.setFillColor(UIColor.black.cgColor) context!.setLineWidth(lineWidth) diff --git a/Deque/Deque-Optimized.swift b/Deque/Deque-Optimized.swift index f565458c7..4eea01f1a 100644 --- a/Deque/Deque-Optimized.swift +++ b/Deque/Deque-Optimized.swift @@ -7,7 +7,7 @@ public struct Deque { private var array: [T?] private var head: Int private var capacity: Int - private let originalCapacity:Int + private let originalCapacity: Int public init(_ capacity: Int = 10) { self.capacity = max(capacity, 1) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 10677935a..08e14ef70 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -177,7 +177,7 @@ public final class LinkedList { if list.isEmpty { return } var (prev, next) = nodesBeforeAndAfter(index: index) var nodeToCopy = list.head - var newNode:Node? + var newNode: Node? while let node = nodeToCopy { newNode = Node(value: node.value) newNode?.previous = prev diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index a7ef9bf5e..783e650e8 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -129,7 +129,7 @@ public final class LinkedList { if list.isEmpty { return } var (prev, next) = nodesBeforeAndAfter(index: index) var nodeToCopy = list.head - var newNode:Node? + var newNode: Node? while let node = nodeToCopy { newNode = Node(value: node.value) newNode?.previous = prev diff --git a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift index 0038494d3..42a68237e 100644 --- a/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift +++ b/Red-Black Tree/Red-Black Tree 2.playground/Sources/RBTree.swift @@ -7,9 +7,9 @@ private enum RBTColor { public class RBTNode: CustomStringConvertible { fileprivate var color: RBTColor = .red public var value: T! = nil - public var right: RBTNode! - public var left: RBTNode! - public var parent: RBTNode! + public var right: RBTNode! + public var left: RBTNode! + public var parent: RBTNode! public var description: String { if self.value == nil { @@ -435,7 +435,7 @@ public class RBTree: CustomStringConvertible { private func property3() { let bDepth = blackDepth(root: self.root) - let leaves:[RBTNode] = getLeaves(n: self.root) + let leaves: [RBTNode] = getLeaves(n: self.root) for leaflet in leaves { var leaf = leaflet diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index 52de1412e..14b5a4076 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -283,7 +283,7 @@ extension SkipList { extension SkipList { - public func get(key:Key) -> Payload? { + public func get(key: Key) -> Payload? { return search(key: key) } } diff --git a/Topological Sort/Graph.swift b/Topological Sort/Graph.swift index 1e1be6919..5032ba1d1 100644 --- a/Topological Sort/Graph.swift +++ b/Topological Sort/Graph.swift @@ -4,7 +4,7 @@ public class Graph: CustomStringConvertible { private(set) public var adjacencyLists: [Node : [Node]] public init() { - adjacencyLists = [Node : [Node]]() + adjacencyLists = [Node: [Node]]() } public func addNode(_ value: Node) -> Node { @@ -35,7 +35,7 @@ extension Graph { typealias InDegree = Int func calculateInDegreeOfNodes() -> [Node : InDegree] { - var inDegrees = [Node : InDegree]() + var inDegrees = [Node: InDegree]() for (node, _) in adjacencyLists { inDegrees[node] = 0 diff --git a/Topological Sort/Topological Sort.playground/Sources/Graph.swift b/Topological Sort/Topological Sort.playground/Sources/Graph.swift index 1e1be6919..5032ba1d1 100644 --- a/Topological Sort/Topological Sort.playground/Sources/Graph.swift +++ b/Topological Sort/Topological Sort.playground/Sources/Graph.swift @@ -4,7 +4,7 @@ public class Graph: CustomStringConvertible { private(set) public var adjacencyLists: [Node : [Node]] public init() { - adjacencyLists = [Node : [Node]]() + adjacencyLists = [Node: [Node]]() } public func addNode(_ value: Node) -> Node { @@ -35,7 +35,7 @@ extension Graph { typealias InDegree = Int func calculateInDegreeOfNodes() -> [Node : InDegree] { - var inDegrees = [Node : InDegree]() + var inDegrees = [Node: InDegree]() for (node, _) in adjacencyLists { inDegrees[node] = 0 diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift index 0f9566f6a..4d3717fe6 100644 --- a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift @@ -23,7 +23,7 @@ extension Graph { return node }) - var visited = [Node : Bool]() + var visited = [Node: Bool]() for (node, _) in adjacencyLists { visited[node] = false } diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift index 0f9566f6a..4d3717fe6 100644 --- a/Topological Sort/TopologicalSort1.swift +++ b/Topological Sort/TopologicalSort1.swift @@ -23,7 +23,7 @@ extension Graph { return node }) - var visited = [Node : Bool]() + var visited = [Node: Bool]() for (node, _) in adjacencyLists { visited[node] = false } From c4fdd035df77487756eee2389d18c89f9dc652cd Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Sat, 29 Apr 2017 00:52:39 -0700 Subject: [PATCH 0595/1275] switch removeFirst to dropFirst we don't need a mutable copy of `array` to alter it, instead we can just drop the first element --- Select Minimum Maximum/Maximum.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Select Minimum Maximum/Maximum.swift b/Select Minimum Maximum/Maximum.swift index 991a0544e..c999504fb 100644 --- a/Select Minimum Maximum/Maximum.swift +++ b/Select Minimum Maximum/Maximum.swift @@ -3,13 +3,12 @@ */ func maximum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - var maximum = array.removeFirst() - for element in array { + var maximum = array.first! + for element in array.dropFirst() { maximum = element > maximum ? element : maximum } return maximum From 5e7fc5487f833fd96852d21d7f856c300956a62b Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Sat, 29 Apr 2017 00:56:51 -0700 Subject: [PATCH 0596/1275] switch removeFirst to dropFirst we don't need to alter a mutable copy of `array`, instead we can just drop the first element. --- Select Minimum Maximum/Minimum.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Select Minimum Maximum/Minimum.swift b/Select Minimum Maximum/Minimum.swift index 90dfbd54b..88a562170 100644 --- a/Select Minimum Maximum/Minimum.swift +++ b/Select Minimum Maximum/Minimum.swift @@ -3,13 +3,12 @@ */ func minimum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - var minimum = array.removeFirst() - for element in array { + var minimum = array.first! + for element in array.dropFirst() { minimum = element < minimum ? element : minimum } return minimum From e15e1330417dcbe2222d2606a35dd5462eac6b2c Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Sat, 29 Apr 2017 18:14:37 -0700 Subject: [PATCH 0597/1275] switch from removeFirst to stride for pairing We don't need to alter a local copy of `array` to generate each pair, instead use stride(from:to:by). In my simple [tests](https://gist.github.com/TheIronBorn/cc0507b36fddad291aa34674eb52ad8f), this can be up to an order of magnitude faster. --- Select Minimum Maximum/MinimumMaximumPairs.swift | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Select Minimum Maximum/MinimumMaximumPairs.swift b/Select Minimum Maximum/MinimumMaximumPairs.swift index b7deb570a..2c7b5bb5f 100644 --- a/Select Minimum Maximum/MinimumMaximumPairs.swift +++ b/Select Minimum Maximum/MinimumMaximumPairs.swift @@ -3,7 +3,6 @@ */ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { - var array = array guard !array.isEmpty else { return nil } @@ -11,13 +10,11 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { var minimum = array.first! var maximum = array.first! + // if 'array' has an odd number of items, let 'minimum' or 'maximum' deal with the leftover let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } - - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) + let start = hasOddNumberOfItems ? 1 : 0 + for i in stride(from: start, to: array.count, by: 2) { + let pair = (array[i], array[i+1]) if pair.0 > pair.1 { if pair.0 > maximum { @@ -35,6 +32,6 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { } } } - + return (minimum, maximum) } From b8d668d3883f79754aa83f5944a3e3d97e13d3a6 Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Sat, 29 Apr 2017 18:19:43 -0700 Subject: [PATCH 0598/1275] update to match source --- Select Minimum Maximum/README.markdown | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Select Minimum Maximum/README.markdown b/Select Minimum Maximum/README.markdown index fa0f8fed8..3c29b5764 100644 --- a/Select Minimum Maximum/README.markdown +++ b/Select Minimum Maximum/README.markdown @@ -24,26 +24,24 @@ Here is a simple implementation in Swift: ```swift func minimum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - var minimum = array.removeFirst() - for element in array { + var minimum = array.first! + for element in array.dropFirst() { minimum = element < minimum ? element : minimum } return minimum } func maximum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - var maximum = array.removeFirst() - for element in array { + var maximum = array.first! + for element in array.dropFirst() { maximum = element > maximum ? element : maximum } return maximum @@ -99,7 +97,6 @@ Here is a simple implementation in Swift: ```swift func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { - var array = array guard !array.isEmpty else { return nil } @@ -107,13 +104,12 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { var minimum = array.first! var maximum = array.first! + // if 'array' has an odd number of items, let 'minimum' or 'maximum' deal with the leftover let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } + let start = hasOddNumberOfItems ? 1 : 0 + for i in stride(from: start, to: array.count, by: 2) { + let pair = (array[i], array[i+1]) - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) if pair.0 > pair.1 { if pair.0 > maximum { maximum = pair.0 From 5ddf933c48da612a9489c77b095496b0c80c1b66 Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Sat, 29 Apr 2017 18:21:35 -0700 Subject: [PATCH 0599/1275] update to match source --- .../Contents.swift | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift index 182060805..427ccdb9e 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift @@ -1,12 +1,11 @@ // Compare each item to find minimum func minimum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - - var minimum = array.removeFirst() - for element in array { + + var minimum = array.first! + for element in array.dropFirst() { minimum = element < minimum ? element : minimum } return minimum @@ -14,13 +13,12 @@ func minimum(_ array: [T]) -> T? { // Compare each item to find maximum func maximum(_ array: [T]) -> T? { - var array = array guard !array.isEmpty else { return nil } - - var maximum = array.removeFirst() - for element in array { + + var maximum = array.first! + for element in array.dropFirst() { maximum = element > maximum ? element : maximum } return maximum @@ -28,22 +26,19 @@ func maximum(_ array: [T]) -> T? { // Compare in pairs to find minimum and maximum func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { - var array = array guard !array.isEmpty else { return nil } - + var minimum = array.first! var maximum = array.first! - + + // if 'array' has an odd number of items, let 'minimum' or 'maximum' deal with the leftover let hasOddNumberOfItems = array.count % 2 != 0 - if hasOddNumberOfItems { - array.removeFirst() - } - - while !array.isEmpty { - let pair = (array.removeFirst(), array.removeFirst()) - + let start = hasOddNumberOfItems ? 1 : 0 + for i in stride(from: start, to: array.count, by: 2) { + let pair = (array[i], array[i+1]) + if pair.0 > pair.1 { if pair.0 > maximum { maximum = pair.0 @@ -60,7 +55,7 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { } } } - + return (minimum, maximum) } From 3f156498b0cb043f103eef22216f2e4e9df6edd6 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 1 May 2017 01:03:09 +0500 Subject: [PATCH 0600/1275] Fix alignment by adding an additional tab --- Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tree/README.markdown b/Tree/README.markdown index 440d9c9a4..566864a8f 100644 --- a/Tree/README.markdown +++ b/Tree/README.markdown @@ -153,7 +153,7 @@ tree.search("bubbly") // nil It's also possible to describe a tree using nothing more than an array. The indices in the array then create the links between the different nodes. For example, if we have: - 0 = beverage 5 = cocoa 9 = green + 0 = beverage 5 = cocoa 9 = green 1 = hot 6 = soda 10 = chai 2 = cold 7 = milk 11 = ginger ale 3 = tea 8 = black 12 = bitter lemon From 32457ce5aca5bcdee4acc1f8d6f6c0c6a075daba Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 1 May 2017 02:03:34 +0500 Subject: [PATCH 0601/1275] Fix misindented return statement --- Trie/ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 7caa927a7..356f6887e 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -46,7 +46,7 @@ func contains(word: String) -> Bool { if currentIndex == characters.count && currentNode.isTerminating { return true } else { - return false + return false } } ``` From 09f2c8fb8564bd956beb1a067b6ad21255bad97c Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 1 May 2017 05:25:13 +0500 Subject: [PATCH 0602/1275] [swiftlint] Fix rule: force_cast (Force casts should be avoided) --- Trie/Trie/TrieTests/TrieTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 960b65791..b69c5666e 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -164,8 +164,8 @@ class TrieTests: XCTestCase { 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) + let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie + XCTAssertEqual(trieCopy?.count, trie.count) } From b1319ce90d5288e20ee02b56390c61895d1d7765 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:23:06 +0500 Subject: [PATCH 0603/1275] [swiftlint] Fix violation: unused_closure_parameter warning: Unused Closure Parameter Violation: Unused parameters in a closure should be replaced with _. --- B-Tree/Tests/Tests/BTreeTests.swift | 2 +- .../Topological Sort.playground/Sources/TopologicalSort1.swift | 2 +- .../Topological Sort.playground/Sources/TopologicalSort2.swift | 2 +- Topological Sort/TopologicalSort1.swift | 2 +- Topological Sort/TopologicalSort2.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/B-Tree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift index c8db17fa3..f2dac7511 100644 --- a/B-Tree/Tests/Tests/BTreeTests.swift +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -31,7 +31,7 @@ class BTreeTests: XCTestCase { } func testInorderTraversalOfEmptyTree() { - bTree.traverseKeysInOrder { i in + bTree.traverseKeysInOrder { _ in XCTFail("Inorder travelsal fail.") } } diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift index 4d3717fe6..2ad9b51a0 100644 --- a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift @@ -19,7 +19,7 @@ extension Graph { let startNodes = calculateInDegreeOfNodes().filter({ _, indegree in return indegree == 0 - }).map({ node, indegree in + }).map({ node, _ in return node }) diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift index f4c1cdd6f..589801d33 100644 --- a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift @@ -8,7 +8,7 @@ extension Graph { // topologically sorted list. var leaders = nodes.filter({ _, indegree in return indegree == 0 - }).map({ node, indegree in + }).map({ node, _ in return node }) diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift index 4d3717fe6..2ad9b51a0 100644 --- a/Topological Sort/TopologicalSort1.swift +++ b/Topological Sort/TopologicalSort1.swift @@ -19,7 +19,7 @@ extension Graph { let startNodes = calculateInDegreeOfNodes().filter({ _, indegree in return indegree == 0 - }).map({ node, indegree in + }).map({ node, _ in return node }) diff --git a/Topological Sort/TopologicalSort2.swift b/Topological Sort/TopologicalSort2.swift index f4c1cdd6f..589801d33 100644 --- a/Topological Sort/TopologicalSort2.swift +++ b/Topological Sort/TopologicalSort2.swift @@ -8,7 +8,7 @@ extension Graph { // topologically sorted list. var leaders = nodes.filter({ _, indegree in return indegree == 0 - }).map({ node, indegree in + }).map({ node, _ in return node }) From 9107542b7753210cef8eaf982373db377f6a8a62 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:25:35 +0500 Subject: [PATCH 0604/1275] [swiftlint] Fix violation: redundant_discardable_let warning: Redundant Discardable Let Violation: Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function. --- Breadth-First Search/Tests/Graph.swift | 2 +- Palindromes/Test/Test/Test.swift | 6 +++--- Treap/TreapCollectionType.swift | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Breadth-First Search/Tests/Graph.swift b/Breadth-First Search/Tests/Graph.swift index 5e0837160..a8c34b3f6 100644 --- a/Breadth-First Search/Tests/Graph.swift +++ b/Breadth-First Search/Tests/Graph.swift @@ -86,7 +86,7 @@ public class Graph: CustomStringConvertible, Equatable { let duplicated = Graph() for node in nodes { - let _ = duplicated.addNode(node.label) + _ = duplicated.addNode(node.label) } for node in nodes { diff --git a/Palindromes/Test/Test/Test.swift b/Palindromes/Test/Test/Test.swift index e86a40cfb..1dd79ea97 100644 --- a/Palindromes/Test/Test/Test.swift +++ b/Palindromes/Test/Test/Test.swift @@ -29,9 +29,9 @@ class PalindromeTests: XCTestCase { // This is an example of a performance test case. self.measure { // Put the code you want to measure the time of here. - let _ = isPalindrome("abbcbba") - let _ = isPalindrome("asdkfaksjdfasjkdfhaslkjdfakjsdfhakljsdhflkjasdfhkasdjhfklajsdfhkljasdf") - let _ = isPalindrome("abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa") + _ = isPalindrome("abbcbba") + _ = isPalindrome("asdkfaksjdfasjkdfhaslkjdfakjsdfhakljsdhflkjasdfhkasdjhfklajsdfhkljasdf") + _ = isPalindrome("abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa") } } diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index de40464d1..9f7f81905 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -50,7 +50,7 @@ extension Treap: MutableCollection { mutating set { guard let value = newValue else { - let _ = try? self.delete(key: key) + _ = try? self.delete(key: key) return } From c67a277487e3611ad51b0c88855540d3f56f58bb Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:34:24 +0500 Subject: [PATCH 0605/1275] [swiftlint] Fix violation: operator_whitespace warning: Operator Function Whitespace Violation: Operators should be surrounded by a single whitespace when defining them. Apple has also used spacing in The Swift Programming Language book https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID42 --- QuadTree/Tests/Tests/Tests.swift | 2 +- .../Sources/Matrix.swift | 2 +- .../Sources/Number.swift | 6 +++--- Treap/TreapCollectionType.swift | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/QuadTree/Tests/Tests/Tests.swift b/QuadTree/Tests/Tests/Tests.swift index b7bcda4e6..b408c4f7e 100644 --- a/QuadTree/Tests/Tests/Tests.swift +++ b/QuadTree/Tests/Tests/Tests.swift @@ -12,7 +12,7 @@ extension Point: Equatable { } -public func ==(lhs: Point, rhs: Point) -> Bool { +public func == (lhs: Point, rhs: Point) -> Bool { return lhs.x == rhs.x && lhs.y == rhs.y } diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift index c13b3eeee..ccfa58b09 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift @@ -19,7 +19,7 @@ public struct Matrix { public struct Size: Equatable { let rows: Int, columns: Int - public static func ==(lhs: Size, rhs: Size) -> Bool { + public static func == (lhs: Size, rhs: Size) -> Bool { return lhs.columns == rhs.columns && lhs.rows == rhs.rows } } diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift index 69afe76e4..d53ef75bd 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Number.swift @@ -13,12 +13,12 @@ public protocol Number: Multipliable, Addable { } public protocol Addable { - static func +(lhs: Self, rhs: Self) -> Self - static func -(lhs: Self, rhs: Self) -> Self + static func + (lhs: Self, rhs: Self) -> Self + static func - (lhs: Self, rhs: Self) -> Self } public protocol Multipliable { - static func *(lhs: Self, rhs: Self) -> Self + static func * (lhs: Self, rhs: Self) -> Self } extension Int: Number { diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index 9f7f81905..7292c5f0a 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -85,7 +85,7 @@ extension Treap: MutableCollection { public struct TreapIndex: Comparable { - public static func <(lhs: TreapIndex, rhs: TreapIndex) -> Bool { + public static func < (lhs: TreapIndex, rhs: TreapIndex) -> Bool { return lhs.keyIndex < rhs.keyIndex } From 18c7b435cec0eafb657f28f7c80345d8a7aa513a Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:41:07 +0500 Subject: [PATCH 0606/1275] [swiftlint] Fix violation: Colons should be next to the identifier warning: Colon Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals. --- Bucket Sort/BucketSort.swift | 4 ++-- Skip-List/SkipList.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift index ff36b372a..5845819f2 100644 --- a/Bucket Sort/BucketSort.swift +++ b/Bucket Sort/BucketSort.swift @@ -23,7 +23,7 @@ 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 { +fileprivate func < (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l < r @@ -36,7 +36,7 @@ fileprivate func < (lhs: T?, rhs: T?) -> Bool { // 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 { +fileprivate func >= (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l >= r diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index 14b5a4076..e844f9959 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -71,10 +71,10 @@ private func coinFlip() -> Bool { public class DataNode { public typealias Node = DataNode - var data : Payload? - fileprivate var key : Key? - var next : Node? - var down : Node? + var data: Payload? + fileprivate var key: Key? + var next: Node? + var down: Node? public init(key: Key, data: Payload) { self.key = key @@ -102,8 +102,8 @@ open class SkipList { extension SkipList { func findNode(key: Key) -> Node? { - var currentNode : Node? = head - var isFound : Bool = false + var currentNode: Node? = head + var isFound: Bool = false while !isFound { if let node = currentNode { From e3a4494138ca4776aab23bed0428b3e4063395ca Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:47:57 +0500 Subject: [PATCH 0607/1275] [swiftlint] Fix violation: Computed properties should avoid using get Rule: implicit_getter warning: Implicit Getter Violation: Computed read-only properties should avoid using the get keyword. --- Graph/Graph/AdjacencyListGraph.swift | 58 ++++++++++++-------------- Graph/Graph/AdjacencyMatrixGraph.swift | 44 +++++++++---------- Graph/Graph/Edge.swift | 19 ++++----- Graph/Graph/Graph.swift | 12 ++---- Graph/Graph/Vertex.swift | 8 +--- Treap/Treap.swift | 31 ++++++-------- Treap/TreapMergeSplit.swift | 4 +- 7 files changed, 71 insertions(+), 105 deletions(-) diff --git a/Graph/Graph/AdjacencyListGraph.swift b/Graph/Graph/AdjacencyListGraph.swift index 3d86c78f7..57fd75fed 100644 --- a/Graph/Graph/AdjacencyListGraph.swift +++ b/Graph/Graph/AdjacencyListGraph.swift @@ -37,29 +37,25 @@ open class AdjacencyListGraph: AbstractGraph where T: Equatable, T: Hashab } open override var vertices: [Vertex] { - get { - var vertices = [Vertex]() - for edgeList in adjacencyList { - vertices.append(edgeList.vertex) - } - return vertices + var vertices = [Vertex]() + for edgeList in adjacencyList { + vertices.append(edgeList.vertex) } + return vertices } open override var edges: [Edge] { - get { - var allEdges = Set>() - for edgeList in adjacencyList { - guard let edges = edgeList.edges else { - continue - } + var allEdges = Set>() + for edgeList in adjacencyList { + guard let edges = edgeList.edges else { + continue + } - for edge in edges { - allEdges.insert(edge) - } + for edge in edges { + allEdges.insert(edge) } - return Array(allEdges) } + return Array(allEdges) } open override func createVertex(_ data: T) -> Vertex { @@ -114,27 +110,25 @@ open class AdjacencyListGraph: AbstractGraph where T: Equatable, T: Hashab } open override var description: String { - get { - var rows = [String]() - for edgeList in adjacencyList { + var rows = [String]() + for edgeList in adjacencyList { - guard let edges = edgeList.edges else { - continue - } + guard let edges = edgeList.edges else { + continue + } - var row = [String]() - for edge in edges { - var value = "\(edge.to.data)" - if edge.weight != nil { - value = "(\(value): \(edge.weight!))" - } - row.append(value) + var row = [String]() + for edge in edges { + var value = "\(edge.to.data)" + if edge.weight != nil { + value = "(\(value): \(edge.weight!))" } - - rows.append("\(edgeList.vertex.data) -> [\(row.joined(separator: ", "))]") + row.append(value) } - return rows.joined(separator: "\n") + rows.append("\(edgeList.vertex.data) -> [\(row.joined(separator: ", "))]") } + + return rows.joined(separator: "\n") } } diff --git a/Graph/Graph/AdjacencyMatrixGraph.swift b/Graph/Graph/AdjacencyMatrixGraph.swift index a9b43fb6d..1b12790d8 100644 --- a/Graph/Graph/AdjacencyMatrixGraph.swift +++ b/Graph/Graph/AdjacencyMatrixGraph.swift @@ -23,23 +23,19 @@ open class AdjacencyMatrixGraph: AbstractGraph where T: Equatable, T: Hash } open override var vertices: [Vertex] { - get { - return _vertices - } + return _vertices } open override var edges: [Edge] { - get { - var edges = [Edge]() - for row in 0 ..< adjacencyMatrix.count { - for column in 0 ..< adjacencyMatrix.count { - if let weight = adjacencyMatrix[row][column] { - edges.append(Edge(from: vertices[row], to: vertices[column], weight: weight)) - } + var edges = [Edge]() + for row in 0 ..< adjacencyMatrix.count { + for column in 0 ..< adjacencyMatrix.count { + if let weight = adjacencyMatrix[row][column] { + edges.append(Edge(from: vertices[row], to: vertices[column], weight: weight)) } } - return edges } + return edges } // Adds a new vertex to the matrix. @@ -96,23 +92,21 @@ open class AdjacencyMatrixGraph: AbstractGraph where T: Equatable, T: Hash } open override var description: String { - get { - var grid = [String]() - let n = self.adjacencyMatrix.count - for i in 0..: Equatable where T: Equatable, T: Hashable { extension Edge: CustomStringConvertible { public var description: String { - get { - guard let unwrappedWeight = weight else { - return "\(from.description) -> \(to.description)" - } - return "\(from.description) -(\(unwrappedWeight))-> \(to.description)" + guard let unwrappedWeight = weight else { + return "\(from.description) -> \(to.description)" } + return "\(from.description) -(\(unwrappedWeight))-> \(to.description)" } } @@ -32,15 +30,12 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { public var hashValue: Int { - get { - var string = "\(from.description)\(to.description)" - if weight != nil { - string.append("\(weight!)") - } - return string.hashValue + var string = "\(from.description)\(to.description)" + if weight != nil { + string.append("\(weight!)") } + return string.hashValue } - } public func == (lhs: Edge, rhs: Edge) -> Bool { diff --git a/Graph/Graph/Graph.swift b/Graph/Graph/Graph.swift index 2ad91608b..13d6802b9 100644 --- a/Graph/Graph/Graph.swift +++ b/Graph/Graph/Graph.swift @@ -21,21 +21,15 @@ open class AbstractGraph: CustomStringConvertible where T: Equatable, T: Hash } open var description: String { - get { - fatalError("abstract property accessed") - } + fatalError("abstract property accessed") } open var vertices: [Vertex] { - get { - fatalError("abstract property accessed") - } + fatalError("abstract property accessed") } open var edges: [Edge] { - get { - fatalError("abstract property accessed") - } + fatalError("abstract property accessed") } // Adds a new vertex to the matrix. diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 43cabcd1f..42a7dad7b 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -17,9 +17,7 @@ public struct Vertex: Equatable where T: Equatable, T: Hashable { extension Vertex: CustomStringConvertible { public var description: String { - get { - return "\(index): \(data)" - } + return "\(index): \(data)" } } @@ -27,9 +25,7 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { public var hashValue: Int { - get { - return "\(data)\(index)".hashValue - } + return "\(data)\(index)".hashValue } } diff --git a/Treap/Treap.swift b/Treap/Treap.swift index 478f248df..6e80abfb2 100644 --- a/Treap/Treap.swift +++ b/Treap/Treap.swift @@ -63,27 +63,22 @@ public indirect enum Treap { } public var depth: Int { - get { - switch self { - case .empty: - return 0 - case let .node(_, _, _, left, .empty): - return 1 + left.depth - case let .node(_, _, _, .empty, right): - return 1 + right.depth - case let .node(_, _, _, left, right): - let leftDepth = left.depth - let rightDepth = right.depth - return 1 + leftDepth > rightDepth ? leftDepth : rightDepth - } - + switch self { + case .empty: + return 0 + case let .node(_, _, _, left, .empty): + return 1 + left.depth + case let .node(_, _, _, .empty, right): + return 1 + right.depth + case let .node(_, _, _, left, right): + let leftDepth = left.depth + let rightDepth = right.depth + return 1 + leftDepth > rightDepth ? leftDepth : rightDepth } } - + public var count: Int { - get { - return Treap.countHelper(self) - } + return Treap.countHelper(self) } fileprivate static func countHelper(_ treap: Treap) -> Int { diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift index 660bd4932..34cfec3d2 100644 --- a/Treap/TreapMergeSplit.swift +++ b/Treap/TreapMergeSplit.swift @@ -94,9 +94,7 @@ internal func merge(_ left: Treap, right extension Treap: CustomStringConvertible { public var description: String { - get { - return Treap.descHelper(self, indent: 0) - } + return Treap.descHelper(self, indent: 0) } fileprivate static func descHelper(_ treap: Treap, indent: Int) -> String { From 9af41f20ed8318739bd4f1d582a6789fe650e9b5 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:49:49 +0500 Subject: [PATCH 0608/1275] [swiftlint] Fix violation: trailing_whitespace --- Array2D/Array2D.playground/Contents.swift | 4 +- Array2D/Array2D.swift | 4 +- B-Tree/BTree.playground/Sources/BTree.swift | 108 +++++++------- B-Tree/BTree.swift | 108 +++++++------- B-Tree/Tests/Tests/BTreeNodeTests.swift | 18 +-- B-Tree/Tests/Tests/BTreeTests.swift | 112 +++++++------- .../Contents.swift | 2 +- .../Sources/Comb Sort.swift | 4 +- Comb Sort/Comb Sort.swift | 4 +- Comb Sort/Tests/CombSortTests.swift | 2 +- Convex Hull/Convex Hull/AppDelegate.swift | 8 +- Convex Hull/Convex Hull/View.swift | 80 +++++----- .../FixedSizeArray.playground/Contents.swift | 10 +- Graph/Graph.playground/Contents.swift | 2 +- .../HashSet.playground/Sources/HashSet.swift | 16 +- .../Sources/HashTable.swift | 28 ++-- .../Contents.swift | 10 +- Heap/Heap.swift | 4 +- Heap/Tests/HeapTests.swift | 4 +- Huffman Coding/Huffman.swift | 34 ++--- Huffman Coding/NSData+Bits.swift | 8 +- .../Contents.swift | 16 +- .../KaratsubaMultiplication.swift | 12 +- Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 26 ++-- .../LinkedList.playground/Contents.swift | 62 ++++---- Linked List/LinkedList.swift | 62 ++++---- Linked List/Tests/LinkedListTests.swift | 18 +-- .../Sources/MRPrimality.swift | 28 ++-- Miller-Rabin Primality Test/MRPrimality.swift | 28 ++-- .../Contents.swift | 8 +- .../OrderedArray.playground/Contents.swift | 2 +- .../Palindromes.playground/Contents.swift | 8 +- Palindromes/Palindromes.swift | 8 +- Palindromes/Test/Palindromes.swift | 8 +- Palindromes/Test/Test/Test.swift | 18 +-- .../Sources/QuadTree.swift | 88 +++++------ QuadTree/Tests/Tests/Tests.swift | 34 ++--- .../Sources/radixSort.swift | 18 +-- Radix Sort/RadixSortExample.swift | 12 +- Radix Sort/radixSort.swift | 18 +-- .../Contents.swift | 2 +- .../Sources/RBTree.swift | 138 +++++++++--------- .../RLE.playground/Contents.swift | 14 +- .../RLE.playground/Sources/RLE.swift | 12 +- .../SegmentTree.playground/Contents.swift | 18 +-- Segment Tree/SegmentTree.swift | 16 +- .../MinimumMaximumPairs.swift | 2 +- .../Contents.swift | 14 +- Shell Sort/ShellSortExample.swift | 10 +- Shortest Path (Unweighted)/Tests/Graph.swift | 32 ++-- .../ShuntingYard.playground/Contents.swift | 52 +++---- .../Sources/Stack.swift | 14 +- Shunting Yard/ShuntingYard.swift | 52 +++---- Skip-List/SkipList.swift | 84 +++++------ .../Sources/Matrix.swift | 88 +++++------ .../TST.playground/Sources/Utils.swift | 8 +- .../Tests/TernarySearchTreeTests.swift | 18 +-- Ternary Search Tree/Utils.swift | 8 +- .../Sources/ThreadedBinaryTree.swift | 52 +++---- Treap/Treap.swift | 18 +-- Treap/Treap/TreapTests/TreapTests.swift | 12 +- Treap/TreapCollectionType.swift | 34 ++--- Treap/TreapMergeSplit.swift | 14 +- Trie/Trie/Trie/Trie.swift | 16 +- Trie/Trie/TrieUITests/TrieUITests.swift | 12 +- Z-Algorithm/ZAlgorithm.swift | 22 +-- .../ZetaAlgorithm.playground/Contents.swift | 34 ++--- Z-Algorithm/ZetaAlgorithm.swift | 12 +- 68 files changed, 926 insertions(+), 926 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index d088c99af..1a6a439bd 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -7,13 +7,13 @@ public struct Array2D { public let columns: Int public let rows: Int fileprivate var array: [T] - + public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows array = .init(repeating: initialValue, count: rows*columns) } - + public subscript(column: Int, row: Int) -> T { get { precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") diff --git a/Array2D/Array2D.swift b/Array2D/Array2D.swift index df4822916..caff8373c 100644 --- a/Array2D/Array2D.swift +++ b/Array2D/Array2D.swift @@ -7,13 +7,13 @@ public struct Array2D { public let columns: Int public let rows: Int fileprivate var array: [T] - + public init(columns: Int, rows: Int, initialValue: T) { self.columns = columns self.rows = rows array = .init(repeating: initialValue, count: rows*columns) } - + public subscript(column: Int, row: Int) -> T { get { precondition(column < columns, "Column \(column) Index is out of range. Array(columns: \(columns), rows:\(rows))") diff --git a/B-Tree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift index 52cda4e43..2693eb308 100644 --- a/B-Tree/BTree.playground/Sources/BTree.swift +++ b/B-Tree/BTree.playground/Sources/BTree.swift @@ -33,23 +33,23 @@ class BTreeNode { * The tree that owns the node. */ unowned var owner: BTree - + fileprivate var keys = [Key]() fileprivate var values = [Value]() var children: [BTreeNode]? - + var isLeaf: Bool { return children == nil } - + var numberOfKeys: Int { return keys.count } - + init(owner: BTree) { self.owner = owner } - + convenience init(owner: BTree, keys: [Key], values: [Value], children: [BTreeNode]? = nil) { self.init(owner: owner) @@ -62,7 +62,7 @@ class BTreeNode { // MARK: BTreeNode extesnion: Searching extension BTreeNode { - + /** * Returns the value for a given `key`, returns nil if the `key` is not found. * @@ -71,11 +71,11 @@ extension BTreeNode { */ func value(for key: Key) -> Value? { var index = keys.startIndex - + while (index + 1) < keys.endIndex && keys[index] < key { index = (index + 1) } - + if key == keys[index] { return values[index] } else if key < keys[index] { @@ -89,7 +89,7 @@ extension BTreeNode { // MARK: BTreeNode extension: Travelsals extension BTreeNode { - + /** * Traverses the keys in order, executes `process` for every key. * @@ -101,7 +101,7 @@ extension BTreeNode { children?[i].traverseKeysInOrder(process) process(keys[i]) } - + children?.last?.traverseKeysInOrder(process) } } @@ -109,7 +109,7 @@ extension BTreeNode { // MARK: BTreeNode extension: Insertion extension BTreeNode { - + /** * Inserts `value` for `key` to the node, or to one if its descendants. * @@ -119,16 +119,16 @@ extension BTreeNode { */ func insert(_ value: Value, for key: Key) { var index = keys.startIndex - + while index < keys.endIndex && keys[index] < key { index = (index + 1) } - + if index < keys.endIndex && keys[index] == key { values[index] = value return } - + if isLeaf { keys.insert(key, at: index) values.insert(value, at: index) @@ -140,7 +140,7 @@ extension BTreeNode { } } } - + /** * Splits `child` at `index`. * The key-value pair at `index` gets moved up to the parent node, @@ -156,7 +156,7 @@ extension BTreeNode { values.insert(child.values[middleIndex], at: index) child.keys.remove(at: middleIndex) child.values.remove(at: middleIndex) - + let rightSibling = BTreeNode( owner: owner, keys: Array(child.keys[child.keys.indices.suffix(from: middleIndex)]), @@ -164,9 +164,9 @@ extension BTreeNode { ) child.keys.removeSubrange(child.keys.indices.suffix(from: middleIndex)) child.values.removeSubrange(child.values.indices.suffix(from: middleIndex)) - + children!.insert(rightSibling, at: (index + 1)) - + if child.children != nil { rightSibling.children = Array( child.children![child.children!.indices.suffix(from: (middleIndex + 1))] @@ -198,7 +198,7 @@ extension BTreeNode { return children!.last!.inorderPredecessor } } - + /** * Removes `key` and the value associated with it from the node * or one of its descendants. @@ -208,11 +208,11 @@ extension BTreeNode { */ func remove(_ key: Key) { var index = keys.startIndex - + while (index + 1) < keys.endIndex && keys[index] < key { index = (index + 1) } - + if keys[index] == key { if isLeaf { keys.remove(at: index) @@ -229,7 +229,7 @@ extension BTreeNode { } } else if key < keys[index] { // We should go to left child... - + if let leftChild = children?[index] { leftChild.remove(key) if leftChild.numberOfKeys < owner.order { @@ -240,7 +240,7 @@ extension BTreeNode { } } else { // We should go to right child... - + if let rightChild = children?[(index + 1)] { rightChild.remove(key) if rightChild.numberOfKeys < owner.order { @@ -251,7 +251,7 @@ extension BTreeNode { } } } - + /** * Fixes `childWithTooFewKeys` by either moving a key to it from * one of its neighbouring nodes, or by merging. @@ -264,7 +264,7 @@ extension BTreeNode { * - index: the index of the child to be fixed in the current node */ private func fix(childWithTooFewKeys child: BTreeNode, atIndex index: Int) { - + if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { move(keyAtIndex: (index - 1), to: child, from: children![(index - 1)], at: .left) } else if (index + 1) < children!.count && children![(index + 1)].numberOfKeys > owner.order { @@ -275,7 +275,7 @@ extension BTreeNode { merge(child: child, atIndex: index, to: .right) } } - + /** * Moves the key at the specified `index` from `node` to * the `targetNode` at `position` @@ -301,7 +301,7 @@ extension BTreeNode { at: targetNode.children!.startIndex) node.children!.removeLast() } - + case .right: targetNode.keys.insert(keys[index], at: targetNode.keys.endIndex) targetNode.values.insert(values[index], at: targetNode.values.endIndex) @@ -316,7 +316,7 @@ extension BTreeNode { } } } - + /** * Merges `child` at `position` to the node at the `position`. * @@ -329,33 +329,33 @@ extension BTreeNode { switch position { case .left: // We can merge to the left sibling - + children![(index - 1)].keys = children![(index - 1)].keys + [keys[(index - 1)]] + child.keys - + children![(index - 1)].values = children![(index - 1)].values + [values[(index - 1)]] + child.values - + keys.remove(at: (index - 1)) values.remove(at: (index - 1)) - + if !child.isLeaf { children![(index - 1)].children = children![(index - 1)].children! + child.children! } - + case .right: // We should merge to the right sibling - + children![(index + 1)].keys = child.keys + [keys[index]] + children![(index + 1)].keys - + children![(index + 1)].values = child.values + [values[index]] + children![(index + 1)].values - + keys.remove(at: index) values.remove(at: index) - + if !child.isLeaf { children![(index + 1)].children = child.children! + children![(index + 1)].children! @@ -374,18 +374,18 @@ extension BTreeNode { */ var inorderArrayFromKeys: [Key] { var array = [Key] () - + for i in 0.. { * except the root node which is allowed to contain less keys than the value of order. */ public let order: Int - + /** * The root node of the tree */ var rootNode: BTreeNode! - + fileprivate(set) public var numberOfKeys = 0 - + /** * Designated initializer for the tree * @@ -484,7 +484,7 @@ extension BTree { guard rootNode.numberOfKeys > 0 else { return nil } - + return rootNode.value(for: key) } } @@ -501,12 +501,12 @@ extension BTree { */ public func insert(_ value: Value, for key: Key) { rootNode.insert(value, for: key) - + if rootNode.numberOfKeys > order * 2 { splitRoot() } } - + /** * Splits the root node of the tree. * @@ -515,7 +515,7 @@ extension BTree { */ private func splitRoot() { let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 - + let newRoot = BTreeNode( owner: self, keys: [rootNode.keys[middleIndexOfOldRoot]], @@ -524,7 +524,7 @@ extension BTree { ) rootNode.keys.remove(at: middleIndexOfOldRoot) rootNode.values.remove(at: middleIndexOfOldRoot) - + let newRightChild = BTreeNode( owner: self, keys: Array(rootNode.keys[rootNode.keys.indices.suffix(from: middleIndexOfOldRoot)]), @@ -532,7 +532,7 @@ extension BTree { ) rootNode.keys.removeSubrange(rootNode.keys.indices.suffix(from: middleIndexOfOldRoot)) rootNode.values.removeSubrange(rootNode.values.indices.suffix(from: middleIndexOfOldRoot)) - + if rootNode.children != nil { newRightChild.children = Array( rootNode.children![rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1))] @@ -541,7 +541,7 @@ extension BTree { rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1)) ) } - + newRoot.children!.append(newRightChild) rootNode = newRoot } @@ -560,9 +560,9 @@ extension BTree { guard rootNode.numberOfKeys > 0 else { return } - + rootNode.remove(key) - + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { rootNode = rootNode.children!.first! } diff --git a/B-Tree/BTree.swift b/B-Tree/BTree.swift index 52cda4e43..2693eb308 100644 --- a/B-Tree/BTree.swift +++ b/B-Tree/BTree.swift @@ -33,23 +33,23 @@ class BTreeNode { * The tree that owns the node. */ unowned var owner: BTree - + fileprivate var keys = [Key]() fileprivate var values = [Value]() var children: [BTreeNode]? - + var isLeaf: Bool { return children == nil } - + var numberOfKeys: Int { return keys.count } - + init(owner: BTree) { self.owner = owner } - + convenience init(owner: BTree, keys: [Key], values: [Value], children: [BTreeNode]? = nil) { self.init(owner: owner) @@ -62,7 +62,7 @@ class BTreeNode { // MARK: BTreeNode extesnion: Searching extension BTreeNode { - + /** * Returns the value for a given `key`, returns nil if the `key` is not found. * @@ -71,11 +71,11 @@ extension BTreeNode { */ func value(for key: Key) -> Value? { var index = keys.startIndex - + while (index + 1) < keys.endIndex && keys[index] < key { index = (index + 1) } - + if key == keys[index] { return values[index] } else if key < keys[index] { @@ -89,7 +89,7 @@ extension BTreeNode { // MARK: BTreeNode extension: Travelsals extension BTreeNode { - + /** * Traverses the keys in order, executes `process` for every key. * @@ -101,7 +101,7 @@ extension BTreeNode { children?[i].traverseKeysInOrder(process) process(keys[i]) } - + children?.last?.traverseKeysInOrder(process) } } @@ -109,7 +109,7 @@ extension BTreeNode { // MARK: BTreeNode extension: Insertion extension BTreeNode { - + /** * Inserts `value` for `key` to the node, or to one if its descendants. * @@ -119,16 +119,16 @@ extension BTreeNode { */ func insert(_ value: Value, for key: Key) { var index = keys.startIndex - + while index < keys.endIndex && keys[index] < key { index = (index + 1) } - + if index < keys.endIndex && keys[index] == key { values[index] = value return } - + if isLeaf { keys.insert(key, at: index) values.insert(value, at: index) @@ -140,7 +140,7 @@ extension BTreeNode { } } } - + /** * Splits `child` at `index`. * The key-value pair at `index` gets moved up to the parent node, @@ -156,7 +156,7 @@ extension BTreeNode { values.insert(child.values[middleIndex], at: index) child.keys.remove(at: middleIndex) child.values.remove(at: middleIndex) - + let rightSibling = BTreeNode( owner: owner, keys: Array(child.keys[child.keys.indices.suffix(from: middleIndex)]), @@ -164,9 +164,9 @@ extension BTreeNode { ) child.keys.removeSubrange(child.keys.indices.suffix(from: middleIndex)) child.values.removeSubrange(child.values.indices.suffix(from: middleIndex)) - + children!.insert(rightSibling, at: (index + 1)) - + if child.children != nil { rightSibling.children = Array( child.children![child.children!.indices.suffix(from: (middleIndex + 1))] @@ -198,7 +198,7 @@ extension BTreeNode { return children!.last!.inorderPredecessor } } - + /** * Removes `key` and the value associated with it from the node * or one of its descendants. @@ -208,11 +208,11 @@ extension BTreeNode { */ func remove(_ key: Key) { var index = keys.startIndex - + while (index + 1) < keys.endIndex && keys[index] < key { index = (index + 1) } - + if keys[index] == key { if isLeaf { keys.remove(at: index) @@ -229,7 +229,7 @@ extension BTreeNode { } } else if key < keys[index] { // We should go to left child... - + if let leftChild = children?[index] { leftChild.remove(key) if leftChild.numberOfKeys < owner.order { @@ -240,7 +240,7 @@ extension BTreeNode { } } else { // We should go to right child... - + if let rightChild = children?[(index + 1)] { rightChild.remove(key) if rightChild.numberOfKeys < owner.order { @@ -251,7 +251,7 @@ extension BTreeNode { } } } - + /** * Fixes `childWithTooFewKeys` by either moving a key to it from * one of its neighbouring nodes, or by merging. @@ -264,7 +264,7 @@ extension BTreeNode { * - index: the index of the child to be fixed in the current node */ private func fix(childWithTooFewKeys child: BTreeNode, atIndex index: Int) { - + if (index - 1) >= 0 && children![(index - 1)].numberOfKeys > owner.order { move(keyAtIndex: (index - 1), to: child, from: children![(index - 1)], at: .left) } else if (index + 1) < children!.count && children![(index + 1)].numberOfKeys > owner.order { @@ -275,7 +275,7 @@ extension BTreeNode { merge(child: child, atIndex: index, to: .right) } } - + /** * Moves the key at the specified `index` from `node` to * the `targetNode` at `position` @@ -301,7 +301,7 @@ extension BTreeNode { at: targetNode.children!.startIndex) node.children!.removeLast() } - + case .right: targetNode.keys.insert(keys[index], at: targetNode.keys.endIndex) targetNode.values.insert(values[index], at: targetNode.values.endIndex) @@ -316,7 +316,7 @@ extension BTreeNode { } } } - + /** * Merges `child` at `position` to the node at the `position`. * @@ -329,33 +329,33 @@ extension BTreeNode { switch position { case .left: // We can merge to the left sibling - + children![(index - 1)].keys = children![(index - 1)].keys + [keys[(index - 1)]] + child.keys - + children![(index - 1)].values = children![(index - 1)].values + [values[(index - 1)]] + child.values - + keys.remove(at: (index - 1)) values.remove(at: (index - 1)) - + if !child.isLeaf { children![(index - 1)].children = children![(index - 1)].children! + child.children! } - + case .right: // We should merge to the right sibling - + children![(index + 1)].keys = child.keys + [keys[index]] + children![(index + 1)].keys - + children![(index + 1)].values = child.values + [values[index]] + children![(index + 1)].values - + keys.remove(at: index) values.remove(at: index) - + if !child.isLeaf { children![(index + 1)].children = child.children! + children![(index + 1)].children! @@ -374,18 +374,18 @@ extension BTreeNode { */ var inorderArrayFromKeys: [Key] { var array = [Key] () - + for i in 0.. { * except the root node which is allowed to contain less keys than the value of order. */ public let order: Int - + /** * The root node of the tree */ var rootNode: BTreeNode! - + fileprivate(set) public var numberOfKeys = 0 - + /** * Designated initializer for the tree * @@ -484,7 +484,7 @@ extension BTree { guard rootNode.numberOfKeys > 0 else { return nil } - + return rootNode.value(for: key) } } @@ -501,12 +501,12 @@ extension BTree { */ public func insert(_ value: Value, for key: Key) { rootNode.insert(value, for: key) - + if rootNode.numberOfKeys > order * 2 { splitRoot() } } - + /** * Splits the root node of the tree. * @@ -515,7 +515,7 @@ extension BTree { */ private func splitRoot() { let middleIndexOfOldRoot = rootNode.numberOfKeys / 2 - + let newRoot = BTreeNode( owner: self, keys: [rootNode.keys[middleIndexOfOldRoot]], @@ -524,7 +524,7 @@ extension BTree { ) rootNode.keys.remove(at: middleIndexOfOldRoot) rootNode.values.remove(at: middleIndexOfOldRoot) - + let newRightChild = BTreeNode( owner: self, keys: Array(rootNode.keys[rootNode.keys.indices.suffix(from: middleIndexOfOldRoot)]), @@ -532,7 +532,7 @@ extension BTree { ) rootNode.keys.removeSubrange(rootNode.keys.indices.suffix(from: middleIndexOfOldRoot)) rootNode.values.removeSubrange(rootNode.values.indices.suffix(from: middleIndexOfOldRoot)) - + if rootNode.children != nil { newRightChild.children = Array( rootNode.children![rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1))] @@ -541,7 +541,7 @@ extension BTree { rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1)) ) } - + newRoot.children!.append(newRightChild) rootNode = newRoot } @@ -560,9 +560,9 @@ extension BTree { guard rootNode.numberOfKeys > 0 else { return } - + rootNode.remove(key) - + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { rootNode = rootNode.children!.first! } diff --git a/B-Tree/Tests/Tests/BTreeNodeTests.swift b/B-Tree/Tests/Tests/BTreeNodeTests.swift index fd3ba10e8..8eff926b5 100644 --- a/B-Tree/Tests/Tests/BTreeNodeTests.swift +++ b/B-Tree/Tests/Tests/BTreeNodeTests.swift @@ -9,44 +9,44 @@ import XCTest class BTreeNodeTests: XCTestCase { - + let owner = BTree(order: 2)! var root: BTreeNode! var leftChild: BTreeNode! var rightChild: BTreeNode! - + override func setUp() { super.setUp() - + root = BTreeNode(owner: owner) leftChild = BTreeNode(owner: owner) rightChild = BTreeNode(owner: owner) - + root.insert(1, for: 1) root.children = [leftChild, rightChild] } - + func testIsLeafRoot() { XCTAssertFalse(root.isLeaf) } - + func testIsLeafLeaf() { XCTAssertTrue(leftChild.isLeaf) XCTAssertTrue(rightChild.isLeaf) } - + func testOwner() { XCTAssert(root.owner === owner) XCTAssert(leftChild.owner === owner) XCTAssert(rightChild.owner === owner) } - + func testNumberOfKeys() { XCTAssertEqual(root.numberOfKeys, 1) XCTAssertEqual(leftChild.numberOfKeys, 0) XCTAssertEqual(rightChild.numberOfKeys, 0) } - + func testChildren() { XCTAssertEqual(root.children!.count, 2) } diff --git a/B-Tree/Tests/Tests/BTreeTests.swift b/B-Tree/Tests/Tests/BTreeTests.swift index f2dac7511..1e94bfd7d 100644 --- a/B-Tree/Tests/Tests/BTreeTests.swift +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -10,201 +10,201 @@ import XCTest class BTreeTests: XCTestCase { var bTree: BTree! - + override func setUp() { super.setUp() bTree = BTree(order: 3)! } - + // MARK: - Tests on empty tree - + func testOrder() { XCTAssertEqual(bTree.order, 3) } - + func testRootNode() { XCTAssertNotNil(bTree.rootNode) } - + func testNumberOfNodesOnEmptyTree() { XCTAssertEqual(bTree.numberOfKeys, 0) } - + func testInorderTraversalOfEmptyTree() { bTree.traverseKeysInOrder { _ in XCTFail("Inorder travelsal fail.") } } - + func testSubscriptOnEmptyTree() { XCTAssertEqual(bTree[1], nil) } - + func testSearchEmptyTree() { XCTAssertEqual(bTree.value(for: 1), nil) } - + func testInsertToEmptyTree() { bTree.insert(1, for: 1) - + XCTAssertEqual(bTree[1]!, 1) } - + func testRemoveFromEmptyTree() { bTree.remove(1) XCTAssertEqual(bTree.description, "[]") } - + func testInorderArrayFromEmptyTree() { XCTAssertEqual(bTree.inorderArrayFromKeys, [Int]()) } - + func testDescriptionOfEmptyTree() { XCTAssertEqual(bTree.description, "[]") } - + // MARK: - Travelsal - + func testInorderTravelsal() { for i in 1...20 { bTree.insert(i, for: i) } - + var j = 1 - + bTree.traverseKeysInOrder { i in XCTAssertEqual(i, j) j += 1 } } - + // MARK: - Searching - + func testSearchForMaximum() { for i in 1...20 { bTree.insert(i, for: i) } - + XCTAssertEqual(bTree.value(for: 20)!, 20) } - + func testSearchForMinimum() { for i in 1...20 { bTree.insert(i, for: i) } - + XCTAssertEqual(bTree.value(for: 1)!, 1) } - + // MARK: - Insertion - + func testInsertion() { bTree.insertKeysUpTo(20) - + XCTAssertEqual(bTree.numberOfKeys, 20) - + for i in 1...20 { XCTAssertNotNil(bTree[i]) } - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } } - + // MARK: - Removal - + func testRemoveMaximum() { for i in 1...20 { bTree.insert(i, for: i) } - + bTree.remove(20) - + XCTAssertNil(bTree[20]) - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } } - + func testRemoveMinimum() { bTree.insertKeysUpTo(20) - + bTree.remove(1) - + XCTAssertNil(bTree[1]) - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } } - + func testRemoveSome() { bTree.insertKeysUpTo(20) - + bTree.remove(6) bTree.remove(9) - + XCTAssertNil(bTree[6]) XCTAssertNil(bTree[9]) - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } } - + func testRemoveSomeFrom2ndOrder() { bTree = BTree(order: 2)! bTree.insertKeysUpTo(20) - + bTree.remove(6) bTree.remove(9) - + XCTAssertNil(bTree[6]) XCTAssertNil(bTree[9]) - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } } - + func testRemoveAll() { bTree.insertKeysUpTo(20) - + XCTAssertEqual(bTree.numberOfKeys, 20) - + for i in (1...20).reversed() { bTree.remove(i) } - + do { try bTree.checkBalance() } catch { XCTFail("BTree is not balanced") } - + XCTAssertEqual(bTree.numberOfKeys, 0) } - + // MARK: - InorderArray - + func testInorderArray() { bTree.insertKeysUpTo(20) - + let returnedArray = bTree.inorderArrayFromKeys let targetArray = Array(1...20) - + XCTAssertEqual(returnedArray, targetArray) } } @@ -221,7 +221,7 @@ extension BTreeNode { } else if !root && numberOfKeys < owner.order { throw BTreeError.tooFewNodes } - + if !isLeaf { for child in children! { try child.checkBalance(isRoot: false) @@ -234,14 +234,14 @@ extension BTree where Key: SignedInteger, Value: SignedInteger { func insertKeysUpTo(_ to: Int) { var k: Key = 1 var v: Value = 1 - + for _ in 1...to { insert(v, for: k) k = k + 1 v = v + 1 } } - + func checkBalance() throws { try rootNode.checkBalance(isRoot: true) } diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift index 00ac6da97..b9f2b1432 100644 --- a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift +++ b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift @@ -2,7 +2,7 @@ extension String { func indexOf(_ pattern: String) -> String.Index? { - + for i in self.characters.indices { var j = i var found = true diff --git a/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift b/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift index b6e85fa2b..f7c4eec61 100644 --- a/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift +++ b/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift @@ -11,13 +11,13 @@ public func combSort(_ input: [T]) -> [T] { var copy: [T] = input var gap = copy.count let shrink = 1.3 - + while gap > 1 { gap = (Int)(Double(gap) / shrink) if gap < 1 { gap = 1 } - + var index = 0 while !(index + gap >= copy.count) { if copy[index] > copy[index + gap] { diff --git a/Comb Sort/Comb Sort.swift b/Comb Sort/Comb Sort.swift index b6e85fa2b..f7c4eec61 100644 --- a/Comb Sort/Comb Sort.swift +++ b/Comb Sort/Comb Sort.swift @@ -11,13 +11,13 @@ public func combSort(_ input: [T]) -> [T] { var copy: [T] = input var gap = copy.count let shrink = 1.3 - + while gap > 1 { gap = (Int)(Double(gap) / shrink) if gap < 1 { gap = 1 } - + var index = 0 while !(index + gap >= copy.count) { if copy[index] > copy[index + gap] { diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index 1bcc67fd0..b9287f84a 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -16,7 +16,7 @@ class CombSortTests: XCTestCase { super.setUp() sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] } - + override func tearDown() { super.tearDown() } diff --git a/Convex Hull/Convex Hull/AppDelegate.swift b/Convex Hull/Convex Hull/AppDelegate.swift index 4f8496cd5..bfe15e1a7 100644 --- a/Convex Hull/Convex Hull/AppDelegate.swift +++ b/Convex Hull/Convex Hull/AppDelegate.swift @@ -17,16 +17,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let screenBounds = UIScreen.main.bounds - + window = UIWindow(frame: screenBounds) - + let viewController = UIViewController() viewController.view = View(frame: (window?.frame)!) viewController.view.backgroundColor = .white - + window?.rootViewController = viewController window?.makeKeyAndVisible() - + return true } diff --git a/Convex Hull/Convex Hull/View.swift b/Convex Hull/Convex Hull/View.swift index f9f9f6ef4..2f2c3e046 100644 --- a/Convex Hull/Convex Hull/View.swift +++ b/Convex Hull/Convex Hull/View.swift @@ -9,24 +9,24 @@ import UIKit class View: UIView { - + let MAX_POINTS = 100 - + var points = [CGPoint]() - + var convexHull = [CGPoint]() - + override init(frame: CGRect) { super.init(frame: frame) - + generatePoints() quickHull(points: points) } - + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func generatePoints() { for _ in 0.. Bool in return a.x < b.x } } - + func quickHull(points: [CGPoint]) { var pts = points - + // Assume points has at least 2 points // Assume list is ordered on x - + // left most point let p1 = pts.removeFirst() // right most point let p2 = pts.removeLast() - + // p1 and p2 are outer most points and thus are part of the hull convexHull.append(p1) convexHull.append(p2) - + // points to the right of oriented line from p1 to p2 var s1 = [CGPoint]() - + // points to the right of oriented line from p2 to p1 var s2 = [CGPoint]() - + // p1 to p2 line let lineVec1 = CGPoint(x: p2.x - p1.x, y: p2.y - p1.y) - + for p in pts { // per point check if point is to right or left of p1 to p2 line let pVec1 = CGPoint(x: p.x - p1.x, y: p.y - p1.y) let sign1 = lineVec1.x * pVec1.y - pVec1.x * lineVec1.y // cross product to check on which side of the line point p is. - + if sign1 > 0 { // right of p1 p2 line (in a normal xy coordinate system this would be < 0 but due to the weird iPhone screen coordinates this is > 0 s1.append(p) } else { // right of p2 p1 line s2.append(p) } } - + // find new hull points findHull(s1, p1, p2) findHull(s2, p2, p1) } - + func findHull(_ points: [CGPoint], _ p1: CGPoint, _ p2: CGPoint) { // if set of points is empty there are no points to the right of this line so this line is part of the hull. if points.isEmpty { return } - + var pts = points - + // calculate parameters of general line equation y = a * x + b let a = (p1.y - p2.y) / (p1.x - p2.x) let b = p1.y - a * p1.x - + // calculate normal line's growth factor let a1 = -1 / a - + var maxDist: CGFloat = -1 var maxPoint: CGPoint = pts.first! - + for p in pts { // for every point check the distance from our line let b1 = p.y - a1 * p.x // calculate offset to line equation for given point p let x = -(b - b1)/(a - a1) // calculate x where the two lines intersect let y = a * x + b // calculate y value of this intersect point - + let dist = pow(x - p.x, 2) + pow(y - p.y, 2) // calculate distance squared between intersection point and point p if dist > maxDist { // if distance is larger than current maxDist remember new point p maxDist = dist maxPoint = p } } - + convexHull.insert(maxPoint, at: convexHull.index(of: p1)! + 1) // insert point with max distance from line in the convexHull after p1 - + pts.remove(at: pts.index(of: maxPoint)!) // remove maxPoint from points array as we are going to split this array in points left and right of the line - + // points to the right of oriented line from p1 to maxPoint var s1 = [CGPoint]() - + // points to the right of oriented line from maxPoint to p2 var s2 = [CGPoint]() - + // p1 to maxPoint line let lineVec1 = CGPoint(x: maxPoint.x - p1.x, y: maxPoint.y - p1.y) // maxPoint to p2 line let lineVec2 = CGPoint(x: p2.x - maxPoint.x, y: p2.y - maxPoint.y) - + for p in pts { let pVec1 = CGPoint(x: p.x - p1.x, y: p.y - p1.y) // vector from p1 to p let sign1 = lineVec1.x * pVec1.y - pVec1.x * lineVec1.y // sign to check is p is to the right or left of lineVec1 - + let pVec2 = CGPoint(x: p.x - maxPoint.x, y: p.y - maxPoint.y) // vector from p2 to p let sign2 = lineVec2.x * pVec2.y - pVec2.x * lineVec2.y // sign to check is p is to the right or left of lineVec2 @@ -139,34 +139,34 @@ class View: UIView { s2.append(p) } } - + // find new hull points findHull(s1, p1, maxPoint) findHull(s2, maxPoint, p2) } override func draw(_ rect: CGRect) { - + let context = UIGraphicsGetCurrentContext() - + // Draw hull let lineWidth: CGFloat = 2.0 - + context!.setFillColor(UIColor.black.cgColor) context!.setLineWidth(lineWidth) context!.setStrokeColor(UIColor.red.cgColor) context!.setFillColor(UIColor.black.cgColor) - + let firstPoint = convexHull.first! context!.move(to: firstPoint) - + for p in convexHull.dropFirst() { context!.addLine(to: p) } context!.addLine(to: firstPoint) - + context!.strokePath() - + // Draw points for p in points { let radius: CGFloat = 5 diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index 4bc5d66df..8ef545e45 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -10,25 +10,25 @@ struct FixedSizeArray { private var defaultValue: T private var array: [T] private (set) var count = 0 - + init(maxSize: Int, defaultValue: T) { self.maxSize = maxSize self.defaultValue = defaultValue self.array = [T](repeating: defaultValue, count: maxSize) } - + subscript(index: Int) -> T { assert(index >= 0) assert(index < count) return array[index] } - + mutating func append(_ newElement: T) { assert(count < maxSize) array[count] = newElement count += 1 } - + mutating func removeAt(index: Int) -> T { assert(index >= 0) assert(index < count) @@ -38,7 +38,7 @@ struct FixedSizeArray { array[count] = defaultValue return result } - + mutating func removeAll() { for i in 0..(), AdjacencyListGraph()] { - + let v1 = graph.createVertex(1) let v2 = graph.createVertex(2) let v3 = graph.createVertex(3) diff --git a/Hash Set/HashSet.playground/Sources/HashSet.swift b/Hash Set/HashSet.playground/Sources/HashSet.swift index c3365110b..3ccaa94ea 100644 --- a/Hash Set/HashSet.playground/Sources/HashSet.swift +++ b/Hash Set/HashSet.playground/Sources/HashSet.swift @@ -2,31 +2,31 @@ public struct HashSet { fileprivate var dictionary = Dictionary() - + public init() { - + } - + public mutating func insert(_ element: T) { dictionary[element] = true } - + public mutating func remove(_ element: T) { dictionary[element] = nil } - + public func contains(_ element: T) -> Bool { return dictionary[element] != nil } - + public func allElements() -> [T] { return Array(dictionary.keys) } - + public var count: Int { return dictionary.count } - + public var isEmpty: Bool { return dictionary.isEmpty } diff --git a/Hash Table/HashTable.playground/Sources/HashTable.swift b/Hash Table/HashTable.playground/Sources/HashTable.swift index 947737c32..2383b8192 100644 --- a/Hash Table/HashTable.playground/Sources/HashTable.swift +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -34,19 +34,19 @@ public struct HashTable: CustomStringConvertible { private typealias Element = (key: Key, value: Value) private typealias Bucket = [Element] private var buckets: [Bucket] - + /// The number of key-value pairs in the hash table. private(set) public var count = 0 - + /// 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 { @@ -57,7 +57,7 @@ public struct HashTable: CustomStringConvertible { } return str } - + /** Create a hash table with the given capacity. */ @@ -65,7 +65,7 @@ public struct HashTable: CustomStringConvertible { assert(capacity > 0) buckets = Array(repeatElement([], count: capacity)) } - + /** Accesses the value associated with the given key for reading and writing. @@ -82,7 +82,7 @@ public struct HashTable: CustomStringConvertible { } } } - + /** Returns the value for the given key. */ @@ -95,14 +95,14 @@ public struct HashTable: CustomStringConvertible { } return nil // key not in hash table } - + /** Updates the value stored in the hash table for the given key, or adds a new key-value pair if the key does not exist. */ @discardableResult public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { let index = self.index(forKey: key) - + // Do we already have this key in the bucket? for (i, element) in buckets[index].enumerated() { if element.key == key { @@ -111,20 +111,20 @@ public struct HashTable: CustomStringConvertible { return oldValue } } - + // This key isn't in the bucket yet; add it to the chain. buckets[index].append((key: key, value: value)) count += 1 return nil } - + /** Removes the given key and its associated value from the hash table. */ @discardableResult public mutating func removeValue(forKey key: Key) -> Value? { let index = self.index(forKey: key) - + // Find the element in the bucket's chain and remove it. for (i, element) in buckets[index].enumerated() { if element.key == key { @@ -135,7 +135,7 @@ public struct HashTable: CustomStringConvertible { } return nil // key not in hash table } - + /** Removes all key-value pairs from the hash table. */ @@ -143,7 +143,7 @@ public struct HashTable: CustomStringConvertible { buckets = Array(repeatElement([], count: buckets.count)) count = 0 } - + /** Returns the given key's array index. */ diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index a6effb7b0..449fa366d 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,25 +1,25 @@ import UIKit func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { - + let haversin = { (angle: Double) -> Double in return (1 - cos(angle))/2 } - + let ahaversin = { (angle: Double) -> Double in return 2*asin(sqrt(angle)) } - + // Converts from degrees to radians let dToR = { (angle: Double) -> Double in return (angle / 360) * 2 * M_PI } - + let lat1 = dToR(la1) let lon1 = dToR(lo1) let lat2 = dToR(la2) let lon2 = dToR(lo2) - + return radius * ahaversin(haversin(lat2 - lat1) + cos(lat1) * cos(lat2) * haversin(lon2 - lon1)) } diff --git a/Heap/Heap.swift b/Heap/Heap.swift index fa30df362..80b40c65f 100644 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -113,7 +113,7 @@ public struct Heap { */ public mutating func replace(index i: Int, value: T) { guard i < elements.count else { return } - + assert(isOrderedBefore(value, elements[i])) elements[i] = value shiftUp(i) @@ -144,7 +144,7 @@ public struct Heap { */ public mutating func removeAt(_ index: Int) -> T? { guard index < elements.count else { return nil } - + let size = elements.count - 1 if index != size { swap(&elements[index], &elements[size]) diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index 0e6c504f3..cac934406 100644 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -201,7 +201,7 @@ class HeapTests: XCTestCase { XCTAssertEqual(v, nil) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) - + let v1 = h.removeAt(5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) @@ -314,7 +314,7 @@ class HeapTests: XCTestCase { 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)) diff --git a/Huffman Coding/Huffman.swift b/Huffman Coding/Huffman.swift index 7e2961a2f..cad80327d 100644 --- a/Huffman Coding/Huffman.swift +++ b/Huffman Coding/Huffman.swift @@ -13,7 +13,7 @@ public class Huffman { /* Tree nodes don't use pointers to refer to each other, but simple integer indices. That allows us to use structs for the nodes. */ typealias NodeIndex = Int - + /* A node in the compression tree. Leaf nodes represent the actual bytes that are present in the input data. The count of an intermediary node is the sum of the counts of all nodes below it. The root node's count is the number of @@ -25,15 +25,15 @@ public class Huffman { var left: NodeIndex = -1 var right: NodeIndex = -1 } - + /* The tree structure. The first 256 entries are for the leaf nodes (not all of those may be used, depending on the input). We add additional nodes as we build the tree. */ var tree = [Node](repeating: Node(), count: 256) - + /* This is the last node we add to the tree. */ var root: NodeIndex = -1 - + /* The frequency table describes how often a byte occurs in the input data. You need it to decompress the Huffman-encoded data. The frequency table should be serialized along with the compressed data. */ @@ -41,7 +41,7 @@ public class Huffman { var byte: UInt8 = 0 var count = 0 } - + public init() { } } @@ -59,7 +59,7 @@ extension Huffman { ptr = ptr.successor() } } - + /* Takes a frequency table and rebuilds the tree. This is the first step of decompression. */ fileprivate func restoreTree(fromTable frequencyTable: [Freq]) { @@ -70,7 +70,7 @@ extension Huffman { } buildTree() } - + /* Returns the frequency table. This is the first 256 nodes from the tree but only those that are actually used, without the parent/left/right pointers. You would serialize this along with the compressed file. */ @@ -91,13 +91,13 @@ extension Huffman { for node in tree where node.count > 0 { queue.enqueue(node) } - + while queue.count > 1 { // Find the two nodes with the smallest frequencies that do not have // a parent node yet. let node1 = queue.dequeue()! let node2 = queue.dequeue()! - + // Create a new intermediate node. var parentNode = Node() parentNode.count = node1.count + node2.count @@ -105,15 +105,15 @@ extension Huffman { parentNode.right = node2.index parentNode.index = tree.count tree.append(parentNode) - + // Link the two nodes into their new parent node. tree[node1.index].parent = parentNode.index tree[node2.index].parent = parentNode.index - + // Put the intermediate node back into the queue. queue.enqueue(parentNode) } - + // The final remaining node in the queue becomes the root of the tree. let rootNode = queue.dequeue()! root = rootNode.index @@ -125,7 +125,7 @@ extension Huffman { public func compressData(data: NSData) -> NSData { countByteFrequency(inData: data) buildTree() - + let writer = BitWriter() var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0.. NSData { restoreTree(fromTable: frequencyTable) - + let reader = BitReader(data: data) let outData = NSMutableData() let byteCount = tree[root].count - + var i = 0 while i < byteCount { var b = findLeafNode(reader: reader, nodeIndex: root) @@ -172,7 +172,7 @@ extension Huffman { } return outData } - + /* Walks the tree from the root down to the leaf node. At every node, read the next bit and use that to determine whether to step to the left or right. When we get to the leaf node, we simply return its index, which is equal to diff --git a/Huffman Coding/NSData+Bits.swift b/Huffman Coding/NSData+Bits.swift index 4ae3c5c6d..1f5333296 100644 --- a/Huffman Coding/NSData+Bits.swift +++ b/Huffman Coding/NSData+Bits.swift @@ -5,7 +5,7 @@ public class BitWriter { public var data = NSMutableData() var outByte: UInt8 = 0 var outCount = 0 - + public func writeBit(bit: Bool) { if outCount == 8 { data.append(&outByte, length: 1) @@ -14,7 +14,7 @@ public class BitWriter { outByte = (outByte << 1) | (bit ? 1 : 0) outCount += 1 } - + public func flush() { if outCount > 0 { if outCount < 8 { @@ -31,11 +31,11 @@ public class BitReader { var ptr: UnsafePointer var inByte: UInt8 = 0 var inCount = 8 - + public init(data: NSData) { ptr = data.bytes.assumingMemoryBound(to: UInt8.self) } - + public func readBit() -> Bool { if inCount == 8 { inByte = ptr.pointee // load the next byte diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 3ac29301a..2d327fbac 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -17,7 +17,7 @@ func ^^ (radix: Int, power: Int) -> Int { 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))! } - + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) for i in num1Array.indices { @@ -29,7 +29,7 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { } product[i + num2Array.count] += carry } - + return Int(product.reversed().map { String($0) }.reduce("", +))! } @@ -37,24 +37,24 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1Array = String(num1).characters let num2Array = String(num2).characters - + guard num1Array.count > 1 && num2Array.count > 1 else { return multiply(num1, by: num2) } - + let n = max(num1Array.count, num2Array.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/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index fb20a667d..0f0e8ed12 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -22,24 +22,24 @@ func ^^ (radix: Int, power: Int) -> Int { func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1Array = String(num1).characters let num2Array = String(num2).characters - + guard num1Array.count > 1 && num2Array.count > 1 else { return num1 * num2 } - + let n = max(num1Array.count, num2Array.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/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift index 46a88c134..45d9812b7 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -9,54 +9,54 @@ import Foundation extension String { - + func indexesOf(ptnr: String) -> [Int]? { - + let text = Array(self.characters) let pattern = Array(ptnr.characters) - + let textLength: Int = text.count let patternLength: Int = pattern.count - + guard patternLength > 0 else { return nil } - + var suffixPrefix: [Int] = [Int](repeating: 0, count: patternLength) var textIndex: Int = 0 var patternIndex: Int = 0 var indexes: [Int] = [Int]() - + /* Pre-processing stage: computing the table for the shifts (through Z-Algorithm) */ let zeta = ZetaAlgorithm(ptnr: ptnr) - + for patternIndex in (1 ..< patternLength).reversed() { textIndex = patternIndex + zeta![patternIndex] - 1 suffixPrefix[textIndex] = zeta![patternIndex] } - + /* Search stage: scanning the text for pattern matching */ textIndex = 0 patternIndex = 0 - + while textIndex + (patternLength - patternIndex - 1) < textLength { - + while patternIndex < patternLength && text[textIndex] == pattern[patternIndex] { textIndex = textIndex + 1 patternIndex = patternIndex + 1 } - + if patternIndex == patternLength { indexes.append(textIndex - patternIndex) } - + if patternIndex == 0 { textIndex = textIndex + 1 } else { patternIndex = suffixPrefix[patternIndex - 1] } } - + guard !indexes.isEmpty else { return nil } diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 08e14ef70..9ee4cc4c4 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -4,37 +4,37 @@ //: Linked List Class Declaration: 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 - + /// 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? { if var node = head { @@ -46,7 +46,7 @@ public final class LinkedList { return nil } } - + /// Computed property to iterate through the linked list and return the total number of nodes public var count: Int { if var node = head { @@ -60,7 +60,7 @@ public final class LinkedList { return 0 } } - + /// 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 @@ -77,7 +77,7 @@ public final class LinkedList { } return nil } - + /// Subscript function to return the node at a specific index /// /// - Parameter index: Integer value of the requested value's index @@ -86,7 +86,7 @@ public final class LinkedList { assert(node != nil) return node!.value } - + /// Append a value to the end of the list /// /// - Parameter value: The data value to be appended @@ -94,7 +94,7 @@ public final class LinkedList { 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 @@ -107,7 +107,7 @@ 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. @@ -118,28 +118,28 @@ public final class LinkedList { nodeToCopy = node.next } } - + /// 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: @@ -149,7 +149,7 @@ public final class LinkedList { let newNode = Node(value: value) self.insert(newNode, atIndex: index) } - + /// Insert a copy of a node at a specific index. Crashes if index is out of bounds (0...self.count) /// /// - Parameters: @@ -162,12 +162,12 @@ public final class LinkedList { newNode.next = next prev?.next = newNode next?.previous = newNode - + if prev == nil { head = newNode } } - + /// Insert a copy of a LinkedList at a specific index. Crashes if index is out of bounds (0...self.count) /// /// - Parameters: @@ -192,12 +192,12 @@ public final class LinkedList { prev?.next = next next?.previous = prev } - + /// 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 @@ -205,19 +205,19 @@ public final class LinkedList { @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. @@ -225,7 +225,7 @@ public final class LinkedList { 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 @@ -276,7 +276,7 @@ extension LinkedList { } return result } - + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head @@ -294,7 +294,7 @@ extension LinkedList { extension LinkedList { convenience init(array: Array) { self.init() - + for element in array { self.append(element) } @@ -305,7 +305,7 @@ extension LinkedList { extension LinkedList: ExpressibleByArrayLiteral { public convenience init(arrayLiteral elements: T...) { self.init() - + for element in elements { self.append(element) } diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 783e650e8..94e978c07 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,29 +1,29 @@ public final class LinkedList { - + public class LinkedListNode { var value: T var next: LinkedListNode? weak var previous: LinkedListNode? - + public init(value: T) { self.value = value } } - + public typealias Node = LinkedListNode - + fileprivate var head: Node? - + public init() {} - + public var isEmpty: Bool { return head == nil } - + public var first: Node? { return head } - + public var last: Node? { if var node = head { while case let next? = node.next { @@ -34,7 +34,7 @@ public final class LinkedList { return nil } } - + public var count: Int { if var node = head { var c = 1 @@ -47,7 +47,7 @@ public final class LinkedList { return 0 } } - + public func node(atIndex index: Int) -> Node? { if index >= 0 { var node = head @@ -60,18 +60,18 @@ public final class LinkedList { } return nil } - + public subscript(index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) return node!.value } - + public func append(_ value: T) { let newNode = Node(value: value) self.append(newNode) } - + public func append(_ node: Node) { let newNode = LinkedListNode(value: node.value) if let lastNode = last { @@ -81,7 +81,7 @@ public final class LinkedList { head = newNode } } - + public func append(_ list: LinkedList) { var nodeToCopy = list.head while let node = nodeToCopy { @@ -89,29 +89,29 @@ public final class LinkedList { nodeToCopy = node.next } } - + 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) @@ -119,12 +119,12 @@ public final class LinkedList { newNode.next = next prev?.next = newNode next?.previous = newNode - + if prev == nil { head = newNode } } - + public func insert(_ list: LinkedList, atIndex index: Int) { if list.isEmpty { return } var (prev, next) = nodesBeforeAndAfter(index: index) @@ -144,32 +144,32 @@ public final class LinkedList { prev?.next = next next?.previous = prev } - + public func removeAll() { head = nil } - + @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 } - + @discardableResult public func removeLast() -> T { assert(!isEmpty) return remove(node: last!) } - + @discardableResult public func remove(atIndex index: Int) -> T { let node = self.node(atIndex: index) assert(node != nil) @@ -211,7 +211,7 @@ extension LinkedList { } return result } - + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head @@ -228,7 +228,7 @@ extension LinkedList { extension LinkedList { convenience init(array: Array) { self.init() - + for element in array { self.append(element) } @@ -238,7 +238,7 @@ extension LinkedList { extension LinkedList: ExpressibleByArrayLiteral { public convenience init(arrayLiteral elements: T...) { self.init() - + for element in elements { self.append(element) } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index ea063cacb..7fd31c2c7 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -165,7 +165,7 @@ class LinkedListTest: XCTestCase { XCTAssertTrue(prev!.next === node) XCTAssertTrue(next!.previous === node) } - + func testInsertListAtIndex() { let list = buildList() let list2 = LinkedList() @@ -190,7 +190,7 @@ class LinkedListTest: XCTestCase { XCTAssertEqual(list.node(atIndex: 1)?.value, 102) XCTAssertEqual(list.node(atIndex: 2)?.value, 8) } - + func testInsertListAtLastIndex() { let list = buildList() let list2 = LinkedList() @@ -202,7 +202,7 @@ class LinkedListTest: XCTestCase { XCTAssertEqual(list.node(atIndex: 6)?.value, 99) XCTAssertEqual(list.node(atIndex: 7)?.value, 102) } - + func testAppendList() { let list = buildList() let list2 = LinkedList() @@ -214,7 +214,7 @@ class LinkedListTest: XCTestCase { XCTAssertEqual(list.node(atIndex: 6)?.value, 99) XCTAssertEqual(list.node(atIndex: 7)?.value, 102) } - + func testAppendListToEmptyList() { let list = LinkedList() let list2 = LinkedList() @@ -225,7 +225,7 @@ class LinkedListTest: XCTestCase { XCTAssertEqual(list.node(atIndex: 0)?.value, 5) XCTAssertEqual(list.node(atIndex: 1)?.value, 10) } - + func testRemoveAtIndexOnListWithOneElement() { let list = LinkedList() list.append(123) @@ -308,10 +308,10 @@ class LinkedListTest: XCTestCase { 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) @@ -319,10 +319,10 @@ class LinkedListTest: XCTestCase { 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) diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift index 9dca23996..ee2ace8b9 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift @@ -23,38 +23,38 @@ import Foundation */ 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 } @@ -71,17 +71,17 @@ public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { */ 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 } @@ -100,12 +100,12 @@ 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.swift b/Miller-Rabin Primality Test/MRPrimality.swift index 9dca23996..ee2ace8b9 100644 --- a/Miller-Rabin Primality Test/MRPrimality.swift +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -23,38 +23,38 @@ import Foundation */ 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 } @@ -71,17 +71,17 @@ public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { */ 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 } @@ -100,12 +100,12 @@ 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/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift index d651ddf2e..238afeb9b 100755 --- a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift +++ b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift @@ -1,21 +1,21 @@ extension String { - + public func minimumEditDistance(other: String) -> Int { let m = self.characters.count let n = other.characters.count var matrix = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) - + // initialize matrix for index in 1...m { // the distance of any first string to an empty second string matrix[index][0] = index } - + for index in 1...n { // the distance of any second string to an empty first string matrix[0][index] = index } - + // compute Levenshtein distance for (i, selfChar) in self.characters.enumerated() { for (j, otherChar) in other.characters.enumerated() { diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index 1a0320a65..5ca0d7d31 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -49,7 +49,7 @@ public struct OrderedArray { private func findInsertionPoint(_ newElement: T) -> Int { var startIndex = 0 var endIndex = array.count - + while startIndex < endIndex { let midIndex = startIndex + (endIndex - startIndex) / 2 if array[midIndex] == newElement { diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index e8562a367..b9e857dd0 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -10,7 +10,7 @@ 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) } @@ -28,14 +28,14 @@ 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.swift b/Palindromes/Palindromes.swift index 2760137ca..9ddd04c80 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Palindromes.swift @@ -3,7 +3,7 @@ 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) } @@ -14,13 +14,13 @@ 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/Palindromes.swift b/Palindromes/Test/Palindromes.swift index 2760137ca..9ddd04c80 100644 --- a/Palindromes/Test/Palindromes.swift +++ b/Palindromes/Test/Palindromes.swift @@ -3,7 +3,7 @@ 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) } @@ -14,13 +14,13 @@ 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/Test.swift b/Palindromes/Test/Test/Test.swift index 1dd79ea97..ddf970300 100644 --- a/Palindromes/Test/Test/Test.swift +++ b/Palindromes/Test/Test/Test.swift @@ -9,22 +9,22 @@ import XCTest class PalindromeTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + 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() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + func testPerformanceExample() { // This is an example of a performance test case. self.measure { @@ -34,12 +34,12 @@ class PalindromeTests: XCTestCase { _ = isPalindrome("abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa") } } - + func testPalindromeWord() { XCTAssertTrue(isPalindrome("abbcbba")) XCTAssertTrue(isPalindrome("racecar")) } - + func testPalindromeSentence() { XCTAssertTrue(isPalindrome("A man, a plan, a canal, Panama!")) XCTAssertTrue(isPalindrome("Madam, I'm Adam")) @@ -47,17 +47,17 @@ class PalindromeTests: XCTestCase { XCTAssertTrue(isPalindrome("In girum imus nocte et consumimur igni")) XCTAssertTrue(isPalindrome("Never odd or even")) } - + func testPalindromeNumber() { XCTAssertTrue(isPalindrome("5885")) XCTAssertTrue(isPalindrome("5 8 8 5")) XCTAssertTrue(isPalindrome("58 85")) } - + func testSpecialCharacters() { XCTAssertTrue(isPalindrome("৯৯")) } - + func testNonPalindromes() { XCTAssertFalse(isPalindrome("\\\\")) XCTAssertFalse(isPalindrome("desserts")) diff --git a/QuadTree/QuadTree.playground/Sources/QuadTree.swift b/QuadTree/QuadTree.playground/Sources/QuadTree.swift index 14d0dbba7..7fd459e97 100644 --- a/QuadTree/QuadTree.playground/Sources/QuadTree.swift +++ b/QuadTree/QuadTree.playground/Sources/QuadTree.swift @@ -1,7 +1,7 @@ public struct Point { let x: Double let y: Double - + public init(_ x: Double, _ y: Double) { self.x = x self.y = y @@ -17,18 +17,18 @@ extension Point: CustomStringConvertible { public struct Size: CustomStringConvertible { var xLength: Double var yLength: Double - + public init(xLength: Double, yLength: Double) { precondition(xLength >= 0, "xLength can not be negative") precondition(yLength >= 0, "yLength can not be negative") self.xLength = xLength self.yLength = yLength } - + var half: Size { return Size(xLength: xLength / 2, yLength: yLength / 2) } - + public var description: String { return "Size(\(xLength), \(yLength))" } @@ -38,49 +38,49 @@ public struct Rect { // left top vertice var origin: Point var size: Size - + public init(origin: Point, size: Size) { self.origin = origin self.size = size } - + var minX: Double { return origin.x } - + var minY: Double { return origin.y } - + var maxX: Double { return origin.x + size.xLength } - + var maxY: Double { return origin.y + size.yLength } - + func containts(point: Point) -> Bool { return (minX <= point.x && point.x <= maxX) && (minY <= point.y && point.y <= maxY) } - + var leftTopRect: Rect { return Rect(origin: origin, size: size.half) } - + var leftBottomRect: Rect { return Rect(origin: Point(origin.x, origin.y + size.half.yLength), size: size.half) } - + var rightTopRect: Rect { return Rect(origin: Point(origin.x + size.half.xLength, origin.y), size: size.half) } - + var rightBottomRect: Rect { return Rect(origin: Point(origin.x + size.half.xLength, origin.y + size.half.yLength), size: size.half) } - + func intersects(rect: Rect) -> Bool { func lineSegmentsIntersect(lStart: Double, lEnd: Double, rStart: Double, rEnd: Double) -> Bool { @@ -91,7 +91,7 @@ public struct Rect { if !lineSegmentsIntersect(lStart: minX, lEnd: maxX, rStart: rect.minX, rEnd: rect.maxX) { return false } - + // vertical return lineSegmentsIntersect(lStart: minY, lEnd: maxY, rStart: rect.minY, rEnd: rect.maxY) } @@ -109,37 +109,37 @@ protocol PointsContainer { } class QuadTreeNode { - + enum NodeType { case leaf case `internal`(children: Children) } - + struct Children: Sequence { let leftTop: QuadTreeNode let leftBottom: QuadTreeNode let rightTop: QuadTreeNode let rightBottom: QuadTreeNode - + init(parentNode: QuadTreeNode) { leftTop = QuadTreeNode(rect: parentNode.rect.leftTopRect) leftBottom = QuadTreeNode(rect: parentNode.rect.leftBottomRect) rightTop = QuadTreeNode(rect: parentNode.rect.rightTopRect) rightBottom = QuadTreeNode(rect: parentNode.rect.rightBottomRect) } - + struct ChildrenIterator: IteratorProtocol { private var index = 0 private let children: Children - + init(children: Children) { self.children = children } - + mutating func next() -> QuadTreeNode? { - + defer { index += 1 } - + switch index { case 0: return children.leftTop case 1: return children.leftBottom @@ -149,26 +149,26 @@ class QuadTreeNode { } } } - + public func makeIterator() -> ChildrenIterator { return ChildrenIterator(children: self) } } - + var points: [Point] = [] let rect: Rect var type: NodeType = .leaf - + static let maxPointCapacity = 3 - + init(rect: Rect) { self.rect = rect } - + var recursiveDescription: String { return recursiveDescription(withTabCount: 0) } - + private func recursiveDescription(withTabCount count: Int) -> String { let indent = String(repeating: "\t", count: count) var result = "\(indent)" + description + "\n" @@ -185,13 +185,13 @@ class QuadTreeNode { } extension QuadTreeNode: PointsContainer { - + @discardableResult func add(point: Point) -> Bool { if !rect.containts(point: point) { return false } - + switch type { case .internal(let children): // pass the point to one of the children @@ -200,7 +200,7 @@ extension QuadTreeNode: PointsContainer { return true } } - + fatalError("rect.containts evaluted to true, but none of the children added the point") case .leaf: points.append(point) @@ -211,7 +211,7 @@ extension QuadTreeNode: PointsContainer { } return true } - + private func subdivide() { switch type { case .leaf: @@ -220,25 +220,25 @@ extension QuadTreeNode: PointsContainer { preconditionFailure("Calling subdivide on an internal node") } } - + 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) { result.append(point) } } - + switch type { case .leaf: break @@ -248,7 +248,7 @@ extension QuadTreeNode: PointsContainer { result.append(contentsOf: childNode.points(inRect: rect)) } } - + return result } } @@ -265,18 +265,18 @@ extension QuadTreeNode: CustomStringConvertible { } public class QuadTree: PointsContainer { - + let root: QuadTreeNode - + public init(rect: Rect) { self.root = QuadTreeNode(rect: rect) } - + @discardableResult public func add(point: Point) -> Bool { return root.add(point: point) } - + public func points(inRect rect: Rect) -> [Point] { return root.points(inRect: rect) } diff --git a/QuadTree/Tests/Tests/Tests.swift b/QuadTree/Tests/Tests/Tests.swift index b408c4f7e..9bd8ad28f 100644 --- a/QuadTree/Tests/Tests/Tests.swift +++ b/QuadTree/Tests/Tests/Tests.swift @@ -17,68 +17,68 @@ public func == (lhs: Point, rhs: Point) -> Bool { } class Tests: XCTestCase { - + func testRectContains() { let rect = Rect(origin: Point(0, 0), size: Size(xLength: 3, yLength: 3)) - + XCTAssertTrue(rect.containts(point: Point(1, 1))) XCTAssertTrue(rect.containts(point: Point(0, 0))) XCTAssertTrue(rect.containts(point: Point(0, 3))) XCTAssertTrue(rect.containts(point: Point(3, 3))) - + XCTAssertFalse(rect.containts(point: Point(-1, 1))) XCTAssertFalse(rect.containts(point: Point(-0.1, 0.1))) XCTAssertFalse(rect.containts(point: Point(0, 3.1))) XCTAssertFalse(rect.containts(point: Point(-4, 1))) } - + func testIntersects() { let rect = Rect(origin: Point(0, 0), size: Size(xLength: 5, yLength: 5)) let rect2 = Rect(origin: Point(1, 1), size: Size(xLength: 1, yLength: 1)) XCTAssertTrue(rect.intersects(rect: rect2)) - + let rect3 = Rect(origin: Point(1, 0), size: Size(xLength: 1, yLength: 10)) let rect4 = Rect(origin: Point(0, 1), size: Size(xLength: 10, yLength: 1)) XCTAssertTrue(rect3.intersects(rect: rect4)) - + let rect5 = Rect(origin: Point(0, 0), size: Size(xLength: 4, yLength: 4)) let rect6 = Rect(origin: Point(2, 2), size: Size(xLength: 4, yLength: 4)) XCTAssertTrue(rect5.intersects(rect: rect6)) - + let rect7 = Rect(origin: Point(0, 0), size: Size(xLength: 4, yLength: 4)) let rect8 = Rect(origin: Point(4, 4), size: Size(xLength: 1, yLength: 1)) XCTAssertTrue(rect7.intersects(rect: rect8)) - + let rect9 = Rect(origin: Point(-1, -1), size: Size(xLength: 0.5, yLength: 0.5)) let rect10 = Rect(origin: Point(0, 0), size: Size(xLength: 1, yLength: 1)) XCTAssertFalse(rect9.intersects(rect: rect10)) - + let rect11 = Rect(origin: Point(0, 0), size: Size(xLength: 2, yLength: 1)) let rect12 = Rect(origin: Point(3, 0), size: Size(xLength: 1, yLength: 1)) XCTAssertFalse(rect11.intersects(rect: rect12)) } - + func testQuadTree() { let rect = Rect(origin: Point(0, 0), size: Size(xLength: 5, yLength: 5)) let qt = QuadTree(rect: rect) - + XCTAssertTrue(qt.points(inRect: rect) == [Point]()) - + XCTAssertFalse(qt.add(point: Point(-0.1, 0.1))) - + XCTAssertTrue(qt.points(inRect: rect) == [Point]()) - + XCTAssertTrue(qt.add(point: Point(1, 1))) XCTAssertTrue(qt.add(point: Point(3, 3))) XCTAssertTrue(qt.add(point: Point(4, 4))) XCTAssertTrue(qt.add(point: Point(0.5, 0.5))) - + XCTAssertFalse(qt.add(point: Point(5.5, 0))) XCTAssertFalse(qt.add(point: Point(5.5, 1))) XCTAssertFalse(qt.add(point: Point(5.5, 2))) - + XCTAssertTrue(qt.add(point: Point(1.5, 1.5))) - + let rect2 = Rect(origin: Point(0, 0), size: Size(xLength: 2, yLength: 2)) XCTAssertTrue(qt.points(inRect: rect2) == [Point(1, 1), Point(0.5, 0.5), Point(1.5, 1.5)]) } diff --git a/Radix Sort/RadixSort.playground/Sources/radixSort.swift b/Radix Sort/RadixSort.playground/Sources/radixSort.swift index 136ede4fd..81c2479e8 100644 --- a/Radix Sort/RadixSort.playground/Sources/radixSort.swift +++ b/Radix Sort/RadixSort.playground/Sources/radixSort.swift @@ -11,18 +11,18 @@ public func radixSort(_ array: inout [Int] ) { var done = false var index: Int var digit = 1 //Which digit are we on? - - + + while !done { //While our sorting is not completed done = true //Assume it is done for now - + var buckets: [[Int]] = [] //Our sorting subroutine is bucket sort, so let us predefine our buckets - + for _ in 1...radix { buckets.append([]) } - - + + for number in array { index = number / digit //Which bucket will we access? buckets[index % radix].append(number) @@ -30,9 +30,9 @@ public func radixSort(_ array: inout [Int] ) { done = false } } - + var i = 0 - + for j in 0..: CustomStringConvertible { public var right: RBTNode! public var left: RBTNode! public var parent: RBTNode! - + public var description: String { if self.value == nil { return "null" } else { var nodeValue: String - + // If the value is encapsulated by parentheses it is red // If the value is encapsulated by pipes it is black // If the value is encapsulated by double pipes it is double black (This should not occur in a verified RBTree) @@ -27,33 +27,33 @@ public class RBTNode: CustomStringConvertible { } else { nodeValue = "||\(self.value!)||" } - + return "(\(self.left.description)<-\(nodeValue)->\(self.right.description))" } } - + init(tree: RBTree) { right = tree.nullLeaf left = tree.nullLeaf parent = tree.nullLeaf } - + init() { //This method is here to support the creation of a nullLeaf } - + public var isLeftChild: Bool { return self.parent.left === self } - + public var isRightChild: Bool { return self.parent.right === self } - + public var grandparent: RBTNode { return parent.parent } - + public var sibling: RBTNode { if isLeftChild { return self.parent.right @@ -61,19 +61,19 @@ public class RBTNode: CustomStringConvertible { return self.parent.left } } - + public var uncle: RBTNode { return parent.sibling } - + fileprivate var isRed: Bool { return color == .red } - + fileprivate var isBlack: Bool { return color == .black } - + fileprivate var isDoubleBlack: Bool { return color == .doubleBlack } @@ -82,70 +82,70 @@ public class RBTNode: CustomStringConvertible { public class RBTree: CustomStringConvertible { public var root: RBTNode fileprivate let nullLeaf: RBTNode - + public var description: String { return root.description } - + public init() { nullLeaf = RBTNode() nullLeaf.color = .black root = nullLeaf } - + public convenience init(withValue value: T) { self.init() insert(value) } - + public convenience init(withArray array: [T]) { self.init() insert(array) } - + public func insert(_ value: T) { let newNode = RBTNode(tree: self) newNode.value = value insertNode(n: newNode) } - + public func insert(_ values: [T]) { for value in values { print(value) insert(value) } } - + public func delete(_ value: T) { let nodeToDelete = find(value) if nodeToDelete !== nullLeaf { deleteNode(n: nodeToDelete) } } - + public func find(_ value: T) -> RBTNode { let foundNode = findNode(rootNode: root, value: value) return foundNode } - + public func minimum(n: RBTNode) -> RBTNode { var min = n if n.left !== nullLeaf { min = minimum(n: n.left) } - + return min } - + public func maximum(n: RBTNode) -> RBTNode { var max = n if n.right !== nullLeaf { max = maximum(n: n.right) } - + return max } - + public func verify() { if self.root === nullLeaf { print("The tree is empty") @@ -155,7 +155,7 @@ public class RBTree: CustomStringConvertible { property2(n: self.root) property3() } - + private func findNode(rootNode: RBTNode, value: T) -> RBTNode { var nextNode = rootNode if rootNode !== nullLeaf && value != rootNode.value { @@ -165,15 +165,15 @@ public class RBTree: CustomStringConvertible { nextNode = findNode(rootNode: rootNode.right, value: value) } } - + return nextNode } - + private func insertNode(n: RBTNode) { BSTInsertNode(n: n, parent: root) insertCase1(n: n) } - + private func BSTInsertNode(n: RBTNode, parent: RBTNode) { if parent === nullLeaf { self.root = n @@ -193,7 +193,7 @@ public class RBTree: CustomStringConvertible { } } } - + // if node is root change color to black, else move on private func insertCase1(n: RBTNode) { if n === root { @@ -202,14 +202,14 @@ public class RBTree: CustomStringConvertible { insertCase2(n: n) } } - + // if parent of node is not black, and node is not root move on private func insertCase2(n: RBTNode) { if !n.parent.isBlack { insertCase3(n: n) } } - + // if uncle is red do stuff otherwise move to 4 private func insertCase3(n: RBTNode) { if n.uncle.isRed { // node must have grandparent as children of root have a black parent @@ -224,14 +224,14 @@ public class RBTree: CustomStringConvertible { insertCase4(n: n) } } - + // parent is red, grandparent is black, uncle is black // There are 4 cases left: // - left left // - left right // - right right // - right left - + // the cases "left right" and "right left" can be rotated into the other two // so if either of the two is detected we apply a rotation and then move on to // deal with the final two cases, if neither is detected we move on to those cases anyway @@ -246,28 +246,28 @@ public class RBTree: CustomStringConvertible { insertCase5(n: n) } } - + private func insertCase5(n: RBTNode) { // swap color of parent and grandparent // parent is red grandparent is black n.parent.color = .black n.grandparent.color = .red - + if n.isLeftChild { // left left case rightRotate(n: n.grandparent) } else { // right right case leftRotate(n: n.grandparent) } } - + private func deleteNode(n: RBTNode) { var toDel = n - + if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.parent === nullLeaf { self.root = nullLeaf return } - + if toDel.left === nullLeaf && toDel.right === nullLeaf && toDel.isRed { if toDel.isLeftChild { toDel.parent.left = nullLeaf @@ -276,38 +276,38 @@ public class RBTree: CustomStringConvertible { } return } - + if toDel.left !== nullLeaf && toDel.right !== nullLeaf { let pred = maximum(n: toDel.left) toDel.value = pred.value toDel = pred } - + // from here toDel has at most 1 non nullLeaf child - + var child: RBTNode if toDel.left !== nullLeaf { child = toDel.left } else { child = toDel.right } - + if toDel.isRed || child.isRed { child.color = .black - + if toDel.isLeftChild { toDel.parent.left = child } else { toDel.parent.right = child } - + if child !== nullLeaf { child.parent = toDel.parent } } else { // both toDel and child are black - + var sibling = toDel.sibling - + if toDel.isLeftChild { toDel.parent.left = child } else { @@ -317,10 +317,10 @@ public class RBTree: CustomStringConvertible { child.parent = toDel.parent } child.color = .doubleBlack - + while child.isDoubleBlack || (child.parent !== nullLeaf && child.parent != nil) { if sibling.isBlack { - + var leftRedChild: RBTNode! = nil if sibling.left.isRed { leftRedChild = sibling.left @@ -329,7 +329,7 @@ public class RBTree: CustomStringConvertible { if sibling.right.isRed { rightRedChild = sibling.right } - + if leftRedChild != nil || rightRedChild != nil { // at least one of sibling's children are red child.color = .black if sibling.isLeftChild { @@ -389,7 +389,7 @@ public class RBTree: CustomStringConvertible { } } else { // sibling is red sibling.color = .black - + if sibling.isLeftChild { // left case rightRotate(n: sibling.parent) sibling = sibling.right.left @@ -400,7 +400,7 @@ public class RBTree: CustomStringConvertible { sibling.parent.color = .red } } - + // sibling check is here for when child is a nullLeaf and thus does not have a parent. // child is here as sibling can become nil when child is the root if (sibling.parent === nullLeaf) || (child !== nullLeaf && child.parent === nullLeaf) { @@ -409,14 +409,14 @@ public class RBTree: CustomStringConvertible { } } } - + private func property1() { - + if self.root.isRed { print("Root is not black") } } - + private func property2(n: RBTNode) { if n === nullLeaf { return @@ -431,48 +431,48 @@ public class RBTree: CustomStringConvertible { property2(n: n.left) property2(n: n.right) } - + private func property3() { let bDepth = blackDepth(root: self.root) - + let leaves: [RBTNode] = getLeaves(n: self.root) - + for leaflet in leaves { var leaf = leaflet var i = 0 - + while leaf !== nullLeaf { if leaf.isBlack { i = i + 1 } leaf = leaf.parent } - + if i != bDepth { print("black depth: \(bDepth), is not equal (depth: \(i)) for leaf with value: \(leaflet.value)") } } - + } - + private func getLeaves(n: RBTNode) -> [RBTNode] { var leaves = [RBTNode]() - + if n !== nullLeaf { if n.left === nullLeaf && n.right === nullLeaf { leaves.append(n) } else { let leftLeaves = getLeaves(n: n.left) let rightLeaves = getLeaves(n: n.right) - + leaves.append(contentsOf: leftLeaves) leaves.append(contentsOf: rightLeaves) } } - + return leaves } - + private func blackDepth(root: RBTNode) -> Int { if root === nullLeaf { return 0 @@ -481,7 +481,7 @@ public class RBTree: CustomStringConvertible { return returnValue + (max(blackDepth(root: root.left), blackDepth(root: root.right))) } } - + private func leftRotate(n: RBTNode) { let newRoot = n.right! n.right = newRoot.left! @@ -499,7 +499,7 @@ public class RBTree: CustomStringConvertible { newRoot.left = n n.parent = newRoot } - + private func rightRotate(n: RBTNode) { let newRoot = n.left! n.left = newRoot.right! diff --git a/Run-Length Encoding/RLE.playground/Contents.swift b/Run-Length Encoding/RLE.playground/Contents.swift index 11e177d0d..26f7dca48 100644 --- a/Run-Length Encoding/RLE.playground/Contents.swift +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -12,16 +12,16 @@ originalString == restoredString func encodeAndDecode(_ bytes: [UInt8]) -> Bool { var bytes = bytes - + var data1 = Data(bytes: &bytes, count: bytes.count) print("data1 is \(data1.count) bytes") - + var rleData = data1.compressRLE() print("encoded data is \(rleData.count) bytes") - + var data2 = rleData.decompressRLE() print("data2 is \(data2.count) bytes") - + return data1 == data2 } @@ -66,10 +66,10 @@ func testBufferWithoutSpans() -> Bool { func testBufferWithSpans(_ spanSize: Int) -> Bool { print("span size \(spanSize)") - + let length = spanSize * 32 var bytes: [UInt8] = Array(repeating: 0, count: length) - + for t in stride(from: 0, to: length, by: spanSize) { for i in 0.. Bool { for bool in tests { result = result && bool } - + return result } diff --git a/Run-Length Encoding/RLE.playground/Sources/RLE.swift b/Run-Length Encoding/RLE.playground/Sources/RLE.swift index 5707e3d9d..0bb6fa00d 100644 --- a/Run-Length Encoding/RLE.playground/Sources/RLE.swift +++ b/Run-Length Encoding/RLE.playground/Sources/RLE.swift @@ -13,7 +13,7 @@ extension Data { var count = 0 var byte = ptr.pointee var next = byte - + // Is the next byte the same? Keep reading until we find a different // value, or we reach the end of the data, or the run is 64 bytes. while next == byte && ptr < end && count < 64 { @@ -21,7 +21,7 @@ extension Data { next = ptr.pointee count += 1 } - + if count > 1 || byte >= 192 { // byte run of up to 64 repeats var size = 191 + UInt8(count) data.append(&size, count: 1) @@ -33,7 +33,7 @@ extension Data { } return data } - + /* Converts a run-length encoded NSData back to the original. */ @@ -42,20 +42,20 @@ extension Data { self.withUnsafeBytes { (uPtr: UnsafePointer) in var ptr = uPtr let end = ptr + count - + while ptr < end { // Read the next byte. This is either a single value less than 192, // or the start of a byte run. var byte = ptr.pointee ptr = ptr.advanced(by: 1) - + if byte < 192 { // single value data.append(&byte, count: 1) } else if ptr < end { // byte run // Read the actual data value. var value = ptr.pointee ptr = ptr.advanced(by: 1) - + // And write it out repeatedly. for _ in 0 ..< byte - 191 { data.append(&value, count: 1) diff --git a/Segment Tree/SegmentTree.playground/Contents.swift b/Segment Tree/SegmentTree.playground/Contents.swift index 5bba56cc0..08474aee2 100644 --- a/Segment Tree/SegmentTree.playground/Contents.swift +++ b/Segment Tree/SegmentTree.playground/Contents.swift @@ -1,19 +1,19 @@ //: Playground - noun: a place where people can play public class SegmentTree { - + private var value: T private var function: (T, T) -> T private var leftBound: Int private var rightBound: Int private var leftChild: SegmentTree? private var rightChild: SegmentTree? - + public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) { self.leftBound = leftBound self.rightBound = rightBound self.function = function - + if leftBound == rightBound { value = array[leftBound] } else { @@ -23,19 +23,19 @@ public class SegmentTree { value = function(leftChild!.value, rightChild!.value) } } - + public convenience init(array: [T], function: @escaping (T, T) -> T) { self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) } - + public func query(leftBound: Int, rightBound: Int) -> T { if self.leftBound == leftBound && self.rightBound == rightBound { return self.value } - + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } - + if leftChild.rightBound < leftBound { return rightChild.query(leftBound: leftBound, rightBound: rightBound) } else if rightChild.leftBound > rightBound { @@ -46,7 +46,7 @@ public class SegmentTree { return function(leftResult, rightResult) } } - + public func replaceItem(at index: Int, withItem item: T) { if leftBound == rightBound { value = item @@ -83,7 +83,7 @@ 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 diff --git a/Segment Tree/SegmentTree.swift b/Segment Tree/SegmentTree.swift index a3ec8b1bf..6f4edd306 100644 --- a/Segment Tree/SegmentTree.swift +++ b/Segment Tree/SegmentTree.swift @@ -8,19 +8,19 @@ */ public class SegmentTree { - + private var value: T private var function: (T, T) -> T private var leftBound: Int private var rightBound: Int private var leftChild: SegmentTree? private var rightChild: SegmentTree? - + public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) { self.leftBound = leftBound self.rightBound = rightBound self.function = function - + if leftBound == rightBound { value = array[leftBound] } else { @@ -30,19 +30,19 @@ public class SegmentTree { value = function(leftChild!.value, rightChild!.value) } } - + public convenience init(array: [T], function: @escaping (T, T) -> T) { self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function) } - + public func query(leftBound: Int, rightBound: Int) -> T { if self.leftBound == leftBound && self.rightBound == rightBound { return self.value } - + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } - + if leftChild.rightBound < leftBound { return rightChild.query(leftBound: leftBound, rightBound: rightBound) } else if rightChild.leftBound > rightBound { @@ -53,7 +53,7 @@ public class SegmentTree { return function(leftResult, rightResult) } } - + public func replaceItem(at index: Int, withItem item: T) { if leftBound == rightBound { value = item diff --git a/Select Minimum Maximum/MinimumMaximumPairs.swift b/Select Minimum Maximum/MinimumMaximumPairs.swift index b7deb570a..81942b303 100644 --- a/Select Minimum Maximum/MinimumMaximumPairs.swift +++ b/Select Minimum Maximum/MinimumMaximumPairs.swift @@ -35,6 +35,6 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { } } } - + return (minimum, maximum) } diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift index 182060805..dbf3a7468 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift @@ -4,7 +4,7 @@ func minimum(_ array: [T]) -> T? { guard !array.isEmpty else { return nil } - + var minimum = array.removeFirst() for element in array { minimum = element < minimum ? element : minimum @@ -18,7 +18,7 @@ func maximum(_ array: [T]) -> T? { guard !array.isEmpty else { return nil } - + var maximum = array.removeFirst() for element in array { maximum = element > maximum ? element : maximum @@ -32,18 +32,18 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { guard !array.isEmpty else { return nil } - + var minimum = array.first! var maximum = array.first! - + let hasOddNumberOfItems = array.count % 2 != 0 if hasOddNumberOfItems { array.removeFirst() } - + while !array.isEmpty { let pair = (array.removeFirst(), array.removeFirst()) - + if pair.0 > pair.1 { if pair.0 > maximum { maximum = pair.0 @@ -60,7 +60,7 @@ func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { } } } - + return (minimum, maximum) } diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift index aaf58cf4d..e9cee7543 100644 --- a/Shell Sort/ShellSortExample.swift +++ b/Shell Sort/ShellSortExample.swift @@ -10,18 +10,18 @@ import Foundation public func shellSort(_ list : inout [Int]) { var sublistCount = list.count / 2 - + while sublistCount > 0 { for var index in 0.. list[index + sublistCount] { swap(&list[index], &list[index + sublistCount]) } - + guard sublistCount == 1 && index > 0 else { continue } - + while list[index - 1] > list[index] && index - 1 > 0 { swap(&list[index - 1], &list[index]) index -= 1 diff --git a/Shortest Path (Unweighted)/Tests/Graph.swift b/Shortest Path (Unweighted)/Tests/Graph.swift index 8322ba0a9..4d2e59eab 100644 --- a/Shortest Path (Unweighted)/Tests/Graph.swift +++ b/Shortest Path (Unweighted)/Tests/Graph.swift @@ -2,7 +2,7 @@ open class Edge: Equatable { open var neighbor: Node - + public init(neighbor: Node) { self.neighbor = neighbor } @@ -17,28 +17,28 @@ public func == (lhs: Edge, rhs: Edge) -> Bool { open class Node: CustomStringConvertible, Equatable { open var neighbors: [Edge] - + open fileprivate(set) var label: String open var distance: Int? open var visited: Bool - + public init(label: String) { self.label = label neighbors = [] visited = false } - + open var description: String { if let distance = distance { return "Node(label: \(label), distance: \(distance))" } return "Node(label: \(label), distance: infinity)" } - + open var hasDistance: Bool { return distance != nil } - + open func remove(_ edge: Edge) { neighbors.remove(at: neighbors.index { $0 === edge }!) } @@ -52,25 +52,25 @@ public func == (lhs: Node, rhs: Node) -> Bool { open class Graph: CustomStringConvertible, Equatable { open fileprivate(set) var nodes: [Node] - + public init() { self.nodes = [] } - + open func addNode(label: String) -> Node { let node = Node(label: label) nodes.append(node) return node } - + open func addEdge(_ source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) source.neighbors.append(edge) } - + open var description: String { var description = "" - + for node in nodes { if !node.neighbors.isEmpty { description += "[node: \(node.label) edges: \(node.neighbors.map { $0.neighbor.label})]" @@ -78,18 +78,18 @@ open class Graph: CustomStringConvertible, Equatable { } return description } - + open func findNodeWithLabel(label: String) -> Node { return nodes.filter { $0.label == label }.first! } - + open func duplicate() -> Graph { let duplicated = Graph() - + for node in nodes { duplicated.addNode(label: node.label) } - + for node in nodes { for edge in node.neighbors { let source = duplicated.findNodeWithLabel(label: node.label) @@ -97,7 +97,7 @@ open class Graph: CustomStringConvertible, Equatable { duplicated.addEdge(source, neighbor: neighbour) } } - + return duplicated } } diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index fa9f5745b..bd4d15515 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -12,7 +12,7 @@ public enum OperatorType: CustomStringConvertible { case multiply case percent case exponent - + public var description: String { switch self { case .add: @@ -36,7 +36,7 @@ public enum TokenType: CustomStringConvertible { case closeBracket case Operator(OperatorToken) case operand(Double) - + public var description: String { switch self { case .openBracket: @@ -53,11 +53,11 @@ public enum TokenType: CustomStringConvertible { public struct OperatorToken: CustomStringConvertible { let operatorType: OperatorType - + init(operatorType: OperatorType) { self.operatorType = operatorType } - + var precedence: Int { switch operatorType { case .add, .subtract: @@ -68,7 +68,7 @@ public struct OperatorToken: CustomStringConvertible { return 10 } } - + var associativity: OperatorAssociativity { switch operatorType { case .add, .subtract, .divide, .multiply, .percent: @@ -77,7 +77,7 @@ public struct OperatorToken: CustomStringConvertible { return .rightAssociative } } - + public var description: String { return operatorType.description } @@ -93,19 +93,19 @@ func < (left: OperatorToken, right: OperatorToken) -> Bool { public struct Token: CustomStringConvertible { let tokenType: TokenType - + init(tokenType: TokenType) { self.tokenType = tokenType } - + init(operand: Double) { tokenType = .operand(operand) } - + init(operatorType: OperatorType) { tokenType = .Operator(OperatorToken(operatorType: operatorType)) } - + var isOpenBracket: Bool { switch tokenType { case .openBracket: @@ -114,7 +114,7 @@ public struct Token: CustomStringConvertible { return false } } - + var isOperator: Bool { switch tokenType { case .Operator(_): @@ -123,7 +123,7 @@ public struct Token: CustomStringConvertible { return false } } - + var operatorToken: OperatorToken? { switch tokenType { case .Operator(let operatorToken): @@ -132,7 +132,7 @@ public struct Token: CustomStringConvertible { return nil } } - + public var description: String { return tokenType.description } @@ -140,27 +140,27 @@ public struct Token: CustomStringConvertible { public class InfixExpressionBuilder { private var expression = [Token]() - + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { expression.append(Token(operatorType: operatorType)) return self } - + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { expression.append(Token(operand: operand)) return self } - + public func addOpenBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .openBracket)) return self } - + public func addCloseBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .closeBracket)) return self } - + public func build() -> [Token] { // Maybe do some validation here return expression @@ -169,29 +169,29 @@ public class InfixExpressionBuilder { // This returns the result of the shunting yard algorithm public func reversePolishNotation(_ expression: [Token]) -> String { - + var tokenStack = Stack() var reversePolishNotation = [Token]() - + for token in expression { switch token.tokenType { case .operand(_): reversePolishNotation.append(token) - + case .openBracket: tokenStack.push(token) - + case .closeBracket: while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { reversePolishNotation.append(tempToken) } - + case .Operator(let operatorToken): for tempToken in tokenStack.makeIterator() { if !tempToken.isOperator { break } - + if let tempOperatorToken = tempToken.operatorToken { if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { @@ -204,11 +204,11 @@ public func reversePolishNotation(_ expression: [Token]) -> String { tokenStack.push(token) } } - + while tokenStack.count > 0 { reversePolishNotation.append(tokenStack.pop()!) } - + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } diff --git a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift index 27286fdbd..c54c5a600 100644 --- a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift +++ b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift @@ -2,27 +2,27 @@ import Foundation public struct Stack { fileprivate var array = [T]() - + public init() { - + } - + public var isEmpty: Bool { return array.isEmpty } - + public var count: Int { return array.count } - + public mutating func push(_ element: T) { array.append(element) } - + public mutating func pop() -> T? { return array.popLast() } - + public var top: T? { return array.last } diff --git a/Shunting Yard/ShuntingYard.swift b/Shunting Yard/ShuntingYard.swift index 97a72249d..201264650 100644 --- a/Shunting Yard/ShuntingYard.swift +++ b/Shunting Yard/ShuntingYard.swift @@ -18,7 +18,7 @@ public enum OperatorType: CustomStringConvertible { case multiply case percent case exponent - + public var description: String { switch self { case .add: @@ -42,7 +42,7 @@ public enum TokenType: CustomStringConvertible { case closeBracket case Operator(OperatorToken) case operand(Double) - + public var description: String { switch self { case .openBracket: @@ -59,11 +59,11 @@ public enum TokenType: CustomStringConvertible { public struct OperatorToken: CustomStringConvertible { let operatorType: OperatorType - + init(operatorType: OperatorType) { self.operatorType = operatorType } - + var precedence: Int { switch operatorType { case .add, .subtract: @@ -74,7 +74,7 @@ public struct OperatorToken: CustomStringConvertible { return 10 } } - + var associativity: OperatorAssociativity { switch operatorType { case .add, .subtract, .divide, .multiply, .percent: @@ -83,7 +83,7 @@ public struct OperatorToken: CustomStringConvertible { return .rightAssociative } } - + public var description: String { return operatorType.description } @@ -99,19 +99,19 @@ func < (left: OperatorToken, right: OperatorToken) -> Bool { public struct Token: CustomStringConvertible { let tokenType: TokenType - + init(tokenType: TokenType) { self.tokenType = tokenType } - + init(operand: Double) { tokenType = .operand(operand) } - + init(operatorType: OperatorType) { tokenType = .Operator(OperatorToken(operatorType: operatorType)) } - + var isOpenBracket: Bool { switch tokenType { case .openBracket: @@ -120,7 +120,7 @@ public struct Token: CustomStringConvertible { return false } } - + var isOperator: Bool { switch tokenType { case .Operator(_): @@ -129,7 +129,7 @@ public struct Token: CustomStringConvertible { return false } } - + var operatorToken: OperatorToken? { switch tokenType { case .Operator(let operatorToken): @@ -138,7 +138,7 @@ public struct Token: CustomStringConvertible { return nil } } - + public var description: String { return tokenType.description } @@ -146,27 +146,27 @@ public struct Token: CustomStringConvertible { public class InfixExpressionBuilder { private var expression = [Token]() - + public func addOperator(_ operatorType: OperatorType) -> InfixExpressionBuilder { expression.append(Token(operatorType: operatorType)) return self } - + public func addOperand(_ operand: Double) -> InfixExpressionBuilder { expression.append(Token(operand: operand)) return self } - + public func addOpenBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .openBracket)) return self } - + public func addCloseBracket() -> InfixExpressionBuilder { expression.append(Token(tokenType: .closeBracket)) return self } - + public func build() -> [Token] { // Maybe do some validation here return expression @@ -175,29 +175,29 @@ public class InfixExpressionBuilder { // This returns the result of the shunting yard algorithm public func reversePolishNotation(_ expression: [Token]) -> String { - + var tokenStack = Stack() var reversePolishNotation = [Token]() - + for token in expression { switch token.tokenType { case .operand(_): reversePolishNotation.append(token) - + case .openBracket: tokenStack.push(token) - + case .closeBracket: while tokenStack.count > 0, let tempToken = tokenStack.pop(), !tempToken.isOpenBracket { reversePolishNotation.append(tempToken) } - + case .Operator(let operatorToken): for tempToken in tokenStack.makeIterator() { if !tempToken.isOperator { break } - + if let tempOperatorToken = tempToken.operatorToken { if operatorToken.associativity == .leftAssociative && operatorToken <= tempOperatorToken || operatorToken.associativity == .rightAssociative && operatorToken < tempOperatorToken { @@ -210,10 +210,10 @@ public func reversePolishNotation(_ expression: [Token]) -> String { tokenStack.push(token) } } - + while tokenStack.count > 0 { reversePolishNotation.append(tokenStack.pop()!) } - + return reversePolishNotation.map({token in token.description}).joined(separator: " ") } diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index e844f9959..cd832eef9 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -70,29 +70,29 @@ private func coinFlip() -> Bool { public class DataNode { public typealias Node = DataNode - - var data: Payload? + + var data: Payload? fileprivate var key: Key? var next: Node? var down: Node? - + public init(key: Key, data: Payload) { self.key = key self.data = data } public init(asHead head: Bool){} - + } open class SkipList { public typealias Node = DataNode - + fileprivate(set) var head: Node? public init() {} - + } @@ -100,18 +100,18 @@ open class SkipList { // MARK: - Search lanes for a node with a given key extension SkipList { - + func findNode(key: Key) -> Node? { var currentNode: Node? = head var isFound: Bool = false while !isFound { if let node = currentNode { - + switch node.next { case .none: - - currentNode = node.down + + currentNode = node.down case .some(let value) where value.key != nil: if value.key == key { @@ -122,14 +122,14 @@ extension SkipList { currentNode = node.down } else { currentNode = node.next - } + } } - + default: continue } - - } else { + + } else { break } } @@ -139,7 +139,7 @@ extension SkipList { } else { return nil } - + } func search(key: Key) -> Payload? { @@ -147,9 +147,9 @@ extension SkipList { return nil } - return node.next!.data - } - + return node.next!.data + } + } @@ -157,12 +157,12 @@ extension SkipList { // MARK: - Insert a node into lanes depending on skip list status ( bootstrap base-layer if head is empty / start insertion from current head ). extension SkipList { - private func bootstrapBaseLayer(key: Key, data: Payload) { - head = Node(asHead: true) + private func bootstrapBaseLayer(key: Key, data: Payload) { + head = Node(asHead: true) var node = Node(key: key, data: data) head!.next = node - + var currentTopNode = node while coinFlip() { @@ -174,7 +174,7 @@ extension SkipList { head = newHead currentTopNode = node } - + } @@ -191,13 +191,13 @@ extension SkipList { } else { currentNode = nextNode } - + } else { stack.push(currentNode!) - currentNode = currentNode!.down + currentNode = currentNode!.down } - - } + + } let itemAtLayer = stack.pop() var node = Node(key: key, data: data) @@ -208,24 +208,24 @@ extension SkipList { while coinFlip() { if stack.isEmpty { let newHead = Node(asHead: true) - + node = Node(key: key, data: data) node.down = currentTopNode newHead.next = node newHead.down = head head = newHead currentTopNode = node - - } else { + + } else { let nextNode = stack.pop() - + node = Node(key: key, data: data) node.down = currentTopNode node.next = nextNode!.next nextNode!.next = node currentTopNode = node } - } + } } @@ -233,7 +233,7 @@ extension SkipList { if head != nil { if let node = findNode(key: key) { // replace, in case of key already exists. - var currentNode = node.next + var currentNode = node.next while currentNode != nil && currentNode!.key == key { currentNode!.data = data currentNode = currentNode!.down @@ -241,12 +241,12 @@ extension SkipList { } else { insertItem(key: key, data: data) } - + } else { bootstrapBaseLayer(key: key, data: data) } } - + } @@ -257,32 +257,32 @@ extension SkipList { guard let item = findNode(key: key) else { return } - + var currentNode = Optional(item) - + while currentNode != nil { let node = currentNode!.next - + if node!.key != key { currentNode = node continue } let nextNode = node!.next - + currentNode!.next = nextNode currentNode = currentNode!.down - + } - - } + + } } // MARK: - Get associated payload from a node with a given key. extension SkipList { - + public func get(key: Key) -> Payload? { return search(key: key) } diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift index ccfa58b09..324e906ee 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift @@ -9,53 +9,53 @@ import Foundation public struct Matrix { - + // MARK: - Martix Objects - + public enum Index { case row, column } - + public struct Size: Equatable { let rows: Int, columns: Int - + public static func == (lhs: Size, rhs: Size) -> Bool { return lhs.columns == rhs.columns && lhs.rows == rhs.rows } } - + // MARK: - Variables - + let rows: Int, columns: Int let size: Size - + var grid: [T] - + var isSquare: Bool { return rows == columns } - + // MARK: - Init - + public init(rows: Int, columns: Int, initialValue: T = T.zero) { self.rows = rows self.columns = columns self.size = Size(rows: rows, columns: columns) self.grid = Array(repeating: initialValue, count: rows * columns) } - + public init(size: Int, initialValue: T = T.zero) { self.init(rows: size, columns: size, initialValue: initialValue) } - + // MARK: - Private Functions - + fileprivate func indexIsValid(row: Int, column: Int) -> Bool { return row >= 0 && row < rows && column >= 0 && column < columns } - + // MARK: - Subscript - + public subscript(row: Int, column: Int) -> T { get { assert(indexIsValid(row: row, column: column), "Index out of range") @@ -65,7 +65,7 @@ public struct Matrix { grid[(row * columns) + column] = newValue } } - + public subscript(type: Matrix.Index, value: Int) -> [T] { get { switch type { @@ -95,24 +95,24 @@ public struct Matrix { } } } - + // MARK: - Public Functions - + public func row(for columnIndex: Int) -> [T] { assert(indexIsValid(row: columnIndex, column: 0), "Index out of range") return Array(grid[(columnIndex * columns)..<(columnIndex * columns) + columns]) } - + public func column(for rowIndex: Int) -> [T] { assert(indexIsValid(row: 0, column: rowIndex), "Index out of range") - + let column = (0.. T in let currentColumnIndex = currentRow * columns + rowIndex return grid[currentColumnIndex] } return column } - + public func forEach(_ body: (Int, Int) throws -> Void) rethrows { for row in 0..) -> Matrix { let A = self assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - + var C = Matrix(rows: A.rows, columns: B.columns) - + for i in 0..) -> Matrix { let A = self assert(A.columns == B.rows, "Two matricies can only be matrix mulitiplied if one has dimensions mxn & the other has dimensions nxp where m, n, p are in R") - + let n = max(A.rows, A.columns, B.rows, B.columns) let m = nextPowerOfTwo(after: n) - + var APrep = Matrix(size: m) var BPrep = Matrix(size: m) - + A.forEach { (i, j) in APrep[i,j] = A[i,j] } - + B.forEach { (i, j) in BPrep[i,j] = B[i,j] } - + let CPrep = APrep.strassenR(by: BPrep) var C = Matrix(rows: A.rows, columns: B.columns) for i in 0..) -> Matrix { let A = self assert(A.isSquare && B.isSquare, "This function requires square matricies!") guard A.rows > 1 && B.rows > 1 else { return A * B } - + let n = A.rows let nBy2 = n / 2 - + /* Assume submatricies are allocated as follows matrix A = |a b|, matrix B = |e f| |c d| |g h| */ - + var a = Matrix(size: nBy2) var b = Matrix(size: nBy2) var c = Matrix(size: nBy2) @@ -196,7 +196,7 @@ extension Matrix { var f = Matrix(size: nBy2) var g = Matrix(size: nBy2) var h = Matrix(size: nBy2) - + for i in 0.. Int { return Int(pow(2, ceil(log2(Double(n))))) } @@ -248,7 +248,7 @@ extension Matrix: Addable { assert(lhs.size == rhs.size, "To term-by-term add matricies they need to be the same size!") let rows = lhs.rows let columns = lhs.columns - + var newMatrix = Matrix(rows: rows, columns: columns) for row in 0..(lhs: Matrix, rhs: Matrix) -> Matrix { assert(lhs.size == rhs.size, "To term-by-term subtract matricies they need to be the same size!") let rows = lhs.rows let columns = lhs.columns - + var newMatrix = Matrix(rows: rows, columns: columns) for row in 0..(rows: rows, columns: columns) for row in 0.. String { let allowedCharsCount = UInt32(allowedChars.characters.count) var randomString = "" - + for _ in (0..() for _ in (1...testCount) { var randomLength = Int(arc4random_uniform(10)) - + var key = Utils.shared.randomAlphaNumericString(withLength: randomLength) - + while testStrings.contains(where: { $0.key == key}) { //That key is taken, so we generate a new one with another length randomLength = Int(arc4random_uniform(10)) @@ -29,20 +29,20 @@ class TernarySearchTreeTests: XCTestCase { } let data = Utils.shared.randomAlphaNumericString(withLength: randomLength) // print("Key: \(key) Data: \(data)") - + if key != "" && data != "" { testStrings.append((key, data)) treeOfStrings.insert(data: data, withKey: key) } } - + for aTest in testStrings { let data = treeOfStrings.find(key: aTest.key) XCTAssertNotNil(data) XCTAssertEqual(data, aTest.data) } } - + func testCanFindNumberInTree() { var testNums: [(key: String, data: Int)] = [] let treeOfInts = TernarySearchTree() @@ -55,13 +55,13 @@ class TernarySearchTreeTests: XCTestCase { randomLength = Int(arc4random_uniform(10)) key = Utils.shared.randomAlphaNumericString(withLength: randomLength) } - + if key != "" { testNums.append((key, randomNum)) treeOfInts.insert(data: randomNum, withKey: key) } } - + for aTest in testNums { let data = treeOfInts.find(key: aTest.key) XCTAssertNotNil(data) diff --git a/Ternary Search Tree/Utils.swift b/Ternary Search Tree/Utils.swift index cabfe1b68..97f09fdd2 100644 --- a/Ternary Search Tree/Utils.swift +++ b/Ternary Search Tree/Utils.swift @@ -9,22 +9,22 @@ import Foundation public struct Utils { - + public static let shared = Utils() - + let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" //Random string generator from: //http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710 public func randomAlphaNumericString(withLength length: Int) -> String { let allowedCharsCount = UInt32(allowedChars.characters.count) var randomString = "" - + for _ in (0.. ThreadedBinaryTree? { return search(value)?.remove() } - + /* Deletes "this" node from the tree. */ public func remove() -> ThreadedBinaryTree? { let replacement: ThreadedBinaryTree? - + if let left = left { if let right = right { replacement = removeNodeWithTwoChildren(left, right) @@ -155,33 +155,33 @@ extension ThreadedBinaryTree { parent?.rightThread = rightThread } } - + reconnectParentToNode(replacement) - + // The current node is no longer part of the tree, so clean it up. parent = nil left = nil right = nil leftThread = nil rightThread = nil - + return replacement } - + private func removeNodeWithTwoChildren(_ left: ThreadedBinaryTree, _ right: ThreadedBinaryTree) -> ThreadedBinaryTree { // This node has two children. It must be replaced by the smallest // child that is larger than this node's value, which is the leftmost // descendent of the right child. let successor = right.minimum() - + // If this in-order successor has a right child of its own (it cannot // have a left child by definition), then that must take its place. _ = successor.remove() - + // Connect our left child with the new node. successor.left = left left.parent = successor - + // Connect our right child with the new node. If the right child does // not have any left children of its own, then the in-order successor // *is* the right child. @@ -191,11 +191,11 @@ extension ThreadedBinaryTree { } else { successor.right = nil } - + // And finally, connect the successor node to our parent. return successor } - + private func reconnectParentToNode(_ node: ThreadedBinaryTree?) { if let parent = parent { if isLeftChild { @@ -228,7 +228,7 @@ extension ThreadedBinaryTree { } return nil } - + /* // Recursive version of search // Educational but undesirable due to the overhead cost of recursion @@ -242,11 +242,11 @@ extension ThreadedBinaryTree { } } */ - + public func contains(value: T) -> Bool { return search(value) != nil } - + /* Returns the leftmost descendent. O(h) time. */ @@ -257,7 +257,7 @@ extension ThreadedBinaryTree { } return node } - + /* Returns the rightmost descendent. O(h) time. */ @@ -268,7 +268,7 @@ extension ThreadedBinaryTree { } return node } - + /* Calculates the depth of this node, i.e. the distance to the root. Takes O(h) time. @@ -282,7 +282,7 @@ extension ThreadedBinaryTree { } return edges } - + /* Calculates the height of this node, i.e. the distance to the lowest leaf. Since this looks at all children of this node, performance is O(n). @@ -294,7 +294,7 @@ extension ThreadedBinaryTree { return 1 + max(left?.height() ?? 0, right?.height() ?? 0) } } - + /* Finds the node whose value precedes our value in sorted order. */ @@ -305,7 +305,7 @@ extension ThreadedBinaryTree { return leftThread } } - + /* Finds the node whose value succeeds our value in sorted order. */ @@ -333,7 +333,7 @@ extension ThreadedBinaryTree { } } } - + public func traverseInOrderBackward(_ visit: (T) -> Void) { var n: ThreadedBinaryTree n = maximum() @@ -346,19 +346,19 @@ extension ThreadedBinaryTree { } } } - + public func traversePreOrder(_ visit: (T) -> Void) { visit(value) left?.traversePreOrder(visit) right?.traversePreOrder(visit) } - + public func traversePostOrder(_ visit: (T) -> Void) { left?.traversePostOrder(visit) right?.traversePostOrder(visit) visit(value) } - + /* Performs an in-order traversal and collects the results in an array. */ @@ -390,7 +390,7 @@ extension ThreadedBinaryTree { let rightBST = right?.isBST(minValue: value, maxValue: maxValue) ?? true return leftBST && rightBST } - + /* Is this binary tree properly threaded? Either left or leftThread (but not both) must be nil (likewise for right). @@ -452,7 +452,7 @@ extension ThreadedBinaryTree: CustomDebugStringConvertible { } return s } - + public func toArray() -> [T] { return map { $0 } } diff --git a/Treap/Treap.swift b/Treap/Treap.swift index 6e80abfb2..7038e843e 100644 --- a/Treap/Treap.swift +++ b/Treap/Treap.swift @@ -27,11 +27,11 @@ import Foundation public indirect enum Treap { case empty case node(key: Key, val: Element, p: Int, left: Treap, right: Treap) - + public init() { self = .empty } - + internal func get(_ key: Key) -> Element? { switch self { case .empty: @@ -46,7 +46,7 @@ public indirect enum Treap { return nil } } - + public func contains(_ key: Key) -> Bool { switch self { case .empty: @@ -61,7 +61,7 @@ public indirect enum Treap { return false } } - + public var depth: Int { switch self { case .empty: @@ -80,12 +80,12 @@ public indirect enum Treap { public var count: Int { return Treap.countHelper(self) } - + fileprivate static func countHelper(_ treap: Treap) -> Int { if case let .node(_, _, _, left, right) = treap { return countHelper(left) + 1 + countHelper(right) } - + return 0 } } @@ -121,7 +121,7 @@ public extension Treap { return .empty } } - + fileprivate func insertAndBalance(_ nodeKey: Key, _ nodeVal: Element, _ nodeP: Int, _ left: Treap, _ right: Treap, _ key: Key, _ val: Element, _ p: Int) -> Treap { let newChild: Treap @@ -141,14 +141,14 @@ public extension Treap { newNode = .empty return newNode } - + if case let .node(_, _, newChildP, _, _) = newChild , newChildP < nodeP { return rotate(newNode) } else { return newNode } } - + internal func delete(key: Key) throws -> Treap { switch self { case .empty: diff --git a/Treap/Treap/TreapTests/TreapTests.swift b/Treap/Treap/TreapTests/TreapTests.swift index f349e6ab8..d4fc4cfdb 100644 --- a/Treap/Treap/TreapTests/TreapTests.swift +++ b/Treap/Treap/TreapTests/TreapTests.swift @@ -27,17 +27,17 @@ THE SOFTWARE.*/ import XCTest class TreapTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testSanity() { var treap = Treap.empty treap = treap.set(key: 5, val: "a").set(key: 7, val: "b") @@ -51,7 +51,7 @@ class TreapTests: XCTestCase { XCTAssert(!treap.contains(5)) XCTAssert(treap.contains(7)) } - + func testFairlyBalanced() { var treap = Treap.empty for i in 0..<1000 { @@ -60,7 +60,7 @@ class TreapTests: XCTestCase { let depth = treap.depth XCTAssert(depth < 30, "treap.depth was \(depth)") } - + func testFairlyBalancedCollection() { var treap = Treap() for i in 0..<1000 { @@ -69,5 +69,5 @@ class TreapTests: XCTestCase { let depth = treap.depth XCTAssert(depth > 0 && depth < 30) } - + } diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index 7292c5f0a..eeee065fe 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -25,52 +25,52 @@ THE SOFTWARE.*/ import Foundation extension Treap: MutableCollection { - + public typealias Index = TreapIndex - + public subscript(index: TreapIndex) -> Element { get { guard let result = self.get(index.keys[index.keyIndex]) else { fatalError("Invalid index!") } - + return result } - + mutating set { let key = index.keys[index.keyIndex] self = self.set(key: key, val: newValue) } } - + public subscript(key: Key) -> Element? { get { return self.get(key) } - + mutating set { guard let value = newValue else { _ = try? self.delete(key: key) return } - + self = self.set(key: key, val: value) } } - + public var startIndex: TreapIndex { return TreapIndex(keys: keys, keyIndex: 0) } - + public var endIndex: TreapIndex { let keys = self.keys return TreapIndex(keys: keys, keyIndex: keys.count) } - + public func index(after i: TreapIndex) -> TreapIndex { return i.successor() } - + fileprivate var keys: [Key] { var results: [Key] = [] if case let .node(key, _, _, left, right) = self { @@ -78,28 +78,28 @@ extension Treap: MutableCollection { results.append(key) results.append(contentsOf: right.keys) } - + return results } } public struct TreapIndex: Comparable { - + public static func < (lhs: TreapIndex, rhs: TreapIndex) -> Bool { return lhs.keyIndex < rhs.keyIndex } - + fileprivate let keys: [Key] fileprivate let keyIndex: Int - + public func successor() -> TreapIndex { return TreapIndex(keys: keys, keyIndex: keyIndex + 1) } - + public func predecessor() -> TreapIndex { return TreapIndex(keys: keys, keyIndex: keyIndex - 1) } - + fileprivate init(keys: [Key] = [], keyIndex: Int = 0) { self.keys = keys self.keyIndex = keyIndex diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift index 34cfec3d2..62d18d16f 100644 --- a/Treap/TreapMergeSplit.swift +++ b/Treap/TreapMergeSplit.swift @@ -37,7 +37,7 @@ public extension Treap { } else { fatalError("No values in treap") } - + switch self { case .node: if case let .node(_, _, _, left, right) = current.set(key: key, val: val, p: -1) { @@ -49,7 +49,7 @@ public extension Treap { return (left: .empty, right: .empty) } } - + internal var leastKey: Key? { switch self { case .empty: @@ -60,7 +60,7 @@ public extension Treap { return left.leastKey } } - + internal var mostKey: Key? { switch self { case .empty: @@ -79,7 +79,7 @@ internal func merge(_ left: Treap, right return right case (_, .empty): return left - + case let (.node(leftKey, leftVal, leftP, leftLeft, leftRight), .node(rightKey, rightVal, rightP, rightLeft, rightRight)): if leftP < rightP { return .node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, right: merge(leftRight, right: right)) @@ -96,16 +96,16 @@ extension Treap: CustomStringConvertible { public var description: String { return Treap.descHelper(self, indent: 0) } - + fileprivate static func descHelper(_ treap: Treap, indent: Int) -> String { if case let .node(key, value, priority, left, right) = treap { var result = "" let tabs = String(repeating: "\t", count: indent) - + result += descHelper(left, indent: indent + 1) result += "\n" + tabs + "\(key), \(value), \(priority)\n" result += descHelper(right, indent: indent + 1) - + return result } else { return "" diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index 4321479c3..7ff9638d7 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -18,8 +18,8 @@ class TrieNode { var isLeaf: Bool { return children.count == 0 } - - + + /// Initializes a node. /// /// - Parameters: @@ -29,7 +29,7 @@ class TrieNode { self.value = value self.parentNode = parentNode } - + /// Adds a child node to self. If the child is already present, /// do nothing. /// @@ -92,7 +92,7 @@ class Trie: NSObject, NSCoding { // MARK: - Adds methods: insert, remove, contains extension Trie { - + /// Inserts a word into the trie. If the word is already present, /// there is no change. /// @@ -117,7 +117,7 @@ extension Trie { wordCount += 1 currentNode.isTerminating = true } - + /// Determines whether a word is in the trie. /// /// - Parameter word: the word to check for @@ -168,7 +168,7 @@ extension Trie { return nil } - + /// Deletes a word from the trie by starting with the last letter /// and moving back, deleting nodes until either a non-leaf or a /// terminating node is found. @@ -187,7 +187,7 @@ extension Trie { } } } - + /// Removes a word from the trie. If the word is not present or /// it is empty, just ignore it. If the last node is a leaf, /// delete that node and higher nodes that are leaves until a @@ -210,7 +210,7 @@ extension Trie { } wordCount -= 1 } - + /// Returns an array of words in a subtrie of the trie /// /// - Parameters: diff --git a/Trie/Trie/TrieUITests/TrieUITests.swift b/Trie/Trie/TrieUITests/TrieUITests.swift index f3da2a67f..acb3b1756 100644 --- a/Trie/Trie/TrieUITests/TrieUITests.swift +++ b/Trie/Trie/TrieUITests/TrieUITests.swift @@ -9,12 +9,12 @@ import XCTest class TrieUITests: XCTestCase { - + override func setUp() { super.setUp() - + // 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. @@ -22,15 +22,15 @@ class TrieUITests: XCTestCase { // 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() } - + func testExample() { // Use recording to get started writing UI tests. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + } diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift index 9bef69687..969a3599b 100644 --- a/Z-Algorithm/ZAlgorithm.swift +++ b/Z-Algorithm/ZAlgorithm.swift @@ -9,34 +9,34 @@ import Foundation func ZetaAlgorithm(ptrn: String) -> [Int]? { - + let pattern = Array(ptrn.characters) let patternLength = pattern.count - + guard patternLength > 0 else { return nil } - + var zeta = [Int](repeating: 0, count: patternLength) - + var left = 0 var right = 0 var k_1 = 0 var betaLength = 0 var textIndex = 0 var patternIndex = 0 - + for k in 1 ..< patternLength { if k > right { patternIndex = 0 - + while k + patternIndex < patternLength && pattern[k + patternIndex] == pattern[patternIndex] { patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - + if zeta[k] > 0 { left = k right = k + zeta[k] - 1 @@ -44,18 +44,18 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { } else { k_1 = k - left + 1 betaLength = right - k + 1 - + if zeta[k_1 - 1] < betaLength { zeta[k] = zeta[k_1 - 1] } else if zeta[k_1 - 1] >= betaLength { textIndex = betaLength patternIndex = right + 1 - + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { textIndex = textIndex + 1 patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - k left = k right = patternIndex - 1 diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift index 395122af0..44faf6790 100644 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -2,34 +2,34 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { - + let pattern = Array(ptrn.characters) let patternLength = pattern.count - + guard patternLength > 0 else { return nil } - + var zeta = [Int](repeating: 0, count: patternLength) - + var left = 0 var right = 0 var k_1 = 0 var betaLength = 0 var textIndex = 0 var patternIndex = 0 - + for k in 1 ..< patternLength { if k > right { patternIndex = 0 - + while k + patternIndex < patternLength && pattern[k + patternIndex] == pattern[patternIndex] { patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - + if zeta[k] > 0 { left = k right = k + zeta[k] - 1 @@ -37,18 +37,18 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { } else { k_1 = k - left + 1 betaLength = right - k + 1 - + if zeta[k_1 - 1] < betaLength { zeta[k] = zeta[k_1 - 1] } else if zeta[k_1 - 1] >= betaLength { textIndex = betaLength patternIndex = right + 1 - + while patternIndex < patternLength && pattern[textIndex] == pattern[patternIndex] { textIndex = textIndex + 1 patternIndex = patternIndex + 1 } - + zeta[k] = patternIndex - k left = k right = patternIndex - 1 @@ -60,28 +60,28 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { extension String { - + func indexesOf(pattern: String) -> [Int]? { let patternLength = pattern.characters.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) - + guard zeta != nil else { return nil } - + var indexes: [Int] = [] - + /* Scan the zeta array to find matched patterns */ for i in 0 ..< zeta!.count { if zeta![i] == patternLength { indexes.append(i - patternLength - 1) } } - + guard !indexes.isEmpty else { return nil } - + return indexes } } diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift index c35703272..e60c1617f 100644 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -9,28 +9,28 @@ import Foundation extension String { - + func indexesOf(pattern: String) -> [Int]? { let patternLength = pattern.characters.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) - + guard zeta != nil else { return nil } - + var indexes: [Int] = [Int]() - + /* Scan the zeta array to find matched patterns */ for i in 0 ..< zeta!.count { if zeta![i] == patternLength { indexes.append(i - patternLength - 1) } } - + guard !indexes.isEmpty else { return nil } - + return indexes } } From b718f04b4be46ebe9d82cc1d18264d92b12be0a9 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Thu, 4 May 2017 03:53:31 +0500 Subject: [PATCH 0609/1275] Fix violation: unused_optional_binding warning: Unused Optional Binding Violation: Prefer `!= nil` over `let _ =` () --- Graph/Graph/AdjacencyListGraph.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graph/Graph/AdjacencyListGraph.swift b/Graph/Graph/AdjacencyListGraph.swift index 57fd75fed..b58ef6417 100644 --- a/Graph/Graph/AdjacencyListGraph.swift +++ b/Graph/Graph/AdjacencyListGraph.swift @@ -78,7 +78,7 @@ open class AdjacencyListGraph: AbstractGraph where T: Equatable, T: Hashab // works let edge = Edge(from: from, to: to, weight: weight) let edgeList = adjacencyList[from.index] - if let _ = edgeList.edges { + if edgeList.edges != nil { edgeList.addEdge(edge) } else { edgeList.edges = [edge] From 9a363c7082c2acbc6984864b67ac6c20ac911cdb Mon Sep 17 00:00:00 2001 From: Xiangxin Date: Fri, 17 Mar 2017 00:19:36 +0800 Subject: [PATCH 0610/1275] Minimum Spanning Tree (Kruskal's and Prim's) --- Minimum Spanning Tree/Images/kruskal.png | Bin 0 -> 22083 bytes Minimum Spanning Tree/Images/prim.png | Bin 0 -> 19053 bytes Minimum Spanning Tree/Kruskal.swift | 31 +++ .../Contents.swift | 93 +++++++ .../Resources/mst.png | Bin 0 -> 19209 bytes .../Sources/Graph.swift | 55 +++++ .../Sources/Heap.swift | 227 ++++++++++++++++++ .../Sources/PriorityQueue.swift | 58 +++++ .../Sources/UnionFind.swift | 61 +++++ .../contents.xcplayground | 4 + Minimum Spanning Tree/Prim.swift | 45 ++++ Minimum Spanning Tree/README.markdown | 102 ++++++++ README.markdown | 1 + .../contents.xcworkspacedata | 26 ++ 14 files changed, 703 insertions(+) create mode 100644 Minimum Spanning Tree/Images/kruskal.png create mode 100644 Minimum Spanning Tree/Images/prim.png create mode 100644 Minimum Spanning Tree/Kruskal.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Resources/mst.png create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Heap.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/PriorityQueue.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/UnionFind.swift create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/contents.xcplayground create mode 100644 Minimum Spanning Tree/Prim.swift create mode 100644 Minimum Spanning Tree/README.markdown diff --git a/Minimum Spanning Tree/Images/kruskal.png b/Minimum Spanning Tree/Images/kruskal.png new file mode 100644 index 0000000000000000000000000000000000000000..5172f180fda8dff8666a4a38f08e675311c515dd GIT binary patch literal 22083 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 literal 0 HcmV?d00001 diff --git a/Minimum Spanning Tree/Kruskal.swift b/Minimum Spanning Tree/Kruskal.swift new file mode 100644 index 000000000..bebd32602 --- /dev/null +++ b/Minimum Spanning Tree/Kruskal.swift @@ -0,0 +1,31 @@ +// +// Kruskal.swift +// +// +// Created by xiang xin on 16/3/17. +// +// + + +func minimumSpanningTreeKruskal(graph: Graph) -> (cost: Int, tree: Graph) { + var cost: Int = 0 + var tree = Graph() + let sortedEdgeListByWeight = graph.edgeList.sorted(by: { $0.weight < $1.weight }) + + var unionFind = UnionFind() + for vertex in graph.vertices { + unionFind.addSetWith(vertex) + } + + for edge in sortedEdgeListByWeight { + let v1 = edge.vertex1 + let v2 = edge.vertex2 + if !unionFind.inSameSet(v1, and: v2) { + cost += edge.weight + tree.addEdge(edge) + unionFind.unionSetsContaining(v1, and: v2) + } + } + + return (cost: cost, tree: tree) +} diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift new file mode 100644 index 000000000..99b5e859f --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift @@ -0,0 +1,93 @@ +/** + The following code demonstrates getting MST of the graph below by both + Kruskal's and Prim's algorithms. + */ + +func minimumSpanningTreeKruskal(graph: Graph) -> (cost: Int, tree: Graph) { + var cost: Int = 0 + var tree = Graph() + let sortedEdgeListByWeight = graph.edgeList.sorted(by: { $0.weight < $1.weight }) + + var unionFind = UnionFind() + for vertex in graph.vertices { + unionFind.addSetWith(vertex) + } + + for edge in sortedEdgeListByWeight { + let v1 = edge.vertex1 + let v2 = edge.vertex2 + if !unionFind.inSameSet(v1, and: v2) { + cost += edge.weight + tree.addEdge(edge) + unionFind.unionSetsContaining(v1, and: v2) + } + } + + return (cost: cost, tree: tree) +} + +func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) { + var cost: Int = 0 + var tree = Graph() + + if graph.vertices.isEmpty { + return (cost: cost, tree: tree) + } + + var visited = Set() + var priorityQueue = PriorityQueue<(vertex: T, weight: Int, parent: T?)>( + sort: { $0.weight < $1.weight }) + + priorityQueue.enqueue((vertex: graph.vertices.first!, weight: 0, parent: nil)) + while let head = priorityQueue.dequeue() { + let vertex = head.vertex + if visited.contains(vertex) { + continue + } + visited.insert(vertex) + + cost += head.weight + if let prev = head.parent { + tree.addEdge(vertex1: prev, vertex2: vertex, weight: head.weight) + } + + if let neighbours = graph.adjList[vertex] { + for neighbour in neighbours { + let nextVertex = neighbour.vertex + if !visited.contains(nextVertex) { + priorityQueue.enqueue((vertex: nextVertex, weight: neighbour.weight, parent: vertex)) + } + } + } + } + + return (cost: cost, tree: tree) +} + +/*: + ![Graph](mst.png) + */ + +var graph = Graph() +graph.addEdge(vertex1: 1, vertex2: 2, weight: 6) +graph.addEdge(vertex1: 1, vertex2: 3, weight: 1) +graph.addEdge(vertex1: 1, vertex2: 4, weight: 5) +graph.addEdge(vertex1: 2, vertex2: 3, weight: 5) +graph.addEdge(vertex1: 2, vertex2: 5, weight: 3) +graph.addEdge(vertex1: 3, vertex2: 4, weight: 5) +graph.addEdge(vertex1: 3, vertex2: 5, weight: 6) +graph.addEdge(vertex1: 3, vertex2: 6, weight: 4) +graph.addEdge(vertex1: 4, vertex2: 6, weight: 2) +graph.addEdge(vertex1: 5, vertex2: 6, weight: 6) + +print("===== Kruskal's =====") +let result1 = minimumSpanningTreeKruskal(graph: graph) +print("Minimum spanning tree total weight: \(result1.cost)") +print("Minimum spanning tree:") +print(result1.tree) + +print("===== Prim's =====") +let result2 = minimumSpanningTreePrim(graph: graph) +print("Minimum spanning tree total weight: \(result2.cost)") +print("Minimum spanning tree:") +print(result2.tree) diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Resources/mst.png b/Minimum Spanning Tree/MinimumSpanningTree.playground/Resources/mst.png new file mode 100644 index 0000000000000000000000000000000000000000..2138fd535de977e68e4a08878f6e8782eab9ca2e GIT binary patch literal 19209 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 LpB?Rl2?zi?V2Grt literal 0 HcmV?d00001 diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift new file mode 100644 index 000000000..0ae996646 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift @@ -0,0 +1,55 @@ + +// Undirected edge +public struct Edge: CustomStringConvertible { + public let vertex1: T + public let vertex2: T + public let weight: Int + + public var description: String { + return "[\(vertex1)-\(vertex2), \(weight)]" + } +} + + +// Undirected weighted graph +public struct Graph: CustomStringConvertible { + + public private(set) var edgeList: [Edge] + public private(set) var vertices: Set + public private(set) var adjList: [T: [(vertex: T, weight: Int)]] + + public init() { + edgeList = [Edge]() + vertices = Set() + adjList = [T: [(vertex: T, weight: Int)]]() + } + + public var description: String { + var description = "" + for edge in edgeList { + description += edge.description + "\n" + } + return description + } + + public mutating func addEdge(vertex1 v1: T, vertex2 v2: T, weight w: Int) { + edgeList.append(Edge(vertex1: v1, vertex2: v2, weight: w)) + vertices.insert(v1) + vertices.insert(v2) + if adjList[v1] == nil { + adjList[v1] = [(vertex: v2, weight: w)] + } else { + adjList[v1]!.append((vertex: v2, weight: w)) + } + + if adjList[v2] == nil { + adjList[v2] = [(vertex: v1, weight: w)] + } else { + adjList[v2]!.append((vertex: v1, weight: w)) + } + } + + public mutating func addEdge(_ edge: Edge) { + addEdge(vertex1: edge.vertex1, vertex2: edge.vertex2, weight: edge.weight) + } +} diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Heap.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Heap.swift new file mode 100644 index 000000000..fa30df362 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Heap.swift @@ -0,0 +1,227 @@ +// +// Heap.swift +// Written for the Swift Algorithm Club by Kevin Randrup and Matthijs Hollemans +// + +public struct Heap { + /** The array that stores the heap's nodes. */ + var elements = [T]() + + /** Determines whether this is a max-heap (>) or min-heap (<). */ + fileprivate var isOrderedBefore: (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. + */ + public init(sort: @escaping (T, T) -> Bool) { + self.isOrderedBefore = 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. + */ + public init(array: [T], sort: @escaping (T, T) -> Bool) { + self.isOrderedBefore = 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. + * 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) + } + } + + public var isEmpty: Bool { + return elements.isEmpty + } + + public var count: Int { + return elements.count + } + + /** + * 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 { + return (i - 1) / 2 + } + + /** + * Returns the index of the left child of the element at index i. + * 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 { + return 2*i + 1 + } + + /** + * Returns the index of the right child of the element at index i. + * 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 { + return 2*i + 2 + } + + /** + * Returns the maximum value in the heap (for a max-heap) or the minimum + * value (for a min-heap). + */ + public func peek() -> T? { + return elements.first + } + + /** + * 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). + */ + public mutating func insert(_ value: T) { + elements.append(value) + shiftUp(elements.count - 1) + } + + public mutating func insert(_ sequence: S) where S.Iterator.Element == T { + for value in sequence { + insert(value) + } + } + + /** + * 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. + */ + public mutating func replace(index i: Int, value: T) { + guard i < elements.count else { return } + + assert(isOrderedBefore(value, elements[i])) + elements[i] = value + shiftUp(i) + } + + /** + * Removes the root node from the heap. For a max-heap, this is the maximum + * 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 + } + } + + /** + * 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. + */ + public mutating func removeAt(_ index: Int) -> T? { + guard index < elements.count else { return nil } + + let size = elements.count - 1 + if index != size { + swap(&elements[index], &elements[size]) + shiftDown(index, heapSize: size) + shiftUp(index) + } + return elements.removeLast() + } + + /** + * 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) { + var childIndex = index + let child = elements[childIndex] + var parentIndex = self.parentIndex(ofIndex: childIndex) + + while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { + elements[childIndex] = elements[parentIndex] + childIndex = parentIndex + parentIndex = self.parentIndex(ofIndex: childIndex) + } + + elements[childIndex] = child + } + + mutating func shiftDown() { + shiftDown(0, heapSize: elements.count) + } + + /** + * 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 + + 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 } + + swap(&elements[parentIndex], &elements[first]) + parentIndex = first + } + } +} + +// 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) + } + + 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 } + return nil + } +} diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/PriorityQueue.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/PriorityQueue.swift new file mode 100644 index 000000000..92f7b6d3f --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/PriorityQueue.swift @@ -0,0 +1,58 @@ +/* + Priority Queue, a queue where the most "important" items are at the front of + the queue. + + The heap is a natural data structure for a priority queue, so this object + simply wraps the Heap struct. + + All operations are O(lg n). + + Just like a heap can be a max-heap or min-heap, the queue can be a max-priority + queue (largest element first) or a min-priority queue (smallest element first). +*/ +public struct PriorityQueue { + fileprivate var heap: Heap + + /* + To create a max-priority queue, supply a > sort function. For a min-priority + queue, use <. + */ + public init(sort: @escaping (T, T) -> Bool) { + heap = Heap(sort: sort) + } + + public var isEmpty: Bool { + return heap.isEmpty + } + + public var count: Int { + return heap.count + } + + public func peek() -> T? { + return heap.peek() + } + + public mutating func enqueue(_ element: T) { + heap.insert(element) + } + + public mutating func dequeue() -> T? { + return heap.remove() + } + + /* + Allows you to change the priority of an element. In a max-priority queue, + the new priority should be larger than the old one; in a min-priority queue + it should be smaller. + */ + public mutating func changePriority(index i: Int, value: T) { + return heap.replace(index: i, value: value) + } +} + +extension PriorityQueue where T: Equatable { + public func index(of element: T) -> Int? { + return heap.index(of: element) + } +} diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/UnionFind.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/UnionFind.swift new file mode 100644 index 000000000..29ea0a373 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/UnionFind.swift @@ -0,0 +1,61 @@ +/* + Union-Find Data Structure + + Performance: + adding new set is almost O(1) + finding set of element is almost O(1) + union sets is almost O(1) + */ + +public struct UnionFind { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + if parent[index] == index { + return index + } else { + parent[index] = setByIndex(parent[index]) + return parent[index] + } + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] + } else { + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] + } + } + } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } + } +} diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/contents.xcplayground b/Minimum Spanning Tree/MinimumSpanningTree.playground/contents.xcplayground new file mode 100644 index 000000000..89da2d470 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Minimum Spanning Tree/Prim.swift b/Minimum Spanning Tree/Prim.swift new file mode 100644 index 000000000..89c26cff0 --- /dev/null +++ b/Minimum Spanning Tree/Prim.swift @@ -0,0 +1,45 @@ +// +// Prim.swift +// +// +// Created by xiang xin on 16/3/17. +// +// + +func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) { + var cost: Int = 0 + var tree = Graph() + + if graph.vertices.isEmpty { + return (cost: cost, tree: tree) + } + + var visited = Set() + var priorityQueue = PriorityQueue<(vertex: T, weight: Int, parent: T?)>( + sort: { $0.weight < $1.weight }) + + priorityQueue.enqueue((vertex: graph.vertices.first!, weight: 0, parent: nil)) + while let head = priorityQueue.dequeue() { + let vertex = head.vertex + if visited.contains(vertex) { + continue + } + visited.insert(vertex) + + cost += head.weight + if let prev = head.parent { + tree.addEdge(vertex1: prev, vertex2: vertex, weight: head.weight) + } + + if let neighbours = graph.adjList[vertex] { + for neighbour in neighbours { + let nextVertex = neighbour.vertex + if !visited.contains(nextVertex) { + priorityQueue.enqueue((vertex: nextVertex, weight: neighbour.weight, parent: vertex)) + } + } + } + } + + return (cost: cost, tree: tree) +} diff --git a/Minimum Spanning Tree/README.markdown b/Minimum Spanning Tree/README.markdown new file mode 100644 index 000000000..c47713701 --- /dev/null +++ b/Minimum Spanning Tree/README.markdown @@ -0,0 +1,102 @@ +# Minimum Spanning Tree (Weighted Graph) + +A [minimum spanning tree](https://en.wikipedia.org/wiki/Minimum_spanning_tree) (MST) of a connected undirected weighted graph has a subset of the edges from the original graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. There can be more than one MSTs of a graph. + +There are two popular algorithms to calculate MST of a graph - [Kruskal's algorithm](https://en.wikipedia.org/wiki/Kruskal's_algorithm) and [Prim's algorithm](https://en.wikipedia.org/wiki/Prim's_algorithm). Both algorithms have a total time complexity of `O(ElogE)` where `E` is the number of edges from the original graph. + +### Kruskal's Algorithm +Sort the edges base on weight. Greedily select the smallest one each time and add into the MST as long as it doesn't form a cycle. +Kruskal's algoritm uses [Union Find](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Union-Find) data structure to check whether any additional edge causes a cycle. The logic is to put all connected vertices into the same set (in Union Find's concept). If the two vertices from a new edge do not belong to the same set, then it's safe to add that edge into the MST. + +The following graph demonstrates the steps: + +![Graph](Images/kruskal.png) + +Preparation +```swift +// Initialize the values to be returned and Union Find data structure. +var cost: Int = 0 +var tree = Graph() +var unionFind = UnionFind() +for vertex in graph.vertices { + +// Initially all vertices are disconnected. +// Each of them belongs to it's individual set. + unionFind.addSetWith(vertex) +} +``` + +Sort the edges +```swift +let sortedEdgeListByWeight = graph.edgeList.sorted(by: { $0.weight < $1.weight }) +``` + +Take one edge at a time and try to insert it into the MST. +```swift +for edge in sortedEdgeListByWeight { + let v1 = edge.vertex1 + let v2 = edge.vertex2 + + // Same set means the two vertices of this edge were already connected in the MST. + // Adding this one will cause a cycle. + if !unionFind.inSameSet(v1, and: v2) { + // Add the edge into the MST and update the final cost. + cost += edge.weight + tree.addEdge(edge) + + // Put the two vertices into the same set. + unionFind.unionSetsContaining(v1, and: v2) + } +} +``` +### Prim's Algorithm +Prim's algorithm doesn't pre-sort all edges. Instead, it uses a [Priority Queue](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Priority%20Queue) to maintain a running sorted next-possile vertices. +Starting from one vertex, loop through all unvisited neighbours and enqueue a pair of values for each neighbour - the vertex and the weight of edge connecting current vertex to the neighbour. Each time it greedily select the top of the priority queue (the one with least weight value) and add the edge into the final MST if the enqueued neighbour hasn't been already visited. + +The following graph demonstrates the steps: + +![Graph](Images/prim.png) + +Preparation +```swift +// Initialize the values to be returned and Priority Queue data structure. +var cost: Int = 0 +var tree = Graph() +var visited = Set() + +// In addition to the (neighbour vertex, weight) pair, parent is added for the purpose of printing out the MST later. +// parent is basically current vertex. aka. the previous vertex before neigbour vertex gets visited. +var priorityQueue = PriorityQueue<(vertex: T, weight: Int, parent: T?)>(sort: { $0.weight < $1.weight }) +``` + +Start from any vertex +```swift +priorityQueue.enqueue((vertex: graph.vertices.first!, weight: 0, parent: nil)) +``` + +```swift +// Take from the top of the priority queue ensures getting the least weight edge. +while let head = priorityQueue.dequeue() { + let vertex = head.vertex + if visited.contains(vertex) { + continue + } + + // If the vertex hasn't been visited before, its edge (parent-vertex) is selected for MST. + visited.insert(vertex) + cost += head.weight + if let prev = head.parent { // The first vertex doesn't have a parent. + tree.addEdge(vertex1: prev, vertex2: vertex, weight: head.weight) + } + + // Add all unvisted neighbours into the priority queue. + if let neighbours = graph.adjList[vertex] { + for neighbour in neighbours { + let nextVertex = neighbour.vertex + if !visited.contains(nextVertex) { + priorityQueue.enqueue((vertex: nextVertex, weight: neighbour.weight, parent: vertex)) + } + } + } +} +``` diff --git a/README.markdown b/README.markdown index e0983f22e..579ca0b4e 100644 --- a/README.markdown +++ b/README.markdown @@ -178,6 +178,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Shortest Path](Shortest%20Path%20%28Unweighted%29/) on an unweighted tree - [Single-Source Shortest Paths](Single-Source%20Shortest%20Paths%20(Weighted)/) - [Minimum Spanning Tree](Minimum%20Spanning%20Tree%20%28Unweighted%29/) on an unweighted tree +- [Minimum Spanning Tree](Minimum%20Spanning%20Tree/) - [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) ## Puzzles diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index b2ffce836..c89ac0dfe 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1267,6 +1267,32 @@ location = "group:README.markdown"> + + + + + + + + + + + + + + + + From 6bc50e5f9a966738b8331d68de8ed421067d4f4e Mon Sep 17 00:00:00 2001 From: Xiangxin Date: Tue, 25 Apr 2017 15:29:45 +0800 Subject: [PATCH 0611/1275] Address comments and refactor --- .../MinimumSpanningTree.playground/Contents.swift | 4 ++-- .../Sources/Graph.swift | 13 +++++++------ .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ Minimum Spanning Tree/Prim.swift | 5 +++-- 4 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift index 99b5e859f..2981d30ea 100644 --- a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift @@ -30,7 +30,7 @@ func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) var cost: Int = 0 var tree = Graph() - if graph.vertices.isEmpty { + guard let start = graph.vertices.first else { return (cost: cost, tree: tree) } @@ -38,7 +38,7 @@ func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) var priorityQueue = PriorityQueue<(vertex: T, weight: Int, parent: T?)>( sort: { $0.weight < $1.weight }) - priorityQueue.enqueue((vertex: graph.vertices.first!, weight: 0, parent: nil)) + priorityQueue.enqueue((vertex: start, weight: 0, parent: nil)) while let head = priorityQueue.dequeue() { let vertex = head.vertex if visited.contains(vertex) { diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift index 0ae996646..a2f243202 100644 --- a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift @@ -36,16 +36,17 @@ public struct Graph: CustomStringConvertible { edgeList.append(Edge(vertex1: v1, vertex2: v2, weight: w)) vertices.insert(v1) vertices.insert(v2) - if adjList[v1] == nil { - adjList[v1] = [(vertex: v2, weight: w)] + + if let _ = adjList[v1] { + adjList[v1]?.append((vertex: v2, weight: w)) } else { - adjList[v1]!.append((vertex: v2, weight: w)) + adjList[v1] = [(vertex: v2, weight: w)] } - if adjList[v2] == nil { - adjList[v2] = [(vertex: v1, weight: w)] + if let _ = adjList[v2] { + adjList[v2]?.append((vertex: v1, weight: w)) } else { - adjList[v2]!.append((vertex: v1, weight: w)) + adjList[v2] = [(vertex: v1, weight: w)] } } diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Minimum Spanning Tree/Prim.swift b/Minimum Spanning Tree/Prim.swift index 89c26cff0..d975fc430 100644 --- a/Minimum Spanning Tree/Prim.swift +++ b/Minimum Spanning Tree/Prim.swift @@ -10,7 +10,7 @@ func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) var cost: Int = 0 var tree = Graph() - if graph.vertices.isEmpty { + guard let start = graph.vertices.first else { return (cost: cost, tree: tree) } @@ -18,7 +18,7 @@ func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) var priorityQueue = PriorityQueue<(vertex: T, weight: Int, parent: T?)>( sort: { $0.weight < $1.weight }) - priorityQueue.enqueue((vertex: graph.vertices.first!, weight: 0, parent: nil)) + priorityQueue.enqueue((vertex: start, weight: 0, parent: nil)) while let head = priorityQueue.dequeue() { let vertex = head.vertex if visited.contains(vertex) { @@ -43,3 +43,4 @@ func minimumSpanningTreePrim(graph: Graph) -> (cost: Int, tree: Graph) return (cost: cost, tree: tree) } + From ea777fb3bc861e4818c414a97eb72fb8b9e3b644 Mon Sep 17 00:00:00 2001 From: Xiangxin Date: Sat, 6 May 2017 13:08:41 +0800 Subject: [PATCH 0612/1275] refactor --- .../Sources/Graph.swift | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift index a2f243202..5e74e14cb 100644 --- a/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift @@ -37,17 +37,11 @@ public struct Graph: CustomStringConvertible { vertices.insert(v1) vertices.insert(v2) - if let _ = adjList[v1] { - adjList[v1]?.append((vertex: v2, weight: w)) - } else { - adjList[v1] = [(vertex: v2, weight: w)] - } + adjList[v1] = adjList[v1] ?? [] + adjList[v1]?.append((vertex: v2, weight: w)) - if let _ = adjList[v2] { - adjList[v2]?.append((vertex: v1, weight: w)) - } else { - adjList[v2] = [(vertex: v1, weight: w)] - } + adjList[v2] = adjList[v2] ?? [] + adjList[v2]?.append((vertex: v1, weight: w)) } public mutating func addEdge(_ edge: Edge) { From 12fac48235b369612be3a96b807e4e4ba2ad237c Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 7 May 2017 04:45:19 -0700 Subject: [PATCH 0613/1275] Fixed spacing, and fixes some English. --- .../UnionFind.playground/Contents.swift | 24 ++--- .../Sources/UnionFindQuickFind.swift | 80 ++++++++-------- .../Sources/UnionFindQuickUnion.swift | 82 ++++++++-------- .../Sources/UnionFindWeightedQuickFind.swift | 94 +++++++++---------- .../Sources/UnionFindWeightedQuickUnion.swift | 92 +++++++++--------- ...indWeightedQuickUnionPathCompression.swift | 86 ++++++++--------- 6 files changed, 229 insertions(+), 229 deletions(-) diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 9ad5215b3..0a50d1ba6 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -3,17 +3,17 @@ var dsu = UnionFindQuickUnion() for i in 1...10 { - dsu.addSetWith(i) + dsu.addSetWith(i) } // now our dsu contains 10 independent sets // let's divide our numbers into two sets by divisibility by 2 for i in 3...10 { - if i % 2 == 0 { - dsu.unionSetsContaining(2, and: i) - } else { - dsu.unionSetsContaining(1, and: i) - } + if i % 2 == 0 { + dsu.unionSetsContaining(2, and: i) + } else { + dsu.unionSetsContaining(1, and: i) + } } // check our division @@ -42,12 +42,12 @@ dsuForStrings.addSetWith("b") // In that example we divide strings by its first letter for word in words { - dsuForStrings.addSetWith(word) - if word.hasPrefix("a") { - dsuForStrings.unionSetsContaining("a", and: word) - } else if word.hasPrefix("b") { - dsuForStrings.unionSetsContaining("b", and: word) - } + dsuForStrings.addSetWith(word) + if word.hasPrefix("a") { + dsuForStrings.unionSetsContaining("a", and: word) + } else if word.hasPrefix("b") { + dsuForStrings.unionSetsContaining("b", and: word) + } } print(dsuForStrings.inSameSet("a", and: "all")) diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift b/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift index 25d7f5b5d..33e81832d 100644 --- a/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift +++ b/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift @@ -3,48 +3,48 @@ import Foundation /// Quick-find algorithm may take ~MN steps /// to process M union commands on N objects public struct UnionFindQuickFind { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public init() {} - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil } - - private mutating func setByIndex(_ index: Int) -> Int { - return parent[index] - } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) - } else { - return nil - } - } - - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - for index in 0.. Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false } + } } diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift b/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift index 4c848e61d..9bff31616 100644 --- a/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift +++ b/Union-Find/UnionFind.playground/Sources/UnionFindQuickUnion.swift @@ -3,49 +3,49 @@ import Foundation /// Quick-Union algorithm may take ~MN steps /// to process M union commands on N objects public struct UnionFindQuickUnion { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public init() {} - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + if parent[index] == index { + return index + } else { + parent[index] = setByIndex(parent[index]) + return parent[index] } - - private mutating func setByIndex(_ index: Int) -> Int { - if parent[index] == index { - return index - } else { - parent[index] = setByIndex(parent[index]) - return parent[index] - } + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) - } else { - return nil - } + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] + } } - - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - parent[firstSet] = secondSet - size[secondSet] += size[firstSet] - } - } - } - - public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false } + } } diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift index 02bec94a8..c89f2a457 100644 --- a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickFind.swift @@ -3,57 +3,57 @@ import Foundation /// Quick-find algorithm may take ~MN steps /// to process M union commands on N objects public struct UnionFindWeightedQuickFind { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public init() {} - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil } - - private mutating func setByIndex(_ index: Int) -> Int { - return parent[index] - } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + for index in 0.. Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false } + } } diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift index b3ac7445e..cd33007bc 100644 --- a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnion.swift @@ -1,56 +1,56 @@ import Foundation public struct UnionFindWeightedQuickUnion { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public init() {} - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + private mutating func setByIndex(_ index: Int) -> Int { + if parent[index] == index { + return index + } else { + parent[index] = setByIndex(parent[index]) + return parent[index] } - - private mutating func setByIndex(_ index: Int) -> Int { - if parent[index] == index { - return index - } else { - parent[index] = setByIndex(parent[index]) - return parent[index] - } + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) + } + + /// Weighted, by comparing set size. + /// Merge small set into the large one. + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] } else { - return nil - } - } - - /// Weighted, by comparing set size. - /// Merge small set into the large one. - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - if size[firstSet] < size[secondSet] { - parent[firstSet] = secondSet - size[secondSet] += size[firstSet] - } else { - parent[secondSet] = firstSet - size[firstSet] += size[secondSet] - } - } + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] } + } } - - public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false } + } } diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift index 892f46a3c..7eb8fe209 100644 --- a/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift +++ b/Union-Find/UnionFind.playground/Sources/UnionFindWeightedQuickUnionPathCompression.swift @@ -1,53 +1,53 @@ import Foundation public struct UnionFindWeightedQuickUnionPathCompression { - private var index = [T: Int]() - private var parent = [Int]() - private var size = [Int]() - - public init() {} - - public mutating func addSetWith(_ element: T) { - index[element] = parent.count - parent.append(parent.count) - size.append(1) + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() + + public init() {} + + public mutating func addSetWith(_ element: T) { + index[element] = parent.count + parent.append(parent.count) + size.append(1) + } + + /// Path Compression. + private mutating func setByIndex(_ index: Int) -> Int { + if index != parent[index] { + parent[index] = setByIndex(parent[index]) } - - /// Path Compression. - private mutating func setByIndex(_ index: Int) -> Int { - if index != parent[index] { - parent[index] = setByIndex(parent[index]) - } - return parent[index] + return parent[index] + } + + public mutating func setOf(_ element: T) -> Int? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil } - - public mutating func setOf(_ element: T) -> Int? { - if let indexOfElement = index[element] { - return setByIndex(indexOfElement) + } + + public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + if firstSet != secondSet { + if size[firstSet] < size[secondSet] { + parent[firstSet] = secondSet + size[secondSet] += size[firstSet] } else { - return nil - } - } - - public mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - if firstSet != secondSet { - if size[firstSet] < size[secondSet] { - parent[firstSet] = secondSet - size[secondSet] += size[firstSet] - } else { - parent[secondSet] = firstSet - size[firstSet] += size[secondSet] - } - } + parent[secondSet] = firstSet + size[firstSet] += size[secondSet] } + } } - - public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { - if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { - return firstSet == secondSet - } else { - return false - } + } + + public mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool { + if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false } + } } From e560f60fc35889fefba95389ea53c6d02a9e22e9 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 8 May 2017 01:09:02 +0500 Subject: [PATCH 0614/1275] Fix a few typos in DiningPhilosophers Readme an -> a dinining -> dining "no needs" -> "no need" --- DiningPhilosophers/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 0bf4f28ce..bc622e559 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -22,12 +22,12 @@ Eating is not limited by the remaining amounts of spaghetti or stomach space; an The problem is how to design a discipline of behavior (a concurrent algorithm) such that no philosopher will starve; i.e., each can forever continue to alternate between eating and thinking, assuming that no philosopher can know when others may want to eat or think. -This is an illustration of an dinining table: +This is an illustration of a dining table: ![Dining Philosophers table](https://upload.wikimedia.org/wikipedia/commons/7/7b/An_illustration_of_the_dining_philosophers_problem.png) # Solution -There are different solutions for this classic algorithm, and this Swift implementation is based on the Chandy/Misra solution. This implementation allows agents to contend for an arbitrary number of resources in a completely distributed scenario with no needs for a central authority to control the locking and serialization of resources. +There are different solutions for this classic algorithm, and this Swift implementation is based on the Chandy/Misra solution. This implementation allows agents to contend for an arbitrary number of resources in a completely distributed scenario with no need for a central authority to control the locking and serialization of resources. However, this solution violates the requirement that "the philosophers do not speak to each other" (due to the request messages). From 297b0d4679fbd8607edb5b59b87d273962354e84 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 8 May 2017 01:26:16 +0500 Subject: [PATCH 0615/1275] Fix minor grammar typo --- Graph/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graph/README.markdown b/Graph/README.markdown index bc33b044a..d3c8b89e5 100644 --- a/Graph/README.markdown +++ b/Graph/README.markdown @@ -143,7 +143,7 @@ Here is an example of a simple graph: ![Demo](Images/Demo1.png) -We can represent it as an adjacency matrix or adjacency list. The classes implementing those concept both inherit a common API from `AbstractGraph`, so they can be created in an identical fashion, with different optimized data structures behind the scenes. +We can represent it as an adjacency matrix or adjacency list. The classes implementing those concepts both inherit a common API from `AbstractGraph`, so they can be created in an identical fashion, with different optimized data structures behind the scenes. Let's create some directed, weighted graphs, using each representation, to store the example: From 24d5adeba873dc184e2fc28dcaf942b15c60b95e Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Mon, 8 May 2017 01:32:34 +0500 Subject: [PATCH 0616/1275] Fix broken links by replacing spaces with %20 --- Heap/README.markdown | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 7beea4f34..a3b0038ab 100644 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -1,11 +1,11 @@ # Heap -A heap is a [binary tree](../Binary Tree/) inside an array, so it does not use parent/child pointers. A heap is sorted based on the "heap property" that determines the order of the nodes in the tree. +A heap is a [binary tree](../Binary%20Tree/) inside an array, so it does not use parent/child pointers. A heap is sorted based on the "heap property" that determines the order of the nodes in the tree. Common uses for heap: -- To build [priority queues](../Priority Queue/). -- To support [heap sorts](../Heap Sort/). +- To build [priority queues](../Priority%20Queue/). +- To support [heap sorts](../Heap%20Sort/). - To compute the minimum (or maximum) element of a collection quickly. - To impress your non-programmer friends. @@ -21,7 +21,7 @@ An example: This is a max-heap because every parent node is greater than its children. `(10)` is greater than `(7)` and `(2)`. `(7)` is greater than `(5)` and `(1)`. -As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. The heap property is useful because heaps are often used as a [priority queue](../Priority Queue/)to access the "most important" element quickly. +As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. The heap property is useful because heaps are often used as a [priority queue](../Priority%20Queue/)to access the "most important" element quickly. > **Note:** The root of the heap has the maximum or minimum element, but the sort order of other elements are not predictable. For example, the maximum element is always at index 0 in a max-heap, but the minimum element isn’t necessarily the last one. -- the only guarantee you have is that it is one of the leaf nodes, but not which one. @@ -30,11 +30,11 @@ As a result of this heap property, a max-heap always stores its largest item at A heap is not a replacement for a binary search tree, and there are similarities and differnces between them. Here are some main differences: -**Order of the nodes.** In a [binary search tree (BST)](../Binary Search Tree/), 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. +**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. **Memory.** Traditional trees take up more memory than just the data they store. You need to allocate additional storage for the node objects and pointers to the left/right child nodes. A heap only uses a plain array for storage and uses no pointers. -**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 Tree/) or [red-black tree](../Red-Black Tree/), 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. +**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. @@ -112,7 +112,7 @@ Is this a valid heap? The answer is yes! A sorted array from low-to-high is a va The heap property holds for each node because a parent is always smaller than its children. (Verify for yourself that an array sorted from high-to-low is always a valid max-heap.) -> **Note:** But not every min-heap is necessarily a sorted array! It only works one way. To turn a heap back into a sorted array, you need to use [heap sort](../Heap Sort/). +> **Note:** But not every min-heap is necessarily a sorted array! It only works one way. To turn a heap back into a sorted array, you need to use [heap sort](../Heap%20Sort/). ## More math! @@ -162,7 +162,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 Sort/). 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 lg 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)**. @@ -289,7 +289,7 @@ Here, `elements` is the heap's own array. We walk backwards through this array, Heaps are not made for fast searches, but if you want to remove an arbitrary element using `removeAtIndex()` or change the value of an element with `replace()`, then you need to obtain the index of that element. Searching is one way to do this, but it is slow. -In a [binary search tree](../Binary Search Tree/), depending on the order of the nodes, a fast search can be guaranteed. Since a heap orders its nodes differently, a binary search will not work, and you need to check every node in the tree. +In a [binary search tree](../Binary%20Search%20Tree/), depending on the order of the nodes, a fast search can be guaranteed. Since a heap orders its nodes differently, a binary search will not work, and you need to check every node in the tree. Let's take our example heap again: From 1eb61c97a7949a0088834759bd9b1f40d884a9e9 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 8 May 2017 05:16:23 -0700 Subject: [PATCH 0617/1275] Improves the wording for a few sentences. --- Union-Find/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Union-Find/README.markdown b/Union-Find/README.markdown index dfec7dbe6..a268f1d70 100644 --- a/Union-Find/README.markdown +++ b/Union-Find/README.markdown @@ -9,7 +9,7 @@ What do we mean by this? For example, the Union-Find data structure could be kee [ g, d, c ] [ i, j ] -These sets are disjoint because they have no members in common. +These sets are **disjoint** because they have no members in common. Union-Find supports three basic operations: @@ -24,7 +24,7 @@ The most common application of this data structure is keeping track of the conne ## Implementation Union-Find can be implemented in many ways but we'll look at an efficient and easy to understand implementation: Weighted Quick Union. -> __PS: Variety implementation of Union-Find has been included in playground.__ +> __PS: Multiple implementations of Union-Find has been included in playground.__ ```swift public struct UnionFind { @@ -198,7 +198,7 @@ private mutating func setByIndex(_ index: Int) -> Int { ``` Path Compression helps keep trees very flat, thus find operation could take __ALMOST__ in __O(1)__ -## Complexity Summary of Variety Implementation +## Complexity Summary ##### To process N objects | Data Structure | Union | Find | From a087b19f146e32ac731fac5c4c989b1eff3c7401 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 8 May 2017 05:17:49 -0700 Subject: [PATCH 0618/1275] Fixes spelling. --- DiningPhilosophers/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index 0bf4f28ce..e4db0d7e0 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -10,7 +10,7 @@ In computer science, the dining philosophers problem is often used in the concur It was originally formulated in 1965 by Edsger Dijkstra as a student exam exercise, presented in terms of computers competing for access to tape drive peripherals. Soon after, Tony Hoare gave the problem its present formulation. -This Swift implementation is based on the Chandy/Misra solution, and it uses the GCD Dispatch and Semaphone on the Swift cross platform. +This Swift implementation is based on the Chandy/Misra solution, and it uses the GCD Dispatch and Semaphores on the Swift cross platform. # Problem statement From 988e354fed9122acb0b7b7ec8098b0a29c374070 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 8 May 2017 18:54:43 -0400 Subject: [PATCH 0619/1275] Formatted headers in readme Github seems to require spaces between "#" and headings . --- Radix Sort/ReadMe.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Radix Sort/ReadMe.md b/Radix Sort/ReadMe.md index 5bdb931ca..ceb4459d7 100644 --- a/Radix Sort/ReadMe.md +++ b/Radix Sort/ReadMe.md @@ -2,19 +2,19 @@ Radix sort is a sorting algorithm that takes as input an array of integers and uses a sorting subroutine( that is often another efficient sorting algorith) to sort the integers by their radix, or rather their digit. Counting Sort, and Bucket Sort are often times used as the subroutine for Radix Sort. -##Example +## Example * Input Array: [170, 45, 75, 90, 802, 24, 2, 66] * Output Array (Sorted): [2, 24, 45, 66, 75, 90, 170, 802] -###Step 1: +### Step 1: The first step in this algorithm is to define the digit or rather the "base" or radix that we will use to sort. For this example we will let radix = 10, since the integers we are working with in the example are of base 10. -###Step 2: +### Step 2: The next step is to simply iterate n times (where n is the number of digits in the largest integer in the input array), and upon each iteration perform a sorting subroutine on the current digit in question. -###Algorithm in Action +### Algorithm in Action Let's take a look at our example input array. From 90730ade45d11947529e51acf15e09f1ef622596 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 16 May 2017 09:56:13 -0700 Subject: [PATCH 0620/1275] Fixes #464. --- Threaded Binary Tree/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Threaded Binary Tree/README.markdown b/Threaded Binary Tree/README.markdown index 8a1c518f1..f631b86f9 100644 --- a/Threaded Binary Tree/README.markdown +++ b/Threaded Binary Tree/README.markdown @@ -267,9 +267,9 @@ something simple, like removing **7**, which has no children: Before we can just throw **7** away, we have to perform some clean-up. In this case, because **7** is a `right` child and has no children itself, we can simply set the `rightThread` of **7**'s `parent`(**5**) to **7**'s (now -outdated) `rightThread`. Then we can just set **7**'s `parent`, `left`, +outdated) `rightThread`. Then we can just set **7**'s `parent`, `left`, `right`, `leftThread`, and `rightThread` to `nil`, effectively removing it from -the tree. +the tree. We also set the parent's `rightChild` to `nil`, which completes the deletion of this right child. Let's try something a little harder. Say we remove **5** from the tree: From cde6f854865d19c4cefb187894a4da09a0be4fee Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Wed, 17 May 2017 05:16:52 +0500 Subject: [PATCH 0621/1275] Fix a few typos in Heap/README --- Heap/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index a3b0038ab..bb7a785a5 100644 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -21,7 +21,7 @@ An example: This is a max-heap because every parent node is greater than its children. `(10)` is greater than `(7)` and `(2)`. `(7)` is greater than `(5)` and `(1)`. -As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. The heap property is useful because heaps are often used as a [priority queue](../Priority%20Queue/)to access the "most important" element quickly. +As a result of this heap property, a max-heap always stores its largest item at the root of the tree. For a min-heap, the root is always the smallest item in the tree. The heap property is useful because heaps are often used as a [priority queue](../Priority%20Queue/) to access the "most important" element quickly. > **Note:** The root of the heap has the maximum or minimum element, but the sort order of other elements are not predictable. For example, the maximum element is always at index 0 in a max-heap, but the minimum element isn’t necessarily the last one. -- the only guarantee you have is that it is one of the leaf nodes, but not which one. @@ -124,7 +124,7 @@ This heap has height 3, so it has 4 levels: ![Large heap](Images/LargeHeap.png) -A heap with *n* nodes has height *h = floor(log_2(n))*. This is because we always fill up the lowest level completely before we add a new level. The example has 15 nodes, so the height is `floor(log_2(15)) = floor(3.91) = 3`. +A heap with *n* nodes has height *h = floor(log2(n))*. This is because we always fill up the lowest level completely before we add a new level. The example has 15 nodes, so the height is `floor(log2(15)) = floor(3.91) = 3`. If the lowest level is completely full, then that level contains *2^h* nodes. The rest of the tree above it contains *2^h - 1* nodes. Fill in the numbers from the example: the lowest level has 8 nodes, which indeed is `2^3 = 8`. The first three levels contain a total of 7 nodes, i.e. `2^3 - 1 = 8 - 1 = 7`. @@ -303,7 +303,7 @@ Let's say we want to see if the heap contains the value `8` (it doesn't). We sta Despite this small optimization, searching is still an **O(n)** operation. -> **Note:** There is away to turn lookups into a **O(1)** operation by keeping an additional dictionary that maps node values to indices. This may be worth doing if you often need to call `replace()` to change the "priority" of objects in a [priority queue](../Priority%20Queue/) that's built on a heap. +> **Note:** There is a way to turn lookups into a **O(1)** operation by keeping an additional dictionary that maps node values to indices. This may be worth doing if you often need to call `replace()` to change the "priority" of objects in a [priority queue](../Priority%20Queue/) that's built on a heap. ## The code From c014bd9a0823d6206fa18e915f6e4f01d5852beb Mon Sep 17 00:00:00 2001 From: Artur Date: Wed, 17 May 2017 03:19:47 +0300 Subject: [PATCH 0622/1275] remove "countingSort" func throws if you received empty array, just return empty array --- Counting Sort/CountingSort.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Counting Sort/CountingSort.swift b/Counting Sort/CountingSort.swift index abece0213..725a634a4 100644 --- a/Counting Sort/CountingSort.swift +++ b/Counting Sort/CountingSort.swift @@ -6,14 +6,8 @@ // Copyright © 2016 Ali Hafizji. All rights reserved. // -enum CountingSortError: Error { - case arrayEmpty -} - -func countingSort(_ array: [Int]) throws -> [Int] { - guard array.count > 0 else { - throw CountingSortError.arrayEmpty - } +func countingSort(_ array: [Int])-> [Int] { + guard array.count > 0 else {return []} // Step 1 // Create an array to store the count of each element From d705414bbcf2eb62232d5c456befc193e397b208 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Wed, 17 May 2017 05:20:54 +0500 Subject: [PATCH 0623/1275] Update displayed code to use 2 space indentation --- Heap Sort/README.markdown | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Heap Sort/README.markdown b/Heap Sort/README.markdown index 7fdd8d2ca..a45dad6f9 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -48,13 +48,13 @@ Here's how you can implement heap sort in Swift: ```swift extension Heap { - public mutating func sort() -> [T] { - for i in stride(from: (elements.count - 1), through: 1, by: -1) { - swap(&elements[0], &elements[i]) - shiftDown(0, heapSize: i) - } - return elements + public mutating func sort() -> [T] { + for i in stride(from: (elements.count - 1), through: 1, by: -1) { + swap(&elements[0], &elements[i]) + shiftDown(0, heapSize: i) } + return elements + } } ``` @@ -71,9 +71,9 @@ We can write a handy helper function for that: ```swift public func heapsort(_ a: [T], _ sort: @escaping (T, T) -> Bool) -> [T] { - let reverseOrder = { i1, i2 in sort(i2, i1) } - var h = Heap(array: a, sort: reverseOrder) - return h.sort() + let reverseOrder = { i1, i2 in sort(i2, i1) } + var h = Heap(array: a, sort: reverseOrder) + return h.sort() } ``` From e311ee9b88a16d9dfaeacc7f2e7ea7825169fe8b Mon Sep 17 00:00:00 2001 From: Tobias Helmrich Date: Thu, 18 May 2017 21:52:38 +0900 Subject: [PATCH 0624/1275] Fix typos and markdown formatting --- Linear Regression/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 1a1a1eb8b..29ac2e321 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -75,7 +75,7 @@ for n 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 minimse 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 proprotional 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. @@ -98,7 +98,7 @@ Here is the same data shown as a graph. Each of the blue lines on the graph repr After 18,000 iterations it looks as if the line is getting closer to what we would expect (just by looking) to be the correct line of best fit. Also, each additional 2,000 iterations has less and less effect on the final result - the values of the intercept and the slope are converging on the correct values. -##A closed form solution +## A closed form solution There is another way we can calculate the line of best fit, without having to do multiple iterations. We can solve the equations describing the least squares minimisation and just work out the intercept and slope directly. @@ -139,7 +139,7 @@ This function takes as arguments two arrays of Doubles, and returns a function w Using this line, we would predict a price for our 4 year old car of £6952. -##Summary +## Summary We've seen two different ways to implement a simple linear regression in Swift. An obvious question is: why bother with the iterative approach at all? Well, the line we've found doesn't fit the data perfectly. For one thing, the graph includes some negative values at high car ages! Possibly we would have to pay someone to tow away a very old car... but really these negative values just show that we have not modelled the real life situation very accurately. The relationship between the car age and the car price is not linear but instead is some other function. We also know that a car's price is not just related to its age but also other factors such as the make, model and engine size of the car. We would need to use additional variables to describe these other factors. From d2f02efd49d2367382c7a6fffc5fa1e3b74c8eff Mon Sep 17 00:00:00 2001 From: Barbara Martina Rodeker Date: Sun, 21 May 2017 21:46:01 +0200 Subject: [PATCH 0625/1275] Initial Docs template and text --- Splay Tree/readme.md | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index 2282502fa..aa6bdd4db 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -1 +1,60 @@ -In progress +# Splay Tree +Splay tree is a data structure, structurally identitical to a Balanced Binary Search Tree. Every operation performed on a Splay Tree causes a readjustment in order to provide fast access to recently operated values. On every access, the tree is rearranged and the node accessed is moved to the root of the tree using a set of specific rotations, which together are referred to as **Splaying**. + + +## Rotations + +### Zig-Zig + +Given a node *a* if *a* is not the root, and *a* has a child *b*, and both *a* and *b* are left children or right children, a **Zig-Zig** is performed. + +### Zig-Zag + +Given a node *a* if *a* is not the root, and *a* has a child *b*, and *b* is the left child of *a* being the right child (or the opporsite), a **Zig-Zag** is performed. + +### Zig + +A **Zig** is performed when the node *a* to be rotated has the root as parent. + +## Splaying + +## Operations + +### Insertion + +### Deletion + +### Search + +## Examples + +### Example 1 + +### Example 2 + +### Example 3 + +## 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. + +## Disadvantages + +Splay tree are not perfectly balanced always, so in case of accessing all the elements in the tree in an increasing order, the height of the tree becomes *n*. + +## Time complexity + +| Case | Performance | +| ------------- |:-------------:| +| Average | O(log n) | +| Worst | n | + +With *n* being the number of items in the tree. + + +## See also + +[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) + +*Written for Swift Algorithm Club by Mike Taghavi and Matthijs Hollemans* From 7f751918b92881d93aabce634a891b95f46a90f0 Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 21 May 2017 22:03:23 +0200 Subject: [PATCH 0626/1275] images for documentation --- Splay Tree/Images /zig.png | Bin 0 -> 7793 bytes Splay Tree/Images /zigzag1.png | Bin 0 -> 13964 bytes Splay Tree/Images /zigzag2.png | Bin 0 -> 13877 bytes Splay Tree/Images /zigzig1.png | Bin 0 -> 13855 bytes Splay Tree/Images /zigzig2.png | Bin 0 -> 15179 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Splay Tree/Images /zig.png create mode 100644 Splay Tree/Images /zigzag1.png create mode 100644 Splay Tree/Images /zigzag2.png create mode 100644 Splay Tree/Images /zigzig1.png create mode 100644 Splay Tree/Images /zigzig2.png diff --git a/Splay Tree/Images /zig.png b/Splay Tree/Images /zig.png new file mode 100644 index 0000000000000000000000000000000000000000..e21522b6fe55f9529b2f818a4e108cd47964908b GIT binary patch literal 7793 zcmY*;1yGcK)b8%Gz=Cu)OE-&j2}>y*QY+ovAdRpfQj&s%v~+_Y2q+;E(kVzwNS7cD z_x1mMcjn%md3WBO{pE@0ob#L*ZOte6xHPyR5C~sIS@9_d1cm_bl`t&eJDw+{8w6qy zS5cJH^EcZ!#ZDquB0XSH#saG_bLK08<-${R3fGw{;BwGZ7G)w<6#@!sMI@8;`QguTmsJ+;M24I zjDSwsKZ%5dWb21{D0yBSC4&8$->h9cM>-(oWMlA2z@JU>WtDr=B4y&h%}jggwimfA zbOb#QiTW*z-h2)|n>K8GaT|DC{uqo-kj_CDE-zb7z+|_d)mhsI+iaNvDJ3?<^9uQRZO$7D271gxvIm3 zPo$u1QVvb+NL+GGmTv{TiMgo)3+^kiQ%!z9)Zm5scx3!bM7YhWwR@)g#sx$ z3%Ezr;lShlu>uToUX=FD#Abi8LIibWUUwRgA(Uw4ujP25($CR!4ysHHJZN%2(P>PB z?chWw8spLBZmj9hYigk_;D>5JPfq1;K#+k9*z~JgOdib= ziTiuFtflsr*VEtT?Ca;7lR>@rkMRTl42w+@_Od8%0Q>3rzBRU*a2jutgvP7JF`=C)iYP|w@P{9_e0zxV*^N_RY zjC!05OKQBRO2gU`5;oP0fb2ZafA=MTfkxzB#Qpsebk1+vpM<`<{LP3hKBO@FZ);P6 z#}0(DU^?vfU?qn%r6Yv@TD+Lz7}=X8K&slDjQ)5twdTujM&ui2A)^W}MG+<~+6L(h zi4Xz-B2EkL)}99*SEr5%vn(WCx>~ZgjkRE%*k^Q$p63z*z zd*7f>+X{0~WSY&5P|)_fV(9&CbNTN}CVPoaBs_DupEs4yShPANR@tm@0&J=pmV;p?cg{^w^TeBK4%TAhQ1_#VFcrezN+rP#tk9yt2Hom8k ze!J+$9lao?(tMgn# zaS?-c^E+}LgR!4Y&W@KS8})6J zHF);v2>Q?Akm2m`(auK4Nryk1!z6)!o=`sDnPM_&`f~9r?haMAS!n}Lg6HQx3W`m! z$xiE&7P247RskO3XGxh0|I8aoO~$Dm2Kc^$Aa06kMgm8xxZgoG=VsvFy=PiOVlx~A zNDJL=<=^q&6$Qc`D)pgfs*U3WonXpVUg>~6iC!l9m<+z)alFzxFP+lp5yZ^?YlrfVsl0 zKZ!{+=)~L`%E-j+dAc=zXWVYbV+XI}N&-+br^29G)wI>8e(uf9rtJOAhuQMZ<_@#Z zfiF?83#l!6#?YIG`}56-GFMwHrX}n10Rlv`WVdRF&x)S|&kA4R)BfC3ar?9U;#xy| zKOc|U3a;%B_50iMaWWFXM@7aL7fh}TEjsC3m%a?ZrIgIS1P2(^S%8_69&^Zx6tDFq zVw>FnxE)JLAVtZlIgS<|tS5NdB8!a$dDqaNj$mBHedxZ_E*g|F-|qaQ=H(5HQvgy* zpWU~%w#Ef$#0$G&oc4qS?sA=O{z7HuL4vUC-33e65707jVoqSdK(F$GFbM#R%$}Ux z%g)mkX)Phwf5qP|D!VVW`MFy%W(eBG9t8&PH~lD6dBgrox<(hbX=l2U>yh11h7O3rm%rJ4xdez5ae=YwJK~*4i#N@Zhp;0xC)9eqv*TDk_+Q{@upf2v zp7zS3m4Z+`EM7oao+OYN#@6A(tFAA9=W*=O zX&c=A8I|RjN)blNaeOV6u4$Ph#XxI(SyNJ&Hoy6`qa1p7S?XWDqMJXc*}0<2IVwMk zcl2w`h@vl|sPXyk42To%fYbI82#LG>fm*{cfC0CN&vZ&+eEmk#`4L??>LJ09w1e07 zGDpfU))Znz;i1q?_6Sg2;qPY+6m%gDIp~H$!dmkVeqWr6&OD5^54hyqsJsk9V?jV5 zR|N`DJn}5dijrujruX0CDoGwG$YD`n%VbLXi zBSEktNm@^cgM+h4qj*VnqRjj)c(L{Q9M3rPkP4=7ge95_*$M_C zQTMA(vTVS$Q-oPUu1=xv(=?CoQr@zErkxV%f5S0~!T)UnTXlkIVwmL|OsQ`P*Dkl8 zD$$_r{wyk^zA6z$mq;t>k`KVTzhE|^0&!?$1G`7ypD{e8 z6f#b}6M_~E@m#p^8}(5IsGoj~NoE3_1ao(BHAL>|(n?v33~>T}+jl^p7|5eVzvYj_j-l!5>J0eZga04$){hjaz0g#c!daRrwVB zl54uozaO;=dA6f^*Iqgl{E-Zo6BKUdrh z29Mm8p)LIjm>*+uZKROoK5P(L%}6FwPx%|4de#qeO`VU3-vNBm>c<&yA6$1;EJ%72 z-a!>89EX&>MVj6T8GkbQz4yV6hMl^;t2SXga4Up+CU zIA=k*fji|k-fBO^TtLcya!+94WJmpq-;i+qsu`(>B&Q!WeB5_eX-T%QnSdg;$#@T} zC)~nCI_WCOVekdiD^H?G2P{H{>>+$wgxHA$O*0nZqf;XN3cZ*HyJ2o_FP8VBNHBqM ziy07lx%A(KY-erEZZ@ckL@_fn>)Lbh=#_=9YTGSB$?VX@%dzzy(-rzmi&NmT{tro0 zi6HBOZ2ER1{BS=Wyn>7SU}1sciV^AcK4a*j8;-n6U{5r0s;H~cDrntSp2mNHYQ?Ts zb%mDp0ezCpM@QJ>@ZnCx%M}JF1v#IQ-Y%PUbGQYoBKuV)6^t%LrrUg#{?!MQDpF)E zkef_Z=<{gtk~579&|H18gJ7T|DsXv3Ufb1S^>KHxhoc^3YkijIqN>sy36H9-Ud9vN~tzO_WYP6AZSk2`C7kSj^+Z+@#N!lqad*ai z-qT>cl2aV&BB$s>dz|4G?#vcMt=hsOm`r^BTU42W*m1hjkV8C>3QDQdE-mnM0590n zLSo=mCpps$mbRJ`Rq)Mm-#2m!U!+<7<9M2wN=<*-t7PCpNs?y%dh0lEI~a95>Wsc# z_B%uE3xHAz^Ncj?7(dw)1Va!lJSSw7;oaf?H-SuzUWLV@`2nI{`z4YXRds!Sc!)D7 zVuhWAN9OlqRT_&!Gn>;($iHitMkm+<65d?E7=uO@OabYZbMhlB<8|eivrrJYVRHqu zJ5ygQoX-NNj|wYDnR$nM2v%l6@G#@5gLQj^HWnoE=jG8?!Ut_gVXpTjnmOFQgh&2D zs#!eQh1)fj3yL`PKnPbNSA9(n-op&NIgZ+{UkE(j?(vj)1;z!# z4PgAWWg`)k2oog>o{%S#SQ1$E52yqz!ZwEFm5skRPO@8ajA#DKLW$Q1G0OhUMfccp z-3`AJ`=-_sbnXUJD6Ar`KlO?#pJpBs4hSVvJUHm;&xt|>ge5ON+=sk}JjC25Ar8hS zWFWgEdclkZ8JIArCx6_HBfdq2;A~$3;a^oe z-L>3DMk@SO*DVe!coMHG$7}2PkFF2eTVO&;Q`9d8}JiB(MnWtwwlBo_kX5*CSwwsdr)3bJ0 zN}F&hy#JlT>RKx?rfl@F*sWUv^=wDmi-j)6LilC<4@3_Vt}oo+o7?$wc!QRB<|CT|`pBTvTb!*R-7w zk&8b~8X7kx-MjSlj#RO*|+CYgOCy ze0Pe8d*NF317Bzzxj)x^p}w3T5o#s-;CzMR?Rp?7{jGons8^r)7r#}G2{vTm2Rkb( zRC*1d4><2!gDDYaCVH>C{^FtGucES#-Tiw9s-BXnth5I8DrI$yg!+9I5=yx%*2*&@ zBcE2f*Bclmha=fgEd7|{uF5o-CzxVpKEb8Xs3IiTJb)}hICx`sy0SFZa2?Y;z&6gW z%$mbWq`e}PTWJMGbaQuo$jq=9ovUD}z4lEh#J}w&^INRCz1ez}XQw80SEmMjf8wVTPl0zk&uNYm1Cm|5S{a`{rcufBKimOjzkh zBvJeQ-8J)XhLico!G+zPUnvRbOE@Kc7>bF;Cq?x7`w~;|5ZqWCvzSw1qiL3?vRCF=f0%l5C5$5*{@t&dvXQNzm zYT$4JddcWm(Tn2YWR@sh?`G+d|A$Oqy7pX?96TwsYAndy{fU~Eg?)d^r-p$| zAbhsFv)(=QI?_CuTF7n;je*VJZ}J42Qph>>n|-&0$G3_*3BD(T$S_JwhZW{&MTCz}z!`Vq{)kkDnqSp!o@uVq{1ORKJ~!cOL9=pa${4OXdeD%z+P};@ zw{nx#F{J+JyhzThz9!VIpT`NFA>#a&Gw_qm0EyUUrH^{*QFuJYbd30T^iu=l9XiWp z52V6=Bx<^YM#L#PI7U-f4+$a?_uWIO|MpU7oZGGKIBY$3E!HQWALvRAPc-KsEQ?i|Sw=ijBHg7Z})NAx4AF8^sCy zFJs5J6IaZ`jQn9)R$fuS+9O-$D0o<(0ie4_+q|r5uB!pjW1Eo=D8KKdTt6HD&&ZPG z)@p8}%{RgaFT!b@{sTsfL!6i$X)-CifI{WqjPQ>YXKLG%!m8B7eO zBjV%>()mrFJ|a864<)F(yDh~9Mrp&te!v@A;Wp{pGT21gX|ka&h%E<--U4SKJTYv# z!^DKFgI~^9ClvHJ=?nNAwmj-jFuG<|grBFezIK8=4|g4&v` zx5gwQhVW=O$lF1Bm#Kv6l>VS@~#a|igeLZEo$qHHn5?oVNh>$gsl@V2Yvmzxjx zaHm8O&wZg zraD>x!h((8_~UDXY9m`$Q5m=CLZt^g0G5fkFD>+$)HVAQMOfc{=vBzPq7-wUsp`=! z)g%_|5mf2}&+66Dda&I3_y|p(Z_j<5-)Qh3GsKSaii-P)P~Oh#UB7GMrT zhA@NF7$tqmqIYb7Ya|MuA!^jp`D1_+6!V+5D$0_6<4Y1EA~uBGM!qMlpe)sRXK-A$ z*>-=imguB6QFw4_ogc;MO{`Q>t8Q;f+mI)}+UVGr#&aXgv39@6quyg_`DnJs3H71{WFdtA5 zL8yJ0U8n(>(9imQZC%Kh!$_9VNVi}d@p3V@{+^D|lH6i^y;0X4VbLrQwi1Wc>(I=Z!vd$6u>IO;G9N{Wn1KFZXWFNFac;G z1``6TT6B9dh>%q8d*l6&Y}qaf1rU#1HWrHr1kVoww8Lbh8E!1`^m?r$*=bQD1(1S> z^UTdZLc!CGpL1b$HmfUcC&zDz_=kFH8dD`8`NEN#N&TAMcAqtKRruCon;1aB@q+LG z=7eG;(R9dr^wDq0AlqZDd3vxo-d7Evq~r8ESYRfQZ(fU2SM)V~Z;};uAQk?}`**D3 z7x9X45VVfcW%*0a3h_4kz?7`3D|D9s*G;r35^%Gox``69)*+#+ceopyv#ql*JcgnL zVk*&afV+r(&utRKV_2gOP%uS+Ww#AT0>}TkL}Q`$HYo{Cm*XKV0Gk)4uW=J#%rr1I z6#4$G>-i@U7$(&JIJu9MI0d+9(U*|x2>=BZWpF_e?^t#38&6r3)z!&f;FtNnN%c@1 z1INTm47B$>*DY9}GZvE#PZb3pVYP(=)E7*YoZkd>ksy82&*Ijg@tO}%$}0l;tmul4 zUh4j{=>P|a;G;I_MwfD3dQq2*GRf+;JEjj}B;hN4%9N#|nOA-FSfW!#CAH1*j{dD& zeKaV_JoVePErne#c;>jdXvyk!2|$UM1_MTau+kL~15jzDKH zLg*xYqEYu%$66(KF?dRVfsy(Bbz6=zvW}9fPRfMU6SmA*H1vUII<_u3jPIdDJ$-$; zF(hn|CEanY!BD=WN}}!znUL0d3Piv+08fPU{^7}NgY5&2OhKiEG{MX@kS|7^PsdUB zgH4(vT_%anE6UGa{WBd%(}>gU$;q?bA2^pAncdzXG)KV6dciv}cfm@a0Rcc5%YR6> zB7hc9XCa%sX}mdSUC0%4nMDFFe75|HygCCIWc}YDfJ>G)Zgyjv%D2WHMH`w0L;__w zv*5JAz$$1rFF>YZ>>oUP<4z}?A1=GUcq|h_Vp$d~qfi~lE&(8%(C8ELD@qVV9b?Wv z*#+#_l@ab8_Gop=5o_1nW~pN0UzBKf{lC0Kk|*T=pOD>9KX1wqAeeqU{o>GpFwo@6 z=|n*!x^d(DV3CyCHFN484%6QTfnWmo>rh1kQ1e>#bXiuDSy!UVTtf_=h`JLXjB|LX z{_ekM=S@5T*T|KAR^9VxN{ZwuTuv!ZCPZ4;*`?Ag`AkPXGRzTvKtmnjz43iR z!!agrEi zlWOv3u=TkK$8KI=c?JZcZVgcEKtzz#@nD_7$&V`J21uINv*JLz5Fm9?vZVpUlnQ!+ z$(*D5X3&n1dr=Rl>sz1ivbQ-OjIsj(#zjy-{ZCmK=oV-hMEM>pP`{DF*n{rOR1d=Q zHJ4q^hpz13MaoG<)4*O^Lv9Xq2sP75HhgC>zQR>a6KTZ~5;1(KwzZAvNKyCeg7YLq z7Pvs!NrWK$F1s4rSNW2s8z6NbXj^~H_bckZ;xIILi|)+8N?|?SnN|~L42WN;0(fTW zzobW5D=9zohLWm^Fl(23p*H;J|T2TBuv^ zOqC1!A6d{mw1O5)RP#gENK~DHZeff<%yZ({@PN9zXVw)yaDkGC!51Dnm@ouG#m82q z{^M7sonc@M@efJH@*b8ZfX`;s-~nPK19koX6)D&ds7Svt0zDigfx2gy0vU$Ew}lfJ9;pJ&5uD3H7F;6Z8*QWx(30ggZEakB{_cl+GGLhJ)aSB( YUzYE4d4Gxltz?jjlBQyfyhZr`0hMWjJpcdz literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /zigzag1.png b/Splay Tree/Images /zigzag1.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd40624802f9bbafa93472c6d3b8ec37711d0bc GIT binary patch literal 13964 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 W8y_a@5`1NbBL7lJrbNov@BaW;q?*+L literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /zigzag2.png b/Splay Tree/Images /zigzag2.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8e4c63f9763560028d3088396d3e24b5787b4a GIT binary patch literal 13877 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 literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /zigzig1.png b/Splay Tree/Images /zigzig1.png new file mode 100644 index 0000000000000000000000000000000000000000..11ec330f2a33a56b5cb2aa983f05d7b9ed7b97c1 GIT binary patch literal 13855 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 LH5H2GUikfg>;GAg literal 0 HcmV?d00001 From 6c1c12651247ed73e3e727c0e7dc28e2a0b1e518 Mon Sep 17 00:00:00 2001 From: barbara Date: Sun, 21 May 2017 22:17:44 +0200 Subject: [PATCH 0627/1275] Images for examples documentation --- Splay Tree/Images /example1-1.png | Bin 0 -> 13964 bytes Splay Tree/Images /example1-2.png | Bin 0 -> 15451 bytes Splay Tree/Images /example1-3.png | Bin 0 -> 14778 bytes Splay Tree/Images /examplezig.svg | 2 ++ Splay Tree/Images /examplezig1.png | Bin 0 -> 6583 bytes Splay Tree/Images /examplezig2.png | Bin 0 -> 9317 bytes Splay Tree/Images /examplezigzig.svg | 2 ++ Splay Tree/Images /examplezigzig1.png | Bin 0 -> 13855 bytes Splay Tree/Images /examplezigzig2.png | Bin 0 -> 15247 bytes Splay Tree/Images /examplezigzig3.png | Bin 0 -> 18128 bytes 10 files changed, 4 insertions(+) create mode 100644 Splay Tree/Images /example1-1.png create mode 100644 Splay Tree/Images /example1-2.png create mode 100644 Splay Tree/Images /example1-3.png create mode 100644 Splay Tree/Images /examplezig.svg create mode 100644 Splay Tree/Images /examplezig1.png create mode 100644 Splay Tree/Images /examplezig2.png create mode 100644 Splay Tree/Images /examplezigzig.svg create mode 100644 Splay Tree/Images /examplezigzig1.png create mode 100644 Splay Tree/Images /examplezigzig2.png create mode 100644 Splay Tree/Images /examplezigzig3.png diff --git a/Splay Tree/Images /example1-1.png b/Splay Tree/Images /example1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd40624802f9bbafa93472c6d3b8ec37711d0bc GIT binary patch literal 13964 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 W8y_a@5`1NbBL7lJrbNov@BaW;q?*+L literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /example1-2.png b/Splay Tree/Images /example1-2.png new file mode 100644 index 0000000000000000000000000000000000000000..46dd35bcd131dc43f7edb45a9efe7c6c585950f0 GIT binary patch literal 15451 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 TFbIB=iK8U1CRZY38t{JrK7T3H literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /examplezig.svg b/Splay Tree/Images /examplezig.svg new file mode 100644 index 000000000..800ef1886 --- /dev/null +++ b/Splay Tree/Images /examplezig.svg @@ -0,0 +1,2 @@ + +
2
2
6
6
10
10
2
2
6
6
10
10
\ No newline at end of file diff --git a/Splay Tree/Images /examplezig1.png b/Splay Tree/Images /examplezig1.png new file mode 100644 index 0000000000000000000000000000000000000000..dda9d6de91d4dcd011fcc9356ee305a8c0eb68e1 GIT binary patch literal 6583 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 U21jw=A2I}Y(05T)YIYI-53Dwf-2eap literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /examplezig2.png b/Splay Tree/Images /examplezig2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba8a48867103c53ac775bd74046d239deaf747eb GIT binary patch literal 9317 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 literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /examplezigzig.svg b/Splay Tree/Images /examplezigzig.svg new file mode 100644 index 000000000..7bd4dcf6f --- /dev/null +++ b/Splay Tree/Images /examplezigzig.svg @@ -0,0 +1,2 @@ + +
4
4
3
3
9
9
2
2
7
7
20
20
2 - ZIG
2 - ZIG
1 - ZIG
1 - ZIG
9
9
7
7
20
20
4
4
2
2
3
3
9
9
7
7
20
20
4
4
2
2
3
3
\ No newline at end of file diff --git a/Splay Tree/Images /examplezigzig1.png b/Splay Tree/Images /examplezigzig1.png new file mode 100644 index 0000000000000000000000000000000000000000..11ec330f2a33a56b5cb2aa983f05d7b9ed7b97c1 GIT binary patch literal 13855 zcmY*=WmHvNyS9`xlG4)M4N@ZAUDAzoC`fmAcb9ZG2&nW1r9n~}B&3`DO`hj{&pF=@ zhhuEko^$QF=De@CuN9%9B#n+jg!1g!Gjv%Q3AJa>VA#PwLZs*56HFZs^k>h=pUFyy zX?!v~%t4*kR=*t7mc;5nW27!cE%9JXRGCOZBcjAYXDpYJm2rn^6n^02=CMg;O@8}c zAxM^}ggx4vF(cCD&sW@}Qu>FyALDF2SBE~UtL@NBfu81EtK2!KaS1O=}c{I6F1j;CC+GIhFIPn(F_8gudSPt*=CY=3g^`qne({f_8XNt$6| ze-!@cWQqJ%RpWS~=f!?T&rGFun!2*ECZkrB^$^NrU>7;Z5SrRz$Hz+V+r6>|-v>|K zM$4Eg{r1Uw`^n-6ZrfP})}DJ8ft_sEb%e+-_T!ZK@GpZ3pjSOm7G>d!WJm_rV7zM7 zOO|4fvu&3NN&I2wLDHR0MCik@-`2&PQJQ4b%i*sfsOWpm@28|3I`(MGRf|H8FPmW` z$(iAkd%wQr^>@p7|8NrLmuxYbI?U3#M9H`EsfgQdp4~q+%3-~_btQ43(P}iBkgM2v zW5DI^ur(_qBa_mY7*@`>B_=%lev8d7LA6L~m~YjaYPsWM(s+)b)gcR=axOCttwMZ* z#i-ozO7|9D&yC{jiX>ST(x&tqWC&#*If1D4Px6H}=c4nRb{wg7R8rCL6`GYJ z@f6|;e~lEehIqjw3$Ft5a$h*dyb^vFib2XK>~-0+S&iWrQ*Smn(i;F*qFrkkIy8+N zU5i(E_Lln9d>km?Qu`p zkMpED0*5a1jmJ_ndT5P7CyH}}QqJrC!;1?a9Djdooz&;`%6THRdA1|T3@%6QJC=Ja z_oA0M?kfqgq=K0SBMDT}w~i`$D)9Q``S9DYRr#zmG=Zd2up45V&IlKVhKm$&(ddY7 zjI!M->hOhc-ykzH7W;XQ^UUc}ZH=a-m8+LY-EaOSbN^G_Is!&Cf4sl>Evk^0j}#t` ztrP6<%tNz6W0<;(b|!qwexX59mbo0xPPZqymy!rGHAb4mS%T8a@P@*iw#9K(#6U@E zQ?LD=fTj*fD$oBRjLerF^(Axo+Iu&lLhx+W8Z8yk4;DE{B79J3>f*yvH6o^MPLGbe6X0Q z(1d9vfo|_lms5QUd!eoR{rW`-kFW|X>L>b4UV9r{T03kiw6>_+tc?S@5j^=+=98t+ zmCs1URN!dki{`WT9sKFOT0yOwG3WVsxnPy0n{IPJXRF^hLrhcmEP?Ja#L}CW=K$_N ziC&Qd&Mc$4zD{LrtX(Rl7naCHF3-TJ58-r1+X!LW)Fn&ccQB55eNmn^}idR0XF+|nk}p9~zx`}{OFwv_sb>&QX}vp2Qb&6b}9 zBTNzS`etxpM3LwNZp4nuyadkXTkQ3cJZiVmU^vgL#xhH+sB`*CwDAJLDnF~?0Ec(s zi%%yjnSt>z=jnGG z@{I_%2Uw>FwGz3EywfGFM2ozwePqF>H-JdLpqOJAp zO(>p~O`;_nW9O0VMFl6;P({8Iv0rmqD@n&n}k(TWaxMvEmf3yZP)P0;o4>t3+F zwv6Z(N6UiQh}3N}VBck+NSO^p%Q~?&+nP}3bFt^`x_E!~xx1XK&}7PE*;+X~+a61L zKUKO{U${hk+v`~czl|f;bd;djqI;J6ZOe6MJOz==TO|^o?Wl3EZ#mXdWhv4p zF;Hz#ZQfsLl&kfB@3qr3e7Ib63^DcqOP6Dg;qAWrlOjFLhA9FRCdiJ{F9Nv5Myoh|ufyhskAJkp7^p1p z7&X{SRz}j;jvMFtmU1Hlgl~6?wwW2Y`af(8!X(-*cQh|ZYO2GZg2S^tMQ67fQtb6- zu9lD5SPzZa2R|`KEwzn75PWBAgsGPML@+hgCi0Eg(>^|r;@=FQaQ9iXZ_TiI!;5e- zb=GU>b;yHLW`^uBtty=nlQ2;vZELTX_n2|Mn9}PVTW7iMg~;wlDOiSZZ|7D@hEcsA;DK02F3j#miYkvX zyO8c)mE>6lju%yBWYv+_dBsqs2(ftRj&{#&%3atW(g?88nEeYh6uqy=Z)d*GEu?!v zl0JojFBDa1Ml1ypNN7^##Iz3zzjvn(KwvL?hd(JCE;bu74KBP-asd~!?Mc^$PwVX#8elEO^lW$sIEoQaU&1eU zwOA2?vj>BYH29IVZ4FkPOs(1)UL{MX-ZW(Tvnmzt=kyq{L=sug`;$S%iIieO%J|Q* zb#T5AjzQ{buh_dH_-%p;2);{I`2JFkp!>MDbF3kU$EmpqBKF7mx){QhBxMnXsWRoX zDAo@8ronnUQhulW^W#;cSm8?@?H?2-tpGT`G6dgC#Zqw1SdL{P7c2bUT<&zw+R0x_ z;2dvnu-pEn&jm`T^gW)mSkG4Jo-VFF&eBg64q-JF z?7ScpJ^v}5TM{{2t>-R-o1{xc6Em@U!w$p6+itFy$1|L%}Gi9)zaL)Fgv8Qw~6rH#ju&LASEXQ|67cU8h z2#M5SQ3>9sN<+Rn*)(?{)oGYs_Hzo_cs*RqZ8eOtChg>Uje8%65pmH}Fx}uqne$41 zWU_RHdyd9lo33P>M61Y&V6HYQZE5RK*AI-56Too}rf6D71pb5Z;JWo3TtD zbZ5Y3`9`G4E~^G#c`4-j-o9@{B}&GVG~UfHaPG%DJsoAs8dMd>U6tXh*<0!E)aB)L zRi^7ZZ(+#4@5eVn^68zA*i>MU*WE`1dz`26S1cM4w+zzwc&@PE&P3bE0C5Q9jzTE z74=^+83-j4cAS>Nn6{XLg?Zkm5eow6*x%{8H*WvbvSAXXwhxl|dFKkT=Z5TVtUg}0 zieLSV0|Ft_ua<*7tBV=tIM9@-Q|i0O(8e$x74Nrk{kT`c#p-2BT5eex==F4|ZO)BP z8o?4VaZ|J5#C3){oUCu?YHw=r{`Jn}f)FDbRvVdsi#a@!mlwQX;S16Gy5T&vC^~Sy zv0{i9uk2!!b6)cl(pesJ*d1~SrgNA{T^fG7v?CRp{_Y-A1vbhF!ap@I8EI^* z7L$%IZ_%*2VeEJPjSTV}t_*&9Jq$2~U^6KfrbI#brX+qGv+e!?1ZToTtqo&A_ap8A z7tW=m&+o9pIR2i+${G9qbag(4KCD7B%qZ-Z8?%Flu4k0r8t3WKSe=uzrp9FRQRnUT zA(DLvP`PBapQ%WB!VpXS>GcpW4g7}WOJ3w~^WCI35m@um-GPVq{Ej|JjA9r#``G3F z4=whK3IoE@2J4u5l;{EeBGRA!{oWAxo?Ex)1%zVz-i5VT$En7C{d+{cf*Xx&%9+P! zp-ttKwV&K!zqD)g8NlLW5L)<+aRr%Q4o#4>dKy0FR=M9v0$gJYBs`L~i;Y_cn#m_X z8=H#~zg#Ybaobv+WL(LmrQZE`CGh3!^~naRqFVQ#nob4F8ysaJEY6X~tT~HfKeWb) zKy01x&&pZ6W0?5VDZ~7N0-opAgs(q*o?(3XSuS7XSEV+av=#9}o&ONOpLOFN=j8ST z!~Jq{?^_~1>c9v%tQ|_KaeILkic8xjBYG?qZYf2h4mfCtFX{-y!*VAa1wIx zI|!;%e=ALn!+w4{a;)$%kdg}d;PgWk78OH&N{v9C_HlhH0xF6nN6Iv)?n*|L~ znJq}H?-fc$ng9M8B30N14y7eBvBn-3oBY0i7_FIWM>GT};Uhjc_CnO~)vCti$4qEu z;{F+g(jRqF3v4AbpZlq9nd3K__D8DK=nEu$c}6JaS?n7B@e5!YCiqyS?%c&Pu4`rcmT>L%Z0M1+wjIf&+4rcs~;E!P9uvfLnB8Zb;zmZI^@Hv@TW83H^#mo%mKO z{^ce@gqUSKQAE>jgLb8sqRmW&Mc_%cQS=CBNs7e9s}N!7w1kCMFz!FJVO_(t3$zCr zoVoH@y=+Q9e>YS{f9|brLny0ei#dAcZ={?x`gAy+vGzrWS&$$$Z8&|P^=G}a2`thi zxwpK@eEn{#vd`af*228kKXg7DT)8%I_}Ar`!R4~V?Qgf$7=$H%Rw}sX+~2p8d%Xik zRf*gXHz>(A8ao44##tFVb4W@WhCdL#pR&e%V3ji#8HijHke5zmue!zMagMR4rSYp{b@N z=(-|mztDnpMVRZ0vR{=v`&m-8V)}=bb#%zKrhNdHPOA|I(Au;OQ?FM^qenWf?J*u7 zvJrCl9CI0)-)+!@^~lU3D{u|7T*ihQDJpYHpnZaUg)b1Wr~3u|lVZ5R&&Fbkz^vX< zDhhT@b(#E~;AtAoGbH5sU|wRzfbv|;x81ax4&}M;hMv)VzEMF^z>~z;q|n`uB!l^0 zd}EXvO8znqJ-Jt7O8BMOtEjYdO8;~TXjH$k#R&}@6?=6>QopLgZc%fE`ddWaUWXf6 z_G(*#HEV12Fp7BDXB@+iWk>OZFh=mDDJ5KRRod6$J{uRDtT&S`LJ)P?l$m-F+mg>35ZZ}?Yw2e#&>h@k0XJdRUU(L-FnEezoU^pLoI^ot=NWSjEm(| z6f?wIWRd0tN#Cb3#t`vvYPJY|+}}Ls?PfKGpN39DBVEcVk)!?H06r>0D8|dN4SN{W zn8PEw?~XcYovL24!0!9)`(+5#$iQ|2RUebh8qlxL!^=$nx6b?KR6m5=_CX7Z(`Zuq zsNIJ8QqDNrUcc2L2Le#u7Q=2d$g%50O5hB_Wib>_(bA>1zAFB3yhEV{b(J+X7drbR zz4kb*uB>=Jm{=Z^=X+a@yvv0;bsLxQ^Ax%|13fkU{J4|YJ9I_)zRv1L?qfFx1xqxk z;4F2kO`^#)T*ae1|G>TDrR-h!F`PsZ5cZSwtOw&L#p5w)$$%%|LK3moQTw<>K^ zpF_4Qwd?ta*HQbR%#nY_J9h9O1qM|gYM;Rh{;6t=o|O0&ik?H2QKbFlVpcEEv_F%_ z)&)0Ut+N^orhd`m4L^|42mmw_;>BZy6rUk#JIgFgwTD(iS*r$heNlM3Dh7dIyUf>_ zH2B=P8HjZJr7At4%l%Y{M!??NZ{Yb}3{2R5g?iD$4Qsp7)&4A;*7~(OwHsvwKI^-t zp&La{i-4yq+|iz{VA8BeUhsj?bhBNtCS75if1OAF)#+ZlTI%xXdm(zon*Vr(6VMF= zHe$zzy~5$jBOe(V#%%8Qi4$n*XQ9vDx$gU|)Tu*p7bcLK6MXXoc=JDN6LnR_F4i?UyrG$E39UY?glYFrSGNv>T0@#iV0fL`F4|rIL zB}`ym{t9RWZs+ZO<%=fARl|49He0XyNP5gxx;!}Te{l#deV*=n~GuG->Ji?JS{cw8w28 zXO?<~3~tA&C31K;aE)V7nYi}zN%sJ>AqGsrypE4^ik+2W})d zgvw8j^9!NB{>}u{zVUUxe>!GxT2whv`erB#Y~kJj2c!B^9{(43v-d^NWv6fGlZBF~ zja~ge*NFsNit8AA+3eY$Mx~KU=6}PQ#1fR~5)DK_ru*xSXf8-krhscH8tH2dty)8S z#^6QcyQ^b-m-Nr;)!XPW1CvtFpx)OXcFDE%okRBKm)cz|z6K+o?pM~zovinFf8<^3 ze0nw!NM#YQp}cL|P7Wx4)N(Q!!!)exhk={%+@H5wt!kxT>s~6Ffa0ktYa4n=t~!g-~EYNgSjjY zoL-w#0kXyXdepw(%j36~yA$HP4omcLK&R%Og${+!ufOR)-OTH?TMp?0eDBHZ53S?1 z|7AWMY4qtgf&ldX?7{tY{!1|77#vmUG=LJ1(_y+ZG#+``$ivf7>!A0qVxg*aJTDG_ zyYNzj^BSu^{+ia_kcoVVD&pEWmT~<(UFE$=S-XC_%cCH%6Y9Pn z@F>#c_jI|9{$^xdFc-U{%|JC`zII-P6Bu}F7X3vi_zdice-1$Tt8{lnHDTK0`H~|I zVfJH!3g|;|L~UgHQH~5A$FiB$Jn6pQQN0FKFg$}{zaVq-h*XAW`2Tz^53m(wV&6!$D1X=_}MMjI9(HWaJ&cA9@t`fucfP_50)aDI2&B6vJJ~0 zcW@c7p6V4R2m9mkT3^ssmgAR+^%ji#@I9}E1`Bjcn?CYz3f_!+C3sY6 zal=jr>Hljwh!>zB0Sw!DQvt<$V|>pP`%xvQ6IgZQ6OekQgf>e=Bm??pV=NWuXmr`F zkzq6j3&qWxwZjE)6{412{+6bGfk7s+G^AIF5aoYsWGOTQjU;D(RG%tU978)O&2kut zwv06hpvCR+2QKb#eXjJJ!9~y4dM&6RNtO^7`y zjVO-=%ofJ%&Vv(X_S6xO~-r{Y6Mg=Wan2^s~+w2htmnB5T+h}7_?4qYF zTBGTBFTM8@%c(0PK!>s=&!$@9$Eo?c`38%qZLg3Q&41`NBcV^A@OEYHeOV4|S)Ol) zW;4CPi+4kOZIpGm5vn@85nLRWhJtPfDyJw5d-vQgB50POh8|mZ4622}`5!Kp-B*$K zasID&$(syH)EeTz_oY9Xy=tSfP2c#lQi6L$V7$hC3r|W$rS5#Pw#*YB;v&zjeGiw~ zxqcX9el3`H0CnEtXsP}3g$BIiZbYwIfX_5ssX_+!A6!&5n%8az*3&fH#$*A52ZDxG+vhn2^?kvyEmKO4*OBP)=}o){@bIf75_(uRsk8> z0N{d9)VGVad?2n9quV+0;ke^ZO%lG5x2jw!Gs6$zt85DP=pIl-V^2OKT$IGa)nU)r8ZU2RI_xW00mMyh~v@gxce%z z=lihBGAtFlzl7v7Y1r#8K6meEB8Ni1g=0|_1N9WzrlCpcQIjVD{R2$?1!gloPK!$I zTHYl1@WWWaqxj024#vx%;ca+gu6Z`!6V$;6qFIoPdf~~u9GdNADSOp6Ex%LTP3#xy}|8Wat?kqK5{vw;x-PXD*(eH2dSVQ4^1hH z+Vcm%zAe|l%$)&8O?)nC;V)>IVl@37$6yYgt>U#*Ugktc~S-@ZnI zm&zPE_Pr9MTIh#bm1jEy7hb!eW)7Da;Ufo>h{hXG5x4<>ZuqdLrjFHR*zLK^mN9T( zs#T?{`Hshw z3`Qfbm3t{z6U&ROH;>Pr;r)8b0x(8ere#vDAp{iO$Mp)x6UiLRo5eM+K(8r8fswbl zm1e}Nrs5l2C<57MKmU7usW#v)i-Ii`OSHp-+JJBPsV_Uv^5b`SDhmeKAY9NgFy$gN zp?SW7Nw_LHkeEn>>kSRjokeEG8EUi~<8%@6gWj#asQ*yvb>71S>x*UV@hxmrZ5#Ac z(g3B`JnDh^{=vx=D7pu}>nK3NJ!IIxYoMT#q+fY_hvXuy@8qF#EEx9(pWru)_DsZg zl;%^P;0DxlZ`oOSMjuA8ePREx!H>7KW{>j@PgLL26U)`L!K2QcoayWVHKmT zdaVT@Do6==1g9Ce>FU(3bsBJ9XDly)7E;YG)4hTE*GRn4q@wkP>1J z0o?42z69dTRW*32rKmsQwFzi>4)OF{BNCVdq@93Gj-4hRYVt^uqruZEW||M7u8)vu zC=9Wb4Ub!vKlm*M zX24kx+cJm1nR(p_l6y*gEIy8}le8l7iXd1TMY2QaCwL@|>|4XN@yE?{k?jN{Qf=EcHf_@Vp)>5_Qv^ zz~DBp7hfNi8I~cDg!(7Z6yeOPs95kmFW_)BzOf8)UdtkX-L56uJdZ^HC-z9dRe!(O zC`(FxsQnkI&4BZ@2i&>{CSmzA$WTL0+z`e-^zo`k;?GilVy_deVy)Au>>kez*55|+ z50Tq#&Kr=)L}r)p1JI5A;AxvbhXt|HJ_&jug4AS?MHIyn08?11J-;b;*(0waFGVLz zgO#;FP#6`j(_-3^ZS$Kz*<`p>>DKg&r=FJGf94z|Yk4%+9o1}jx7eN9gOk`y8-r5( zC%K&2x2Wa2;(;hLWn=!JQf-MF+3$aJRhbEM$OFH>;No?0r(~<7J02LAUbevB0ZOmHN+6LdArBwG!JcWDAaQlR zQf3Dhx{G6BJDz|;UnaW5B0V%1osrdIBpLaPL-)NP2mEtSa48;H!+t>vnB6~6iBKZc ziCp5PR{gti$%cq{3DqAGSOiK%dw5DBIp&6D8;KLhljdVMyMyU59y2S92f9rW)R^WO z-0~y=9B;r_+IWX~N4dTTDs+xkL7Tb$sbPL#w1d4na?m>H)e&KrZ_-bpeS5Hm)5dMJzbt`=b4WO@?R z2nt8^h-Kh$DLHV-%eYbh0Qm{&xxwFsfE7F!pJG~HOY~Uf&;}1s3Z+>yJenO@VxUx0 zHMHx6fMx57XJyj1nX{r276Db^9$x)l`Lo0h^AEgQ(?--kl`G%_e7W~fIo&8Gx}{5a z7*bu~2YTOohCCcq%1d3DNt~dEqal-qqrH{qtC&}Z31?i8tuBe8 z_{%~D?S@3A$`AVJK}5Z)yeu7zkz_0&YmAl+Hulb!4s$dI1xyuc5vlCxYl0KDXdzBF zc81qk@T0o0W`AXB*T@fn#7JUKtv?E4CHzMCCC$ip0h4erfgGTFDzeL*oi$CLOJ;8( zyT9`>xT1(qtm#Jgotlk3&~Fh~{19E(BGb{k;~q9Zrc(eDNas92WA0HR@m%il>q(|p zeJhv7%Ca?*!bLM#j$#PnTk5a60db$q7YnlPVjEC)4&*A?h!fZ*=oiR$W<_x|HP`s2 z6zRBw7J!BNX|E*B9H6V^-cUmHe}i0nlV9L@DVSuUU_!r>bIG7f%45ve81<~+S{qA; z^(4zX&Q@h$MUA?V_WIwiYI8+4vRw-;AG~yJ>LahGzIH1_M(ZCf%k`84b=Yj^Gawd| zT^_FLxL0i(v1gmidwi-WIqMy}%q;qCKjRGn7lCMf1XhxFD_Poe+?`!%IS$cq4`AbE zyzIw8(pdpKy);=9V6ylX=l-$tuG>H~;ghna3P_Y7T*Zx#blqkBI1h(=))h}3*-H;X zQYf(C=l_$}l0G&O6;80T;>;UOWw8z3>l(>7uZEKp(s7RU)xbRq0p-GsB1b zi>^l=BSlz_cNIsmr6$$$T9n!t|`l5vr65x$UI=cPU1gjS&!Qmd~QH2zpjO0du9F3STxb>>W z_?Y~^X|1~crzL*NaTV%ehjfr>Tf=d?3i@{!v+7aDZz+;0xXyNd{J7O)9G`d*V0uJ) zrUN_;{c<&$r0h%$s=be38Fgtm`UO0X)gTWh4#EK(%_8gJRM-M%BcdN5-!Bgr(^9sI z*AI@xPhDC~j}V%>u5=WQ;dxZ!^nt?*%^fHXNoCQK13g(P^aG~x3BfSaS7_U_*aVBi zaU!>$yFe#3;>q7-g}nn?BJq{5r$nM@0l##R>+LnucAtp@O+dns_LFFwqX+h`k}MPS zW3f&?Pw2c+`fyF8D>r{xT&?LV=4~x(0=!_*P{kjm)~qc~fr|W}+}7~7U#i*tc4#3n zuCM<_deo)sNgHQF-vOsLp=9`@`15ea5tHm3jcmWm8g^%;E0cbqPmpR#cBPdwRLM0F z3@hSqv^wKT*gvgazATOmSX!`>VOb{MfQeEB#Y=W!({vj57Mg>c^whLFrG2Uj+A{i_+`2^ zYGC=rwk{p}i1>fQUKW=%|7-YuVq7TY7j%Cm%3mfb$?<~htO{oyl(v|GIluz4uXv?v zyFfA^+KnK+ou_|6z|_}C$uH9MmB`bOjAlhAc#_LfAdKTd^N~)qDxb1VPdz(_Y8&z2 z`!mbcgx%2B0X0u?yE~H$eh8AsW1CvZl^EH`Wj9rO8t8ia5b434Zk5st0t>W2&dhBU zMb%q+xUNUgjrhaBk*t>R3x@9h3^Dw7TJ&vQnmV9zP-7E|D`t+u#+FGBB(T}^o2(Ny zi1DljRY*I2qK@w=t3rzUgeu{+Dl`}x@6v-|Nsq!t7fE+R>g8M9j|~UW>BnOWUVkXS z&z{OFOqUMwm_?u7kWXTm$aTi?adwtnMn3+s)!KCFFfiN!Acs8vy20J80-igcRf`l5 zih!y%mw4kmj-*Wm3!T z7K{M1Ki%ciuxQm@o8I=*U4C0B+UEDyCu#+65#EDXlRgMMtVmM_3r;}FVyXSOGOGE- zG4lK#+i{t+ARm6Go5dzPg-_hiESyIDQZXX#Sf;Q#UjKPNnRhHA96GuVss1@)|z^8*&6>YHWOQrD93m zf8oJ361m-_`uzY}$CSV=cxj_fS?C0UR_!A!kljzO*qoxk53f?l;M~Tae`$qq42Ou3 zzVMQ0kM#8icJW>ZGQIupJa!x_J0Rbd;MnuPyTP;&?)sSac+`0e&(UX<>oHJ4*bdh4 z&Kz#r$oHls+xv9bGPGZga%=G(GmS}mJiAPCJF{?t%=>RZeCxn(*A?Nc?U!d&SOmQs z{Vb}561*p`4;Fym!(NOM50H%$HVWJVcd=#EAxK*faTP|o(>CJmoL^b;rNkWuAif%! z&XM_N&lo|TLoz%P#senhhZAYW;z*&8L~OD=U}y^g+txBA;TGmM6j9f!Z`8QGAMCAx z$p9k+y_mTD2)bPM+AvySb%!hngRfHUsMacGeb@DRlm&py?eJv#Z3I!atKbDk^Iz&& z7SlxC(8oK)=1Re%Hh?QXa)nDVm>zu}Z+60N7-N6A1sTmEK|+nn6|6bMy$|XKqqEOI zs&4GV;&azCCJVvwmhmqHR($-6yl@*ne^-4UZihi*fiioHI{XJDXRHwz4DY~Nei4V4 z5<(k3wHqv6HqGUMZKP0&&x=;;kx&+WI4>yYmLt@VE1cH5Io+~fV{7bEe2W%cg4Sso zh0n$dW3dQ9AKyE62y$%fc!IZ+#iz6p^MpFD`;k5loSCH*QrH;oW|iGv=hk$qm|na2 z@?mHn`|kISr@WS{ai$TR1{qR#={f?hx4DCxjoo*F5Q+=d1%$h~o<|EeN_#GF^m;nc z(`x~vp}%UV^c^6y8Ujfa<45;NS-N3hcWtKi+?RBLPi6eYCP^l#8w>HB0DY4`2UH=(;+s?w$koxvSwI0Dft9=-= zmC$O@X$&gj;H1>U$C}<4Y}JZQCVDzVRZW2L&#yo4N_Y2jc9l|gj(z@59i1=%>pg{Y zw}QA3BNw<%0@m`W!abFv(oET>PnA;szfYy`HJc|N-gv2^Xl57n{R1ig6j=?vr3Z4a z2^;PI@6#ris5`MsH5Tdrna>#1?WtcLM~DmZ-EaE^i2hq9wUDD(Z7xiA;10`7oBliF zw?Uylps`ow_~k|_YVkFJZE76gz&tziOPT8jBpm+-SO_R>c5xGKYJlrba`6=P6WG|E z#kJZAzxnqbuhXq^dUq+M+2Wn0erZ)3!}GHZVQk*toC%8;^IL_oBK>n8VNvaP@RyVF zY=qqo82J@=(a(k}L3BC|SW`<}5&#}|1OEl(wkH(*P!Dprmd`_j8{ZkitJoV``mbdh zsb`}~v&;NDT39;|{J?3rE&-*jjR#i#8bTvm>VmJLGb>3Sx${3*_iB37iu_9J}%{a?1%NKc$%M9ARN?+~e9yo%Y*7F>K-r^+uk#sBx;esH;c!HSEu2`f8 zd%B*Y@rQ(t0FAWV*B@=zgSQwx2^>NBrM!H z6zN|gc38qAhLvZbo50wByu*gQgFg_six|-6O^pd@M<12#U$~Rr+EVIYLbc(bs?#ve z!+8XKy@-#I2<6zMf^OXV*s9MDaypR3Ec+K2-u3C1rFRZ;XmQnPT+N3{wVVDYw3Ry7 zY^zw25C3@~q#)b=gUIGe zjYf9&@9iDdejzT;dOG%wAz8oYUK;~3ldX}?Brp_X9@7G{{H!Ac||k+!%y^eW?b zX#HKr5FAP4a@GbfseEtH9HU(%Y)=LZEcEE(w7tah@Z|7;7~(AS=b}WH1wC~?5b4K7 zV9uR7O>^;^B(QZVqLQ0Uk@>8~Nfv-uZL*$to5|E{)0{e+3 zGzMR&-9myy^_-*DNgmkgw-Gs%xdTc%@dO3$Jy{I9bW&LjY#0OQDz$&yR~vSBEc93D z)E6c*X)6H@Y(IoFx%l*A(^9+oljnRu2}G+Qh~83x$T_!P7T^p(cW`l4vzIs)LM6I{ zRh=(Gv+_D!2+y)9>h3WDX9-{?0jn4RzizYfhe#3-;Dil{Kxx#-*>L-?CWyavuE$M_g>Ha{O)_jXd#pc@o4ZcFfa&Jl;w3WFfcj6|4A@x z@CoOjCl>|=6NZYsjGmAAPcvLseTAvtvRaQ48^S{%qqt0QLfd+_Y1T{8qWJ@Q7^GTI z#aq2r78ICP(kvgNxt2mgo`f}r)T-x^Ct1@|*t)UZl~!bpht?SNri%7ndY+5il1=vB z4LoW8*0j69&GYMeW@kFEeK%|8!t>@3a+;>IDOORT840}r}vMv1z~ zB61{o*FNXGY-@Wk`1$k8$w{M9quPAEas!Q}rKJMr*%qCSpg_m5f*3)UIn$}er{&*E zCh5gty@{yp&OZD1vI}oNOQvYN79RZZ*K51!#;0TTj=GMc`4Q*SxiU9O4Xd-q%kx2mzqha!$&%hC*I?OPd` zq>%?0dcux`p>LF43}p&Ew*7s66zkC9z00SfqB8c*-M-ZHU0s9Xkk4l8ZhK1Q!zR^7 zkBV$Ef2`I<$@gH8^J{FZf+kcM;WyPcVE+F4>f&H2j(;cupUU=h zZ}Fb(Kw`;r_rYZLI)_n~Qj>kn%(Kka-u`1a zF8R298Xs0pn){DWN#WtpSCWA(cm;3QLoo(bh{bPB<0p>IymPnv5Kn#2@6h3CKRoy< z;MG05*m!zzgCq*ILsBNV!aTO(F-EHkt73fO>8Z~VSJbTVEWX#pUd+ps6xPzx(wW(~ zx-Mmews1&Hb@0(wL;VL_yu2D%S-%ZPDj0>IWH9jw`RrMCc+O{BC8Od63K?!tO9i!w zRo6fHe$Vks(Q}3@^Pj>%iu0l!*I@jaa|{bJh9KUNlBA_$ikeR`Y#)$uHs@|3d1j871zG5O$t%n3?oo zAQ@D#-#RUDVJezxcwGK0t>|X&Fd|D#AuKjGR0Tl_o$fVU)U66QJ5a33h@HmgDd91! z+9T(eO;AV1l8kV)V|VTLL=mg``L)FK@VKc<_#GyGcusp?nE^8{1;v6<7gOEo77Fgr zPy)SpJS^y818LX_y_iR0606cdMyUP>oum>H2{TPBUktI^nyAFeR11>iTNsZNeS}e2 z^4|aCAh$@Dgm;`3Zj2H0!Zc3$;`pasX9#Bd1IvwcUeZg8cgVu+nRj0*IldzVz@T{G zK7=h)&48n)9x9LE7nsusIrX;sFu);$gRGVsPi}5PjD(nBJ5jAj^Jxt4eG z#%~|p^FMxqHxY5e8rM?=!FR*S$=$5QLtFKR7;fK2n9vTHY?tN7blw(^!RVkwRQ%mH zP0vDxFbp)nHT*hOkaT`;_c7h+NL~YZ60eLz606xfl&!#}nI0X#oS-+YK<#aOoJ{dg zXMw+qDoo;K4%BV+`nj_G{jFlc=f7mWmT1d){haEn*X0XUMIv#Pbzi>{ewsPvU{Yfl zS}N!9)bx$wbDb&8&Up3!^uuD~;DJBTjQ_kyc_r&uPb7O7`H z_^!w+X+j2J<2+X=g|V@-;|4wX6!~~orN$=e)D*n>N2&pJ^61+VuR~g*l@~Tuc%Ru= zrr;C7d(Q1Cv-SYEPPO2%1RJM~2JKvD?pHyNbuETA4-8f!TR!tPBS*sjtu$?{jd#Y|%pr$c1LOBx<{tP{ zo*fFo5>e|U>?|QXJU4KNQnMxe$(Ucmo=n!r7*rT_mERF|TvJ{Jv01l)QNQ6J&jv`Wo0mBik@|SwzbJ)cg`#j znJ=xz#m=tankgYHEDRY455h9=@Z20vilgF>49d_GU%z!%3w z`fbgw?n z6ci33AK>mk2I}lSuJjN~r7{Mc%2ej>wEaR*224btFfyx79qmW%iOC}mQW{t$4b2P@ zM$aD{jq7q7Sr{?+EMQg+#PD!>)1|Gf5G8zQ$bb9^7s>Xu-0POGkuep@bIk5*xa2-6MO+FeIYnHQ=3DGAXD{iO zP!ot(Z<&615&iK4=A8r;WyH>cgDFqj!?l?Lu%TBRzIkXPq)K(f$N*=3a_T zvJ#wYKMJ!`+_%AZEbRk$^t$U^thueG`YY;bE-T!L)s{{2Bbx(LbmV3vAF*+s+{IT{ z`_yhdKMppG_mflnGq8%-e^kD8aRQqc)PsW(pCDh!?q8XRh=5K1&`?S|+*pRI^RxPE zVGTah=FZ;Cn*kU(9{S}5l$IaJBq40Ydjf(j5ukLIT|5>|`b!7gc*Ca0-}oFSYnbzp zn3%~a_)M8|(5gD7t=&XsId#Ue<$Ye`I{6x195b$)-Xwny*J$OFsd^PK6ZJx0+Zj>g z@Y{dR=ACWvygx<70vAozWg9)-Z*B3|$TvWM;{0p>cH4%SU||h%s?IJ>gdgTm&Q=^k zGq+Q-KN$A)OV=};p9Vr#XOI5MEY&BM3^bmR1MeF{`iG|QN!_*KEW5+?(GM@aZejpA zQmvyaFkwq6u=P0!RbfMU%1KNonoDNHAQ@oP8sIg0mxzL&R>b*^xc5#f&>c!|@D)2! zR&48iXBlV4OLbQVl344UXT?rvPmJRN&kspaupCfsKl|;x*hxlRT5(qT#eDq|f_X!4 z=x6Rt+hAibv6~3h`aA=#9j)neXG-rKlO|{0k$|uXpAkI4ZXj!T{7-h$3@S~qo}QA@ z@(*%ZYrQ^VxoroAUdwBHGS6%X$)6Nyt{X)}Z@V&(bPtqSehbReMioS;H|82fJfoC3 zR{xhTU$R7&-e!Wjr6seMno5y#G!s0_4nO<+$mFOQ=#jAPPEa_%m06g3U{5U!h_*R> z<>t?{f87V}#wdHYVlL1~VV~)HbJcmH1@x;-jfGw2o@|md&{7Smh^L%Z%ZX;-8dE}} zG)!fz`oc9Z2J#j<+0|^pw-vDMZRQWQ-+sok)t~cOChX#5P{#BAt7d4=zsrfl8&^j4 zG<6G17|C+4;O<59Q9t6YQcwX_91`MZT{w&bHZLSNMBxlnRK;R3OmIDdbl!(QwrsFP z`R+Q5Fcsd@x^*cTcwR4tdo}gAdhq?pTzRoJ!6xP4Ad`(E^0u$9?^wP9zUN|tVYT_U zHky8dT+77t^dBFeWr|wDpG@8@6x6zG?woe%sN|F0o$s*VHmJCzGH~OBFIjg%eP=i% z$7cz*RIfC-?Ql$uT{!yIU(uwjY?6}ZiP^2@@BMb#CVLEA4V`D2-ID*2L4^!80p}aV zt7C;~bsif!#Qr@+Du_eOX;_6(t!xq*?6zK)S=&4JwV`>N5RR|v2 zJk&r)y0hBd@92nHS@FhKEV+hZ zEOST>3;Al3nD)oweUsZO4Oj0GEeq)&q!H9=4Qz1wn(Xwotduu^gb+rkL^GTt#sBWz zyRg~DKcarzK&?1?!$pJfo7-qbAr}K%ILG!Hy-jL8FHbA-A7B=aO$`C#A?a9KBv_B zuUj>CGE-W!78g~Jc*IgRPQOqIB1J23fwksj6w1c%kw&)bG0ccj_#^r8aJ(WC89D9Q z;3M*hor&;iq&N9b+VmA$#<%4{KIM`Gdk}-PGNNNb1hVeMs}>1O2^O4AtTw!(nr%3k zy0FdlkoA~18F@)VU3)jwe|2c_$s+M05~GuMa!bz!L) z61}ms`_$sFyZ+CG>Xi|N3%zZRC+MOz;c`r=qFIAi_LKt2y12>$HkJA(i|zgz6+lzRTzi3 zwQ9tY2ggN@S+5F0fkZBoWkpX;kwl~}cv2{G`ZMbV?A~)G5!x~4eU`FmSk%1vXxu~* z*c+Ue6zlPb9I?vL=GQc~N=K}*+Gwkgg4+zmIiAeg&s0c@2Q-d4+}DN&K{xO;R1--? zN}~I7s^M#wsxJP$Buk;_akV>s%pv3YMypGbMWtA{>Y7<%c5%57O@xu^OMZ*F0qXMR zH#S(Ft3#AWG5z^Cki(9#pCk@Q*}eU}#h&Es?5e0@#ayaC4Tl9`veH6YfC3k6Hq!GLCgF4#bz0IL{Hf#%F^!xXhbl6Wn5gjbSw~opvBsRlkE~SBp7% zs(B+gUpPnh%wk~x*LyXA4$cC)n7B;$&4VQ{|0)9!ZhL;X0a}35ppok!0k_-N_!RI( zHoix^(5|ho<@T4v%;OjxSLcr@(VfWIhHM_?RmYd>s=m9a*I2PA*KAyzImH(Y^zFse zW8If$zrJ>Y zuxp&Anp|>}s@AR_J#2hZYM`klVChDMd2ZqGK_xrOCG86PG z$#0B6zv7t+IbQ)grdHtHwQxE9R;w% zn|o-6F$`D5tULpxqfDLp*N?yOZ$lP|UxVFx{@%^i&T^qMbnLCY=Gtwn`X7;mw6=Y* zlx;&~k-s;Bhr4(VrECUqrxp?+UyWJmsFLObercff1n3%u-wByj;XZd$zO~FBcOUAp zFZJXJQ&N9FWAGi%tqFaTM+dL{aN}cQ+=MNu9#f*Pk%E!2+8WWq zZEoJ?qm6Zi?kKv{Noi@f@_l% z6AaIU;OmR|uq)8>sGKn(*A{gy$u%G3^_?~TeNkn4r7WD9+2aSdWMpJQ31|eBCC^sK zOD#Iu&jZFBSHpkKhY*K&gSL|;b44XyhNs^wi%t06Gx)J(Dr*dnkk-upGQ9Zft8>zrr2K2`FZk>NxR zef~^^8kO;~ylD?xUkEl5SX92D2S>L%Lf;pHm+$WaE(DPZSj+NG-3`3{eF9NXy__GN zNa6o`wC9I2xIB22t6WcJy~_)a&VH?7QTv?i&R6#}1!-4!^l6Itr%y1>?mc_px%h+R zfKu{g#-01uaL)Cmy-+y1L0d(dws@4zcz!d}j-oyVCoA^Jw2wDF4OZ8&;JR#abwGuF z9H0+}Gb&yEe@D_fN4Mza-Y|tnxL})I5?c_Hb0ShZe*bg{YYl=$+vvytmG9E=+aTNb z$E)&{@Kf@F%s2GKLP4tqJtDzwRQ=nBdp*SEw=kS5sBZS&sL3w_V|UttM`dF9i7SA_ zbFZU&k|SX2XVbjFesOo0nRPF!CSP`a`6GXaUY)GiY2Lm7C%u=N?7P!in|?i4ou&+O z?=4wlzQYc1Ud7@7_e{ zp3&G*Xg&D2mOy<@Ou8q&e1bllI=Irt?nvc4N54Rx9>SaHHZ>X75s`S;@V)2S?dy4h=5xf#NyhlfDuh%2W)vFxO98({NiZYD~I-*Ao7X9$OR7N#4a{ z{N@+TWk0iE8o(X#*cel&M4caPQPGr!NYp<1i>B)nmM8RoRFiH_d;?9AZ`PocI4IeC z4cD~zAAjbKm+;(~F;+>dyOe_bTKoJGXvcdK6qr%c+c8((yd!pJ7P$ksj;^_jgj{0| zTWm@TP2g3~qLUBn%M$lilvq|A7^d07_`Pew8VQO{5_#?`z-{T^NO@4O?L%6lM8ZLV zEg_&AI3FUThOP&9EYJ;ILzEC9*yY8TH?T`mr)78t+G|0rZg8@WxdTQ~`@01w)S&2l zXD7bF&lDf=BQgn9yg#PP9BiyY^F^kIb!@rt+89*9WO5X#YQ#W5?B#wMk6}W6u;S0a zk&hcdL&Vd;b+CyU=o*5czx%+bUQrn#yIq6a+C$Vv@i3I?>e*~fnX$D~0?m729S z;*GsBA-R(i&Cp-*x^+UCt=Jk7$HeZO#Q(7I)3<&CS5wQ8Tp3ln zkS-U-yI($=6~s z5@uc}q3A@py?&8+%(Vx$idhkDMD_N{O6gnN5O`~;xjO&5M@!y#-F+9utgmqbPD(8y zc9!y!!)py}ioj=GiEzU~^!* zV6{H&PoPhciy|5X&&St!K;BipRhfOoi#g!nqyE_WX#1RzLrlFy?1B;SYo!PS3dk#C zV`JpysTWq4jxm4bIS&Yf{~k>n@*Fn8M;^sI*!R>HRiqRm4%|1 zw9>Cb6Q$LeZmXxZoP)!~tkO@&VEF&|^lI}LvG-Ya@RhI3kC=|@-@8NFM$s6gr&s_D zL)#X!yyvtFJU;R^4FFrIeC!R?&Fym;ZYs><)}0m}$ooZ}=nyG@GkhJ2&04*>Yu>=r}t@^g`KZl|T*7*)#92pAO2>=bxfNw*tM%g7jexZFu75Wkl0@BVo0LR1W& zV24bxN+atmSwx=A-ZVG-!J5LUnf}cp*evkJtpD!&MdAK)dFhAX$L%sclv{c?&xMe$ z87VLqiiYjok?%x0dp*Re%Ciny=WC~byWJwM$be zRDgW{3G2;gS|lk^F% zgD!qHZQduY>oii3xq2A^JH^FZ9vs{S*Oi5fD`MfZh^3$ftRAAj&zw}Q(*b#peUiRP zgo%|v@>lM|go0c!8pN<$Du^QN)*iPK0LjZfw_RVIbU0CdZFXD!=O)4-ib=X8VY7>V zy`WE8eYcja3q4wY^CEJZZi^iAGs)dBRM^dJqHnZ`hvenAZ8?KB3SV|VO*o1P;e?%L zqQbz_(a#!mx`;y=B^zl~ksow1Jst% z;E+Ld2tMpI0d;HJt823_^K?z>x>WKP=$`nQ0&lY9-hi|-7k68p0D<~OFy2R~$Ls_c zx`sKvz(mq3F9GcG-36pk5&DEBR|5RN(=Yi}k_l=(&GH0XH*d0#Xh8E3h@7DFQaVvr z>AJc)sMvSlN+bfHUjCR0AiOYY2@VcLZvC=?!?(--IK!J_iYXi#1-`$2i~)G%U_IbX zj>)os2_fYy{w#T+F8p+gO|&7N_h*sDYt^`$yyF%HOOfMBl_m`or1}*`+Q5~jfQOby z8v%9%p;X?!2dp~fW1w8GSj72sI6+(RJco^lzHdk#DE;#7?wD@ofr>}eq0xz7M&Bse z{go+H7xde&foyZ`eXE$wmp_K^>Tvq;g731s*#m-^#o4YSVwU1#+Tw3Y#bbZ37tE$t#$x**8vK< zFqTnKC+12j_dXoOTWc#ENaPsX3*=hIr-cH1pVm?!%7qVM2VBD zi`^F{7Wrq^2#QhpoL#T55TJ-Vl@8MMF)(OV(OCdtFJClUd}I<}u%WYOjC+;{oZ-T^ z&!zoH@Hk_cjJ|&oXi-Ek75;&hwt$dNlUde0Rc>tMG!(B(a1NDU@Xt{1SzZK z*&9tt26`pQ)k~&|7qgN9OQ0`;Rk>t%EhLghDD1A;n6Q%Egfm;vEU7p;I&!aXH-%aL zuCeNYx^WfgANViIFM8wGT`Q2fsw0;BUl^{X0n*FybgF)zx6J=|J4xmlcIj*zAlLH= z&&VTOH2M=>hJ~;qyZ_4vUrTIrg<_quP=f(JIq!MUyl@UK}qzlC#Q zpoPSZ!NfnnCh&_3f}&l3Qrw9g^Wh5Ax(rAXF(XGOnQa0pi{H{(sN3pCvI+PwBM#0_ zBdZ@@iXi*+W+-dIT9B);6FEMp+ov~#=`qz-!ZSWB_C&EuNX&XXs7k0-dcnXg7n2}^ zL{Nmf^+*#7vcavW92UDH>TLRnSi|NGDxWj?{=xMo^!FF!t-gi@4DZ5HRS=>gUs^mL zho(m6yucR~B1@o_=5gAcdv8KFz9OIZO@48_+UPS4#4ed!un>pf*22dd=@XHR=UmWh z!zxoQU`Y`Cu8Gog%^!K3zc(`eIHd3iJ3J$ zM{Mpj1B=iV*&yyq#eExTk{M#})i!MWfBa%D8YgVj?V#EkBJzlDS09eA8AHL2)8ksD z}L=}g2#^OTvNAr(K-aWW1}7-D7SniLcM-JG+EK-5<$9{x|)c_KyJ8+E(l zJBFsOgtpNxZjJ{nrUC*0t>pXm!+R;i*ew~gk0&a)KqYO|<~e)=uEj?05|^J7@8Z1` zVH1hgN@{8<+i5M95N#Ft-P%7sbjoJo#GNgP2 z1jTXEp;La%Jo$txd1wacwkV`m$9kV|J45t!9->X^qKCL}=FR???pI&iGH#=e!W(8} znI3@&18blp>~QAJF^TlKr>)Z~5tr=uv4sx^3)K)5!?_;*`K}ZA6G(7O&>q+Pi|&X_ z6UslN6@HRP$z#y$m1g%TLxB6}Cb;aKV$nSeNs$qwFy-4ZTJ5{^uOCrvi6jirUpNB_Ct3P@2 z1ao*Z1m?jF^l+J`_l#TA=EUaLa&%hfppVL;g8oX*MwBvjaF^x7BK{cLjUpa zlX?8`IkeqYDT@gX=RBG6G&~ApVnZ~F+MI`B0^5zHlrvdniH{b#EL(Hz03Y}g-@ ze|t_;*lnw_$=qyo(;6RKq1gw@l^};!WSI6|%opJN#KgssM^`W2i9_`LWDI{TzlMc4 ztp^~gb@gY`c!cGn2t=_xkT}D|Lo)@~ZCuu2FLgrfRyM>B zVa2r3sE(tLi=yrM8Pn~nY4n8`S`xlNqQVayE?HX{xy7VRij=TpFnVmcOGmc#YZ(vS7rxo!N=0H$P zP_-1uLDZ|y%DBzKwLL{Q|7KJNvSDpf!?544Jzv#mhw zC7;tOFxI51=QgIj+|DSaqIn-S`bc7feVG&fGXb-52Gm&|dF(C7@XxJn3Fl=!N4xf{ z+M?R22}m~1Smnvg-DZZ+t%1_J$KybKQA_v<3S3Z!0tERHU=xYwLX5YY{60TVlr`T*`NCSHXF$^3$(MjhcJ)z|=@jmq}l8oaQp95GMs{Iyrx)}T)CSqIF$fK9R#%ZAD7 zsF53L83{1It$g{?Zx%_0pm1g$^zu;X6oyjlBxbPDTMs;4zH7ne&Srk}!z- ztapc$f?#ZHEWlTby!NeCPb60%CVc|Fs3#qC5Uwq%@Z!irf$0viJJD9iK+ZfMP5sq5WlYk~j5HG*RQ;F>3TJ43#X z0SF57{Ev;S&qE%sgeNQ~b1QR$ybgzYMsAuVeb~vL6s3Y{k^xn8ffZa^p6qG+M;@pt zdvP~HHVT&G0~;q|lzdQ@xf0C@2#NB~-bGzL9a%SX>Q7Fspy;#ot%2bpM{?8M39E;R zxy-klW!>$6egNRj=UV9&Cgt}F;og9k=-13W{>$Yv&gvc(>NXvu-$`4kQx|-TzAk3r ztrJMSB;J|$=r}GY znDBQSMXxEWfRUjB`kX=#nH?)oA*Y;-{6Q8M2o=?y?2i{>iIN^4$Jf4lQNgvYqT0j?d6DOheIEA5Z$zU>NK00|IXH};BrG}*b!h-r~X{wYLv zeLm=-vcjx&BB0zgTs{PrnjNU1^n@W`PbLkk?*)~IXKzX%3q*`{;dL6hbeqRU@>JTh z*iKzdiNgC;+q9%i5G$4i9%Q#sZ8=U@w}Rn1buEBAmK>0FR?dt?blMC=?#eLWI);CL z&H!m=tDR&hFr*itZsfx{?Su_Fi z&hjRUH1v~9=Qo~W+52c0iCcUZ=+IBK1WK|{NJ0qdN_eY}mS~9i7hoZgx~3pc z_81`_lD}w5{Vv#9I9eZ-D=f8UhRAnXz;3A_?)Dg31Qxj2aY;1=Z)y}KeBWFQL#1EGMpCFnV@aVg))2!ke|a^(`leL&h*)N|nX;+t(dX;K&+ zylZ%b8Ak?W%EHA~Fg*i^9tJ}p;5zU<2adcE$9E@T&~%ig*JdKl^cmdmJt<5O-X*B@ zd8XC|2kddId(0Ptrbm|UV2_bsaND0Cjr02n%X%UR#F&E$Q1yOvQig>D3c!`r!&hP} zGOpeUqnaS$5o;7Dwi1LiJO1hc{?>Pgfc^lO)#c(o|{(d>ab9M_stOzIT==gcs4pjb<_k}aGh#% ziBkRYbQTs8vS=2G*;!fTNKKH)y2Gt+nrKtq z>*5KxE4ZP+mp4$ZZaauoCI9+g%*1)^zk>AKykAo^B})zT&<}mMA|P#kz`a}rdN~!J zif;e}E9`)*$s^rg$1QQ@15fk}-C{)A_VyD` zC`OKc3q^ndi-tbH^*YkhOj!{ylF%*Ey9p?1RlpO{sP8`-SRZ}U&~OF@-EJtA>z>!P z(NMj^V|K4QnXp@Oh{-@X^OpZlc>c?*<+g=9DPVWzfk*n3nyPAQx-#}1l+djxLfWFb zE@@JLVM#Da=Tpe})~!W|xFKjVQmJvW{r$~KSncbV$;nI8ZZ*sDoxIQh4TR{;kStN? zt69Ocq>;P7bhMrUP-dB#HR%0l5)iD(44$7R?a;LB>L-d7nxISz3AX$;la^Rti` z*l8?^VBc~Dw|=j zWN#pA6cgwMZLkewmfaPZ7VweXm}m`$FZl8@z_hcpe<1_2K0mP~_TC+Ywyi`5GuT6x zV-7f9rw1X04~aq-u7}ci>_CXqS!mEJI%ERopowVa@m?7qWtSj3gp|Hid``2^XFfvD z%(VP16P3#sqE8;S5Y)`G*6?|Ok0ET?NJ9Is&d2rNgX&2~GSNvC?liG-eEF#mt@|NU z9K;TaG`{WpV=xCb1WD{`LC0je2R?VlG90ek|F8`%qvH34lU=SPBkBKv8u&O4B3ny* z%oGHTPrffbdix{}<`5B*z5-3dtjGjwK#D1i#5{}s6^zfS=x%S00e=oRA{T6YQ+oE3 zW5B#VA`OUMYX1X>S!3x9$W#*fmOicvC~Is=bsMD%t!FI; z?<&{xA}suyqV&3!o6rAni<>N#H0bZ&+mU_4MdrJD>8!re_Y8@7j}W*OUr0tk{wAsl z$dFBW(KsQft91ZKFtxec6Y@!}vO?=w{yS6>y60&4_L0V`2flUBO#)KE1RY}V2So_b zR(bY!CD1Rq0|_$0v#-Lka0C5qJWB2ovlgZep@=Qk5&!P0SwPZyp2h+oZ2)tSLyS1l zhH*<({01hDKU*v*^ax@|QCJ;1Vq!7tsiQNLnKb22KJO`gr^M``kYY zUN6}xDn^P;VZ2%Z)0GOCozRJj*a8nOtpWK@T%4RrFZpU20T4x>Apq6`fE+Z4DQanH z;!>iJH_NAWzVsMwQUQUb?1! zcSJ&-jly&EwR=c1Cs2})laY9QkWrt-(~RDFM0(s$2*#3guF~BZ0X7Nrk2m8&gjeMC zA!`U(u$inaYDeFnad+en8`%772WWIjxZ}Jw*f8Fo08+ywiCn1nr#K%ed+N$(P2{v5!C zEpy`+xJ40AThlE#6T<3vCrhWB-QGOZsH11erG%Iye?b>rpo7(Gj3dhz7FGc`Ed*YI z37kS)4mu+%t%mGg_$Tt7*k=deDyX8jyIMg9O+v$Bc?U9;OfG3$<0s~`ms`6aPHzNg z;&>TuPCGb1J!n1XPA19qI6?J&%6-+?F9a5O6avG9Xduw5^T5o+qhdOH z@Li#2SgY;HOmi(*b@Z$3iL2mwmp56cGE=S)95bX;w;0c(HEI0bI#zO*C@IJ%9OlY( z?c-oz{v5;=?%Z?)E0?%ey|nOk8mdj-=~QMKMN5;A>|wzdhw1BbrGMd?EX(kWz+9#q zE4OD`4bl3be$l-RQ=yY;1v)Lw<^G42SL&qu{}dT{y!j`PkT{tF%t$QE`9yMpdmsc# zNvEl)NgNwkfF|yLvIy?E@)+n+G_nYs=5qB`^m4Gdun}w!W{j;cX&5@KMTW@dilVhU z0fzUk)3+*K7}@K8rx0E_StjtX0R@k4b;Vr&ZgoLUBcYdKEbuI35M4X*r1o=vhqpcg zweR?S7RluYGg$}0ecj=cA1fH$@}1vS^lq_5#dd*}C;@?=F#55u326%Suy0)weJMAd zg+T)}5j7A1_PdyPdH;HeBSb0=XlI5F&4L>yYmgybI6mx_45AYgM@T9D7BiT306`6E zjspw1(E0?0q62f)DyAA0U8Y9HGa&Kx9LQ$+UWct+62f@-`8EHqRQUf`>gg0A z@0${RCSYO91PNs?UTO>naf6NjSD*UNveEyw7!~h{oO=vfjCqrsN;T6^zu6`(J_8GF OF;o-~@>Q~yVgCoGitcv+ literal 0 HcmV?d00001 diff --git a/Splay Tree/Images /examplezigzig3.png b/Splay Tree/Images /examplezigzig3.png new file mode 100644 index 0000000000000000000000000000000000000000..dbc40a3ba39fe01e44846dba5b16bd6cfed5a351 GIT binary patch literal 18128 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≻M%oM94;*+% zs-#srY}8qlCdTmMuu~$m?z*-&DSe>R`a6nmM!c4&<})trz~NJPh?j*%z!^v}X$~0W zDy3fgkzxE*fqo8(Awf-A1QXyKa(ZoiTx9(5)=nHA5*L6lh3*2b@F=Ll@679{@8Y!2 zX&>KK34&lT#vrqZ5k80k#nRSL>azz-l8{*j<9HAstR`f8zinjK(If5cyB&(9>D(YU9A0bcDCuSkc|IF4C3{LKCz`sXA8I_x?_@t*9ACN-f4z`G@uyClnqzYDC zFCB`i$_S3CWDL}U%SdDTjSmNUySh|4nT`j3MS*WZkx=qMyp9LHJK~g~nN%g|ADV`s zhoS@tB!Kb;3J-_L1T^Z3faX2yVo{!KVij<7&tayPRHN%~tPTJ+oT9tD$pe z2xMk9mP`%@Xo2`$+lrPLe@EUASf9m6+58!-O<5;Cq1AiH4UNYPjzf~-*OEQ z8WpdD4KDkMs=ZG}SR3^3snk4Pg+7UkdR;#3tx3)TJR;xS0lA%V+mg?qs#zRv&E7Ka zif-z_saNC%VmSv8OMs;sCr9VYUs}7>&h#3Ei)x33E@5X`K=mJw?R*@|4bKdRrN+m{ zzqt!-+WHC}b$Zh@q*MqP3PIhr{1Oc~kL^S!7KHpg2C-ZvGht}jZmQ6PqmW5

~t9TomnK zsmVR6O4QK&fW4Jf8*JhLtEUbaDFG#f#^pak$o>WWhx%-AP^g_=e*pL$l6lYMM}vom z^dA`n_Ex5vNtyjt<_1)n0UfqG-spd!N^7-igVUtl2quTdKDy>=$(G$9?T-l9HwEE& z;Bs|S$PJU}XZ{sB&K4&jv~T=w8ZvR9P0?&c6Iy5K7li0=Cy^DxMWDYR|^P ztT@r1KYw0fX;6+FaHCYLdGVb39B`k3w~B=X@EVraZ~qlDT&E<}uUP#_2@K>`y%)Rj z$=w=^-~ByL`h@PXHs!2(Viju2J7TX~QBssoS||%-WMn#F8$DGRP zV(fqvz6PxzMNLYr4&_FPIDa*NiKA=|rXo^2z8B8UsZ){lD`G5r)7TgLG8b7>Ug8F; zRDuf9^F|@g?&n+%(`!21qQ5i<(~3u{c$fYS6}Pb}NZy0!hN}U~VwhVu{*>Y)4cY%> ziX)B`=v5)(VF(`zA{vo+0vZ}Zf*S$)6;?4jo}h1q?yr7vtY2hs>U4K~M- zZ&WA;;=2_JZPtNNLr9PW#RVzh;NbgX-wUvj{FxRv z53m{%0t8Ltlali6(6yd!*r7%d8=UHD5buqNk0Y0G z_Cbh~jE>H+4&i4h`NccUyM_4t1y6%&?~iv6lCzpdHw*?Y2J`c4e-B;0#tFXE8-@v`k01P z3oWt>S)EA)-}@%#>k`0{9I@-7oAs`@`AP0xrZ2Bjv^JtaFOr zN3ccEtxxPAuP0ACaK`-TVt0B8jQ1p>upvQS3|FX{YDjzc(W>62B&_f9zY z$}o@}aGRFc*>Xq$vzzaUv74&*(}^#GAVF`W@E!xWZ3g~lnlo1%ySx9&5QxF8nEx|F zki`ma;Q!1J>@vMh_^%8>2KM>*uMEL4S-H?#5tyaXYOU`-2erUNQ!jb+lS6yR+MrizmH|0_pu`G0Z* z4+sd2&=5aF|3ggw=$|}sP^#9u2{<-KApCTq%;L&GbO0Z;f&%3eWcF z5Ha(yj5%4pi5%1~wZL_lAqA+(_Lm(;)|2iyX6!U8>BZQ_-;}%!(S0!xh)3|o_hi4j zy}$v4h?nG^x&fIy3k0!#zoVX{UupJ;4WNToTto3c1tDTc;}9$xxd**oBjhXwGDdkh z#wSEr^c^UyDF<>YS`2A9DI~|b&zzj z_#ck@CnCH}K+O)!FhFhv55cTTQ3M5NXv4fQptpAq+2(R}mg?e&N)_mbO*M>%JGd@D z(m2HHze2#m5l1x$s5B3H>5|>ae5k*dmlqo`x@BMB&uAtH{-RHdM_~k5fL}pPfco1@ z;h1zqZj{Xy1CMw#t*%WJMMBno}WAgIpn?|~^R-wC?v&D;mcj9{K| z!Qi&5pNd`h6-Y-oLVKo4LWW&bRFCCB((8m^LFB~WuhLKq0r81n*(XT}&@WhwPvJ)V z{}S4D^^>s+#|CS1ATp!&!7)!k-fabXN8h=^e&RcI5Oe(hP7$0$rt`qq1Leciq^9W! zNyX!U;Kb?a={fkx+hcjWvY_dobgm)t_U+pi0D6(q(eVJRw{kmXHbnaPib Date: Sun, 21 May 2017 22:20:42 +0200 Subject: [PATCH 0628/1275] delete blank images space --- Splay Tree/{Images => Images}/example1-1.png | Bin Splay Tree/{Images => Images}/example1-2.png | Bin Splay Tree/{Images => Images}/example1-3.png | Bin Splay Tree/{Images => Images}/examplezig.svg | 0 Splay Tree/{Images => Images}/examplezig1.png | Bin Splay Tree/{Images => Images}/examplezig2.png | Bin Splay Tree/{Images => Images}/examplezigzig.svg | 0 Splay Tree/{Images => Images}/examplezigzig1.png | Bin Splay Tree/{Images => Images}/examplezigzig2.png | Bin Splay Tree/{Images => Images}/examplezigzig3.png | Bin Splay Tree/{Images => Images}/zig.png | Bin Splay Tree/{Images => Images}/zigzag1.png | Bin Splay Tree/{Images => Images}/zigzag2.png | Bin Splay Tree/{Images => Images}/zigzig1.png | Bin Splay Tree/{Images => Images}/zigzig2.png | Bin 15 files changed, 0 insertions(+), 0 deletions(-) rename Splay Tree/{Images => Images}/example1-1.png (100%) rename Splay Tree/{Images => Images}/example1-2.png (100%) rename Splay Tree/{Images => Images}/example1-3.png (100%) rename Splay Tree/{Images => Images}/examplezig.svg (100%) rename Splay Tree/{Images => Images}/examplezig1.png (100%) rename Splay Tree/{Images => Images}/examplezig2.png (100%) rename Splay Tree/{Images => Images}/examplezigzig.svg (100%) rename Splay Tree/{Images => Images}/examplezigzig1.png (100%) rename Splay Tree/{Images => Images}/examplezigzig2.png (100%) rename Splay Tree/{Images => Images}/examplezigzig3.png (100%) rename Splay Tree/{Images => Images}/zig.png (100%) rename Splay Tree/{Images => Images}/zigzag1.png (100%) rename Splay Tree/{Images => Images}/zigzag2.png (100%) rename Splay Tree/{Images => Images}/zigzig1.png (100%) rename Splay Tree/{Images => Images}/zigzig2.png (100%) diff --git a/Splay Tree/Images /example1-1.png b/Splay Tree/Images/example1-1.png similarity index 100% rename from Splay Tree/Images /example1-1.png rename to Splay Tree/Images/example1-1.png diff --git a/Splay Tree/Images /example1-2.png b/Splay Tree/Images/example1-2.png similarity index 100% rename from Splay Tree/Images /example1-2.png rename to Splay Tree/Images/example1-2.png diff --git a/Splay Tree/Images /example1-3.png b/Splay Tree/Images/example1-3.png similarity index 100% rename from Splay Tree/Images /example1-3.png rename to Splay Tree/Images/example1-3.png diff --git a/Splay Tree/Images /examplezig.svg b/Splay Tree/Images/examplezig.svg similarity index 100% rename from Splay Tree/Images /examplezig.svg rename to Splay Tree/Images/examplezig.svg diff --git a/Splay Tree/Images /examplezig1.png b/Splay Tree/Images/examplezig1.png similarity index 100% rename from Splay Tree/Images /examplezig1.png rename to Splay Tree/Images/examplezig1.png diff --git a/Splay Tree/Images /examplezig2.png b/Splay Tree/Images/examplezig2.png similarity index 100% rename from Splay Tree/Images /examplezig2.png rename to Splay Tree/Images/examplezig2.png diff --git a/Splay Tree/Images /examplezigzig.svg b/Splay Tree/Images/examplezigzig.svg similarity index 100% rename from Splay Tree/Images /examplezigzig.svg rename to Splay Tree/Images/examplezigzig.svg diff --git a/Splay Tree/Images /examplezigzig1.png b/Splay Tree/Images/examplezigzig1.png similarity index 100% rename from Splay Tree/Images /examplezigzig1.png rename to Splay Tree/Images/examplezigzig1.png diff --git a/Splay Tree/Images /examplezigzig2.png b/Splay Tree/Images/examplezigzig2.png similarity index 100% rename from Splay Tree/Images /examplezigzig2.png rename to Splay Tree/Images/examplezigzig2.png diff --git a/Splay Tree/Images /examplezigzig3.png b/Splay Tree/Images/examplezigzig3.png similarity index 100% rename from Splay Tree/Images /examplezigzig3.png rename to Splay Tree/Images/examplezigzig3.png diff --git a/Splay Tree/Images /zig.png b/Splay Tree/Images/zig.png similarity index 100% rename from Splay Tree/Images /zig.png rename to Splay Tree/Images/zig.png diff --git a/Splay Tree/Images /zigzag1.png b/Splay Tree/Images/zigzag1.png similarity index 100% rename from Splay Tree/Images /zigzag1.png rename to Splay Tree/Images/zigzag1.png diff --git a/Splay Tree/Images /zigzag2.png b/Splay Tree/Images/zigzag2.png similarity index 100% rename from Splay Tree/Images /zigzag2.png rename to Splay Tree/Images/zigzag2.png diff --git a/Splay Tree/Images /zigzig1.png b/Splay Tree/Images/zigzig1.png similarity index 100% rename from Splay Tree/Images /zigzig1.png rename to Splay Tree/Images/zigzig1.png diff --git a/Splay Tree/Images /zigzig2.png b/Splay Tree/Images/zigzig2.png similarity index 100% rename from Splay Tree/Images /zigzig2.png rename to Splay Tree/Images/zigzig2.png From 5d15f553817310785fc0d5539c01508c86892250 Mon Sep 17 00:00:00 2001 From: Barbara Martina Rodeker Date: Sun, 21 May 2017 22:27:24 +0200 Subject: [PATCH 0629/1275] Adding images for examples and rotation cases --- Splay Tree/readme.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index aa6bdd4db..89444b2cc 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -8,14 +8,25 @@ Splay tree is a data structure, structurally identitical to a Balanced Binary Se Given a node *a* if *a* is not the root, and *a* has a child *b*, and both *a* and *b* are left children or right children, a **Zig-Zig** is performed. +![ZigZigCase1](Images/zigzig1.png) + +![ZigZigCase2](Images/zigzig2.png) + ### Zig-Zag Given a node *a* if *a* is not the root, and *a* has a child *b*, and *b* is the left child of *a* being the right child (or the opporsite), a **Zig-Zag** is performed. +![ZigZagCase1](Images/zigzag1.png) + +![ZigZagCase2](Images/zigzag2.png) + ### Zig A **Zig** is performed when the node *a* to be rotated has the root as parent. +![ZigCase](Images/zig.png) + + ## Splaying ## Operations @@ -30,9 +41,20 @@ A **Zig** is performed when the node *a* to be rotated has the root as parent. ### Example 1 +![ZigEx1](Images/examplezigzig1.png) + +![ZigEx2](Images/examplezigzig2.png) + +![ZigEx3](Images/examplezigzig3.png) + + ### Example 2 -### Example 3 +![ZigEx21](Images/example1-1.png) + +![ZigEx22](Images/example1-2.png) + +![ZigEx23](Images/example1-3.png) ## Advantages @@ -57,4 +79,4 @@ With *n* being the number of items in the tree. [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) -*Written for Swift Algorithm Club by Mike Taghavi and Matthijs Hollemans* +*Written for Swift Algorithm Club by Barbara Martina Rodeker* From c4268801a9340b1776c6b4e0c452fe8a6388031b Mon Sep 17 00:00:00 2001 From: Barbara Martina Rodeker Date: Tue, 23 May 2017 22:08:14 +0200 Subject: [PATCH 0630/1275] Update readme.md --- Splay Tree/readme.md | 64 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index 89444b2cc..29f9dede5 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -4,22 +4,36 @@ Splay tree is a data structure, structurally identitical to a Balanced Binary Se ## Rotations +There are 3 types of rotations that can form an **Splaying**: + +- ZigZig +- ZigZag +- Zig + ### Zig-Zig Given a node *a* if *a* is not the root, and *a* has a child *b*, and both *a* and *b* are left children or right children, a **Zig-Zig** is performed. +### Case both nodes right children ![ZigZigCase1](Images/zigzig1.png) +### Case both nodes left children ![ZigZigCase2](Images/zigzig2.png) +**IMPORTANT** is to note that a *ZigZig* performs first the rotation of the middle node with its parent (call it the grandparent) and later the rotation of the remaining node (grandchild). Doing that helps to keep the trees balanced even if it was first created by inserted a sequence of increasing values (see below worst case scenario). + ### Zig-Zag Given a node *a* if *a* is not the root, and *a* has a child *b*, and *b* is the left child of *a* being the right child (or the opporsite), a **Zig-Zag** is performed. +### Case right - left ![ZigZagCase1](Images/zigzag1.png) +### Case left - right ![ZigZagCase2](Images/zigzag2.png) +**IMPORTANT** A *ZigZag* performs first the rotation of the grandchild node and later the same node with its new parent again. + ### Zig A **Zig** is performed when the node *a* to be rotated has the root as parent. @@ -29,7 +43,53 @@ A **Zig** is performed when the node *a* to be rotated has the root as parent. ## Splaying -## Operations +A splaying consists in making so many rotations as needed until the node affected by the operation is at the top and becomes the root of the tree. + +``` +while (node.parent != nil) { + operation(forNode: node).apply(onNode: node) +} +``` + +Where operation returns the required rotation to be applied. + +``` + public static func operation(forNode node: Node) -> SplayOperation { + + if let parent = node.parent, let _ = parent.parent { + if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { + return .zigZag + } + return .zigZig + } + return .zig + } +``` + +During the applying phase, the algorithms determines which nodes are involved depending on the rotation to be applied and proceeding to re-arrange the node with its parent. + +``` + public func apply(onNode node: Node) { + switch self { + case .zigZag: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node, parent: node.parent!) + rotate(child: node, parent: node.parent!) + + case .zigZig: + assert(node.parent != nil && node.parent!.parent != nil, "Should be at least 2 nodes up in the tree") + rotate(child: node.parent!, parent: node.parent!.parent!) + rotate(child: node, parent: node.parent!) + + case .zig: + assert(node.parent != nil && node.parent!.parent == nil, "There should be a parent which is the root") + rotate(child: node, parent: node.parent!) + } + } +``` + + +## Operations on an Splay Tree ### Insertion @@ -73,6 +133,8 @@ Splay tree are not perfectly balanced always, so in case of accessing all the el With *n* being the number of items in the tree. +# An example of the Worst Case Performance + ## See also From 0a813ba0f16865323529e7de03ff9cb69eea378d Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Wed, 24 May 2017 16:05:34 +0300 Subject: [PATCH 0631/1275] Code improvements --- Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift index f4cd8503a..9c5961c71 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift @@ -13,11 +13,12 @@ public class Dijkstra { public func findShortestPaths(from startVertex: Vertex) { clearCache() + var currentVertices = self.totalVertices startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) var currentVertex: Vertex? = startVertex while let vertex = currentVertex { - totalVertices.remove(vertex) + currentVertices.remove(vertex) let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) } for neighbor in filteredNeighbors { let neighborVertex = neighbor.0 From 35db21bb212b56ab13a1ecf67b251727ca3718a9 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Wed, 24 May 2017 17:54:49 +0300 Subject: [PATCH 0632/1275] Updated description --- Dijkstra Algorithm/Images/DirectedGraph.png | Bin 0 -> 68702 bytes Dijkstra Algorithm/Images/Vertices.png | Bin 0 -> 35896 bytes .../Images/WeightedDirectedGraph.png | Bin 0 -> 70820 bytes .../Images/WeightedDirectedGraphFinal.png | Bin 0 -> 76503 bytes .../Images/WeightedUndirectedGraph.png | Bin 0 -> 78079 bytes Dijkstra Algorithm/README.md | 56 +++++++++++++----- 6 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 Dijkstra Algorithm/Images/DirectedGraph.png create mode 100644 Dijkstra Algorithm/Images/Vertices.png create mode 100644 Dijkstra Algorithm/Images/WeightedDirectedGraph.png create mode 100644 Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png create mode 100644 Dijkstra Algorithm/Images/WeightedUndirectedGraph.png diff --git a/Dijkstra Algorithm/Images/DirectedGraph.png b/Dijkstra Algorithm/Images/DirectedGraph.png new file mode 100644 index 0000000000000000000000000000000000000000..67db4995811de13dbf289b45f4cb0b8125bfe317 GIT binary patch literal 68702 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/Vertices.png b/Dijkstra Algorithm/Images/Vertices.png new file mode 100644 index 0000000000000000000000000000000000000000..09b2ad2c0190c1145627afc85f24157302a4abfb GIT binary patch literal 35896 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/WeightedDirectedGraph.png b/Dijkstra Algorithm/Images/WeightedDirectedGraph.png new file mode 100644 index 0000000000000000000000000000000000000000..542c698e1aa006df61c1dc62bfe950bda1ab1c4c GIT binary patch literal 70820 zcmZU5byU?`v^5+LN{Ezz0wRsTAteN)LAtxUyBh%o1Vl){iCt+gul;THg!j3j zTbAV7bVqW83ukpOg_shBSSTsOx5wV6@8K2Gd}$s0ZovdkH%2o#DjHOry0|s1-BY;R zd)_yO+C1&mi^ff-5KDpzHVR?yf4dey9Y7`;Z{2<6>h5}4GDzn#S)^UFcQr5UdbM-0 z=k6>F!}dpll0`W|jE#-C?VHaw8sp>R17l)hF28>LdO0^Y*LZn(N#Z+HhEDMC;d@Lh ztjLHDA3kheIN00oJJ{OpE{)0y@O_MpeI9@GN&y*F5D9`9FcbID4QpgQ{K@U;OS}R5 zuWv4nU%h(OOBF9gmC@@GND-RnV;f08NEkVg%*Cvtp^-qj9A~^3$M07X|ALs9hzOl- zf2y^$_0MT@b2AAwgY{l%?-pEQXV}eNPfu?soVoeMn)f;#_U&|JNCCB|WQ{9rT|$Tn z=g?C4yg5s%s;V+`b91%Ya&>sHV`G(d$h?~Fae?IiSLz(~Ezx|N0xI<7&>YjgwB6c{6n!@YObkiHhpo+_n zK~*h9Pfy>qy}j*32-Co3D~o&IDVhM)&#kNTtZZoD6?ffI)zz9T)}5_$-BGKED*JED zC@L@}Rlo*2w!feo_6yG=lRB8Js}pr$ZeE_}v+9*9voo;)n2{mQ#Kc5ArFw^*=0cMD z-kj%RiL=53C>hf2X%C~3HD*>AVj=#fh1`2U(yiO*apa2+X2M)c1BtWO(2v*gg?j z-T`Li0-=>lNnloQx{K1)&GFR~nQg?gtd)c)mNVbcFv}^fvB`R}__vE4mTL&GLa-xf z1X3G=1)ne&D?kuW;n^SDh)FFb2KD7HvdJTQ4q|Pb$ZpGRL5i9!ch_P(l*zZeDUVAr z|Jj}3Pbjut+4EIYR6#NfGz|%lAd3?CQod%5-Ta?N#WGz6#;r{H%{Gui*-!iX*kSy! z-pSQM2!j=518a^EN^}NSV=24z{ga3(dPhyt>uU=Hx`cobL42jNktp?HqXMvB{ z4K?ONX$?fPobeGP7SI14y8#newezQMWndj$xZgF3JdxsYW5mGvh#NeQH{Si4j8oV5t+F3sY8L+Ms$?v8kV&7J`L{EH&o5A?JeXty8@qHc zY;jHEx1g|t;5t&Py58E7Egy-1zjx$;Bk19&NRA1??v{c$F&C5h|Iay=Y7ti>~CH=mqR6B01p|fAp z#a=@eI=|CS-H$YD>7~49M1LJS>NnJBv>AmRvDQ`+w8rc69gcU!Q{+j4zL$sJobj#v z>d+>qq?f>z-(KWz?ADbyK3`dBawKFd$cA3-nriy_SdLSvizkwk1Y6(a+3^n%qGMOg z8j*VjCbt_3D5Uc5WMF7WeI`s$Ml6CMWh4_()K30)RAf{Wd}JNWiu?vk7?jKaYU8w4 zR#t|Y^oTn>>hM|*kHAU~j}hy~+FIifRo``aHv8=i67~>{#*v1bTs|lnHYGAzaSA}+ zxIQ@Zkcdks>JWJYD@S$Llm;(}Fu}hSsbP2bg{h55ApXRI#xrVHe+K_~9d8UYdPsd& zWqo~pnF0{~vS!hb_w<{<_2CsXHP{H84&nn#G5>p!mD^187|5voL9L0;&80#@LI`_0 zqr4Y&1bIlT-&c*{*t8=PX#RC=2GoOtX#9B@N^+!t3iF{2%=`BXy?&N`b22%ENCcui zGB(y#P$(UlqW$CY5bLjJpuR+YtG?9m4jq`AANJjH}>f6!vp>7t__%RhD6Hqfd%fT@uVxqSsWf6XE$< z>x~2=?t$-2(2y6d%_PM~Wl&8R0`O?%`k7%cm_*I@!;+S3uTA@#-4;GuK92)~8Q1JG z_;|thbBbMh`JjI%$Paws3>squ;A#oyg~O6yaiK0|GN-LngZF%--!Dq}4D=yVA|j%r zIl?v3ojW@iJF#SwvGup8g9ODD^MBeZ8l9~JTyGr;A_ze@2lM3I@rb48e$%P&WQqQ1 zp%Vzqo2l*#hhT&bG{PR8|1$#8a@@1>kKh77fArT>TU)3$=?ufSbWaaA+eN>VYWwEGCCLD^Ga1>?0f;q%YO%7=xn;4-cqKU9^V0=7f3rNjv$2`+-5xME^rTDre}E)Cagq=4JMzL<@cTt()z zo3H0!gP_ZP7iJReX%e}-i^z%&@7s!uf6vjs1e`(h%4Zf}?QzhxdbKnA6a; zsQTKYB8zxNhAx<1TwI*8R3)p?meol)e?@ch2pQ+U0Q*=1I9WidR4iFk1k{8(T8~b$ z0o7Aah@-JXwN~EtCmcTBSCDeRDs=tvU4KP0hSQTg;=f1NiUmPs7I>y~_m*Pg>SjmB zXM9w*ibvNF#Kb7Xsq;W9=<#g)JxgK$XVOhdVPtGhc9lQ&G(40FU&xHP^;H%^aQb!M zS2e(?u|R`ELc&L7Jrd)3=b*IA6L(9_>S=yVmz(yrpEc3s~6MOil3F0b+!=7>)^FjDfWwKGD`lh(dI<+yhj;#D zeAZ0YT-1DeH(PEDU<(3cqfo&HL>01Szy|W5T3TA@Vd3H5V!TGU)B5{nOpmqr4ms9JlG&4Aow!y=o1Kt zv(9bC%;X%(eN9K=c&^XmVz+$}ljarQ`|*#CQpEt%iFTnQ1~7>p0J5Q%MV6F}jdRFw zMs0#}i=Z;thLr_VNOZXRS+r+hrLC{I@1xH=iiH0Rei0bFA71uLu=6db31d%arx^1V zeu_&QVD#VXoPW?{`&^!201T>RheMeQ-~*U$I}?oX_B+wv&Y1)R1Z>|rlVvEP-Hs-~ z3#oPctP58(1f#|H^Ht8`CX#mST97XeT(P8~MP)_&U@Mpeoczr@1Fh7;eVLc?vqF%6 z9{dKu$#b7uq5~K9feg2HC+Cmoo9xy?+o7$h$SC@K1!J$+wcu zgaije^oJ}aibYjlPX7q6c{1TnleWs2w)$_rEyUeCXcBz_?&dMtdyrRJVE%g35E^cR zLGH{|d2l48U$|e0^+r#A`@b15kh?qvf=IssPz)d=3!gk_Z57N2f{PK^*x00W?O5wy zXmvBNEmyv;pwjrXld}16}G=Walp*X%vX@Hwgyvj^^MB=9mQHkc&>!f`rzoQIY>%MTI@^|jSdlkVpw5pd}AhRC2@6h5g@;6W?<;qF{t zxv7jzp}GQLK{~=$6?P>4%LDvC_I4%|&4%z*-0znS#*~zl?Lzo^dUnCXFcoLyv$`Q) zCKXLh?jqEZWBI<1nb4gIVA6&=?GIH0M*oGG7-4WH5BpP~U=8d6D=RDf&RZBWPGH$l zC=>5=`We4VQ;BVao6dI3#me(@?_wwO{v64c9vyiT#WHMuC6tTd`j1%sZ{Hz8t~=sG z%{&O(*!Zzduz9c0VlP~%$}16LV`<4C@~Lgk{eOoU1ww7$9Pb!NE*xkw9EH7t_c7;m z6!ZeW!E`qW65g32@`lcELV1Q6r~$SvD|Nhh;r}2`jx6pZ-6$g`7mK zxUW9L0x1qDgt_@orWhv)>tt01OmBjzAQ{ebR53W*8@cg&^GBUAUEg`{dH*?6{A%~V zfFmIe5YOc&2ZH)|;C`p-J$=Jw9v6zv{K?qPpYydk1srG|A!z*Cio>*mkLV? zhrXzO{BIX`5ov}&&IlD^7uVOOZ1z(T=UdTS{z9EmE~IleRUe#cE5gj z!W+o_Rbv}R@y_kBb+drfg{@G;@&U9w)qmry6=qn2VfAUJ%x(>T%y_{iNUFmh8oYt~ zKmTgf_q<#LK)ji>j~y8=mx%j;+D9ZI-s|U7V=u7Fyu@od|1XGVMK?y^xJL`_7OqNUKQ4MFvB%~X;1vRpH zRD(mQ8q%z0fChNTDAQAyn^}Ii=~qz&ufI6FHxP){Ve z?alQx>K89{|HY*Mim0c#GYXFptK!E|h>GYU=CWg#@GzV{4b6MnnJfQloXfaeiiePk zRjtIx#iep(b2zIVc>69fr;Wv2z3Wb?Gr7szzxmDQ1SBjfx;-R0kdRRY`?tl_EVjIU z-EWP%+L02iWKL<|Yv}9_61fgOHwI>A=9Y{MgXMcqeGU>tr-CQ-yo=1LkISF_jpW!+ z$X*G_8wKrcM7$uo3n8McEUm7tzK%`5q+(7qT8hstY`I)#7Eew}x{HB<5q|kH1ZHSV zUn0HQzPB8R^dpW-xcYd+i`6eD>(vJd9n$Y!^OG{GwtK07C}z;+7#(Zf+|jBAuW@6hd2 zfqKbrzMISAeR1pA)0P`wJiR`ce{j&p$av;77iTdQ!4HD~OB-+v2ZtZ7aua?-@KUhG zOaND6lp?@yqgbK86!a+ydU-0m&TKS#9=!^+dZ(GzKSRCjeAY>*|I?Lw=vF)#9j#Ca z%$wT3R!V&1Bw%|6%xmw-3kUzY1s$HZFK-#w5=gb+%#Y{*hNJQzhnARz6ENma*E(jE zOnl6!;T=C|@Hosw8MBDptjD+3?Z;Ov&OE`jbFEq`P;ixT(3qGj$+;gt_rF@e9JX^Dw=V8=pF~q6k$+n(p>3`>e+q!~} zkI4(5M~2d2qd##3#8TJvvwm}@hc4u!Nrbt-fBpU)><4Z%!fLR%0J!J#z8L$y<@S&Q zjt4fOnS=yqyJ5L(_f&?xy?_6-OvLtU9#0NrOA`#xda;-lrz^E{EJ2F~V4V$M25iS6 z2_wLU*5PQahZO`i)OzMaA&~(EC=)-Re|ijVqn-SxoafMtmY> zd!4zvI3nvPq~_-L_xJ5*fIrpjIIi_+K_c_kUuU|$xfjqR#k(CX2a>-iQ@{Z=Czja> zA=7fLU6`pnu2#0bzP?-A;{|p1XqEzN-F9cDQhD7;pM@>QnP^4~rtxXRK22s^Gak3& zJF*ePac7RVEpb^D&U|0<^%?SlxM59~oakFIz8Ai;jE{1^2fLdS^3ugbJ91PHIHk#_ zKGT7zQZT5GaQ}t3kjCa80IJ=n9G8CiqG9Lm0bTZtN>9bTu|G5n;~HFPC68B6)M6~R z%8-{TV4ej`yk?PpgRNJAWW)t64+7*@+bhWpc$YG23cqi?L;w-#e5EDcSI#d{p|9Hm zEgKQC9g(>E*0{R9>{$YV=GP-YfQTOAlu5;N>FeT9|Ljt+tI;7LuCbl{P3C7slK2IB z-MoEur^xleiMR*1AO#3f0bm+puS8BTO&avU6CRZ>Q7hJ@uP+Y)9!L$nq^if++}#5b1Zc*`& z0*DLyF8Nr0&!|Zau$gcKYi&@D!iKuugW(W;aI+F6t6??EV24k>!HVIP4WZVa1(#CEwbjn$Q8(9PjpWAXtzS@6SX{v#OS&Vi}WDVPxib zTxj2=yw3_=jY(d&nP^4zJj7B5=zS_iC+#i{%qdkuc#mB$*GTxhTtZ<698yU?yi%n3 zw@RX*Q*TB_MjE!5RCH&Okv;pVPt3J!Z89dE#6oZ0Ot{m!U8|pqddRjefuu4)4r!Sq z6^#ziy}Nj&7Qs#obJ%qCZL;y<8fCv3bz1zc#NQ@iDJPy=lCR3TSk~3sFE*#;c|SJ? zXtY4z=(zgoji`oLD_R%WmTVATs4dHNP>Ce5j0aXWK;*$Dg^%V+>3M6&ls=KSGu+U(( z^=!D@akWdw*Muc?I+^AZe!a)xN-n>*X%Xvb+o$Qs-bNCltT+ZCJ?4TfpE}Hqi)mqJ zu`v#J{Yfpn;&*;A5edc%`8(yu7?z4RVT{;;sJEPtCx{A-9uEmDzEj;;ef?Nhy%US{ zrAGcv_ME-CXdE}i!Y+@padp@n(p*AYTOTCzQo3mIJI_mzrp$=LwsD8M7C!?8IT1&z zY(J`oYC?`&p)fW%X|FVz3Za%T;nP8UAa^_e9c|<{n3=9NCsPtUQ~s_;{4Ok$yinRDH2CPkl<3oZux7-X-2b;d;{>TPb^ z=4THvqubru(xflb+pb~A?3gU=wN*ZVe*si@aP4|Sms<%>h%Bjq{Mds!kkeF{3=`yC zBc-FcY@kZRi;VX9#A}K%mCyXy=a8vAKJVW;u06zq&MO_EXSfEKxO#OAYK0Qs$Yz1k zpGL(`EY0F(!%EFp!!>*;GIHOAv)dJ@O=<vNXz&(=nI zfRSPtxPz!T;-a`GCnsxwCzH_22gGK2^FNl`$@4(81$%qj}u(C0o(Ii6tGBEvfZz^&31t!1Y4}$%se7=_P?~?2s==y?laDo00U5;bbl@uY1dIV`+7{gN*lL`XNpXE7nL^3O33-$9K=N=_6#daVg zwnX(GY!VphKyv>U>vMFlT0MzEp3@`8n=9hja)fI%s?SFx zi}Ula^>esA0UDo035s~ABwx-C}lV#jeY7=vYnr!D( z^`sUJ>gy-nRW{v07@mQ$tzFnwxChkrW;QV!J_6R(ld8aLiYLCB(} z0p=vmw^TlWJeF-0uI~%1Z0jV-c;=KvswyiVO1xh$&^^Od z_B`*8&LC=0FTgY|S9&k$kw|T=L1A56UF~+Tm6J{y!+GplsD=GlF-Jkda4Vduo_K6= z9Yh|JOlt>GQ@3u$YS!EvTEA*8WK;4+T%9Uy7}LI~V!}$MsUMq?cFNk8-Fc<#i7HBNV2sM~r9{uD=L>sxcno8) ziL=YY@9z3BuVdW}L=Z`%)okQ>oS88hXEbBs|D0guPQZ71oS#a-+1w^&qsAUvnx+ z-|uXlv!zdN^$1(fa?Vrb38aS%40P9Y5E)ca6a5G5KZm~NqW>2lSU%o!peJlI{`LowFb5_L4PjO8Tf&N&XR$9~JW9o%v&??@ivHJXV^v z4I`cTnC;v}-e}Zl(ET95h7vHuYSNr0Y>DR(f)^Q0O}?=^mttOb?ClqbM+*~G2qBWx z2BU-|ylytpP>mw!)Jp+*I|6h3X$A(3tV{~Gb4|C_K4A}(#y7d7P$dL}Zj&xu0%D*7 z`R$M!HJu#y_2g@*=jq;j%LgqoMCN7*?T@GdmB2h$Z(OK@*vHx(6_btzO_tO~OrAZUV&{RUpwc0QvZ_H*pc*<9 zTpCq4%<1WA4a$JW0e9}bYO;=+$U`lu+~cRm3h2NS^q@{-H3up63Yo*N&0$O@W|$kd z${7#)mmLv!;~FR;n9&+A^EaP1?T<4^$VL<-@Bhs9OEIQc*}OA=Iq@s5#D_Xo2M0&5 zm=O7lEGiq3wapx|6GMb(GHUiX<<;|~pR9L{HG%$(g1_tQkZb+o`2A*DsR*A*nY+X3 zF4{|c-jO_i5_kNlc9_vtBZ#PVr@6e)7=+9X?M{IJO_TOu#=4|v{PVYUCh<-3Qt?*;2=uTPa|wU#*QO`91?hd?r~3%5A}1B zpkF>i>lva3L&EL!c|p}BbRsGXgYNc8Oyb~o($*#?6yo4AC5z>Vc^k>X_y+0QwYeyyFaj}RdE#B5mGQD$Hke|OW zN_L3@zeHTHlE~6ro%0!}q-oK+f2D8H#W6i3Rj!+_w`aGTt=<)~(%SS?gXyJdNC0W9 z4P3Axt`EpLC21YD$MUqq*tIvDj4&IY>VgEq8`LA8xb?_`ivg?s<&<3r8p-r-+Oz!{ zD7LRzVK@_Nnwry({0Z4mOAK_J#vqUYkcpw&Oe(OVns6eAf1tsbK!>XVEUDcJe~fK6 zlU=tKAovRR`;GS?mfyh}o`~7}I3$LHifDo;5!2s2L=%5Tq?uj+Xu918IBeuE2G}np z06Wg#Jhs7tVQ3aCe%T8uC2o)J7}<$A(RsZ_1X{Xc&Kyu`0i?^j_2v8>qP1X+yrsu= z{P?_j@8_TY$}Xs{pV_#(b6oLLvsc(-0P=1gktL#**t9?_1fVf8t#coKl~xU^y12T# z>tAoHw-9}HB$1@)+Cs#l1&`H;u;OAS3|ajZC;fLp!7xJ+T#q8aLS#Xc*`tW{sTW5S zjVu0LuEUB&NltI9lGYezE|@(XM*ar3M`jR)S(i&%-cZt*;)tp}u8ChP(2Az13tK8zE-pQdhemfZ4v zM0S>@^TgKX(XBbY1qllEeMXeqZlR6iIRjq1ZIQa$=Y8AlL_~{xDt7-QC?} zou@IsexDV0>9e2f;h=-vvW5BYF?QD1z{W9Boq%QAX1c{qf65?n6ChGId5jX-1%wSc z0QFLjz2xo(^wSvJS&t;)F4rs;Dt@z;?7qKnwbTDacn7F=Eof7sKkwYR<68gYVf~`r zoYg0`i**X$eMDGs^j#1XLFtx*fr1TuRE8V1 zIRiMq5q$NR;3%DY+Rk4v6>R<6e&p@t6~E1|g2-8PutTbRloi*&m%c%g;No}U zQ5mS``1^zFb9@4p(u@<8Z5^?|qF(#(ne^lx&3dM~HEKj3Wk4P7cj(?RRdYPOlVMzk z(wqY4dtV^0sCfRO|f0A|Vr$^#3NgMN4_&@7D7?@lKgU+f3Qs{cC{ zIBpW4xMY@=I)uX1vih!9cXbNyTl4FMV{-r_k!Zz2po*$d+{Mj1eExH(Re13 zvRmoWf97g`gR4u({wK9ZO4mR79$-C>kei^riYgtQVPUm`kbVwGfwHfS9ZTFI?~4~x ze?Sb&9^E2i0}9k*M4%p?mtG}{@_?W})@QCs6=O0l7uu4QmEAuimg2J9~S5dIr@xJ*u?XoZ2AG}d2)jmD;w+6@_jac%a!}Me zG`gb+Az#7%(EXk&il9P+{kvS^wuD+~B+{znHeM;KskvFsR@-8k4afj+0L^z2f@-BN zQPy%NeI1)8UJ4`|EI{fbf9K9MAc*hbUvy9s0ryC>mx2$m6mOlg`Q?9@8y+4J%G6ZV zRR8+MuZ!`suDr4#@KaI3+u$?bIxGTMWcAYy2i?W^kbvG3~>H2 zxQ-|~#_mi7wY9a)5{o{HPEpO`(=NGKj{9OpCT|lxS9344X~XS+iGvI*e1-t4o%BZ^3|YbPY5Kvh`c$ z`$3!RbT?2VGM%mk==x(P+ZB>{?C$*^;l5ylM}UsU45d65COd%AklyF4<9}#D(#|I~ zU;pG!u%Zy+GLb1VGQ?2$`1qvn-Mvc>guRbBfwDS_riwTm8`T1W17GN|yS2cg3U|GT z9w6HTP(?HdD`FuBEpUJN((C%g7Q_v%oG<0T+Ym5`{b$d;MLV1B1wo&d>Iy)^t~b-r z-$l%g2g0#$r!-(E6yPqGo`O2hYZx6Gcnp{Pc9sdABTgMWY0xSjl`_jHEuCggp zM6`AP6&%FJu>Zya9oBN`{JNi8A4^xM)yn+9>3h6Z#FBsc1ijl)9htkIq6;_*6#^H( z`qPm@wuF~DLh%aL%`~<&78m9l++Qyxz-?}8R4n3MH-nI zua5DS!*UOsPF3wz2UB_XFSMPd0Js7j^A2{m6C%sEiX!e4CcMunsGYe3u@}|7g)M(U zBQ%S^4cv%XEqV-%L_od0dN?zyd_mZE2c6?QDO2$ZJkattU{k#3iE8yY&(t|9&NVu6 zIEy%uxU&c&wzMc%tERG}an0Ki=xVuC6MSd`26IYHxp(k zYZejfFOCpJ6<}9ijtm&QQKvM%ye>R())FXijhpZ(iX}`wU4v`gWKE=7TwxSFuIO$m zm5b2a9wGBS)&!87cGn=Xc8wMhtN<o-qaRmXrvcNs#)2g{E zKN1!YhtKOLDyz@C`Ah>~8j-d4 zzgKswI~mqxaHWbEVk1a0@PY$0z`b*2RtofttEGU2vooW{%_3-Uw{+c-KE@c!BXHDT zH}6?RlR$V~lU^5bsC~uPY)Gg7`gS%Xns>zT;$XRbJpYFj;jpPa7kJ^p#D6lTd}r%B z=QirC(T}2aOT}e*zfPUQwx(`H|MKIVKYZIWe%kzk2(XBBrbldJTUIt zqYIeYqkK;qcOqYTofv6K)0q3_9+ukXH^+#A&HUoxYe9Rq3tT-`IYbQ?@O*M0PND#% z|K!LlcVu6vIGwf%?n+-$kdd)82)Y^ib<;r;a)Kx@I<&j`&*NJSt87X{c6j1`)TIdenZx1!&c+OkVApbHl>`{UcjKnXa()=RwiY-GErM^R`0W$^`*{ znkPokXH+E^G_#*>AAa@40ygz#VPWA*iO)L2??BLDttkzHNtJFoK4ys`1G9D2Q1`kn zwU6eGzWCn3RI$R$&F2%Q`K@i5TNrY-`ReW zyY=8Gjlbl4t^b5aI=gTG6|AbvK-S6rCn$FFIvGEGzpeqKjQ?JPh_FLm=RRrqQFa_W za*a_`78YKzm0<7n(OmMi{7$;~G`!rTF1mk|xL=mZ?-I|RTEHkR{-Y})Z7`4xv7bQ* z-b=3Z!3;YAQsnmwp_LIdZCb|{WJO>a2Y?C%I87fybK5(+GuIN$rnGb^Jg9dvD{TY62dh^1#5!(5Ch!rKS6D z>+TOuZm*x=xHs))r^k~<+-qn65$VE_upYTi|P8-RLxO3c{HbsSLGN^kSd7er%4cm-iEzEaJgpJ(xC6djfO(iV<{{1`K zD^Gn70q;o>x&03YaNOW^l%rQtpRVm5t8bOpMK0js7snenw+(UFA)bP!S{MU3$j|}KVT*H!ZXlZ6{;>whv8cQ5E z8G}ZJUpmdb=CCaG2LXZ(i0C~^IM$&LSyXpq7JYaoILqmIP^&M}(X7E~3xlh(M665Q zJc|#+jaJXJHoh+qxa-7R$!h=iv~TyF05ZVs zQS!KQrR%Z(gMVCxc*Pjjf{rez@P_K67Rw6+(qW}_+FnbY- zM@!IaRP}xQWd4K%xDwmN+Q!u7Q6F>ig#ZS0BoKfLfWDT8Iybw}8XUjAYRke|RGU%f8^KF+S?i8oKPNv>|cTl-DTWUzJ*Z+*K9{{>3{v0UG*pH=DC0Z6DFT@xKH3!5yk{ zL4!blF|8 z3@g?pP1PF4UkN1q2ab<*z^NR0pLkDxMoZ$ogn_0}(3#vU7sv$5^Rj{sVbkdBVKvFlQBUhqHmI9*g;4HCC>~bf?KH|>*s!gJL;9M zu7~E7W^$@#puLjX4?%#W)!udzzFK;(qN>^?4t++bg%E|nd@8sK8M#&w_q1U+YCkK; zVJ2x$k8mxgn|-~XFFeirx&D*SeNDvVcTC1QC@r^AK(9rL7Dwt$&iB6Glk!&DDdGD~ z4U>HHk#JLd3kQzZJ?X3B$=vv7CEPi+p?}@w?<9ag2@8TAk)53#TbM?~9FFhFcQ$oV z*}=K2GBZTFU*oR{JOEMKQ(|$B@yGr1BY(2@UA^X*FdhfzQ#IghJ;|?&B5vfYmD;D$ zK(9r9Nr`=2pSEDrG_kdXMeRH5&NaJL-oFu__*TVmcXywZeyh4^nprYbyn&yYt-QXl zOl?}P`*=%TU!Qs5mo-1fpcCXqbN4mH-Mbsa*Iy6eWH*u zbY={~*9toZ<%TKT&R;5Xa?G3hBKt+za}d#RN79Xt`@a`pkD(?geLLXg4_qUu#8KPR zFKzVYE2>7XU*2BuMJ0hAC4#naYqDgt4*JIT<9CW)7oRW|35+BiWDso_eR>KP*PUaK zap@tvPMV{xSK<2413+CG9(#3lbpoVF=d+^sDDOaqZmSPk6X!vZ^T9VKm?t^5Bod-! zVb_KNJMti@|67;4ujEd;tlY2T22u3@(McNkQ(QbP9qT0$+>qAh_rzd!kdT zDPEEKxq)08VGP3*TEg~XC;o?#?h*1sb0sA``Q!aZ1c+E!2Uw$OuqCNBO z(WPRIE7=_eU2Uv8_f8}~c>bDl&yKXl4Xt23UMh2R0}|8fB3QC`Pj8ZSaoW|&eAcdB z=wg~nxM=8s)Q^IsdfH_F`4|25C#I2jk#qwTRM&IH`ZAK7?md}e;ha0cE9~~63-@n} z{&F(3;l*E34Mz;L3gxA zulxinc-s`c@iI}k_1gSeWk=x1A}ZqXg|?RL+s-PP%V*$qV9rx$6OPsJY?`)X>iajh z1PlqHDb?DgApHy$Cz$Kvy5%mGO_-T=&bP1C>~oeny)klsauxI?)cjiEC<=7{KhKBP zytviW)!_{WUjw5;i%eiNZDWz2K+CV9OvYxE+7;I<#w;og(T7%;2@+nw6N`IiuS$?a`LkZNWkL(dgDxNRa`=Tku zVeiyFjdvYcT#lw9inrdO?0vEMol`Kq#;FY%ZCFXlWpMD_*$=a>EW^7j@evUbpJr?9 zrAI%^ym)ELSzYji?ny|N06j7nO*5p$WCZ0jPs^7ZFtNmF^r zl989+m>d2Hb+>6ZUKDk{gq@8vbr?MryN|CPr@ClF(6++&cTAe0Ft4MJViTV)wCp7^ zB8Kpuo0`XP(R6G=Lc6Hf*Vnm0OT;60Y8fYv4HusO?}4;+J~W|(a3m$yfdx7eDR^%2 zZQ#G(0w~D0vG1f|uBj@sacZ+!#6L5Sv)fj!Sg*LMH~a;pr60b3%U8E%2C77Q-n&&q zXr(-wa$&LSayg3^%jM% zGhIvb@jn#2%V*ylNO3w2!X=^C!V%L%!(_*c)tezrI9qASPOKXI%Ogv5ubna%qA(>~ zbnho!d|l%?Lg<~qnxgWcFeiO^`61l8q5(KcH{DSw7A%Pxdyne4MxXhuZQ-m_Rhh%+ z7g1z3< zj?Me={C5yp4}9w-c_39&@b(;##w0f1QOec3*}hBBr1B#^PsTPJ4Z=qVygtiI zj?7XKr_`HB8GXcb=CZJ|@?uuK?pDkf106Ge@sr}VjD(g|?-2D~R503l?%hj$eyK4M zL-YgHFRhOm2$^&eauj~n^*H6pKnpZ_$GmqPPep=`pGLpCW*Jtb#?dSL^}us9s8v8s z?50TEw57OG;Fm-s?biNI#?9=iU~=EibJ8uWSWul);QA39g7(~}jCePR!J?K< z&fC}ciH{blk?YG{7~MT%O%x;91-ir%oA0%MJ4X9=J3ua&(oruDOf;8H?6dcSF~*b< z`y4ENtwKCMXO3T`I8IU+3tx&$`dMqT+7(gPll1FFIjPWebx#7bUZcfVF0YgOzYQre zr6?K$M`p*`?IAaEDAyv9!Z-5SSIR}BG_1e6i5a)_t-cAIPFb4rXO2@4%W2yLz6$!F zyY6&nLe^D==H}G>=hU!35gG2kE5eq*fS4(sf5q}spyjI8YVu$_C>Sw298q{Xi+hhV zm~Ug9ckxWFEc0P;QAx>=c9R!}mjUiq@Dl|Q^NpU)qUSrkI-R?pjlQ)&cw$gz6NSl= z7&5B%XSG_0%tcyqSFd06meGD}p0!@=NG_=Y^vYC6%IxEl5}sI41o>;Tub~ecGczhG zoa;nmM;lX_%;T+fLgwxWgi*7+jrb9Rs$*On#EHh%=K>+{XxG82(m8RSBW$zgu~uRW zY1QOd-+DGsrf_gmF;SECGg8J+1#Lt4&ula=O*Qd}Q>2$kFc2la&A^tCdW&GM%evpGBVMXIu0>C@Z0W}9 z&5V4N(s?Ui5kIr$pOCk_k}gsvs3RokX)<_IusJetkfeVzr%d1Wud5yutf*OVimzDV z=7AavRw57CnYM~ENjb$a?t|3EUd5ujJqh$tz8&#pThln}NM78y^g5k)7hf-PLHtU< zahTZ?$>j;sLfYE1uP}86Qp+iO zgY7g~wuMPvSZ;{FNxki$VVGglRoD@~ApZ-c@jo?ali;72IB<``*QcL6Hg zdM^kt+eotdHc_Js_MMEf=hmOf-tTVa)s=b3u76eAzJ5@xhabEvqnC$iK%epoW<4&&T!bbvo7450P*P#t`hG3@_|MhOh=hp8>fExpZn{B1LAR~gI&&BiGMCa*y9%SwjwcSF z^IYKd2N`+Dj>@jDR*hxENl{Rc+iQ^>_p0U+*BPg!)&QL#v-!_Y+(uJeqXpbX0r%PO zPl~?(9|thuL*_GI6FBOoJi}Evrs~+R+)nhtvxPio8iUDZ_R%;E!Vl@kbe&%0GFIw?prnlx+B-qaYMUEb6Jg zb5n34AXm71{!7QDqK_Lq+MsEQpg-uxj?PUs3->9t7o)2953G=&8=|ejFLV6|z)vkO zYk`JkIZw|zzRA)*f~~>>)|u;uXtSr3-$n-18WUMSduRj{wzhr4Q6^`1Q>&?u#yWJj z#FLe?J7u4${ugJyNOTCcZfwu-znF;>z>QZ*_!Y>{T69<`-}6-q?r!Lip~#RMIH&jY zCb)wRz&ImcF-X5>O4{h7k96k7cR;J6fyzMmG)W1U^p5E&v!jqPPRN>`#iyOWKg585 zdGMMV@oNvF0Wb4GgRu-YpMKA^tRZNq8?v;t?0J2$TjTuta`mY^@%{}LcaC3{2vC|a zAgp*%-pg8bgh@Lqh2bz=(AxR4jJsXqKYT=tI+(((oPW3)&S^K-{rrE(`pT#(w{UCO zY^1wGx;q4=LrO|OTDrSaLKEtR*>No3N&K(6%7_R5$x49HTBjVJm{6${Bk@8dV12t`i4h*=U(L7Ozr5ucoPtVs zDn=Q24{Nj*E8Kr?X9 zAqo^%;}qG+j*Qv88;bINoXmKgI%znVygC0qy(M>%xx<^8?bX^%dl?K0F(DS^NvS&9 zalEvVa|1A^Z3{#Twi(0Ox9%IB_mMi176%yajca{J3XsIDBF%VM&Yr^W zHS>}wZ@h$6@96HA!`-j(vb6uRu#T{kik!fkec8)!3LM8eBZvkTTfKPBj_!VUWWN*# zd~vGUOsg_A*`FpMe&?kIA$Uc?uGeRK;|9N{4MJ!wZIx=oUiE#&-03+ zIDAKVWt43-as`ZH-hLA85bU@A$&cl1JHsI+vWk*#=30zBp=pL;;(OR}gmkDYlES@o zl9!Ru8nfm^VGsM^Ty;K$|G$Ptj8X*(NK_n|bRa+=>xeT`t?2N@e`Jon*-a00(sp z(B;OEKh_Utz3&d-$@6U%GLXV)0~$}e@&?zc1O3SecGc}wBGv6DA4yfv+e+dd!ePf5 zIK?lb&e~|4Y6p#{?oPfcwm~6%L*e;9k2?W<>~yqF`KqP;_n||W$lcZ0SOgUresz64 zuc=14$Fdj0*{^R7F!DY5xmIKz3^x?g{;R$+B+L6pQ^}QTbQKJb4rfgqoX%p)m`_tJ)R|3T$+54_}4zcAw9*ZGQxT-JvbIT_->Sh9#zE>=*Q$T zWczTR-E`dDw;Mo6~yfL_qe8WW^+=Kl}wMHB0f@o1lWntY{S;`nFr`-H3 zEOs6?p$q(e!x-0Jo+c4yF02ex&;AA}AJ9)>sxdbdvIDf6jZ9GT^#Tx}QJbV(JEG5;06X!-@l5~b zWxV;l$_MY&EmGy+C#%gsEdu9#ZEV&pkGABw1+FT$^PN& zSL^n8{$A`@rr0*qtcM+cA%Fia3L#uHi$P9PUd<2U<=&|1J8sm}Sz|ztaD$q`R7BEs zv&;7D2BUWbLG1~T?~h7&W%uzfg=~_M`CKkNiqXU{(4+oqKg2p6AbhkE*eUYdR3*|v zwj-xz6F7%F&ebJvMXx7fsS{o{*a2-5Ghc!VC=9wXRz^oTQLq0aq>udpo@4&2HF;6j zdo<#|kH!EO9*M%Hy=6``I2LHXi{NQ`df5Qv78Z=K2x`Z*4L*qAuU%8ZY}|+(L?)J8 zFF!83kUd(HG8$3P{h;yte^qu^@!kOvQK0)i+CDU%tmCqebMISfT!np5xo{u+o;qWRlXm=*VDXXl=3hTGAPaHUV;R$U(lhwT8ZB@1#O=@R z)u8svYv1mr<24_Bq{>8hM1~jma7~2l3CNdgq;J!{Q_0V+0@<$RY$nYAt^+G{@6MZL zDSB-1wll@=pj*$w6k&u)324{Mz&e@xS|mw%dbtyarzxxgy6-uVyK=MLP&P5ykor9p z#lOw)kI)BLFo53L4q+~>s31RYTYbzno=3Xy^y2`XZ1?bYbJ&Geu=S+_=xqKX7$K&t z&Q?`_0sJY zB{ezM+#ArZ2^(9Y{BTROr3`MI|bq+gIfFJrer&?9T zU!yToG2n4O-p6zJ@Cxz2AkBZiU^qP`M<$tY{-$@dmE2iVkgnfjDiYY5gN5>adyH~A zExELKP&k*@FGzbD<~ z+jX@Y-ud-wn4@DcIc`Y#KQTY7;{bns`kkg$DT?s*m{9|W zkp?D{Jg!c+qH$g-C7=#Xx&fFVz%DYryVw7_|4=}c3doi?5!Ys&M$k7wCg|m22+TzW zr@cJ|_63O%-dbPAAsGO4f5`4vQ!mn=r>D9*MK*pXeS|?gXXo5yB3e5KlT42PyQM> zXsmzqQM2pbWL*S^eOd7yui;nF-dl}2x}2($*zbzUx$^Lv`g2Sd-5LL3L|_jQC?>`c zeV*kN<#?JP&;#T>(gd7=ZjQXE>d>e1BNP;re%+-SRedAo2XGt^96bW=_Bk5^)AU~L zPkDs;u?iOdrq2Kjmj=XFyu+g?XZa`GZYE;=HoYP!Q8@MmamTb;g<7I|T`3&_Q)(Kh z{jj?w8Q4`y&Z_^f65a!dI5lPLd+c(pR(b)cjq7JXlPy-bh4F3o@b#B#thKFqGunsm zVezcyfc2|A)fZd)E1*Y)_;0IV{b&_ep~!K+@=@GOdOCfj7K^J4~QdMe@PV$wmF&t3r>hZ z_LP&PDfYjVl`>8V3jFIHmGHMs^V;d*g+I{_K0Q3at>=Z>Eo2r1a@Mo2+RA}O47UDr zsjbS=8Kf!uOh#gYnpgyA5an|C zokRv4NbK`?*`U9IE#JJ9nl<-5BzSnzY@^v+kJVa1QE?Q|@qL`GdogOs74MOJ_nRC` z0Rq5`zVu=>c3wO0JtPdSCsQOGI(|1;Oxe|J!nDc)>fE(M7_Q4!+IeDAR1A?>;SeTE zzLI7ou@{-(>P=5iQw&V<63snS0oc304j7m&YF3Wv$TcHvp3u|N)6mT{o&qPKXE1cS zk|aED`(6O~`Y=$2%zV2JuU@1bZX0OoB_xHfyM~gni^7ddno?vH{kp6jsnW6Xg!n0h zWJ;ZWqJBZjbzamG0C&v7E807GgHb??6HaZYPl{^6ber{yXU2s<_5k26)~S^%*3jwJ zXz<017MpWZ`U$=c3ptQi;Ftxu;9HVN=UQCqlS;=Eide*nDmpf5?Xt#}11e%*UdTwd zS*hJv-Q3T$CmmO#<1k&aw3;*n!UkiM3&%##05`V(KO-xtUvT4O3n~TK9xO&Ye zdP{({8N?(w2aYWF`_5A9)lcSD1#Kku>2#Pau<*NAL2QiNx5iT#Pk#+^c3?b#h)O?m zV!DNXgdv4%iGveFg7_FuF=z1OOuj|_JVg|F7E`@J`=9g5Fk8i5AXG*YfrGMcIv9Ug z4>Z1NU4u1gA2q!EA1HY~?vo1QeUm(Sk+E4=@le=A+8w~3(xeTeNzOVX@<)*zPZIyc%lzc^!g5X?*hD8!Zu;*sdL;H5~vguXMJUUHSW;|^R*U2zW{(> zS2)@1Ji*IvS%$*5PW%Z^aTD{|!!?@liZ84^k}gznhtPvRj&e3m4M91-LB@KDZ22*L z5uKC|Zz#kzy`BZTo-3dz%tQEevwqO*WC1{(m}y&aoIZ-BGy!Fsalnmy_Cn;!G-sc` z$$6XogGdX7(lgJH=f`Qz5RefMcL1EabU3>v&vhk!o1;16YT~B|6tK^bDUWN0&>CI> z6+p%Kzqj3e768?#hj=DEzr~Y-;txFH9P6j0vm#bC4E07?m@uB&)GF8k{V8s3Z{6&q zcWR@(nMFWa*EDy%<2ZyP7_W}DDjqezUf-8@VP$0ndpQ<{Z|5n59vn^pitLkxeX^8@ zU21!utt8EKy;E4HYJd^K@-^MTTrJWPsLTO1;$LJnz{)eL7wG=*>7%cqZ8+_L$Op1~ za7%0?9p}$*SZbawY8FPrDyUXmBH>9idB&z27)w__=>!xrj7%C7Oy{jvMw`t7Z9pPp z^-XC%|HqFXWc#(8Bn%!Ej^-j%K$NVx=^px-&;|$yaa=kpPj3X2$LVWO1pwF6KMWyvVXY=i^Lg(eq^ zFvZ6G=@+2orVm^3Ny;$gi;o@+h1$XWpz z28zpJ$LR_|N6#5@NLOEnS4gDb?iYP+0^a{0muX5C@UVV>#q~Br?vq=K2I#nhu4`)K zDow1AY7XL}HE93By`;_M9mB|_L@KphqDIyH1T~!cvD8BG(C}^YlgxHdllTIp zCs=tj8>&3fjy8CRpk)qtzTBU$t(~K>^b@R(g+D+ai@Cm6+Qq|`1zlK_0w>`Q_?xC+ z6UHI=7$kjoTcRACmxz%+W;PMa9ecboP!y4>svH^Q-SU>k9!EE+ zw~sT6iT>`p7D8C@bej%FuJ?la$tYeUl8GitPX;gb!^Eg#PNzn2+Pt3l2}j z2#pBEZLH(UwI-S+W}ZYMuM}O$Wbpnd7S$0+ajmwR$t>QQ$5|Q=c^-FK;viifOT91Y z7%fX}%a954>TJyOJ}J0+=HECb+$QKaU@-hBTIEs=-yB}&$@Dk*b;S(zo-OU!S#^*8 z$T>!HB8yOAi9sA%PozWWQ7YmXnG*1a`@M&~zo5P9GEk6xj)t+%W00+q{lP5$W%7hZ zG{238tmg{7h(=uWXspP!Wq=f%DKZ9JM$0~^3J@hW`f=1~Xu;GY-YefjV#lMWpS$kS z^D<7Hx6cI6gm(imHZj~wnrU`b*LoIo!X7aX(xjly6)aBF8O%4AJvg{pHJ6F$89Bec z@Kop3okW?B*6_ZKY{Pg$}3@#9C0jI*aIdU@a> zKYmlquo>CzFn%r!w;u^`JF(g;p40RnwZF3PSYf?Q@n1yUcRf%|**HXxx7RqLJ2l@@ z#e`v|nCO%%YBMsbrFb%1ZzV}Pc=?UiZ`^&?t#{!{JGCEiy@uKCqH|S7&um&Xn5wmMoXJ)A;cH@eKYjZ2BJJ!c_Bm$ChiXUE zt!}M5Ab5#Ws!1e=A__t)gP4Z8x~WDSn9<;?`+*dwI^Nowa?<4eQ>iE;Mu`|Ev;U4G;N)%lV{>$KuNfP_W@p-=kZ|!rARE(`t})jehg+ zaIDv*uj+d-{n-Wcna@5@#xNsbTOmkVq8VOBAML_-n>1NbB2bCjjox7dhiaIrQ8ULqDFdP06d625O6eG%;I~Cps+f%dGX{~DG34i zN9CgI>(#EH?V|(M=8vVNqGGOQ*XrUol$KyEk`A&4-~D_915rQe=YgXjU;PNS}3-(tB z2gZ^F^l!BR2+iYj)hA9`uZwoM2rJ+bF&rt5ci)_EMT2@-Wi3(|`sd9Dy!NMJ`iXpxWdT+3q_(y;AnhlCxfX)MY(=;$5ojdz zE~huS30cQfESU(&QsH-vR3yQ)?P4Q#N)J)vDDOU~p~`F(*~}i4&kuF4^O92i`YhSG zTw&EGmSBHd+it}rpK@C(I{7W2B;EirE5;092ej`x zk4lbt$Qdr}3V+Yh2y3eCIZK8X>2bnz4^(~o{+ z14us^Qgmj|IpL&oSf>lV?u-0P8{14wOr*WEo!4t+9m&o9ePEFf08^S5hu>y5fUeV) zM7U5bP8CJ?moHyNxf=OE=kv$XXe|MZIYdc{G@?nvVO1V&dC)QaOEg?IvY|;&5KDhz zH;!Bug2TX%5}{n?xQhS!ElWb=AI}`r6v9+-OJ(3TwW}W6=DavR@&X=jq0TOuEg26R z%pKUo39o2|otWBoq!%jqJnMC$pzJJje&GGW#hqWfr3|!Lqjs;q@=3t!xoo{`)ppp* z)YWt|u?KY9ou#ic>9wHz3Po$+Cl6|w#KuKD05pg&ad5i;1HpJo7yakS^MAf)d zVVR1)VY~0RhI=cT8#S4ki&kZ>xc>7ZG|h!)YiV5@4)+Y!CVORIV9@;f+&b%Am}!(v zTRY7aNb5g<;zKFbZ+jfydyQddww+AYD%-}SJVycpu(ZL z<`TwjrOSVmlqgiL@VHLhk)ID|H+9ZIo$mMqs8vZ~gyBV5i>GeB1kZ&;o2{nk1MMz@ zm;bNWR(*ntGD70E|C{BFVIvjgK{ zB|tyPEmXWms!T(w=3s|xD*=5IW$OTT)4m#i!i|lp&AoVnF=hIyIw3UI+)rnR6#);{ zA^qY3)P_Gl5)cqnc)|4cSy))$)jzqGM$r>f5b9M!r{3C{=qx^_W*K$=jyy0~uaR8g zoRYqaZa5~-(dIh;H@qpMG7NZJVObtwc|y9-fD~5E{>=@fLmJkb*%D$uwCQl@@kx5r ztT(FaT*w31iztn0(2;kWE51esPJ@0DGFAKfz8J0^tYqBpdgj)&?B1t|QW1LMJp6s* z46{}4t}`A}ej@d3sO>n&Qt&yz7}q3sa@G5INbcKFyJbi=F;Op>xwLRowd%^oGZZ*! z!Dw1Z&OOXiI%O+$kTwN{NaQfKcRAk$K028M;e`7-+xg^#?P);t9F4{#SEHXSm&AE5 zlJw3hB(`3p{gv;6bF#nJ?^`!USc+ARavClNyYWMt@2!nT;_Dpw}S6(_CZ zp@>t3f4=f)LG|DKJ|~IZ@!ouyeXWL(%<-umIg));%Hw?ABD+2%$VCUtkLXU(LmYn5 zC~o~GSH5&BkE^6fh@G zSU~6JG08n1!s^iTy4ng-s)^Z0Uu8_*m~FHq=Yk{FxrkxLruV!vdVWoZG8&bTJ?i_L zpFK^Dgi0c~_gW4zbjNK+z7F9J@i}7BjV3W}PGBIZ7x3@cXxU&XOu!&CYqCF4vs+Ve`o#}rRAPrb`C)a@pb5&>R<8tsaQ{5Q z87r5)f`SqQHfO+7o%X&=myznlKr$5!IE1X4rOEN7h>jy;(%uwgj=lF^ghsy7(P5tA z9S`|UzVMW_oJ418_U8~wWgQ5@n{X)^pg1xB3m~snHbpz^rBEZ3RI3={1G39_&;@2W z369FvS@_BpJgY`-D}@#J{B^+c7h#9_8aYa6ewo{Gngdo zX!R?@93qcTs{Ee9vPI9K-5Xw01$bTxWEjR=jYCp{O}CNL0WkBL_D=5vG@*PyR0F)E zkCs}V2xc^56?_l^vCF5?s^0i>8qSq7$ukYC?&u56i2e={X;GED}_ z1+-FA?-)hq_HLThuP{%$NxD&By5_EwXMxIJJ+{{qFW=6z$w>cxzogwepAc3t1Oj)F zsqNdErY2V7Tvi`GzMsenQYl}~sf-+VBr;7vF^vN7 z4}JWtf)39)RSO3thG{Dz6b-Egf9CEM;BoPfhqQ~vty;_XKDa7)9GW0T*#}k1e9C12 zDFb<%2W-d$N2h`#Y!Z-Kc0P{oCy&F0=`7n`fKkT9+`T&Ztl-R`o`p!wV2Vn?bIJ?~L{`iu1cztSWYT{KVa0pK6kxJRq9x46= z0Cu&@)=%4}$;ilB^SSgIf0$l}fKWdUMyn$KZFX_tn1dRgh@%}4k*KIc=L^x3RYM=v za}+y2nhrAX&O_|*Hl#&{Xus%$rc!%-NkQ=~m9N{7BzizvEK7@2ev# z>9F&IkE8v+)Q~HV5rRRXYhd!ljf@VA_tiEy;31wvaaaU+X3I|hl-!@w#!Yw2=h5zj ziQXE8>sm6OQ^H)|NZ{7@zPMh$Q=uebS|BO)ZC5;+r5Y&^+I&naMGaMbaZh?~-ub$B zSD#l@)X!>cVvZnRk5qf}R{N9b1c{xE&G1C6-KQTRqbTVvqUT>lD&V?V7=_~lU(aEl zSDSpcRnQC=-aDsRrZ%{G^{-gMAhbr>(<-Kqx(!IfxPm84OJv+-Bs2WfSLvd)zztQXIo8PKGSK zZ(m{x4_0RO5UY==n31Xq-<%BQ%75}i^ ztK$r;nULMZ0B@t>zNa!qWRxXAwP(38C`n91Oy`)pc&VR!*M0wu`Tvbyvkj%E>D1)Q#zM82#TaO~4#dYG(~4;cI`U*?3HNz2J}}WVXY| z@^RYj@ZMFYUZwMWk);@uk zt6NU|X7C}f2A@TE<&??#dnz(#6aLQbCD~2InG=T)@&_(lEq8+n)Z&vP0X`U4LXcH_ zmSN&t>{}aiCFm6jTb*+wt|jF~@+K800qBFS$^i68|{4ZeYV)P@M4Pu7?q9bN48RLD)*vsZOrW){=bqG5s{VS^o}Wo_ znNfJz8gSQL#o2%E=Dl$l`D1>5sl66kLA;jOFocIX8Q_Fd2`4kX>Q0c^N3i%@V=;Il zq)O?8gNP9S?rDR$%;WxLJ?&>{Boe(;nNWqn+Rc%-4jxhU^$n}<@nw=9L!V0Qdp*qsYAGL*rOkmFF%3pgYP)bDA;8AU(Lku<%AvcvkRf%1tTZ#E zHS{nOeAddE+&~0v8O|D^U{3!XUreFI`q#eE!J1xj?ASn4N4F-BnCay{lMtrN8p2JR zt+8=&Mfyq2Go}YttFjv+YCXx5At@)1ZnX+r5ptH)5wNk~ERaAlAVd+_Uo0Wc6a@6( z;uj@c1-fI{$GeaSA$=hcQ9K9&nW%!|1E(1Htf`l0iOI>635GK<0)kPR^WkDM*sCt% zA18H#%-lp?jd}eiDpx;!}dKf_&&2zO-D*BQ4k~VLgSYRl(4LG1_I% zW7yes8^wOMI2sn_x_Z_8P%Z{rXgq1ulUqGzKtYc_oxmjJm@BZ#n;tuWG@k%(BBt#B9-odsJ;3~Gzp$-}wxZRL;q za|8@#tz9ff(r9loy>W%{NJK$SA|cWMpCC`Aiynolo5@1?LuE26fs$uXa93Rhe+!kS z=`zu5P1WY845^3|F2a@1#$6X`o?n|qvpy4RB+?W+qWehy`qS>IrW z6C$r(@h(|6L~=jlviX&Fpda@0Kv758wWn`@%VlBX@FY6qFDD?&tM>C1L*; zRVPv6#;5wG7EVu-*j?4wb8yEuo-<#Tn7cc*&CYPcw82sP(3k|B)i*x4Sy~S|9`n0cW^9SGkPBq)_<4HCT;C!9D`g~Jwy>`qdhrC^=&z^qGV^VQ*ph=}qzWxu|+zSoTJ+xB-SJ^}`3l{e1&Q=&;#aqxZ>bqxFJE-g3`Ir|$QYm8lJ!%n zd-fO&ERu6ggRW*FHXL|ETly-SS@!g>S2{y$^DF72Q3qf3B2pg7kw1T_srdvwPvN;V znX7=kN%cjvX~i@zFgNqh{I^G{HaMO|59ewnNerS?_H?6ZC}|VtACc?3x^}r~?UJEA zvv0OY$&YLqEqnp~3w7LMI5eH%!-o>!X$tCl|jldYJ6hTRYC z5XA6p=_B>c(qNM|LXUNsejFZ_2O~Q(J+z2Wd1?PtXf5Y+B#&nN%&I)O+&YpeS@(fD z#rN@-Aoz-jUX`J?qP{!1jr95Y27GMrZnQ|9))54lMVii4r~$7mcdIBV`-UMgDM~=r zZFVE{lbI?J+Y<$w=JCBoqDRGJuy>PsfRdb>A2}evI)detJW#9Lh!F|qyOzTZ%)`@F zqmS|OHy_(ZKIa5ir^NPu8O`MROXrt37tsuMfk1I7yK3vC)J&I;SC7f#Pvldr$XgL# zo^$Y33ucc?$+3c6{0icuAtufwgD~`adpD3ri%6GbOMsPG>v9=&s-F*B`|yyl3s_o+ z#DgG%sdDocEk!Nz#|Q<@R^`&h!dG<>c_X7phL8GOU8QlzW26zwviEr(pW8@loKUa6 zfIJokN=_U-!&Q)uBXFeA>NZUzxe+_A91E#Ao(mxgX+9qyad(C5dU)cKU;4{_#L(@v zk}@(a%!g2m6@KJCwdd;Yg5yCu8%F6uQc}pot0bb-zmdbGa;^IQjtjm!wtzq|YG>_^ zj>$mZMthJ3a)P}2DWeu>MW{AfS9YR})5;L~&`Tz=Y$uNJP`5)r6t1!oY@!G@uZm$g z@9TH?`L<-qd~lkchTU+L0Iof3JcYH+xhU8}<Ak65huM(?=u2^GBW1${@d*N9mh|5}HC_aNdAR>u? zDl>MrH}x%wOwUw8B#G&MLE^~ZJe$gUZY&$7r*~bR-PAQ`aep* zVN^b|(+y7X6=}a8*Q-MFInffsK9I~$+NUu_`Ah#Czt{p-nJ>~C=^cM_e%W-vD4&PB z_^2y4<4(H)f+JBc(%MglSo(Y*0eTv?(Bo(f)L%_$Ft^r+T`e=qKT_oJH6^!?r9xfZVQ_zNM`DLN` zv|$H{?>4Ua4!&rb|BfPhQ*v%$VIc%X79Wp>on)-Ey!;W20o-$-fpqswO#y2?8cil~ zWZ;ey*_{^alxtEqRJ)4%mLkB);0GY7@bk=|(^Wk3@-Q>rByh`mUpCoC0g=G9wRfn= ze++2Tir~yHL4n&c?w} zTV`%qo>joof&@m4 z){|#@&1uL9vMtWc?~yJ;I@fx_A~{{u!&j1z9_fkkAEXI-*td}KocmcB4E{YlSlJKg z;mCtk&8%@_FE%OhDicmzR3m`2UHM5~H^R>@9aj`{<3lkFfrmyfyWbk>{~nwF1i(N% zo5loXs~~nnZ)7?Oy6B2EN}gK}hCHONJ(!`$KU@NhwAuF4q)N-f5Isvd2FM1q5d)Qi zh3oibKYAFKzluNMb8?BN2<>5aJ-7C^C=S1aGBeAY;rVY=!t{k+e$%Yf7v5!K0<~0F zuH(Ogbo|@0(6w5`^U09Yt3dRO_~l-ppZjql6+Ja~u&`SSk=ReDaT|?_5QASrD}gVv z*1hCgJ%An6(Y>NLn16||#r{KrFBKJiBebId3>qjHmeY{dV}SV4bh_okH0M6&JRJ34 z;BPk6E3sVDZPZEQv%^5e{ux%g@HXAi70yf0@MR^!C|Bm0IxHlT>?DQ|jhDuz;9eh% zo=ooEnnEhlNhG}4#f!K7TpdxsoTeYILTtFZTUJW^-wSy;D&TN1EO4!py!(A~ z!4aaWa~^=dB-H| zCQgCa!@Mwk_I$_;D15l}R0P6wSx8*#emu$dp9mvQHB()Cr=3eo+h>6QhoO4gXK*Wp zjL#~h+1MeA{gAF`m2OR5h7h#%ggN!>J-XHSS?nLEtKKgHr5*G#CS<*SatH!VCaP<_ zWVDljKHjKf(ch?Gq)6qn(;?Tb-qGPTjw5n0N7)X`2jm(WVs#*T|qaWFau$S>> z$`vTaQ%-7dU-&9u(WoNLO10~m@Gi_c9cM6y7^_FEJPXLiV;v9(B>ali{ovR3zO?XV z&Cun;L-7s=HPOG}!zNPa;HyX1?`z8|q~FwYyYN zx$?Z{IJ)pC=ES^pf8xPs^9WpNf}-4@8LZK_L!{C_9ZVh`nlPGMtq8I<+xil~eL^-g zZ+*bCfv>DQRAOk=w@=B5dLT8EW?jr4;GknMGx{upKG}<(7Kz`!Y%6$n=-Wgs5-^)77o+4@sGo4|1(A zPo~^V@Fks>1v7HdcOu^T;}7#IU9@baR_8szq^6$#R|}v^)n|u#iOEqSVIxc%1WcYM zXf$Z+pXS2GVFT$0CPGr|xd*B59rr3@06A$cbMm;Q#&mmUkSA_-UpN%guslX@{UmV#iKUz>3p+H<*dZkSWz3o;yM*R?@{ z1XvLP{Mmy5;GG6@QJ?WUe+|lo_1?s|b7Yykner8hodsbZ}r8vQz|AD_`5s6FB;PEQY_qa`K1TH12BT*@y!za>2w9X9FLe7^)6uf zJgAWvZdjG%ydzGm96EY)cjL-Ep47P|#|(+V%E^xeJtJo!SzB(rxsK ztY~PCMKkf-??<3Dp}^&|i!*DbPJf5##`(!BNoeT*eRFN`2R1F=jjSECHO~w(*l>3X z=mHXFJSSSQn#Q~@*TP&LPniwQpV5+`D_^1H!h6Ay8w)7neh)?}5PKk}j&aa1oTH!) z!t)Rue0NuI1eOq6y_Q52f*5ROEyg-bx82ZauQ2lnJsSxA-#{|Ksxf|d^Ffu%3XQr{NUyOWC7fjJAZT41W@C@-_ewi=Qyhm*zhWoG-lX{pog8b zT{6!Ja)-qznffBxH=J0DCX+x@UC{T!G2e{Yfb*LW>7n)Vo^zssBa)HMqV4wAws6 zWepV0?}-k)%v*G1YE_ghM>`;l83AGH_ltK?@1*`YEj4MKpdm(>>!4!Z?@xcXn~}vS zSn25v#c{6avXZ^N*x4RXZ9afgqQy_^o`4hnEc{?5TBqY3lJH$|VLob|FTaAvFpw0L zyU)<1bDRxlNV|ox1CjL`^E4{-d87g{&C1$H`Va7XDRzU%^kAs-W;Y6pk5XzCfBiqw z9F4#Dr0Us|GMt}n6*N*1WF~#(W^+TAiFa2&cNm0TCg){pyYSC9eEO6E3Y#AE%)T@> z%vnuI%{N9Zh-O21y$TD?U<5ihbk4@TCK`a!P#{JD2_D&+1O^s zY}Za&qe&0ne-;`J`t!g+tKYU@uN+qKi9u4{SMG7{3%Q?qeDtpo* z47rm@Vi%0(+ar>uAXyVG`n-0K^ga^G8L1wnJtD`bS*WbFo9~8V9?Tk+sEapNQ!)_R z6X%V@WA9t?Y^*y3RS-5!)7C3jDFPPr!2T{nJ7Hi{e`9qsdd?g8V_F{x0#@_jgU{d6 zPx6rQq&IeaPZP2eC(W|$CYe6Wy*m%1@Vk64m;FxWQ-MmeJJlmSFi0`7Vqq97g6pOF zgTAzmj4HIurqlHU{E!WJe9S4>*EU5L`$C?I>rtlPmR|AA?eCqzFEsVR^3CFlnX?=k zRwlh7PaFXw`IErCZ)Jc&v@;lFBw_nfPGJVu2hy`3etD?8KKJ3zRtB5uvh-Qj!Vj=qqCkY!p|GSS!H_qtH` zsUXwmo+3!T5H5%s9Md_+&Li_t2UZYWx_*H1LT*;QLwy;tQlKn$|8Ad=Gljhy$mJeAqR%<^;CA&F=dK!C_B9$U~5QEbhXzQ^@Q>f zMxyJgxVi=q_sT^b1mm-o^)VmkgL`WpyG*UXhY>D{>)*5?{7_O4`NtPf{)RriYz5a% z(nw&bN;NXr$Ul=$ctn@_#dG2-O8zc7K;Vs~PHvgvI-2{F;_=)bScql}yaw&lTv!9$ z2*H+m(u88};Zet(AN)eEBYls_y16bH<6o4DbPRi*Mb)}uxy46n-7thLYsU3mh_k!# zu@U9V(-Pf(zCNhnVf%k}R;tp{K--^pctt-x7>tz4tbcxfUe7r;To|q&hv|udCJZ=% zz|5f#;d50!+Ax3DWQ#j6bHIDWP4@z9w%0hpc{t0CPZu8JqbO*#dSWIke1*%GHDSB} z)#riPNX4+NU20tPT<(9q02oqY*pi`B`Um@lX)d;w1$CmJd?+-6(4uAB=siEcm57bF z&*xsiMuQ6BhMtR19lSK%!O@%=pXhHnY8S+{n+kLsldi8o*>E;$rP$kr*rW|LVW9RA zuKy_@%tC%SKX6_8HgBuuZF1j9SD%|!oNpWoLHqDT2p!jZyuYR#4qNsKoK}Oj{Rk>* z<{#JLIJ+xSX8qkwjg*v>9Z#=@$o={QfniH4E98miGOa<|Zw>yOraY_c`19IwYbfdD zUCZk%yDmPXZ#k<3ny4NhI2TAh3&8xyWjNe}(s<&O-p6dA7nmR_Y7corCf)r5@Z**8 zedjiJyYcds{yXahX%E_x^T)U+I=GoJieE*q4$H|v)(L6MUj31|4UmRor{8FhxT2b`4W_$2G{#8O*#S##+3Hn7vOw->HVr zXLG;CDac2C>N2=R!rB``&7-N@jP{KwA-*-c>W4Md8AJSwUod&E8xRywk74JY=VX5M z&k>RAB!FX7Ki5E>pS7~L|KSIjWQ;*nnH_$#!cilp?sx|%c&ajA)>}kUJpOt%`sY6I-R?68_V5e63%a0H-&d3}ISerSpGwLYGEt$5e~qO)Lf$ z+k@+&M-waO^Td#ZoLVXpQc{+uf{Eye!bFp%C;J9>*TU0m?ol4ue!r@z4)>^BYqr{zBVx%P27ka=viEbg2;n0y{Vm{{?F zmzURMSL}snBu@(`<4NXK_qG#kvaHfaoY9d+dfR0HY+C2}9WsRe?X4Yx_N29Ug5F{$x{kJxf zKsSH9(u892th4iM08AuBRK(qtoP^Rd>1*|0BM%+|trioI(?!**k%dn4}uzA3STcCX*7W__L%n_?Z7z)Rj*LfZLwJuP4JdTQq0Nmhrl>F0Gk>L@uv3_SX zErUE+F?KM)37m$s3AC6rf5%5dhl4#?Q1ITl%)PM=-4jxqGDHs7^Q?ES{V%&BK<&55 zd;k0Q5<{!laMwW1e=>it@&Qz^={wVs*WTty5~9Zq^Zb3q(uNWzc_zUi7%k)GiOS)5 z^?9pro_%P90_|5ANf5VcK;>clYso*P{LTK8@4|>ntB|csw}(oL0dg( zc-YO?6e6BlKhh|OKR5Vyzl%X}X#GVf*@_e}e|1&OS{7SD-pht}2Cu8Dsi`GJn}-%$ ztc6i5!^hXk>1X{mc?Cqtno!tJWGH;i3ts8!CP&N700k__&IoEij4ZlKQw-rNzwGZ*3q{w@O0|n z;GnQ&c{=A=1?H&8Nh*CY^g78&qmhi~^&&KEQMONCNUL4$nolltwditr|O8e5(wD~KeeoLYV z1(75Y4kUSm$QbsV-moWRp|--uow6?iK@u18@EzKJrvYeE|CagzZ{uZHsU<`9Nt@tZ zA45+Bp{{+3(L*ylveTOIK0uelyFN|n@OhC$lfkm$(rtqMvRLU5jMQWc)v9nPiuz!= z%;Aw!fMG~qia4Y(3t)6NLZPzj|7*7)`9HY6S)?9FM0j`>7M1Lss-J_4jElsgpPJSQ zl?(Thr_C(C;8<0d1+Y~-cVY^*L%`Y-7X5}FPl&J_^&&{f{Vq?+2Fl=kg8>DN?nm@o$BwzEU@@MxmgY%XWtJ^)m}Lo zRBU{X4ZC*$6-yTbO~!o@Fz%l4p&E^jW!?NLD0s3FK9?^3bgh7Z`WXqIwE)!{CovzD z#aMvhpF9aH-XBW;-v%4$#GqOG_$r_8PZD>TXP0f+oI?a*Qn9DEgVQK>5?d&&>Up_z zaCy5UN^!mYq=Wbr7jX#1jA?nduYg$wwCK9>c1Y%KoD*7=8Zmgoc$g6XCwK?B(lIWa z7MptRkp(k1;tD7$j&^xGvZ9T{9OnlkfCgeerRk8E$ujQ)CK|1q-kB7S`3RDe@GN2b zaR`B%z31YCU(U=t&)$3Od#!cf_rgKFbm=&qCiMC~PMUVWfJO6LJep&! z)OB1Y{~^w8V0C91&Y(MoJkRfA|G?eqWy?+nfb}{8%9EcF|FxXe~ z1{TuLRskS+eT`sIDmB3#x!{1C=lS#!=&Lyby~TE?QJIMkmQEY0{MlvihwrvkSLtkn zDSBtAbPtM;*T9?<48Y|t{G9(k*!{PzpFtDodEKCA6K=AVz`*obWIF$b?%e!0vGj^; z!EbX#8WJk+rA#vN=|^FTSsUXX$6xNQzxKqT2Xid$` zka$(%xz$Q3PypL3jh^G08Fyk#irer%J~}f2{cq0a&%r>AoU=1876`sL!_G0RBDX{1WEA`$j;F|5ek9|?W0=Xm+2>u%p0`h6{)JLV?IE{StptKWNH>B)Zc9$K?M8$QiHY53pI z0v&c*xRulo=;*KNE`7T1nDpDNM=NG@AYEo0lZOuwut1iry+VBEz9u>i z2-MFkDl`1I0qJl(kVsRi8h+*u1YLnKKhu>~ai|6HvY`&@2jhr8in51U>I0KkBqgip`js#K;SfHh68(k@PF$IGe+jh z){PD*DAhDrvTkT(I}>Tmz9a5YLDdVn`B_V)!m;TaU~2kJ6KI4a5r;uVfHY)F->hXT zT_30UbycwbN4;y2Bi$uh2HPphCm~%70?YrnlDu)!Q z+7i1Ru7;e5!*gcKizLslU%%Ermw%j<_Ll|m=V}JN{q>EF)5arSH6B1k< z+V+uyZXbVe<3TcA8u=?z_WzayLLYbw2}@PomiS&HjGFhp$J$29me_^ChUQCHoJ34a z%+)w8=aziW92AWCdjvP8qR{i7`k?zJ7p?Cjv|sZ>vzw_j%JfN?ZC_C&L#SHRf6x;) ziEM6@F*7j{e0<7M^5X5ojQ84DlkFaK+(;Jv7&cxVI_=F-t^!mhlMNud9s_++tTHt@ z4`41HzSWK!)$lSkqv1zyxxVshAFE{&zhxGl3R)S*|B3wiX!SrpS*O*?jQKk*IqiKj zt9cp;v0nS~9CEAvLn@x4>5y|~)vR@?8q93`34XDAsTFzG>r83*F0<9N>(50jKO>Flg~MtVMG3bVk_Pe?rFHz7NlTn6X~Ox0+<{3W zFIha9mm8>9= zUytofcVb4*`sd&!(|sf!r~U824sc=Se!03zLK2N&Lt=xDb2;rH$iiN8S!md1DRUPhOEr*6Mq^vt9S!V<4v^ zsA8&AJdZdvGg`2||0&F!AezL+x3zkdErQYSxP-+tap;)NfGO*#R*mIy$*09UHhfA> zt~j#VxaD!K2qzoeSVC?#k^hUpx@q7xRdfavhU#x%#-7Gp&v%!MROiPq;~GgFJd`{3 zK7Z+YpPQTmA+wm6iP>4LD_zejC95&WO>@#5g{eMNR|5m zZblKbM#dL}evXXV@z3F+`0rCfQOAaHW0=|&HO0YO6FPY>m4RNsTO2tO4OJ_m3&(q- z=NyrUE6ecTSq%bqeF@?A$7dcD@88>DD|-5y#(|93A=oeu$U`erZ413+B@_+>Z?&5?c-e|mp$MmfS8)%B2LubXRF;AgOod^G7WjYB?ii#YuQ z4r@%!P8*A$9p;j+S4EL8S2&XX%UpII1tMP3m0i1a4*X~zZBbaJ?vIhPnqJ;4R!Jw% zhkpJX?(2lt^r#*!_xWOMHkS-qIU#qs8e0%g%2v1?m&9H9R%<6uc#$!QILqmuhj{s!+1lDdzmyF}mS`2CRkMR+ zd|*~!{1|deSr!T059ymaJ3G^OEuGmcmvzwl6DTmk;o4Cy?!)~^n`Bz!>ZrGP8)hF3q? z$zc+jx=-URSl0WO&^_ocmvQK`+}UpX_sHp^<#*lUvilFO_m+IV0f~sXlh^kZ=>8fJ z%KMdAlB#aVQ}*r1QJAWVvo%9U)b1xj#8EHW*jhCn1{smTuvPwOKc*Z{O}r58baG~C zlSepL%{W=10nHYq2#*|L<^O)OgQ>d^oWk8?cOp3orR{>-t&uhGQ9?u0=6h`uqFqa`}5Y#To3~;Ai5= zh@HdilCFLmNdI?Cmjw_{CbwXP1;tEas&CpQI!}7Bj``MzB5I3Q`yFa*Cu$i~(g;T~ zxarmPL~^l_7MpfKNWB4#OLvDXA*w0YM;a`a@#Z>=|E>WdO*LSZX_yE1JzrZFHCQ@T zAt__+XTx^X*6#h}Iab682rABaPbiI=oYv8AyrU6FWP@**_uM%}Q{UzNA`?_AvVBwS z{RUj(b6g_3`K9J>D9-Kr`0!qg84jqnR&9}U`%TA^(ro{`vlKZI&w@0AQzwX|yWX>P zXfdD5qV?q-TZS)PeLuI+$P@3d0iIYq!m25*=sWQ4y3g)3yECdEf0$$K=7cJXWldnA z8UdKPYsB3zL6|MS^xt(37}sF*Mpk^oc3pX8MCOY9iPYkvkRdNb4=dQ+&9)u-L?l5l zD?9sL4-vFdKsR3IYr*8=W3pj|Pu~k3-^+`eizO8!3K#VF_#JZT{3WuRWw3~ho5eDy z3rkn(pO~g7irAc3)yNte0^?va)mz`yLSNpTB_P1|qVSI7x9tPEe+Mq<^$&E!Y@IfJmQnxhSV=l$^SDO*AxhP&<82u) ziStGGxTy6VNuv>He~{h0x%>>37}S+9rSi7|^-EdC2>C$D=&OFt0Pgwm@$uLvZF~zG zxY~t|mPFjK)N@&g0)uR+LadfT4{$}e%NFS-`*iGn82$4gr~-)1NqNzoy<%lXmit%z zU|vb1aj{Y_;J~`&GZsO+$K^*0WFp`!gE9|bi-l%Np@5xB&E$HvH#Y|A1Gds=7s6uW zd}y)0$nPV&eQo&cgY!L)-cJooqhssAvHP%n}Y+F2y{4lL$0{h+-EOTa6gv61%ms`V_LH$8z~ zJCwzHP`;4E5EQs_oEEJ!CzwPgp}@*}3wGJd-mLI2_F4GT7_V3(lUTo*yJ5UY-M+;a z(|E>fk@jy1YYce)J%ZhgFma*Zh(qPiqi#PB97Xz1vZ`f`Dji4P696sZmpyUThQK#3 zID*=TndE?Vjj(W14|(}AUU}xR$KJxn^N_3*O1CG#M^QqMMazswT{7C>W40txq@);< zNrD(VgbrnN^0D7=kY7p|Jgykv3xSk|@7^(#vCfzR{QSAp-kHv?v)}S6fv;oSDRac* zdQ^>CV~h1gh~l$n0oABY=^}i|mLW)RzdPje!g2xi&U+6LyV}o{`=LRS%F!fjM{qxM z*vK^!i&>N)Q)=b;(yOiq+C9C^t-KIyu0u))keik2mg#YKU?&hnGFuuTs2s`^XL?K{ z8XqAtpXVB+&jCIC4>WDP1o{*xT_S7H7n+bR4SoWO8I|K&L?tEg3$*AZnLsLio~X;Q z?NZ;vc4iI7U&2T%Y!Jd5;D5sph)nL(0T(NjBYtxZs;s79&;+VQTG@SdzULJvoCljx z55F=`pXC^WFaY~z;Q#X;BCF*rP8Ip?*@vRY%Yyz#RtTuqh(C_fIljt7r(-1Qh5{)r z;^SYL@g0h`hHjD)*YyJGjdUqq}VHx`M_-QxmrdAoIX)CR>+0cjz(V01>AiiXe)hVL(3e04M^#IOeQt76K*B3y6*)2shO zO)_+Qtbk0DujCcz&JUMXG%UV=QSeRB+@EpxKk7!Y(v)=p;qrh{q{8johgP&1!!-7O zN+ZAC^>Y3A3-b9dLx%E%+>6?}P||dpLB6DD(txdy#CO`!8R>@^yr$yfVFdX|Ai`$b!#`0#c!gYI2Lp&{;R-m?t3n|^_h9S3^*>f47}Zj`$z$!aFoDkhUCG zMK{eD4NU@3utj^Q)$dTMf(AzuZ(Yl|c2G zYLhM6vUA?=xgH*#b9JeS<^;$*Z=p3F-xcBQ^litH(95UTL|k3M%lT`VtR_JJYDMaF z(Ogk>?|qwYMiy7^6j@lCJ4xJaxg+l5aZdoH@Z$CDaJWi!wtamx$7C|ny6*M?+>2b}a^ zaC&4EKW#@P#Y?2Kk(F~3r>iEbJ%~y=C-S>{{@+iLJT^jFQSC69>_NL~>D-z_SFBb- z=Bb3rsq~Ujd7S;=_SFFcp?Jf|YK|Tol%#U8a^`&NiJfLnc|(~c+pSY;fAjnF+xXA6 zQ?kZR?IRiE2i8+xE9~kYr#y7-tm?__Fkw~*8Q%&;)x=u>L=2t9yD12_T4>7)He!OM zIbv5--31pv3Hmf5;XC3ZPKM{C z3~q43Su+uAXQi5tpK}-Lz$x?vp)Cz$yn;{SnT>%zv2bEBPHjDmAz%Q^UI;gpf1%;F z_J%HfbwKfpX(KkXLlYP4i(WlT2K*o)|1PC6P5PjNSIjL<3={8LWBKi!f$8ZlPW0efs$-`tupLpM(Il ze&ihmUckeZr^t0uk1H2$?)TiqRX<#@LZ*U;+(a*=?X{7CwkZz@{WCM}`~W2XwVHa2 zLL^Gs<(K_zjcI&!AuN_;&OF-?hGH;zq@T-waNzu@&}-5{qzB%o!Z~RhwtW%1krdvs zg3M3eTa0L5@K%mU@x9)}wi?lqNU4PQ9m)heF(`sEH9A%WEWvT-Cld>O@vl!OC%i0J zOec_C^Ii_};eCla0L?VwOh(3UMFDL`TeufVqy-N@o_pg_D?rICu%+oxMvT1a#!PCS zBw?iL!4r9WhH96kPL%ODep9{R^F4%NObv#tstMcpz(Yb#dY!#x&>}L{c3$ciewqWaPzgE3jppE(JC>f$Iy~bI z@ONr1zYK=Zg$X(@8aR8sIo{s=9@>RC(qk<3bGAj28A5H9#qGvLq4*_{mjHJeTa{nq z<#;SlkO*_B2AV7(ccfVuj9(z5=*_B+lMqJy+>sO}%)?%O*zkttzVGF%RO}%r?+- ze?2)noBwV{mb;V$oWb9O|Kwkv5m7l<#uf6rIMT^L&@YtN>I z7wt+ERQJqeS5AQf)8wmjgQo)L=$%NgO(%j>1b`0i$obHUz*XzUGd|?9xD{YE{A$@G zYVb1_l2-d-{@x2RQSXCtm`Ky*Mfd!3v-pc%_q7&albe)_N=3I!hNRQSC8UYPBuJ*) z$3-E4TDQS59NX|bS^3K%wO(*J?6a8>15CIQ@rtA8l{DAF>wMC!?ZCBcR2%i!(X~Z- zRGnoHcsEya5V?6^zutb5I@;;n=qE9iY z5@1pT_dQsrUS{OK#evWRSmeOIYWPwd=kx7H*;c&1JG7p=Xvu^yulW0lCn7yA8IJ;p zj=z8|PdywdJ(5MpW}I0Ip5_0L{BwJITc`~2my)92F;Mk#X0Zs<7Wfe@N3?t$q*wPC z)#+RgUH@^mzp$UREo)Z!g>G2{u_}Y{x%}{HNrL|Jq~cMl6dkK+0&ND1^@DU(SvTBW ztk74&c<$%D2;!r1&7OkFdGH*7Mi`z$8zCvU+SKjsmBoRp*Z1>AWf>319rPJ@+BCg* zDA;>tpF&=k*ijIzhy@+`ZHa1I*km8`gXAyAWdYg!TBhiZH^hPT?htczU*2th)-aSj z1S5m<*UXkxN2Ns?2v` zcFJt>+8hhY<+60kPmuszI1gYUrX%UAN!L(eZw`MApjE^-=6pGazKLLAfypm)!RnlE zaeQbOLlS?S(K;jz6l}*1NYoMZVeS7RMoLZ~H>*FqnwV&xJAnn%r{{rr6?&7%A}fYq z3yCf8jbc2gE5EP#-qEE#HvTz@*rw}BGd3P7G9sp=&T41naWq}HXGTTs`1!Yr{_{-< zn(M5f^+l$=R;l*4@RtX;P8npQ5t$anhL#){-LMNZ%4$Y*+?tCNc00m)ZaPbWkqQ0T4b!Sb^WBc(9#|o>A`c6tU<2@ARh=GnmT0_-+zhk@_j{ z?J!ICHwtYH@~U9&Mg;+GWG)XJwh|<+ZtR~a#dv_BsyR{do0x5xRvsJbPEHj9MvWM% zJANuK2T)N|Gny$kEOer7_g1I~QAmm_4gu@J?jB!@3GK}Ajy#~H_L31zr zee(hdIS-qj8Zq=G!? z11I>|B_#4fL`qQ3O2x`NyGo#bZqk1a@Qw6~!i}`FG;31(Ov@%dj|1`WpPrM>KE(t< zj`Yh6a+nhP&U-f#txgM#ZvvZod*3f{V*Y5xb3?&gO^)(GBysa%JDUxR4Ef)CKSqVc zUE?<=y(4`luy_PaxI^s-^ldcb;@|-5jCGacv&HvBO?F6oDj51&D9WY z06%_6eA&F!7E~4&-GVB!w5;3HZRq|Qxko9CJ(1zQ;SB=cvmLHA?lV>$iW_fY%==+EpIG4ArZZ@2=Rmt-#vA8hT(`cp^Uetfi2 zMf=^(DO2f%9NgOgRs}{g%!Fi&5Av=B1szE-LzqTJ*}h941J(As3LZKZfnQ}5q@)>6 zGsw{t?DRRolW{sDFL|`gh**&zjFRqz84S~kcrgpgeoY-QM~PC(S+wH8u0zW?x`afH zU9yq<7VG>j^w-o9e`>HnvZ!Nq9$-KYdYMB$^jq+%XD@5q=w%2vO0Vj*<%_RJy*qh{ zI8?XhbUU|SzAGu&d~DPCo0qj2og^rb0ATkym`>#_BJB)~F2(9CvW1{@yA+)d+0_zW zBRy#c?`6)F0;(k$p81)ZukvKL;7QApiy^6>nIgIL{aHD=`CYO(f(-G!I z92-3^h8!=+sj%G29v~>v{C(Aorrp{@>kr2ftmCwIh2+u)*kh{cF&v;Xy1ZBSEBc%S z?3CN*Rk6yxd$Tn?pbE#??SrE&x^9QqB7lrOyRr4gR~-U<+YQ=w&9VserPk1b8Oz32 zOvdOiFWZV-!h|n~v76YduW)Xg!0e+p-|v4Dxri_1jk9$m{uD%aU~S;Yd!wRw{!U<$ zH4`4ORq0?(e${S2mCI~--{kJQ(!X+>2>ZQi3@#hL1&>U;91vNEUy>;|HH`C!ngZ*7 z!RboV>}{XuVI9rlXvsjdXQgx>gWj5=%0sY|o%W?nE+~VwDR`LJA}R?0H3|+GpxW#K^Vv||~odFj9$!a zH7WNgc%T97WeHFsgO<*i2NqFw?Z%Eog32n^3RyQ+?xZli{1(X-o}){$#RO7Z`DYZG>dC}nK(NLt+< zg#8}mGa#QpxTi+sZ(O$D7 zku>eL+((5gt6tN?uh_8dyOf0va$bl&*IK`AQhXq8;wn*M`0z9SYAz4rlEHTisfakQ z3qV8Z4WRoBy#MBq0)%NazmSp2BjuJS{CuEdva2V5NSKtgiSLVX(Xp~0Sss=C%Cvp6 z6FgB8kW9~>)S_AhwT}1CR|d!!%R!dBTfm}7pJ(-FuJd8!B67;A*7gSiwN39I3`EN|F zZz0wAKYADk7mrLMzQFH;m-l?0`Z?G80iJuY=KB}>p9cDWk>*Y-#{aSI5r-EE2jZB< z!9r^>B5aWlak*RjvQZNYiHV6t2Ta&wlDpkWQi(GGCy6brZQWzw<@M$ju!^)Mo%`Ix zMz5OU4EuJ?-nNqp-aTvy`J?S8hib0^y2+BL9K2qe!wLWabke&@mErB^DtwsF#fILM zSLP>we^AF%W85O#=Y=1`Y4ZU5bP9GWBY#6W95UwTBXAp&&38V^dfgzH_AbVh}=(gCA15Mosel zyeFUlV+)YlqytmO#6?KpE+_XZ^Q07Y0@!yV9N3g!>Nmgf?wxNS0}=LUuD2-tqt8ZU z3LLlexmT7-M|>2ncPdMhk8FPbM5#@MtNQva*%0S5M8axcsc3x|`PZSTZpAPDiB;b# zW4BGPfLFv#J%EWSsynhYZK#TPLzQQGPI9nAb}c^u0|z6 z?LEJn!8b`+haV?9@uUU?C8cAvF&?;W(^DpZMn@5E@(H*~m#vYY@)h+~JaG-j4=YUD z8heL4lN>*TsE|r2XqpO)mZ&Dy6H6i*Ulg!Sfm!LiP*kkhR>>&vie-UoY*C~IZYc?) ze1#ExiLo|vZ92kli92SR z*XESrwjqcb;JVt}*-Ub!!-XOp6LMnn6`FbA-{bQ}!l74TWA0~Dq4OdvMUnUj>bW{U-=uhXOv%S_Ky2QL9=>1y58|_j6_e*?rRVR15*Yg_5j`EBK$6D>dQ*S!Uu^!5UlAj8} zoSmVwp8woed?RE(IhaZ`>2%APB%*`wW~MD@Z2aJOT@7dCK;Nu;dU=W4^@R+vEcYK_ zwv(Pwznl`kt zo-Lqe%j0{C;J#%HdhIP19_nu0bTs{J2Kzf#^OBcYC>stRzD2t}r;gG5GOt$U0mn|u zgy13pB-YCQ`8f0pNs@U_;&q+N;fT$d>xeOJ6O(c>?ujv4B}AN@*eOO@HqrsLI!KMTAzX>E$r2flVW zfq0P)%Cr11uY#zRje#Jhl3e7C(K+ zLe0QkK74qSVx2U(y#&USww@F{h^3dUUF#yO+OxA=n*Irl;5VR}?A4-Ls$V1(tK!o9 z7gq62kZU7gP=#`0-ls%actdZz^wsK;5o}==&zt$Qu7ZPu{{UZy^|o7E6aZ)D#z#9V ziv^6%Jbx)c!KTj!Nz@#2@iV$*86?-rr@>O|41`qJFIxqj=D%+DK37~P1ff|OFQ3CZ z0-*zO1*qW|MJ~ORi{5d@(wO!7gxiSjqykeQN#u5U$>@w3BiWzNFc41!Uwrr3tzbDa zGSbx2dW};D^J7+fIqSlQlGp2RJ8UrCV}qF{0Gwhlc~@6JajjtB;j8QTagjl|JRBPv zo1?@Udm;}4j;mzjkr$Y|?N%;|tEXA3 zfWymMz{Nw4#(NUK3F2d%o}S*Og%?}s9WASY7nN^6QW4L`z*7_2;o##tMPFZEj^CV% zyH#)N>rb{mwe3bRy&;Y2&|3=80C?tTK`4>G4^>y1f_;s4_D@wLD6~KsE_psq)-~wElofRSqX>8DJRAyym{rF>d*B#iM$mldK3OO$}KSh^wtOwIloBlYpoJghp zaccQgS3tqO9LG}xeOXBLNDd!4-*4pO_S4*ND%|sY2z9-ahZ!`pvDj&v~_zygc7;PERO}KqH~_XG;a1!S7Pe^HQ=H;aqePj-9o7UO$? zPR$tLA6H*Hc#zhagZ=~7DXE(G+~ATwxY!qMEAgoq|7dNNSA4omH!up-3*9$|g*!kK zS}H>Bsn?&NMFFaUl|U;W(_N+{R)=5|qJm$9PGb#!+MEJGBGV`!j{Mn-8rm~0-vK_3Yv@ z-wL~2iDDy*D?=Hw0Pm9K?b6Tv@7!GGAb5vGRGe7OYHrP!qAM5``1yx+@QLgd>63#! z3pZ{AA@0l9BXVvJ1g9s)xuD^K$#a5@iCGWqi7T+E9ABz=kk@Mb>NPsVH)vZ-Fs$qW zLy@i^E7495Sk0L<-ca_tnB)4V4Y|rJkpPO#jhtk3de^+l#7A1#jgYx=GiKwrmu|1a zHMB2-Rp$OUzc~T00^m-hWFvkeU0MbEVTaG;|L10MsI-$KYjV%)U{RRWyu#K0l}zP! zuGOxWI#?~n%AXVJ=6)7V-~`ARwl!D}rBT?EsNetdk&>wSzl;&sLPSO*SICT>&CJ6- z|4^8Y1f^=F58p>I)Efr5nt#IpAo{r+{bc6gx3kL(Yo|y1jD5iD;-VN53MC2m)dImC zYw-~|h?o!uyw7W>h#7tBuuWfX9+hVy@$lBhdL+W2EIjbl#)9_7V+YstvZ3?ez>djQ zdOSBj;imn4BctXjklud&uRzw0LEa*9~hE{unUTx|4 z-~0+J2Nx)R#9l>q%Xt-(*z}EAxJ1Y>RN(PCb7%~_AVaj_e+aV~U>HhcAM$jVw5pO0 znv5F*74vPsLY%IO7=tU%fwEfV%Fp2PQQItVL3|XLStSfAlsIv;puC5@?4QpH!o;(* zKoUZ3{79i)@b>4fx}A5b+J7o@w-a*Y@H^;z2PCj5mpG&d|I3dYW}RY4H)Y3cW|zvZ zzOwkAFe840Q9F@FZ9GPdO>?8~&qQ1ILBaX0Z3N3g;AS8Ktp6ZnRM0MfvX%G!5~g?P zW99%1+TD=PdTj!gYWaw!ii4*n&4R>Z^@-UuyUpncR4!vDxC1XMu3FO*W-LL}sgQf5 zF^>w^*+nHyO*3cmLm8LknIfJ)?3vAE>1&_jB=#smLYnmE7~%=HCh9~;JN zhn$L6;VYR9UP?{mjBI_VO`l0S)e@-NMFW!7eV`G+y!7XN)>Q5GrRw~!6 zaw+nvR}X4CxhnRMi=4d!!xF*x(t_31)n9*7kQ=tt33hlyqN{izCKt$gw9w?jsrIbU z8j9W83dHbE^?RjhDO?~f%qa(cIW8$FF*4wK<`|b@)0fk6We16*+qe`+9%FAXs$LKbP`s=8b^=VB{zN!z#8%1y zRi#`)Zf~flDLR$CIScF$JxO0#|G5XfO+-jY$cyGAa^-=lwABqEE$eM2Brd_>?javE zRkWD>!MMz-X)x!~r12l92=pmTpxRaZf-Olo_LjuzA+z!3hPn#*aTaQEbzwzCh37y# zRiS$N%K7y+5A}d0tLa=TckQH;Vg!ZBuds#}wj0mC+qZt+V(Mpm>D9^unrq+e$T*KG zK_q{JgNvm5$Fu@T4S)~9?DYL$?;jK3GT0olZm)Ba)&CV27e~rTEncCPmTR5u=nNP& z4DWW46llid(zv7N5>V#I_HKBHg-Aan!s{={IdDpdvni5>N5{pI8<>e+o`qL9^%)S` znuTAK3Mi<5!HLg)yaeVzc>^U~+>ffF2sgSGNd@hC$>+XxKUPs z;_12h(@^+hTx7u?qa2H(+qVPF{fSGEGbk)|>~w?b8M}>6`Pk3WFNU=p6eZ>51D0 zkH%xTiZp0I(Qs#WU=ym$0*R;B4QIi>xMy;g&a!E-^+KgThHRN(h_<=kRn2kNTY94m zz@T6O_WBSrd-(SPVE;bSf>Y7?Oq4$vLSXNS_}br9a~$wW8v&qiNo+$uY_{?E=)zbA zW0;IK7xV>UTz(KUlcOwn5R%(Bzm{qjg2e54Kh5#fqq;F`7X0d|0@WH!Qx2pkTqt6c znbLajqsfoD?HQbc+o7f>T8|Y+>a?*1Cqo^6vq9fC%qms!!H)|KQa8=ApqwKR9OMP+ zD$JI=;W#Xi4Zw8iVBhhA!KBpMnMj`e-Y#tMs!$Ggi+I*ayjR%%YgDw*?$EtcUIGIIf%n6UJ#J)PuE0z84 zd*L-?hv(0^2vWz%xGV8`ugY+8_v3-To!+P;6`YRq<{)iAYhZ5i5A?$WVAG$!;~2D^1oVG!XC$yAH!+SV~Dzyyy? zkqAWG&~=A-ASDtmmk7uk6-hj3r2uutmhP+a2Zx;-q=7jW)|Fmh?(Yj`yUT_K6ZN8A z734pz6-nvq=(UeQHD|H)wk-P{l|#mg9{?%7fWWRk-_SiE!-2wCe!r^Y%&6S3*bp!J ze>!dzq#Cg17Dc9bYvy$EnOyqD^7_Z}NUPrr01GSswgit7r?19oR-PJ{flYP{hn6jC zPB8VPcvY^Ii;6M}fUAfLJBJ%$1&rg`);#*KPJ1de*1v#&0x2Ubi;q5>|H+}1K=~6Y zBG^?qLhgAB^d0;61_yn^B21s>p;7)}Bmye&pNj61(W=4Ms5?<`348m;!0}gFWT)-x zz(ZB6LJO%&@@|{ZhpQXBxKu7@FHJ79qDZD3>-heC3?|egs<4KS_MUq8@0Szqwh(vU zT$_~Ja@aXK=D@SZkLS7AF8JmP)p4_W-&42@w3Lp~^?ZMK2*}q-*o^WEy*;Bq?TV>J zv>@mq!6i-SCJ=A``qA9sRkXlaV()Yii7u5Y-{v2Fz@Okvm-q;=-DS~eNIULycxdIu zm1P?5bCU7v{f%ks*)MD)=yk*^EeIxmslQH0^3nSB?s3xVCzL%2c+E{SqNpzPdkPoS zJvexz0}i){D+zcubj<;-HN5Cfb;evapIN!3o00F__aKFTYF^+w&C?NbM2IFHjXC=i zdXVa1j%N~L8@!9dT>CY4baX`1IXO{?v*as$6zOhC8oAdk{wznXwBLK*${zVEy_-jE zw_01nlHG3#*+SeM+j9Ip0xll@*kS0Cct?nQh84XiHuLq`@lnJ@7r}}#s(p=E7*9(4W;m#Uw{vd0%}sS`g@4GYu`GsKV|Jhm(3tbB$@T9p(Oj2G`G`L4R|M{B zIJmbgJxa(k@c=e1!sLf!q8#hRK|&8y{g_$G;toUHJ{A2pGOfz zUduR-Jds3?;_Hf4uD2Nj9Z$J7G>V_X=|X>?Q#^vr#9)JW`l~Fb#l^7-{=i$rwdx|R zcFG4I_FgkeMv%%oCj<=845;_rn4z}e-lDEBgx*DtMVec`9bh@Ri>;>Yp0WbNeyBiI z9?hk`Tn)?AiIE8Sq=U6zMnE)hQeC03R8oq%*TRA!h+17SYvU*?I5;#7sx8(IL%vnt zT{WPNm>03%?Fz5k~n2t2>9L+eT$9Z9AA9c^gfqLlo%| zSRnSHW#t5P=EcxB8YUm+Yr-B1)EiVAlrQ6%A45>@MjnkL_1zgKyW7VBbN$n0AfuP) z3vrrNmohm*cX{fL^HAJzMk*o~P<{XTt_gVrUZxC5mL#U$dOUTFkF(E26P(iDET*yn zJTc+FOoU_u+#V_iaBq=mlg8_QDc)tHzKSyU5R3T~%gkG*S3w?dHfQ@viKJaVn5>_6 z|1szj$jbj?L<6BmC@v$+g;qr|yj;c2Z=pT=H4&>%sa~3srr!%(4~&@5GFYVU$iuGH zUf+NEbRk|cg1jc1m4x=-KC+LP#||b zHo)wo!0sMP2{s5AgYLBr5;Fk@2hKUT%Ny4fwOqx&nGeQ*$O=7kT{)!V0A@3?X+Zpv*9&37ffXfkn5XvT~L;*jlL^wH%kCmN|Zw+mAr}#;>e5nV5<&mYQXiH7}b_p zyZ6LZw=#<0!q?=dEw_bWr@IaF)SBlr$pOk5lw7w(5{jL(bHF!;$Y!c}4Tb&G73mzW z4e0VJV9EXajBLoDILq$CM|oPex`ED&L);@^wNQiggc(93t2MxmJMvz+k5+PHzbmWg zl06x!UkLbu(2nZrqpWYzfI_AUAYRyF=R8BnKQYZ2w;80Rh-Z}^mSbPB+;rtJ5gVx% zxEPJh0FkqQh&FNX<1b|OY(=}xuf306{(igS+)0-G*sQ*7`~?I85eH3_0hu|gcU6Wd zf7P#&NXX0i-7_}fXgd6fO2WJS0+`P>#57rgP9^CTk@ZnCSRkI2Db97c8B~pj^9{R{ zgdf5(rUs+D4FduK4#vjDw1jqq5>73@9Z&4G|Ff)MK*Dz=xCMpVlG#oQ?Ns}pso#3# z21(Bak}JJMx|A|SFYZqZ3h(dlPvB5KBhO8R$xn`L(GUn(X|+60zKE5Bm%>o$4Bi1} z!!*sBXeLx5KIeK&CMuHB=6;o`Uw^X!xRx&SDvT0IV<)t2pO9SJ@PYb@qr45*QoOkQg z(605UAi!}spfo*#sf#9*m-`{Gjx-kjqzwE3twjg)wYkTJOkaE7b3dW!568lOeU!V} z-+Bo6p&lSlVyf9Jo8iFN6Oq9Bj=eSaPtWFmKWhgxS=nx4b*24~wp3r23q)x!`ec5V z8+BH5(Ng>{{zd$1&yd-S%IjBk?)3{;3WdmZWwR#a#Yy zGtmbmURf~Kg-}%2+$pROwg3t@b;nhOFJWD_i4ubB0ZTOBlb>pKiuatnsxw{5_e(th zp47rNBPXIw7;1kyQlKeJ2UBnR=JZsHRgvUf7{WsQpt})|ehIDTCl3N>80-}{ZV{!M z8DFFZ-w)Ad*eBnW1l+^22n;dm7s(sDUS`j$8#veHhX64<9c5DXki7UWvQo@IDCd>O z^*eP|YkrN`83-&OFkOjwjrdt0Wc^h=g{bX#r^3J2IQ&+~tDhx&S?gg^o-+7$bU`dj@W~Mn%1K2UPx!fv%vedVC&s8>5tV@1C+_*vLj|BN-AGs3qDqkpU2{U zLSaYN$f6FN%83U{^w(Xeb-0!Z0kYS-vx;5*W?(RYpnS1@!5l1L$9i^7c$ zzUr*f{{(zW8elvj_;qQC(|aAedRUeiJc|Y6;Al7xxbbD!uHMDx1pRg=aBGo|86+gC zc0$dQiUbV~aY*3N6)Gp~HGYtC)_6!B`u9md1M+(XY*LwZm=xsY9plv9syIVYmOZSp z4%w>E|6b3~c-UHkL;yy;2n!zU}z+q{C6r2 zSRqP!grR6|><7xnFEC3T$ZAHoGDL?3JSxT>vnfXFr|~!Ad>DEtDyV+@M$M2dv2s>^ zUaDv=^5~tw#BUBXL8I@Wx~x>b_CrPT!Y6}DJW(ee)XY;W z=#jTajt=qOhx(&gJdmav5Pr1z|H}I6uqdDJZCDmqdg+b@Bm|{ILP|A%jUGDSD%$YN1&biNh6MhYp=}(j7 zZWui{X*+5C#!tQ2JNlS}%ghEeP8;Ef92MG_!l{#i1eF=yge+=7agmBX`)*2o?04hH2pFXT}<%^K?j%jcmNYf%}i_IFQVOMCE3swFIF*5Clv zFE7=IJ~_6ExNr%(SM7l4TnmH=)vHC_{NxG%<%fKZLHVwN?ejzvKjzXY!zpIhd$<~> zTjtAX8CXc5R**%{y3~o7`iT(0gD`dF5|Y!Ck>9Uj!?wEt>ux60m>D`!+cG|Yd0 zPo^OJSd?354e#^g5ApCzA_!##4wRT)WB-k&VnqZ2>E*ppSGJb;7j??iTTIXTx{Xpg zm63U?K)T@Cn3$CY8Wq%XFNkqoT6WQV!UGm{S#D2SgR{imbrt+DI!6xbL~7p0D8$K@ zAvU%|0&(K0Pkmi}Sf5N$ad@EfW0SK(Atxrt>!92}hK^t3c&{3Z$$vz~Hh2=~pop*+Bcx=7*iL5^V(`ya@E&)TKhLcPit zA?7=#(tDqCvr5G2nl8X32dj`Rrrk`Vreh3=e5-kcFWX`eX@9?lc_|w~!+1r{ znwm^ZTFH(v7}Wz*=lFX3`UEr8Y?C@bSAZPoDBkFqM%APyvY+NV_VS!MzoU!pfCl#~ z4n|hCE{jP^2c84>u&!qPh6J4RrtC5{A6012;p@7r{`82fu`u>r+t3AtMcd=wu&O>i zQh__SH5U|Ek}!@#9TFNXcq#V+9?@5owQw4s*k3MFw%pcvF5mGI<7DgEuUVnf1^ZOD zgO3h7M+y}Qf6PZ|F)&zPQSGs4|A8N@@D=V<(?WMxS0K$<8-TL_kqY<_iMrW$)()>|I?yh5anZ0J1-;uK_Ws z`6T=Mh6d5X=H@$vMMYeNpp1@7OusgqAy%^-jLWnUhOMCM`g6Hwtqn+EZ-8q;ChD1g zXUqY%DxhV&>!|VN9v~LPSarmi^dDAPtiF?&m{_=2*`1UZ2R+cy1Z(#lCJ{b(8Pl16 z6(oB7p4Sio(ar40bEwpB?@(@Xf%bD$_WoWrx+63KZ_&prYCS;MR?Pk2;Ghe08|k5V z@1DmQ77JwE|tdEM_)Glxf4Q!u0QO+M+=w}UUSbJYm!^c^q!~f zk#q}YdNIc>(EK2w*uv|5y8|Bt;gp0V_wzPh8ysB|$j{5O>H+#=_A_@QhW!&&{`5M` ziq3B!X%mXCn+%;K!=%4Qq^x8w`dPN3QV0*fm_RnnJv!de4QNqPlomg%yq@c(v*<_L zHm+Ri+u%Gqvhd*-Ft|JzQ7E@-z^@1h)?uO*-23nm@c)(8XAxB+05%FT}OAIeA8#>tlCfiRrVYh zG&yK=Z;!pi(Gh2cgG#6;CjI6%3NKh>9+?NR4ei;4Q|pqK#ZcW4$Ijo*ij#OR*x9^n zHSC)o;_vQLjeb`8clXaaAL0G#Ypf<{5kO-IL;i>JG7<~r2G7~vh3e`Rud5moCJ9k& zuVrQ;dSFv z=9#D54+z5?;oBYM<~Ne_J#cm?zdZ94;vauWfUC-#TuS(ov*X*%P>p(}gT{>kYnbRI zmWm<_{VI!+5PysAST{Us!A%7m148B+Pdz7SJUF@Y@>hjm?z0|)TX`!U zkr!2?cs-5kL2>cu1~L-$XNi@jTq++BimYSqs{D}iAF3j|BWXaAFDOoOO#;*&svDG{ z_1*THAK}DxNG5V-O%%!ihw~V>yT6)4Vugiq2;Oi>8=R z*{^zfdfusPn^8%102^!bAc>bdO~6X=P4e|tENEo`51Jj~67=z0t0`{6BD40U5)>Z# zajdtiz;ZJfIOFU-u2qJX&yFh`ijdgqBsl{ke32v1iT$hh-Z%L*=N|cGrghOV9vvP)RLmg%D_Z71A2Qpq0 zX(dOT!bMMb5cyuleZ-+8li@avE&;%TWKXJ$|L zQd56socwMN6zWT%DK_mxYYWcG7FvZ-GryCHK04vRJX^yWh!W}D!HjU!Yl6}wxGjH( zY6MkMN+iE7^plq8oL|%Gh^JJmG3;)8*iPhb@nu`y?$?_pP1+E715SKS*3vk+x|ExuPmt zATPuXjB@r{aZA1|-Unl@uPdvIRh=NUVqZ+M0#8G<-SR6SH5XTe zzT`y7Ww>*7+NW3jzROe!Ej&A@TB)eIRCt3`P=DpxA|=!FT&Em+p2U=^95aG`4(pulC>1# zp=d`ey;$=}is0z*u$FBbbtA&NXMb44bNu_MX$cmHTnfm|2P`jMNJn$N2^X|ejjEuB zo27|-@N_JaA%#Wc3N$aV;psE<9M9=Lm%7k@ZskKv?kP{D_GU;WisasHmDWp~icft` z<9)aQs<__KAtU^hdYvYfZy!^EcDkn@E3)ja+8OC@`q&6NlHAK*A2kZ%9G&g$?S<1= z=O1E`F+hXYrF{?W7(*Y8zP$FpQ#~z6OFSL?aDwE8a3pWIYB7hrQsL9gUr!)S{p}-i z=nlh|EFGc&AD;8YpM1EbA;8AQ=Kb_AkJ-a&MHjjlrS$TLqN1xO7T-E zNXU&#t4~B&cH8pLROwG32iohVY`$T3%-m!!n`=E|HV4Bez=J?Gh# z?n{zbtu~Dp@VX0%y%YI>;|U|=1p%qJepveKH@EKBu9fVK+b7bW5o9 z87~zLUVw3(L!$aJkFeZB&j6sVHN@eMeO1v~ocN~Z9V^R{4W&UM4}|Gj2d@qi-x2x7 zhT)E(u5NE*n~J*Ljs|(r3@aSbQFZ5vcw7A4$IAsFXu?Y8CEsL!HQcpaQA)m5uw_44 zBirQa7%)HBobHx{e!kw-U9eH*rh61XXjw{qREJ=9`%t31^Y8}{5ip8IHRO|-eKZPr zvptk5BqafBXagb+<=-ECrqw0Ce;hHjbzI~R;ty)LOj3z5`zVr2Eor%-m7b9?6EFw9 zJzXC6ya8rzjm%s#7Ux~Yrx;7#QFoF%mpr-!`Bz*ccdy_xm*OMGg_XPBkL#Ol$;t5$ z`|{UX43}Q-DF)7HV#Afr;`lq7k^EnN)ZuD@bQfP=V1M_**@*YWfj@0?H0v9JkJ>kz zhshmcgM{KJm`}AHsOMHe;%E zEo|r>hnLKy7#g9J_Y>{T9_*Z+Joa*zi7So#9=n}mTD!lCow^Te-QQx zaIGW78lT5GqFG!bAO}47MC9>Jk-DaJA_(WGY8+#XDc3Yp)coT26OhK>QFs=iECIXT znP&CG%q>qMZlU!ljL;TgJ@E8~29y;~1fXKEl!ckGIks+S^=f%qG`4`-d~lJ8ucI8; z&bMzxr?Ep^SYHgt51wK*wt1|p^%OR5%04v9Pzz#Ww!QToIxsqT)e#X0Z|zjtOFdvL z9^!#d_q~+~Q)DK~pS~9km;F4~-B8JNF;aKe$=)TO)?Dz5g#H(+m#Yk_)fZ3nGZ@Z* z>mdi+nX1aPS5Izx{bpaX(Hkr>VO?Z}Ffa$7{#@PAd=q8TK4~s`%3YrXm~v%bA@0xKVwSa3wlW`1nn-j0)m8*dU&j2}z=cAF`xSlt zZcL5jH`O}P;Dyeq2o4qDt5$1*!HN9{5@uVRF8s){*th->g-;3Jl;aw}j1qIdi1VmN zZS(*Pwio~bVwOrKO&+l~zNEz)o0y<*aCOb@5dFXdy8W0{%At(TxWERyDxXb*)+#oP zPhVv{eO$=qn4X<70!N+rfG#WenknrmV&nEh8YID^SoL!88#SGJ`K{cl-=4Jt- zY}&Eexj7T;Pq6hVe8T{_5x6Wb8{EqqK)j{_7c=>Q?n0~X-s>_)gy&%E3uFl1Ef5=i zco${@KYrhGyEQ1i+!c>c#6S!1oa2&;B2nfyWUsB!It#kEEAFq47p2qZeelfagI(Yr zo|t{u{3+d8@7ZEn>UPPgZ#7;lG$*zW&1)E(?)pH`KwH*p98`m-C47!hEv!;Gi%b7~ zx5dk8p-r+hK)sOJMU2|29e-cO1tB5hqjG1jUaVbIgj$G-RmF>f^@>h*FY#<_iMk>* zxtpkHEhgv{9{Zh9!Am4ZGC%?CKbw|LgVm@yi#zqBaj%elxzK zUfxN!*Sbc0%CIf>n0UxglgNKvtX=CGQ!m9z!5ud41r0N1mn~Y^A|IR;W5RFqA1XDC z2?)&d(5Vhaz7DPiAcRTP#WPoOBkk*r8NC#rqX)>;KFw?3yaEzo>hIPGNl5r^pI4@- zX8;^YH~9^9n+NaY>cXbx(e2Pi+_&x)Mg|$d{KMn?In^E+Rz0_>y4m+F*>2o_=X6hB zuTLxoZ${UA_&$fQ#6vu7aD$PtOYDBYG^9P?eOTcK2nL-UC*RS=cgv(ZDYCd{%CLV0 z3b?1-9T`bMAyGnH4WPN3bLnI2+~nkBF>dtj=FekJaiMx?7*Co2#Q7X5s!zAfQyi5P z6CItFpybVz<(^cD&EOh5b;5TfFCO4m1nna`ZMHkR>Y}5k>L-5e5FQwEBs!TI`eC6@ zpuNj5OxVi;r*6F}D|*gi?U97`$L@w=2UwX{1Lm;MxjDy|+o%()b-~zD50DNsIW^HJ zXwbH>J(IxaSE-i};p20alK1`b44a_q6`xT6QU0_u$M7Oec~TOUad__I(Bb8k%w{s< zVzRmuA2QS9`glW5NEX6vYohpqUc^Nrn!Ze?B(pbrlEo$M=4Ju6&NJ~(*wD#55(>R2 zDqBu#9QkmjF^?W?6s3M@=!*Tj^h&`8mTy+gEc*ggYK1a)K~3w?hB>86(u2jiN{Q7w zE^eGCzi|>*pP4wuJ2+$Z%_DW3!GHkdHH&ry-Eu2M0@*86MtH0FH!2GXqeGX@Jj$)D ztplOglwaElm@3z8tQ|_hrKG303!Pp>pzk=w)-HxwBdXLm2JcyhUHrs%KR2>2x0hXUIB}s>Z$64%j9EYW81)`t~GGD!wZ<6VGLU6 z%9pp?)M~xGIlMdor8P!0aPSY`#kg`Nha3F{k?|aj-(aK`BdR*Ek!Jl%?`9+m5!yP}W z$MY^&`JJB7w10a=p-*vg|AgsjyvOgUSUIefhWUtnddbL7a$K$~;`9|F{Uyo!u=~iK zyf@C^;HhW9*sp^HdfF7btmna$ay>yBzn0TBXHjSYBVo{G_n@+_h_MePs1@o zTKi zHK5(rjJMeI{1;0sN#`klZ0oulzZBtk2*0-(f$fP}*Pzpz>*@gRr451Ixxm4Hr&j+^ zqLZPbqQbRSZpZ)4XR6TJ?~8b)#kn^a?ggQeD#Gd)?VUxS?_`Z$wnolA@yBfXc~UuP zwMs!~e3oUu(p)L{5$7vkRa^Ygm4$E%|0`o>XXk5e-mAzB4Vk^5rB_;_FS2lEG2%O3 zeSSW%#88o6SwLu8eQ5dt+P8t92}VGrV5$8Pv&7@pqvmQ%S$EEDBB*N;O@ zv^IkCG6+J7e97L-TFNnq0y+xS>z+>x3aO!p&!u^dB67cA{F^KnfA5*sFFHt*qv(L3vH6Rj z(B!)h#nH*x8tBu@pV_zqUq>LJ1W9j=YIG106vinpUU|U3m}f)b`XYBk^5R=bw)2ty8U$sKAh?Fhmu{B7N9-0zwUO^Oj#eW?Qp zD`J1Mab*Kn8zY^1G^*gOoJc9YX1M?5LSLR%upt(lf%P_x7RyR+5v9B?I(`~q>a#P zBQcmdhwU$;DR~(98Z0}tf=n9R5TW!aKlr<^q+7xiez8)`As7XYT-{ULwyeBerK{Wv zk0qa5wCK93s;X{-U)@ya8`FEXeLQB%XGTm{D9i zJjfmcM{A==;_-r#lGdbXGYCLa4s5ZgnF-hPlrL zU_`LT3i?_ttgri7bH4*Z^TP(!)=^J6^JH#|h^T|+?f}SnsXaim7uZC_mdLsi!52d? zVecGZIbx_~Tj1Q&grR$`df=*3*ph`4`&JG-L!Ko($c4)?Xd@47i#xC(_71m|egQ5K zOTWRNZgS19bHiNJb4X{r^RiQsA-NIyHyvk_H5@jXy+NMzO>l6qgK_pXWaW#5*L$df zqwbi=Hh_(~JoL*ULw|S244A_f=fERVsImIuT?nB_rRu22YZU8HFVQY5U;MhD?_K%c z0E9hOH?iOItiqL8a&s7>e4(*HjR%#J^Lgv_9wFkx(WehWt^Kl7X-;HxE0W_0=nb`~ z3IhB2+GgJykSsPCSIn*zhc|NY$5waT!P4-Ny3_aqy59!^ing18kH}vwn@~)vcQwNd z2s;oVE_T)c`n^d|ry_kjHLX4eU)J$v?--?iW+dG7fj<$)J(iq3FHg_fpUsQ5ZCmMR zcVYc1C{*wEW~mGC*RkZ0l;$Xo*-9{z$6cEdPU# z8a_>$Lgw=Roql8QD&?#QX(#b>6{>Wczy;3;8b65yP$^dp4Gnr(SRzGFN~-4{#;6o! zu;H~ct^;@4p#&AZBv8N9o1B<<4eleg<4Vr&jf~hVB7kvdbv+mDy$dtLFc9Raa=Zz3 zKwJOk=Pb4L&2Qg^S~{|-)zm8e0f?}KfaMc}8R>vPeJTP&tJlil7-WU~yezG2$~r^o z8GeSr>tmFK_kJQm`Qr^>3AL8Q5^6rFG!@uY!Y~q-uSqwInqD8w?eG|{g0F~_@de*E zwo+IFwlKqea|ieD_ke7gd!pdHF_z#Le=RNYAHVzBQOoRu_u?41?=F;9CYcNFF?ejM z@ex^(qZ54^X6c&0)YtRSNfcIdPDs)xEX%@?l0Sb22?$?;7UY}D-}}i-*33w(0g-A- z2wn+w@RL_Ftv6e;&|-t`k=fwG8cKSeP}ze!Y9nR*ng--lntZSG@X*TkAMP2V?H0VA zj0_VWE{&2Z0OjzJt0%9W9zVn!LdPCdE53K0e-tzM)k8%D6l`+#GKN znpI`8r{=WKhv-Qi5!9nHE>}tLYO4N1 zh4%9IGl5}l?RXXdD-D6USsGf;8?^y~XafM@C3a}^NFT7K2ee$wa%q=}oVH)?fZkJD zSzI1OZ8Tijt~lZ~BJ_Tn08Z|gnDc2mIy%J+M<29HMY{zi%)#vGo>J|ZKYxuw(Pzc_ zaC$P^XrkDGwTX^SB9L-0j4^bzEnk~(upBr6;x!HUre%$A8En{I&EXPz4;6F{)*Cg4 zUFyXdJw9=Nn-~4YC=SdASK2L6+O0s2p^_fcT7Wl{I`^`;FbiKlb8IHMO~@&Jo~=If zmBbxxm6yxQ05U{uAu(|+bco2HlQUBgu*4@WjE!kN7qorE3X+&GL~ZyB|2(Xfx*rAO zUYR_9!MePV1EkoXsRK|Jk->*9w(9GfneD+wpR5j0GQSi#l{(*GW7ewCa(nE)yb;zF z^9@U{%y8AH)%OXq&M{muTA{k#|LlNmqnmp4cmL!spz@Qrw!W^n+{AVFxQD?O@tw>^ zxY-2mxdJoT;k$X$Wv0dFXU@0PQVH}30hI{+Mc*K;mnIJ|bWL`&Y)50mSzyY1IYmt6 z#Vy}j(A@pw*J22XKZWVXn-n78cDnBjG+=nUUP?-n_l<93?|pslg!D-{_zjZ6ltt|f z0XK%gbw_?qGL-aK#;wlhu~dzUu~vy3dZ{uL!M?Yr(((fjBP3r;$;2k0dUrATzAbSO zE_vr>JCJ1YM~jqCHQOlu+Q0@nJr%C|%RROfj|^!Kr+@Fq2Qu8#U+|f_W^LGshri7J zjiywGNJAXAizj<|VgMTwL(32W66~C0R-Up*RYQa9fxkK$ZcLbAbmE_E9jbus-Gu;n zCMDb$^G@{5aCqDKR_W3U*^oH_&neK1;lFToc@hAClK6fd@2D8U>B2$^dJC}a$o-u} zd`$)WS^@2b0>F$ffvgkCVO17-&BJ%BPxiBFP8KGTcc!zMPqU-2QuzBE`8=^2;O+W|w!o~6X_Dn00C56!=P+1@TPGhj573HRC4wM=;b{F2N}x0N-2xife|$hWNgI( zBMQZMsXBCnn|pso)l8!`6Fgcvmq|A>(T*fZ*Ewoa}73khltRDKl zSb@?-BiB~Skw_YgS7mzB&u-^Be-0nfp6)!G;un^oY*Edy;)&E_?mACNk_0yyiHM8E zFLdFR%`<@D-zCW$0Ph)rn?s*=;*iM;tw!Qk;y@vN@fPI%S4nh4T(4Zz$xbH}g>I(| z?}o0}aKCl)0W$RdXw<C)@vsM3Fy_G0g%UB33 zdkZ}48;Ytc_=MFYI3ELp;--@PUG4RKLzINU7-xb1y>B7N-6_Dl@%~z3(Zj#y{fYEp zQSQ1*IdM$TFFbUoFO=!UHLpSIQ*>WJMk{|7Hdhf>9P69w^8!)z8bPDYJqO%BmTv&k z6ckz#c;Cy$pI(STcH$Pgby`|u^?sZH{c<6hX_+Om_ML{lMxxx*^Sm~xi9X)YeS{)o z#e4J|fX@qFOdrq#TCf5v-ANr|>CqRO5Gx*6>h)F2fm0-b!dJh&R%&9-*!O`2&W9MI zTD>pik#=26VO8ruW=R_F)2|+@>ekPzi@f{{uK=OH^k{WqIRug z<@KYwR+g=l<;?kaBcOr8lY7;#z5@D%4?Wy@R+jkW_d8|t(LvjIGM>ZSe0x zcr^$GXcb$+qWFf$On9^L#8QM4EF!7~D*}HzGIQ`BQ&Lg&{utPJgwGp$XK-_K(+7XK zG$OIP+eV3=|E3e9tDM>K7bqR?`Axyq?34noYyWZhpf{KF1xi_7aRz-lD*?`W$`qb~ zwB}QasE4QzMkzl6K;>xPE5B~HhuZ8AF??RDl*-*Nb%By&-X1>IG%}*6qoLutD{7&S zO#Q;-JI=4`NU>aA2+BFmpxZXjHnGedeUhM$7Dh;YlbBK=8~XMo15I&YV2YEy6KfT% zzXG}#rOK-agoxUXryZ-(RnJu7$@=_zj8dM>6B9Uxer|_{>P=tCX&^!aL8@1pz;)6` z#d4N))CTuKDbZgmAqAUO;r@mWh=TT^i=*5(cz9}bQY=_qspTML6p@F%0>l10`V~Tt zMy9$(C?Zhz=NK6ncx6L=L}1W4GibG0#ZJnA`0AdVTu8C0P@ePWfBg%rF94^5bQeX`HbH6kk&QzBWc=lB%@uyU!` zB`esHTm4MMIhfu*vp@^NzmK2Cs=#a4a|H2slkv3P|LB!vRkD2T3y{OEas^acAE}ZL z_q}Kak8%{pb%7pn=#OY=RcdV3mzJ^Sf!<0=cs-LJLI%dA{_acCN+C=!AzL5O=HatEPbk(_>B`E#K68TVeL&g6@iOQFjuNWsi7|*ZfGo2skH2pDK4#Hek zSVi2@(vnwXS@8V_;NNI{O8;=JgVWGW0=!dS`a?$WI}0XKaZ!f5_W6coI$W_Y+5Q1X z7h$1}!#GjKr_$2W?elu)8JBOhQ4UG}_FRfA%kHhVf?C-y^d6K+gR(S5r@Wa{d*JH2 zSG&evjNON{KNG?Xr?>o3XSx69>;*6Xo*a}On!~#nHZ`qzB{ zYlsIqi(gJ9Oi@AWunY+wcdA}wSO!bW&RXK&agS{Js8_8;{mh&H7P&(iEVAyH&NncT zw2056qY2c6IGjS7sh!HAxFA)~oGCHw(NBm2W!~4Gzg#eEU=ig)jgTF&g!^k*1{OQyC zIhtIgMHrdscm?}(-0h6Ed+6K^`qLo^V$fNu2S@Ut+Z5x~-kNz`CMtS;KRVg1yCyt+ zOVs%uy>Dj7`5!mLy66JF{6~F-FGwu2V7Nvt#90-R`LrxQ|9udeOXm5qesFlWF4Ilz zv$69(fvw=z;PvxERXNf3hA0fz>BgyIRi_6M;AnobzpT(KEL^&qyUUeTGY!-Ed(^T( zsKA<4(^R5+2~jtL0g|M5ws{H@_=M zC7{FuFIz+ittyjiO-xO*c6T0Co}rUUe+Ekk7FaM;2^ak;so+(1MP05Zpa8HcetBfy z=25S1{qy=fWPLSp;(scH-@t#cpE7%n}n%lY{5Lxa6U9J5EGY>a2oXd4w6qX+uxpjh7qu>w5t5*2T3n=aueQ82RQR;t$B$zt=eNUlcc%G`oFBG=r9^*T-~p>j&3T8$%<^6fI`ih_uqclvX(a45%L#3{uo8qZWN(RwaMkvW`4gsz9-zq>1!tCkYvTBe=DFBmVSySkdV# zzwrHkwxR-7-bU~tTCns5BLsyaoYp}mz+M@$lSxsi@U>sKccEn1yz1ko zK{uj#ij11th>W-Q`!Z$@f$u22_H!L1p)TuV1w>Dx{TiE9w8F^vk$>T|NMYXTR61qFGu!zu6f zUvslvU9v_eNr(ghEIkQ0-z-e3f0b44J@3QGyUbh0)zd|5d)mD4+r=M1R@XIoWed@F zee}l)Hg&#PX~k8N3m#F=5~TF{7j5;UldySC{5K#l@2oBuGdiC4+xw>LS+!D2>1<02 zrR4o%9V`&QJ-=kbW>v%u{_7?w4K3}ai=!h!zMit}NP*rD0CPTQy}JB`*B6jKMi$Pc zIU&&UVkyeY)Q)F*XvF#Nr4{Yzcp-EvHdIQ90Im7r2?S0TKqK^hU7sti(7mh6r;e*l zbV)!jZbsQgN^oSfCn^mvF|O436eL3)8PdvL=fDwGs28LD! z1EMKT-vAIQIz_uHil8qrQz}3_!#qUk7EN5A@XPDjZ=!Rf4{bGS1s<@PZEm`cb+rkL zh>!sJY-3N&<}YZ%N%ZG_VvvMs@yl@^^bD~FiRFruc2R|*+^xBU6)5|j_QYLTvf}&h zXDokA-&{6NK{yMKKc4>UmqD=rvDi;f{=P#`8kpS>C+Ow*Iu34O#3Hxa4|fvpt0x=D zQ+E^EvrS+3lh^rAoDz@+h3eV*l->r9kHIsK9T!~-+p^+Hr}87qakgWd9>}_(UHZ?A zJN&^WT@%uY0&i!)v3T-p#?a7^Az_Yxu&7#7(piq)Cf{A>zdM-$Sh2)ws1hKe&>;>< zzwNw55+=K%mNGslj(^OX3NAl(Y<~3*%gFu=9FFM-+?zqSPCnQo)~Og|BD0NNyJ;<^ z2K68nTZ`vR-fWWnFI4K-MW0tL7Dwt(31y6x$REciC+do0m3|ZHiKMmuui$(H$%? z17nmLqWpr#_u#&1#f}+aEvEC`bnA9uhv2`~471J(lK!bvqKIC%euiLld7$S)k3{-t zLd*B_Yq6bi2Q+3%E~S0Dm#3oT4S%=2XYJoM-VOq&C)+YMPiZ{sq6MU76r2n5MQcX` z^9nM@Fo71%(L_o5BHKSE5xfKZ*gzZ61mw^9sHmx#HhXT8N#3OT`gYk0@5LF#ukET| zhX(&#Rtvf;^I%ffOaU;eKRxYcChlAr`!X@{_AN1O8%}@5j(rHBUfI@v>!}MS(#eKc z78k;t z{lgIv{@uUoT$W`8;8WeIzn5AAT*&o56u96)JLtm04=T-H;CB_aN+5mNIXgQ$+1sla z#*n5c{PeDM?7qqF9j_gl$iUG0e-Tg6d$4FegY#QuFk}|`vcK0sFEjxNy*7Pls4!WK z1m^)CgL6#DLv*-|{w#_D(~J{Jr2`J*1uP~IU0um()Ag#A|Fh9` zbR^kE^aTsV0u(S%6^%8wTpiSsMTC)gD&NA4EUVnW50gy>%PGmws=oK{K|tk6s-5MJ zIVR&>93;1A5bb?^3C^xF+fP}$HWb_^nQyj#ev*EqzeI^_^3}R|pYy+IhykF~#;Jy_ zG_VE&kiE8FE}JM6N;8Vjs^v}mn+V%^!fDkbOz9_-0&9MqFeml z4@j)CJ1+WF2TW1584%o zT7N(hg=isu>~1|gzPdShHxrBp?Nx(;kHi1$84adK1P1mHC@xEi|A$yYhjNO2R=ywi zjX}LMJrwRd*YJ3Sv3=pw#QwkZFEHJg=o&nfml3!(P;5ZMqPnaHV?ZO8J3ur*YHWuO zppjKo0%lrTT1Bm`0g#pX@^_%+@-sQ39_N1s2LXeplF>;3ga5&Xy8N}b?&Jb1J%`CN^0Da`7G5Q2ygmc&-=0 z66SzWm8F6?z=hu2_@ZaBIBPtl4`w|2tcoJZ07S`gaJ`z?JZ9b3DWXf6mG;0#U$gurHup#eT z=E8p};NZ&`(5Y4n94!y9z!~>~iZ>8J$^`iM11$c^i}nL|qmSWGec~Ec_xyXjIu$gn z2F9r@Aw1BpP|XG0MW6JbsV!y@$MjCsNacrm&)4Nq{hjTG2;gV^oQku6#}Ez0&>Z_D z%VjA5rK#1k7)7Dn;JJZ~rwsTwA+IRR@9XXLAqAw-sEhY>vJNjH1S{1X2|pw+nAXp$ zXd`fXJv=-j5KTDyKCo3H7RrkhxfeyL|F+_yFEEF4kt%U;qgsSQ;14ceajK7OZEW<1 z&;-$8{j$82*R)TUpIz2sQm(YI&H$Aj|E@%B*Pgge%K)AdJr=7;|erwbJXWpgI aOX&wc5htqAPn9shkCK9#e7UUov;PC-y<_D7 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png b/Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png new file mode 100644 index 0000000000000000000000000000000000000000..b2bb3e8e2b9990ff598b7be178547fa3d0171691 GIT binary patch literal 76503 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/Images/WeightedUndirectedGraph.png b/Dijkstra Algorithm/Images/WeightedUndirectedGraph.png new file mode 100644 index 0000000000000000000000000000000000000000..2f26b74d4dcd457fd32d619744dd5cdbd340a0c0 GIT binary patch literal 78079 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ñx&@q?ReE3{3Qd)#J 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 literal 0 HcmV?d00001 diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index db1726b1f..ddce51525 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,13 +1,50 @@ +#Weighted graph general cocepts + +Every weighted graph should contain: +1. Vertices/Nodes (I will use "vertex" in this readme). + + + +2. Edges connecting vertices. Let's add some edges to our graph. For simplicity let's create directed graph for now. Directed means, that edge have a direction, i.e. vertex, where it starts and vertex, where it ends. But remember VERY IMPORTANT thing: + * All undirected graphs can be viewed as a directed graph. + * A directed graph is undirected if and only if every edge is paired with an edge going in the opposite direction. + + + +3. Weights for every edge. + + + +Final result. +Directed weighted graph: + + + +Undirected weighted graph: + + + +And once again: An undireceted graph - it is a directed graph with every edge paired with an edge going in the opposite direction. This statement is clear on the image above. + +Great! Now we are familiar with general concepts about graphs. + # Dijkstra's algorithm +This [algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) was invented in 1956 by Edsger W. Dijkstra. -This [algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) was invented in 1956 by Edsger W. Dijkstra. +It can be used, when you have one source vertex and want to find the shortest paths to ALL other vertices in the graph. -It can be used, when you have one source vertex and want to find the shortest paths to all other vertices in the graph. +The best example is road network. If you wnat to find the shortest path from your house to your job, or if you want to find the closest store to your house, then it is time for the Dijkstra's algorithm. -The best example is road network. If you wnat to find the shortest path from your house to your job, then it is time for the Dijkstra's algorithm. +The algorithm repeats following cycle until all vertices are marked as visited. +Cycle: +1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) +2. The algorithm marks picked vertex as visited. +3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. +When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. -I have created **VisualizedDijkstra.playground** to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. +I have created **VisualizedDijkstra.playground** game/tutorial to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. +#Example Let's imagine, you want to go to the shop. Your house is A vertex and there are 4 possible stores around your house. How to find the closest one/ones? Luckily, you have graph, that connects your house with all these stores. So, you know what to do :) ## Initialization @@ -38,17 +75,8 @@ To initialize our graph we have to set source vertex path length from source ver | Path Length From Start | 0 | inf | inf | inf | inf | | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | -Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm. - -But before we will go through all process side by side read this explanation. -The algorithm repeats following cycle until all vertices are marked as visited. -Cycle: -1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) -2. The algorithm marks picked vertex as visited. -3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. -When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. +Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm, let's start! -Okay, let's start! Let's follow the algorithm's cycle and pick the first vertex, which neighbors we want to check. All our vertices are not visited, but there is only one has the smallest path length from start - A. This vertex is the first one, which neighbors we will check. First of all, set this vertex as visited From e9017365a47a93a977dc0f26c42045d6fccd4b76 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Wed, 24 May 2017 18:01:53 +0300 Subject: [PATCH 0633/1275] Fix --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index ddce51525..5cf312acc 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,4 +1,4 @@ -#Weighted graph general cocepts +# Weighted graph general cocepts Every weighted graph should contain: 1. Vertices/Nodes (I will use "vertex" in this readme). From b1a50b492373dba7490e603975f9bec8e98c4725 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Wed, 24 May 2017 18:04:09 +0300 Subject: [PATCH 0634/1275] fix --- Dijkstra Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 5cf312acc..a9a898d80 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -44,7 +44,7 @@ When all vertices are marked as visited, the algorithm's job is done. Now, you c I have created **VisualizedDijkstra.playground** game/tutorial to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. -#Example +# Example Let's imagine, you want to go to the shop. Your house is A vertex and there are 4 possible stores around your house. How to find the closest one/ones? Luckily, you have graph, that connects your house with all these stores. So, you know what to do :) ## Initialization From bb8b2a7d480b6e9f3d5eeee87eaf4a7e01e2ba36 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Wed, 24 May 2017 18:07:47 +0300 Subject: [PATCH 0635/1275] Fixes --- Dijkstra Algorithm/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index a9a898d80..7afc34094 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -44,10 +44,10 @@ When all vertices are marked as visited, the algorithm's job is done. Now, you c I have created **VisualizedDijkstra.playground** game/tutorial to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. -# Example +## Example Let's imagine, you want to go to the shop. Your house is A vertex and there are 4 possible stores around your house. How to find the closest one/ones? Luckily, you have graph, that connects your house with all these stores. So, you know what to do :) -## Initialization +### Initialization When the algorithm starts to work initial graph looks like this: @@ -93,7 +93,7 @@ After this step graph has this state: | Path Length From Start | 0 | inf | inf | inf | inf | | Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | -## Step 1 +### Step 1 Then we check all of its neighbors. If checking vertex path length from start + edge weigth is smaller than neighbor's path length from start, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. @@ -118,7 +118,7 @@ And its state is here: | Path Length From Start | 0 | 3 | inf | 1 | inf | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [ ] | -## Step 2 +### Step 2 From now we repeat all actions again and fill our table with new info! @@ -130,7 +130,7 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | inf | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [ ] | [A, D] | [A, D, E] | -## Step 3 +### Step 3 @@ -140,7 +140,7 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 11 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] |[A, D, E, C]| [A, D] | [A, D, E ] | -## Step 4 +### Step 4 @@ -150,7 +150,7 @@ From now we repeat all actions again and fill our table with new info! | Path Length From Start | 0 | 3 | 8 | 1 | 2 | | Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] | -## Step 5 +### Step 5 @@ -300,16 +300,16 @@ Also there is a **VisualizedDijkstra.playground**. Use it to figure out algorith It is up to you how to implement some specific parts of algorithm, you can use Array instead of Set, add _visited_ property to Vertex or you can create some local totalVertices Array/Set inside _func findShortestPaths(from startVertex: Vertex)_ to keep totalVertices Array/Set unchanged. This is a general explanation with one possible implementation :) -## About this repository +# About this repository This repository contains to playgrounds: * To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. * If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. -## Demo video +# Demo video Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) -## Credits +# Credits WWDC 2017 Scholarship Project (Rejected) created by [Taras Nikulin](https://github.com/crabman448) From fbd5d6ea149cccd61c93530a772bad148e3a45e1 Mon Sep 17 00:00:00 2001 From: barbara Date: Thu, 25 May 2017 14:04:49 +0200 Subject: [PATCH 0636/1275] Examples for documentation --- .../Images/SplayTreesWorstCaseExamples.svg | 2 ++ Splay Tree/Images/example-zigzig-1.png | Bin 0 -> 32202 bytes Splay Tree/Images/example-zigzig-2.png | Bin 0 -> 34485 bytes Splay Tree/Images/example-zigzig-3.png | Bin 0 -> 29732 bytes Splay Tree/Images/example-zigzig-4.png | Bin 0 -> 28709 bytes Splay Tree/Images/example-zigzig-5.png | Bin 0 -> 25735 bytes Splay Tree/Images/worst-case-1.png | Bin 0 -> 6795 bytes Splay Tree/Images/worst-case-2.png | Bin 0 -> 7076 bytes Splay Tree/Images/worst-case-3.png | Bin 0 -> 9049 bytes Splay Tree/Images/worst-case-4.png | Bin 0 -> 10813 bytes Splay Tree/Images/worst-case-5.png | Bin 0 -> 11827 bytes Splay Tree/Images/worst-case-6.png | Bin 0 -> 35177 bytes Splay Tree/Images/zigzig-wrongrotated.png | Bin 0 -> 38831 bytes 13 files changed, 2 insertions(+) create mode 100644 Splay Tree/Images/SplayTreesWorstCaseExamples.svg create mode 100644 Splay Tree/Images/example-zigzig-1.png create mode 100644 Splay Tree/Images/example-zigzig-2.png create mode 100644 Splay Tree/Images/example-zigzig-3.png create mode 100644 Splay Tree/Images/example-zigzig-4.png create mode 100644 Splay Tree/Images/example-zigzig-5.png create mode 100644 Splay Tree/Images/worst-case-1.png create mode 100644 Splay Tree/Images/worst-case-2.png create mode 100644 Splay Tree/Images/worst-case-3.png create mode 100644 Splay Tree/Images/worst-case-4.png create mode 100644 Splay Tree/Images/worst-case-5.png create mode 100644 Splay Tree/Images/worst-case-6.png create mode 100644 Splay Tree/Images/zigzig-wrongrotated.png diff --git a/Splay Tree/Images/SplayTreesWorstCaseExamples.svg b/Splay Tree/Images/SplayTreesWorstCaseExamples.svg new file mode 100644 index 000000000..c07312af2 --- /dev/null +++ b/Splay Tree/Images/SplayTreesWorstCaseExamples.svg @@ -0,0 +1,2 @@ + +
1
1
2
2
1
1
2
2
1
1
2
2
3
3
1
1
2
2
3
3
1
1
2
2
3
3
4
4
1
1
2
2
3
3
4
4
1
1
2
2
3
3
4
4
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
5
5
6
6
7
7
8
8
5
5
6
6
7
7
8
8
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
\ No newline at end of file diff --git a/Splay Tree/Images/example-zigzig-1.png b/Splay Tree/Images/example-zigzig-1.png new file mode 100644 index 0000000000000000000000000000000000000000..48a08c17cf8cdbbf4de565b1ae4339a533f8b562 GIT binary patch literal 32202 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

^3u@V70z)B9iJxD+Z%NK(r?LStzHVG-% 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 G@c#kXNwKB? literal 0 HcmV?d00001 diff --git a/Splay Tree/Images/example-zigzig-3.png b/Splay Tree/Images/example-zigzig-3.png new file mode 100644 index 0000000000000000000000000000000000000000..905b4d4bd2d9638e902358172764e23e29c03da6 GIT binary patch literal 29732 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

350Y9 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 Date: Wed, 19 Apr 2017 16:44:55 +0300 Subject: [PATCH 0546/1275] Replaced _vertices with vertices --- .../Dijkstra.playground/Contents.swift | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index cd08e26fb..1c12245bd 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -1,19 +1,19 @@ //: Playground - noun: a place where people can play import Foundation -var _vertices: Set = Set() +var vertices: Set = Set() func createNotConnectedVertices() { //change this value to increase or decrease amount of vertices in the graph let numberOfVerticesInGraph = 15 for i in 0.. Vertex { - var newSet = _vertices + var newSet = vertices newSet.remove(vertex) let offset = Int(arc4random_uniform(UInt32(newSet.count))) let index = newSet.index(newSet.startIndex, offsetBy: offset) @@ -38,9 +38,9 @@ func randomVertex(except vertex: Vertex) -> Vertex { } func randomVertex() -> Vertex { - let offset = Int(arc4random_uniform(UInt32(_vertices.count))) - let index = _vertices.index(_vertices.startIndex, offsetBy: offset) - return _vertices[index] + let offset = Int(arc4random_uniform(UInt32(vertices.count))) + let index = vertices.index(vertices.startIndex, offsetBy: offset) + return vertices[index] } //initialize random graph @@ -48,7 +48,7 @@ createNotConnectedVertices() setupConnections() //initialize Dijkstra algorithm with graph vertices -let dijkstra = Dijkstra(vertices: _vertices) +let dijkstra = Dijkstra(vertices: vertices) //decide which vertex will be the starting one let startVertex = randomVertex() @@ -63,6 +63,7 @@ var pathVerticesFromStartString: [String] = [] for vertex in destinationVertex.pathVerticesFromStart { pathVerticesFromStartString.append(vertex.identifier) } + print(pathVerticesFromStartString.joined(separator: "->")) From 93aad5ea36a1f09d62c8c877675877097e9b29fc Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 03:39:21 -0700 Subject: [PATCH 0547/1275] Added templates for the repository. --- .github/CONTRIBUTING.md | 0 .github/ISSUE_TEMPLATE.md | 19 +++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 0 3 files changed, 19 insertions(+) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..e69de29bb diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..27a857ef5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,19 @@ +### Category + +- [ ] Bug +- [ ] Feature Request +- [ ] Question + +### Brief Intro + +> Describe this issue below in 1 sentence. + +### More Details + +> If necessary, start off with the code snippet. Put the code in between ``` to format them into code blocks. + +[INSERT CODE HERE] + +> Describe the problem in more detail. + +[INSERT DETAILS HERE] \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..e69de29bb From 5128bfa4dca199beeda930dacf0623d7f6e0e926 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:32:41 -0700 Subject: [PATCH 0548/1275] Updated contribution guidelines. --- .github/CONTRIBUTING.md | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e69de29bb..a1393a2e0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing Guidelines + +Want to help out with the Swift Algorithm Club? Great! While we don't have strict templates on the format of each contribution, we do have a few guidelines that should be kept in mind: + +**Readability** + +The `README` file is the cake, and the sample code is the cherry on top. Readablity is really important for us. A good contribution has succinct explanations supported by diagrams. Code is best introduced in chunks, weaved into the explanations where relevant. + +**API Design Guidelines** + +A good contribution abides to the [Swift API Guidelines](https://swift.org/documentation/api-design-guidelines/). We review the pull requests with this in mind. + +**Swift Language Guidelines** + +We follow the following Swift [style guide](https://github.com/raywenderlich/swift-style-guide). + +### Contribution Categories + +### Refinement + +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. + +### New Contributions + +Before writing about something new, you should do 2 things: + +1. Check the main page for existing implementations +2. Check the [pull requests](https://github.com/raywenderlich/swift-algorithm-club/pulls) for "claimed" topics. More info on that below. + +If what you have in mind is a new addition, please follow this process when submitting your contribution: + +1. Create a pull request to "claim" an algorithm or data structure. This is to avoid having multiple people working on the same thing. +2. Use this [style guide](https://github.com/raywenderlich/swift-style-guide) for writing code (more or less). +3. Write an explanation of how the algorithm works. Include **plenty of examples** for readers to follow along. Pictures are good. Take a look at [the explanation of quicksort](Quicksort/) to get an idea. +4. Include your name in the explanation, something like *Written by Your Name* at the end of the document. +5. Add a playground and/or unit tests. + +For the unit tests: + +- Add the unit test project to `.travis.yml` so they will be run on [Travis-CI](https://travis-ci.org/raywenderlich/swift-algorithm-club). Add a line to `.travis.yml` like this: + +``` +- xctool test -project ./Algorithm/Tests/Tests.xcodeproj -scheme Tests +``` + +- Configure the Test project's scheme to run on Travis-CI: + - Open **Product -> Scheme -> Manage Schemes...** + - Uncheck **Autocreate schemes** + - Check **Shared** + +![Screenshot of scheme settings](Images/scheme-settings-for-travis.png) + +## Want to chat? + +This isn't just a repo with a bunch of code... If you want to learn more about how an algorithm works or want to discuss better ways of solving problems, then open a [Github issue](https://github.com/raywenderlich/swift-algorithm-club/issues) and we'll talk! \ No newline at end of file From 1e149dc959731e16eb303396293e1e719f86d2ef Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:33:33 -0700 Subject: [PATCH 0549/1275] Fixed broken link. --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a1393a2e0..fe8a23278 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -50,7 +50,7 @@ For the unit tests: - Uncheck **Autocreate schemes** - Check **Shared** -![Screenshot of scheme settings](Images/scheme-settings-for-travis.png) +![Screenshot of scheme settings](../Images/scheme-settings-for-travis.png) ## Want to chat? From 1620a9cb811ecac68528c8f330f45762ec1beb6a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:34:11 -0700 Subject: [PATCH 0550/1275] Fixes another broken link in the readme. --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fe8a23278..5b6f5d4dd 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -33,7 +33,7 @@ If what you have in mind is a new addition, please follow this process when subm 1. Create a pull request to "claim" an algorithm or data structure. This is to avoid having multiple people working on the same thing. 2. Use this [style guide](https://github.com/raywenderlich/swift-style-guide) for writing code (more or less). -3. Write an explanation of how the algorithm works. Include **plenty of examples** for readers to follow along. Pictures are good. Take a look at [the explanation of quicksort](Quicksort/) to get an idea. +3. Write an explanation of how the algorithm works. Include **plenty of examples** for readers to follow along. Pictures are good. Take a look at [the explanation of quicksort](../Quicksort/) to get an idea. 4. Include your name in the explanation, something like *Written by Your Name* at the end of the document. 5. Add a playground and/or unit tests. From d83263cd7e2dcd13e7e2e8ad7c9f624fab337a00 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:43:55 -0700 Subject: [PATCH 0551/1275] Updated issue and pr template. --- .github/ISSUE_TEMPLATE.md | 10 ++-------- .github/PULL_REQUEST_TEMPLATE.md | 11 +++++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 27a857ef5..416641261 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,14 +6,8 @@ ### Brief Intro -> Describe this issue below in 1 sentence. + ### More Details -> If necessary, start off with the code snippet. Put the code in between ``` to format them into code blocks. - -[INSERT CODE HERE] - -> Describe the problem in more detail. - -[INSERT DETAILS HERE] \ No newline at end of file + \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e69de29bb..c52564721 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ + + +### Checklist + +- [ ] I've looked at the [contribution guidelines](https://github.com/raywenderlich/swift-algorithm-club/blob/master/.github/CONTRIBUTING.md). +- [ ] This pull request is complete and ready for review. + +### Description + + + From bb6c29fee3cf3549c56cf5fb351bf01b15301177 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:45:44 -0700 Subject: [PATCH 0552/1275] Fixes formatting. --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5b6f5d4dd..2b08e2633 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,7 +14,7 @@ A good contribution abides to the [Swift API Guidelines](https://swift.org/docum We follow the following Swift [style guide](https://github.com/raywenderlich/swift-style-guide). -### Contribution Categories +## Contribution Categories ### Refinement From aadae31ed56f8317eae20e94196b2c242994d1fb Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:54:06 -0700 Subject: [PATCH 0553/1275] Updated readme with links to updated/new contributions. --- README.markdown | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/README.markdown b/README.markdown index 29fc9d748..e0983f22e 100644 --- a/README.markdown +++ b/README.markdown @@ -8,9 +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. -Most code is compatible with **Xcode 8.2** and **Swift 3**. We'll keep this updated with the latest version of Swift. - -This is a work in progress. More algorithms will be added soon. :-) +Most code is compatible with **Xcode 8.3** and **Swift 3**. We'll keep this updated with the latest version of Swift. :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: @@ -24,9 +22,7 @@ This is a work in progress. More algorithms will be added soon. :-) [Algorithm design techniques](Algorithm%20Design.markdown). How do you create your own algorithms? -[How to contribute](How%20to%20Contribute.markdown). Report an issue to leave feedback, or submit a pull request. - -[Under construction](Under%20Construction.markdown). Algorithms that are under construction. +[How to contribute](https://github.com/raywenderlich/swift-algorithm-club/blob/master/.github/CONTRIBUTING.md). Report an issue to leave feedback, or submit a pull request. ## Where to start? @@ -56,7 +52,7 @@ If you're new to algorithms and data structures, here are a few good ones to sta - [Brute-Force String Search](Brute-Force%20String%20Search/). A naive method. - [Boyer-Moore](Boyer-Moore/). A fast method to search for substrings. It skips ahead based on a look-up table, to avoid looking at every character in the text. -- Knuth-Morris-Pratt +- [Knuth-Morris-Pratt](Knuth-Morris-Pratt/). A linear-time string algorithm that returns indexes of all occurrencies of a given pattern. - [Rabin-Karp](Rabin-Karp/) Faster search by using hashing. - [Longest Common Subsequence](Longest%20Common%20Subsequence/). Find the longest sequence of characters that appear in the same order in both strings. - [Z-Algorithm](Z-Algorithm/). Finds all instances of a pattern in a String, and returns the indexes of where the pattern starts within the String. @@ -103,7 +99,6 @@ Bad sorting algorithms (don't use these!): - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. - [Permutations and Combinations](Combinatorics/). Get your combinatorics on! - [Shunting Yard Algorithm](Shunting%20Yard/). Convert infix expressions to postfix. -- Statistics - [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication. - [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. - [Strassen's Multiplication Matrix](Strassen%20Matrix%20Multiplication/). Efficient way to handle matrix multiplication. @@ -112,7 +107,7 @@ Bad sorting algorithms (don't use these!): - [k-Means Clustering](K-Means/). Unsupervised classifier that partitions data into *k* clusters. - k-Nearest Neighbors -- [Linear Regression](Linear%20Regression/) +- [Linear Regression](Linear%20Regression/). A technique for creating a model of the relationship between two (or more) variable quantities. - Logistic Regression - Neural Networks - PageRank @@ -153,9 +148,9 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Tree](Tree/). A general-purpose tree structure. - [Binary Tree](Binary%20Tree/). A tree where each node has at most two children. - [Binary Search Tree (BST)](Binary%20Search%20Tree/). A binary tree that orders its nodes in a way that allows for fast queries. -- Red-Black Tree +- [Red-Black Tree](Red-Black%20Tree/). A self balancing binary search tree. - Splay Tree -- Threaded Binary Tree +- [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. - kd-Tree - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. @@ -226,7 +221,7 @@ Other algorithm repositories: 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 [Ross O'brien](https://www.raywenderlich.com/u/narrativium). 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](How%20to%20Contribute.markdown)? :] From 2ce23ca2b1059050be7c87cf45df184dd5090008 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Apr 2017 04:55:50 -0700 Subject: [PATCH 0554/1275] Removed old contribution guidelines. --- How to Contribute.markdown | 55 -------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 How to Contribute.markdown diff --git a/How to Contribute.markdown b/How to Contribute.markdown deleted file mode 100644 index 1235f07ff..000000000 --- a/How to Contribute.markdown +++ /dev/null @@ -1,55 +0,0 @@ -# How to contribute - -Want to help out with the Swift Algorithm Club? Great! - -## What sort of things can you contribute? - -Take a look at the [list](README.markdown). Any algorithms or data structures that don't have a link yet are up for grabs. - -Algorithms in the [Under construction](Under%20Construction.markdown) area are being worked on. Suggestions and feedback is welcome! - -New algorithms and data structures are always welcome (even if they aren't on the list). - -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. - -Unit tests. Fixes for typos. No contribution is too small. :-) - -## Please follow this process - -To keep this a high quality repo, please follow this process when submitting your contribution: - -1. Create a pull request to "claim" an algorithm or data structure. Just so multiple people don't work on the same thing. -2. Use this [style guide](https://github.com/raywenderlich/swift-style-guide) for writing code (more or less). -3. Write an explanation of how the algorithm works. Include **plenty of examples** for readers to follow along. Pictures are good. Take a look at [the explanation of quicksort](Quicksort/) to get an idea. -4. Include your name in the explanation, something like *Written by Your Name* at the end of the document. -5. Add a playground and/or unit tests. -6. Run [SwiftLint](https://github.com/realm/SwiftLint) - - [Install](https://github.com/realm/SwiftLint#installation) - - Open terminal and run the `swiftlint` command: - -``` -cd path/to/swift-algorithm-club -swiftlint -``` - - -Just so you know, I will probably edit your text and code for grammar etc, just to ensure a certain level of polish. - -For the unit tests: - -- Add the unit test project to `.travis.yml` so they will be run on [Travis-CI](https://travis-ci.org/raywenderlich/swift-algorithm-club). Add a line to `.travis.yml` like this: - -``` -- xctool test -project ./Algorithm/Tests/Tests.xcodeproj -scheme Tests -``` - -- Configure the Test project's scheme to run on Travis-CI: - - Open **Product -> Scheme -> Manage Schemes...** - - Uncheck **Autocreate schemes** - - Check **Shared** - -![Screenshot of scheme settings](Images/scheme-settings-for-travis.png) - -## Want to chat? - -This isn't just a repo with a bunch of code... If you want to learn more about how an algorithm works or want to discuss better ways of solving problems, then open a [Github issue](https://github.com/raywenderlich/swift-algorithm-club/issues) and we'll talk! From 37de447879960291131d97aecb3d56c89da77429 Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:07:29 +0300 Subject: [PATCH 0555/1275] Updating --- Dijkstra Algorithm/README.md | 61 +++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md index 325bab40f..7ec9d352e 100644 --- a/Dijkstra Algorithm/README.md +++ b/Dijkstra Algorithm/README.md @@ -1,19 +1,59 @@ # Dijkstra-algorithm -## About this repository +This algorithm was invented in 1956 by Edsger W. Dijkstra. + +This algorithm can be used, when you have one source vertex and want to find the shortest paths to all other vertices in the graph. + +The best example is road network. If you wnat to find the shortest path from your house to your job, then it is time for the Dijkstra's algorithm. + +I have a gif example, which will show you how algorithm works. If this is not enough, then you can play with my **VisualizedDijkstra.playground**. +So let's image, that your house is "A" vertex and your job is "B" vertex. And you are lucky, you have graph with all possible routes. +When the algorithm starts to work initial graph looks like this: +[image1.png all are non visited] +Graph's array contains 5 vertices [A, B, C, D, E]. +Let's assume, that edge weight it is path length in kilometers between vertices. +A vertex has neighbors: B(path from A: 5.0), C(path from A: 0.0), D(path from A: 0.0) +And because algorithm has done nothing, then all vertices' path length from source vertex values are infinity (think about infinity as "I don't know, how long will it takes to get this vertex from source one") +Finally we have to set source vertex path length from source vertex to 0. + +Great, now our graph is initialized and we can pass it to the Dijkstra's algorithm. + +| | A | B | C | D | E | +| ------------------------- | --- | --- | --- | --- | --- | +| Visited | F | F | F | F | F | +| Path Length From Start | inf | inf | inf | inf | inf | +| Path Vertices From Start | [ ] | [ ] | [ ] | [ ] | [ ] | + +But before we will go through all process side by side let me explain how algorithm works. +The algorithm repeats following cycle until all vertices are marked as visited. +Cycle: +1. From the non-visited vertices the algorithm picks a vertex with the shortest path length from the start (if there are more than one vertex with the same shortest path value, then algorithm picks any of them) +2. The algorithm marks picked vertex as visited. +3. The algorithm check all of its neighbors. If the current vertex path length from the start plus an edge weight to a neighbor less than the neighbor current path length from the start, than it assigns new path length from the start to the neihgbor. +When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. + +Okay, let's start! +From now we will keep array which contains non visited vertices. Here they are: +var nonVisitedVertices = [A, B, C, D, E] +Let's follow the algorithm and pick the first vertex, which neighbors we want to check. +Imagine that we have function, that returns vertex with smallest path length from start. +var checkingVertex = nonVisitedVertices.smallestPathLengthFromStartVertex() +Then we set this vertex as visited +checkingVertex.visited = true +[image2.jpg visited first] +Then we check all of its neighbors. +If neighbor's path length from start is bigger than checking vertex path length from start + edge weigth, then we set neighbor's path length from start new value and append to its pathVerticesFromStart array new vertex: checkingVertex. Repeat this action for every vertex. +[image3.jpg visited first with checked neighbors] + + + This repository contains to playgrounds: * To understand how does this algorithm works, I have created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover there are play/pause/stop buttons. * If you need only realization of the algorithm without visualization then run **Dijkstra.playground.** It contains necessary classes and couple functions to create random graph for algorithm testing. -## Demo video -Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) - -## Screenshots - - ## Dijkstra's algorithm explanation - + [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)'s explanation: Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. @@ -37,8 +77,13 @@ Cycle: When all vertices are marked as visited, the algorithm's job is done. Now, you can see the shortest path from the start for every vertex by pressing the one you are interested in. ## Usage +This algorithm is popular in routing. For example, biggest Russian IT company Yandex uses it in [Яндекс.Карты](https://yandex.ru/company/technologies/routes/) +## Demo video +Click the link: [YouTube](https://youtu.be/PPESI7et0cQ) +## VisualizedDijkstra.playground Screenshots + ## Credits WWDC 2017 Scholarship Project From f24ecc22436be2b71f6c840464d6826ddf9e258c Mon Sep 17 00:00:00 2001 From: Taras Nikulin Date: Thu, 20 Apr 2017 15:30:59 +0300 Subject: [PATCH 0556/1275] Still updating --- Dijkstra Algorithm/Images/image1.png | Bin 0 -> 61926 bytes Dijkstra Algorithm/Images/image2.png | Bin 0 -> 63758 bytes Dijkstra Algorithm/Images/image3.png | Bin 0 -> 65232 bytes Dijkstra Algorithm/Images/image4.png | Bin 0 -> 65286 bytes Dijkstra Algorithm/Images/image5.png | Bin 0 -> 66333 bytes Dijkstra Algorithm/Images/image6.png | Bin 0 -> 67070 bytes Dijkstra Algorithm/Images/image7.png | Bin 0 -> 66716 bytes Dijkstra Algorithm/README.md | 66 +++++++++++++++++++++------ 8 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 Dijkstra Algorithm/Images/image1.png create mode 100644 Dijkstra Algorithm/Images/image2.png create mode 100644 Dijkstra Algorithm/Images/image3.png create mode 100644 Dijkstra Algorithm/Images/image4.png create mode 100644 Dijkstra Algorithm/Images/image5.png create mode 100644 Dijkstra Algorithm/Images/image6.png create mode 100644 Dijkstra Algorithm/Images/image7.png diff --git a/Dijkstra Algorithm/Images/image1.png b/Dijkstra Algorithm/Images/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..aabe0969e2cf86efc9a5e2e3e313d8fa3e02818e GIT binary patch literal 61926 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 y9tz2t8pe1{?q0s@KBMqFG) zR$QD+#ns8u#@+$~LMA#b9bV(zA?|R`*R%L$c_;acE+#UMV@cnpy3;w+km9H)R75GV zf~crqR7B06)^u2s67P`3L?My0BtHiegu<$*dN(8w>~*{yWUxP`(m_#O3dXtAa&&H=JUoOHWo12|kYsNb!o2rLFhUKc^8`Ke zX0c>7`{6i8$eTh~14M6%E~60&#DE}`^7N-+GLI-O1VUFn7lW`1a{KWF3-XI3YlIUT zYHH+V64S|%p2g@#Y2d@QUWYB{@1GWbHWy1*Gxo&uLH7a<-DsC2K`q~RhaiJ&kd16K ze$XBEDFj~(;XATSLKnVXm{BrJ7m|Evmc22=XocR7t}bL)qxGWvQBXNIrIqetke04v zxJCvF_WT==D}!|H0vS~`@;uy}^$?=YG+Jw&#GpCE&;30I>|dJdH)E*mdJecL>=w6U z><6oA_;5aP*Aqj$XQ|`x{#wEJ^9~BdbuJ7NRR$V1|Fc33d|U{h>)mMx$0dX?8Ae!0 zd@!n+7#91z1w;DmditNirpo81_h_8ayNJt+hmydKrwE*!7VHjL3 z%JZH42$B zNyy_RvNs8=3RNnM9Aa^#S$-xRsRl1S!JxQ;znQYXWE_|AWm7mRMN6R4v5=25%TsnAu0v z?JsN|DLKO{7!XejZ^w~J+w1(3xi zHH|7<`MSdSkhUePD+Y=N%70f`_;8o%EXQv_S{&k%h{HG3?;t|*+wj>|b^3tTzMC)YhB z#aVo|oXqyj20Up-<mv(4N;le-Jek~|9IIBZcBiJQ2CK%T zMyWEj)DcwdUHoK5*} z>dES^>SHSWWt{nqMU~%)igGH}3tn`>OZ!x!wLWMbtA172)VS4}RCQ1bD3ww%FC8o= z);dww*H}_PSN&bMSuI>hUc6nMR5e?~RxLZ*IIpl+`Kz-ee9_FB+M0NgU?HMuveCSW zq3PnNm;Zp@gz1?8Lc7si*J}=bhhf&IASa(==MqqVd#~TB*W~g&0G+Y4O zc!Xs{bOcvKV%$KSV4Q0_fBYt%9brQ}L;S^86$JwY&rJ8sPVPmvcy=L6-`{bz2M*1{ zmBXhEZQ*>=oh$yoJ}y%96^xn1iJ3pJ$KdfWvZW`a3ox?i1=g~+$hGiW-F7tPd3^RL zyqzG3=Tfz^{iU!F^wYyape=gHV%+fi~ye@FDJ_iO{t6zLr~k5)s3 zO6-$Rl@P1IaKLTZf;~36Sk`OPt2@Cr($@DF9a}FSC!aE&Q}OjgYsrx(F1ut6vW3md z$E(>d^f@Ooe3(1YNV(oB*ed)`oyCDAPrHQY^lUp|#?QZMRquS&lXPqM+->Htt|r2% z{6aZUN5r^CuE*+4>W%L$0CFK%5i%YUIV2%uFeLFaXDIt;-_PNpOYl4}ED^lnsbQDm zs2^LxH_=iMW06k~hQr|_mm;QX+>E@eHx_&wZXZvid93Y6R-N4nCx!;%Gq@3*%pCYh zL!uF)t>YdBu1qx>4k$M$D<}?^74A&$kQ0PTQaK1Mur;x`h#jyEv4pVAvE5iLxqmS? zGu~Mcaa2>Bdvxl*{CyaN`4-k5mNxKZAf3uzO=1qV8jmMrExYndPMTn9K}zzsKIJAk zp;Z3i>%GMvVm5?x{Bt%V(=8(69J|?Z(F$u5V-xq;p*-KFu_kvcZ=Gg0>%GR^o8|BB z^=I{0^!;2@T|M^|?A?|Yle(ujQoet5Q@SN@h2@;{;bz1rAzvb`MooeBMt#>I!++H+53&BsiTgo z3#~iJ3qm?>7U5>nj&B`7H^CbrPgt|br^%zCoA7IL$HlP47ibRr?hO--rw^t(+j0Fb zt~FN)l;zTQq>mby`fO^)IxA|_+D$FCf9Vd7F4>;VCx`bF-;;p6Db5F8Q>tm#$`>of zl}wc_@_eptX+ESziEfc+Qqpo$H&6;nSuhFv9 zZrSl+%&??m>7wm-hfuxeCu>gYo44gBwzq((*RSx==td$F{;fCGhrE`ZTXiG5^|Y?a z?0@58cyTahmO~aSGVtO>NP$!+MDmX(gOAGr)~_VJ1<^R!i&O-2S4A>U7U!p z3f}~vJo0umK4PD%KU!5y=Z@!%?=r|TFnnMnIf;EIN{%Ki4So3o4MGkNVnIwo8?nl^ zS%eeqhNtP8HWas$8b18t$4dM@m16Ct8M2#av0(o@=D}FT8D4sRC33f`)3%YzP zH=EH}NKe8Mc28OwtVE0H9b_#^Ri*zQJzd@Ak8rtgCMwpN3`i)kbVt~5Py{(yG%p=W z&+qqp`+`=Km&5?pi0CY%>jnXVOAY>olvSg;gn)p|wb9UV*HKj9H+OPiHvQyeX2I<3 z;0!zs0U_wk4_rD}xSNuBJJ>tA@p}tV{PP4qa1FlALP7S=Bkp!W6grA3Wa3V)7Gzw^ zoXo5g!boIfWP+}rEcw+Wr2aD;_)Cbw+TGompM}NC%Zu5IgW1W|iiM4jkB^0worRs9 z33!6Z&BxK*)SJoCjq=|~{=a!7EZodpZJgb0oE*u(^O~ADdAJKvP=H_b-=BZwwD7k1 zpEo(W{byOg0$IS{u&^<+vix^$V5lJYF29P6w}riqgpGrRqZ{xJVQyA#!GE6rzrOjO zH~z1Yy8knhi-Y}tkNjWX{AZ*f3wQzlYeD~N>z})Tx`dGgS^lefVWde)33I?2L^cx2 z8o(zM*ffCQz?A{rzn|c1uZ?i0CRGRsQ3zQHF%56X(_DCO{r$z^#82bRo%c}<_avVp zAxtl7dEU`crhdd{vhY{Y(wCAyE-1EmxB3w|wH}#V6pAW@>XYbQJx7lB#Rt29!_Iml z*>neowRX_GPp|e|*G1R8S6YSJ^aE*bF1%?l1VXSVDTZ|m7O{Q({13ST&09c$jLp1`woMcLqi(raCV*?G{@%_xCV`oxu<#MqKA0S3MLPrP z85VL9D|owjMLrQ5KI9UM)lKH_c)zD_KufM?y;nsgP3QBq)g5M=1m(Pk`vw)Uq7{1P zUi`m0r2^g;17mRt4Z|swU%IK(vtnH$)a1GPJCdY&vsM{Tf-@HTuTxG@iM`U;Fa%gz z&e*}*IF5apq%fQky?sX2_jfDD@rItO-efReuP{yCPcMGqfEVaARzpR+(1yu3e@~Wg z3dP#V>HpW|4;h9W6qiBn!+Gtnkiw-;DvM%>G_`$3It5z#8SM+93w~k>oqwy z-zk_o_t)1YJKpFe!J|9tW83>-gAcMqzKjdAh1WN!gPLFP$RMD|Fl+&VJ}SPu4hbGY zu&->KulW_p(&#UFKf#!u$-krJz@ufc z-N2*$4J}J(d+KKI`nUO9{))b)b}1jaAk5f6MYq2e+Bw|3p$X{f%nBQr<3{q3TJG9? z%5t0DUd29ug~XV_g2Xe@YhUHn#y}ts;oA3ng7wSubnDh^9jY|tZ@2rA@Z;0*k^B_# zxM|H246Zm%bc~2&qbha9Mx@&WUU{K0^UUm}2A=WuUR;})s632`x6QHbu7Mbt1Ppfr z^U`aDLt_P}1h(&2sp*{`OLemzLh?e5^;RdcO6%Wp6x~2mtm9*~s~QTy~#v%GuzWGV2qHQKXvxD%8Ash>iK+D+XN1p{y(ga`TBwv2R5r`!XKf!pHeJtu;#6iAwu#k zQ?s+0yEhsuL#Bf@y5$8UN^I-vzN7ZUh5};BlSG03TMUE&ZA(h7_S+;BjZY&kzIqdz zEdL6c3J5AXYAOJBHjBP)oXg*+P* z&Oa$HlrY&N1lpDSNWUaaIW<+mopqx3RN+c!PiO`^GIVp`nv~le(WYv$hsNB%!X^j{DTB-gsJC&nKH`XPQSp zl0pssZugkH9o|RMf5PL18lr#P*h~kAODWMl?}F@GmODmCGphPe1BtpKCk3;<{3FpX zSe6FUMl6S$=F3};Z;aKRIi=dGM(BU*m^MaZ9xE?!%Kq~DbxoN%u>GTh%M1t1n4xsTNe02Y-$fr+z;{AEu=(wO{x!AL_pD(H;LTEetxX zoo&cI)tKMvR^m059r+v2VNQqb5Z)J!?-nYm0pJx*S_Td+EYx>$6LX$<3(}P%fpoX1 zftfn&V?TQprmvMH5{??L*B;!yRvoz$28zf0bIE-0_QJI74ec*e`~pG)Ms-e$q*-_{qF$frcN$KAKd)I9IRhuG72Fmjlr^8|TV@M=xaX_RCV9}q0shyiGWNgL}B5{jIrwq;Yv zs>kwV#{ucDBY#Qk{>%=RQdUm{SNn@*)O)U1c;5Bah^B7AF7sRgg#M3GNV9XuW_00P z-Tx$z-uD1F`F{`d5ETuDA=!glu8}THR=t$#Yq$2w9T~kfy9o#!nG(YHgA-xWmqtc* zPaTVxcIs)Gt*CS)Eu(-qOnS{Krl#79hJ*qjpc@cuADOxm8j65&X2P^vvPPGZMuFa2 z`CESB+K&@!yn9psuM9Y#At?<-_316zhFR+Gqq+u=ZJ$w_X!-DaS_=*xKE9Skb-i8W z;HBB&{%K<)1rp;8Ca~UsrFT{^P-56RgNSEKJ@4C!o*ujl*4pGQ>+5{k>qs)Z*V51a z7-o-;xT1MYx>*MqgK6s+uQbMG zN-$@iQMZ8WikdlcYnDrM-oc^3!cow6Awd_+!<2d2Gim);fH2QYU|t28@z$laI7=S8 zh|5j;(=;w$+>nv>01~kDELs5lu8ko9*5d`WDZ4t|-mp)rj!K zac}IO6kqbg=&B>fk0kekbv5CjcJ~LpfY8`xy+dTqH>m@bzWAi=xUOJPPOyv~DPPg`R|x}Z`;~Czi>87# z0+-tD%;-ij+5*g!0qLMq0B{QN*>GMU!{CMjty&aHYe_Iq@Wy5vg2MD+WW#qdBF}Dk zX-A&d;+`j>3rdO$zvpCv_#fN3-bdC8a%$?p*%p`@FN1$Lm~tg zKxuO44R*pROR+hb_*3_Sx^*|z#tt;@<+9SOkv*$Sj@;YEq5AFgDcPreqJs6onCGPQ zwAKq=V#7fro_}!TC>jti?`Vqy4DzZK-yYHJ2IAALd;L$XiC_0&@Qh}inOxAwFq8mi z?UQ})7TOCzIWy#=%3-v3>Wk8YNQEEW-9|rjaaIe75FFeLaFn@Uw?iwRMH6Ah^mTaC z7zo&)C~IG(@Qgx|`nAaNiGg_<-Kt!Ekj*fJH~=`cC6ZKOeR>-Vw~WNv3AYT}zx^4Y zkHOoE@H2Jt7)LcQTCSSgs2Ba0NHk9ZN< zHTmtjkP+HECYRiR=h6aRmP=O)aEME|d%l+yE7ne^SDOFl44utuQs_*HIlvU~oV{AX z+g!cOcxdloo`M102nQz^eijX)zNGQ%JdYe^*cylKXE1SJ#(?1z2QbExnM>&%j4$ow zcA&sU+q>^Wo3cK}&=DD4%--)|M7IzCDWr8w5Mel#w<_2L0zignkO5a(tdc-()25U%0SE-_ z5UPGia5{MW+~QE%XHgcI)s=%RpoLsx#Om|P%Mfq9Pi>9Ahl92WFy|vGi2e#}SX_Xc zNywP}tk5dALqd;z;4PT=RDj}0SG8-%*^I5pjn&kI8Ll@#k^GFMXQi+(tB!oT4H>Bm zcw7OP3zW8{@?v5jpoR!^*Um}{e6)kZUzy3$EG>kEl?YAoNF9UAOkk?P<(S>J6bMik zYy6X+`)36K*;B&RxO(_$JmtoHQ-+O}?H~5+2lzp|Rj9J4XbQ|GL-V|HMmY0N;cRi| z*x{q2Q%rt>r1C=VMC+V1FU`K8r7LkyUyJNqG|h&42GI_dJ?NR|Nh_%vKLa`B%v7=q(^4CW#@_yAF`bx5iv zh|r|7Ce#RvP}6H-aaOYMX2G8PY0Z% z(wC2yelJ^-($4x3ejrNjw5z7%>x$?yLT}h^`TQ)k>Ms~3b3VTIx2Bsvf_*u7;GY^} z6Y#)4@fgDJkf>O!b*W3TPI_hK%(W?r`vxV{4esufFhck~kFs|rUCo0^H0g<#+ymO~ zn*euWPjmaZjNljDWgfKgsf3@joQSfG#c5bLBNpz>v)*Xb-20j6A_S~?20-)GoV6%W zWHYi`)7cI;&oxlUJeEaR8$8O&R&`4!qJ_DEcTKs!T$?^AH^f_%Mf+Kv*aUVb6j|+= z+c`9LR9-u`8%FJQcM=c8#u5*oo^f=-gL7sc;4(f~KkWb*mCUaUKMK>Xgp?IPnWk>{ zO2|tfE-GX}TRV>S;HIa)z^@D=yvVL8annV%Qx+n$v%hf=oJlD=$OQYMU?};DL3A6h zl+Uf8NI!Twj7up18+how(P2bIeM-*tYzonN$v1zqSwtnA=am(HZR1amss(7qf{xbw zH6s>#=b<&RA)8XoC)#sehr&fazu#U|_xnC@=%h6zv2Cmn|CrDp%p0}UbkG44=4T2i zTXi0oM|2>6E0jJy8qU!XAs3eht=kk@@flaNZ(6{z#F}-lk47vtVc&k*Hhc?W8G{lqvGsQDD$!+qln8cRTmaT+G}^qB6;KLd^cderCsmTF2nbIYx^-UHati;%!T%crxl>kU z$-6rWp@Gp`r~02(rl_@fQh+7|6Ksg&0^THqsQcIUB|i6nCkIPRNmmI6On%8eE+F_; zd|_0hPFrgxhNRH#6Cj<#_ClD@a+XAVo^-A0;bu;?c^lgbz~M^b$&E7I*?yp zxuLE6uVI<(-dk+(qEHHljOOk~X>kXe9|8CDgaMih9T`l?&sk&SL%&H&N(3Dr;{UNx z2$+{3aM=SKkBW?D=A^^nX69-${<|q38gb1ol1F3xf>L5b!qTSEfQq{0uw6*rlqvPY zh6md0qN4DTx1_D{9QxICNiEygNQ^?bo;O|#3SP|Z?8tjWBx9^A%DS2gU6eb|>N$liXF51=(*_2}x!SBZ zwM+=sslhkK{{CIL=@)-CBdH%%M9x%dGMdGd>+60Qwz3I@A62&jC1Mvb18>iXX?n8G zC<*&?j1;k7_NkF4enJ2r%NeynuFtc(Q1P(9@1Mrts71&DvRvo?N?Lm( zUb6Gfthfi~=WHjZeX7?cYEN5J=t;hhZ7hd5SK9P=P8Q1AXnx!OQ~_k~07Zp=rZ|9r zjK}&y^~jZp;JO&p7?39 zhTiB9af`vE-k$4l!VR2`i_&0f-2^^d_ zC5i`Rps|7kIOs<)Ot;|R2*h_h%g2(q{IBSQCVAqWx`(y2Cwh0*s1}8?SN(TxnO7Js z=ve*og0h8k?x}+(Tn$>w43&?!%8u9?YtEl&MlE_=5)vG@v_8th72qme_GAodX1I__ zFV&jU-R-ZRcr>SE7HBgz|Y9OK|Me`=O zwJ;xaN2D~kr}jqQSND&>EtA~kbWQpiUtG9^Q5d4q>v}=*Y;=eB2b#}&G?tAi_3WtZ zRrlvy?DJ!?z<1Piq7=w4t8}{N6gngg-*_W}kzNek3FG{z0I)$an5+p2(8f4w6W@ox zHF7VSzd09Ng0a?m2?;_510>AEvIYL)9Y7zCBDnwC(5$-dWzK%G6syFu!@8S749 zgrwPQ>e|){{c8*6QFj7yRUz_Yk0j9(r)b(Hp&mH1U_gO&3xTN)I4mzh)V*y0tY0+{ zR}mRA=0uT5l2M#Vps_DS&r(w-wmd#OtweTwZ#8=j?Pa#^hSP1QC*6DA%wLNrXNd?i zzTfTSK!HnTQL;U-qY!mm z6!EXY!BU7a+21e9&l;Q8mF$+G?FrGcbHIym-RY$ zAmA>*3Hb1{7qGrQ3DKJlDtLPizn>D&l||9k$l9FeW=@&@xTjHv234|;{8_!4scNu% zNrU>sZgc)L+ENsyc#MYj=zzW%0l|M_4cq~ihQzLQCdrH{KR1WAH@AR3bD}#~I@54s zzY3CFn6WIGG*zsD2?V&w|eWT_KOUfdL`)u)Z~GtQXD?yfi#J0z$)MMol*E z+*Ff_8|{VuRiuX}6LFxQIs^71-yfNn0KTI`;bwoO*S}ZwX}~kYS+H(a;ULsgJn(*F zNnmW|jENoHoh~oiu%+qRl!D7m!!lz^HLI=viK9$8k7T3pBqJ9aYgIUrm}{;H#+@iu zU;&tL2^#?4;YC>1&FlW9A!WhjS6W?_n#ELE^oRZCbYqMgt$2L^GZim;OiBk;vo=I) zL$5E7Kab?w^a+}k%P;cN{m-}ipRr;AO}s_{U>4}k=1fPHj{{Ye4oB~>*>6;d zrBze2x6Yiv*B+-K&b?0?ztdUyQ7&P8Z=Eq$uVmCfk;@^ntkQ?YZ%C(m(_)1GgNtq| zrm?6`r-PnB!gz_!KYjQ&aDx}ripGnCF#`jM$e`7Tt1dY%TyE}^u`-l=%S@^CtrVr2 zXcvP!$Cb~1ncU@~J|XR})UL*4dPz)aj-`N`!E4^L z&acMo{+LK2Q^_j?23Hx@Z$j!{5kvX=W8P|QxR+F!4x^%J75lyzUiZvtyk+2d=n}Or zkb}laJ9U8Kj%)xNk$7}Jpdm4wF>04r`HDtNCGVtskQs)Copq8>nPu}cX7a-jpoxKSNF2^eGlC$ZhY0xl3BM*IvDLPxWOz#s?ZkEzW> za!^Y#zR-apH0T}y0;JU9L!HGiui4ZP({zAO6$~F8lB;5-)UrAn0VUTS$fOq?2^AgJ z^Wpvj7}fv^eU^$s1nR9En5@ZLduP6KoIz-dYhdR5mzwQLXzsY{o_3nQ9hC`^|D?(Pk_OQZn1Oi>W>d*( ztx6}B3$?1u-q9-xbaDdypAk3##f)u6Q!gxKfvL_VR&UzL0 zRx9GzmK-EYxu}^tI6(65{r_fC1F$(_84qAX=xE6{sibvO%W*1}v-gau==co)CxWDQ z)2XY`*NC;$=_<=9=fCM$by%mGvl#fZlggv?iHQnQgn8)b>chX<;{?wZL1_sIIf=ol z&sVvuCy|Dw^+|ll-pNbA%Swk$z?81I+;$MJW%~I^vZ7cvoOu6%K_9)g&DukNiZ5_6 zFv_i`UKg4%(^kGE`Y#lCUnCRg(fXqT7yc9`R-)sff55-^&pZ>?xT<6?XDbrfdB z$8s=DAm2ERH*G(rZ^~ut6x5(`x2O!}-0SYEwkK5-wp^vdHl%-R(%*oLkMSsk!NGS3 zGCFmQJ}q;jw$?T0SX%GGy=|roB~N>iNYeO|adH^Tw&uUIJQCd0 zwl+1yn1KkPadWV0Du~MWwKbOQPT3QZ)lrpDDRhwWuuK^P@mF>R+@9e$mXw;WECD|E z3nXVwuC*7`M&5@E_!tQ|M?s>&%`}`FYPeI%qyRn0?V|#&vtk=EoYE^g%b0VKH$SY zEt=jmKq74d9XKGIOw<=+;Q2BtbbOp71~)tgTsM<7=;apkyq(Chx8x2->K82!EVl|k zntkC2er1!Z{(Is^$(NOl3S;cJ^oif`>i=;vGQcmk{UD$S$YhG%RCCP#G1VF z+N|pZG*>w^nkd3P3T)rhn$$O|80zyK2A&;)?mRxo0C@h@j+wBbKaGvBBJsqO+aCss zEFTuYw?^kQmjpm#)#W(%o*E44DT{@As-0{AdW@J3@`m9+Kh{Up2QjsfmYeKWL|pF+ zQuAV&&+}jPNIAc0laDJOL9d`TLjoBXOxX&yD0be7_7Vd2lsvCm)*9Moovtki>0+f^ zCgf1qr^3%4I!7&>zCd*Ppn}ma|A~)alFM=Jk4()~4|_4le2&g&%JZ3s1&HrPzz`YS z)f`i5<}g&LIsiY@OVMEX)#_tHRhfw?BGc53iMb#lo;7q7cJI!_$V2{UtXY*TuPuR< z;7-iOABrR*w_n&uiWR^Kj)VWUI~O4!XLGQ8qUfnV>&;SE(ouYSr1)Ik7qe2Tg|h3_ zH-LEWacWbk0$})~p3eFmE@?`s#)TVp@$H;*%p&2s@Gv+Qz`Z~Q{u+iUIdd3$PX^5< z;-Z)XGwRQObS>VG8{r}{l-o+4b0H*6%LIs>F6>Q!cI4EK{f@ta(u%Hnkmy)!U@Yos zu^x?++PRm}5pGbyd8?n;4>sfr=9f+iFoL7GC5i!x1K{JTP&g)N0U1LJ1>XZigVo>q zlNu!dWZI6_H3k~fdS$uR1u^h3&)=Fe0(GJUCNPz%JDUsrDg}@M&sEzbJZQ?a+|ey$ zsSN{@Z?qUsOSL4Z4UL1uC%CbZf62WqK^7PPa~TG`O+7?Z+A`B=G%HU64h5ddUq-Dm5z~k zq$x$!hRlb7`_5>Y2=!(Fg_nQ_PC~bqUj%ZIPTRP$Ap0 z&3^gw#FqYy4>@{kd+^0vvEnEQ=Y#lZR8iHgNeU{yeXvVu=Jhqzr^&PqXaS~F(9 zRtXp!)4`C}E>?X-jU}VauON%&rncNKVR3-hHoKHw1rHA5ZT#yUA%N#D^|mVU%AsPF zYJ(H|Uagt>dmMK}207@1q?eZ9xXS5pOkx;4ruc-Hn)HBj=ROV)13Aq~5@?XmpU*z* zI0=M9{GP<>J3bInoNi?<1<>Ka2u}QcG4LIT3_rZI806OQ!*Jlo(r#aQ0e2`8D*_cF z?8IPoAIfllD(|fE=k6}X0vs$a?2-WH3Eanjy>8zs<&^0ia>Ym^W`|b$d!SoI_niij z;h;W)Qb_n)+SD$mjI4eMW1BxJJ*XlKwU)xRiL({*%S#QXqy6~=2n!Jt2&9lVMKEpc z7Ut!T$G~tXVJ|@_k8J&+!4QL+QLeRDE@^HbBUQS^nF}M)px8~Be4#zto+yDn;Sr_E z%on(VnDD~FDd<%kYJqWN3{G)1Cn1Hicp==#kvN)8gQ1o7%w0Gek}8r)WQl1L4Q=0D z6K^AWMl5wtoBjoH#Ps7NM29KrSSw!=Lz}p@o z)zAqa&0#cjlEOL0`9j*O4JA}Ia3%&r$w`>4nkf2W2%bORIJbLt#B;6NYRpRVMUqOc zO?pH{YUrUwpJz0Z%I&LAUG*3sn&QJer2|pWy`R`+7Z<$Ys2x3*ENINoh0_&|6CbMU zlP9U7`R{}=5B}|1**%uD2^gD(>2Ro09}@1Xl)s_kpng&_Z?%dth=1XY@#mk(~9 zH@oI+j%X&f8Kknst)a(n;i}P%IYWoNC&K`rIH5ox>X;{i99=61oJ~@m&97~2q=BtI z42PPEDocR^Ik>jquAA~Z?=G&JP*9It+OnhK8aZx}vy*7*h@Mk2Xn!VPzVc{Xr7^(~PoFja*L2vE^a056SUbUIa}gds8=6e2bqlw&a+R9N&d(Z+>B zS;1G7`U@f);-Bcs_Y9nDs>>x zLkWpH5m+Dvf=Ky5v3`Ma4IYSoeg{F+bvps=VWfPgxuXQR4nZO-*q?=PwF02ecb=ns3)lT2 z{vx@POBVP*+mq}Dm?k{$gXIDOEwYRV9g0jyIags(5AcwvsZ5^r9&Ds!p}2m1?pVUm-Sd)|)~OSSD`TQniLw~Rw* zsY>RAE@L0!-;YV}hF#x*Y1SLCWxr3#Qdva~F8ZZ)k|gN}C$O{{+j0Zw{UEMVq$;lb z!f-Zbwgw?+$;drM%~Sg@W&2u^{ETPAGCx@a@6(`JQ33^DD>)Ak2Ek5%MIVO{?QEig zIVz7TwcfD=pG3{mmOIO%(aw~V*-E|~wO;*nb;kg}_QxFoGuifAVwL0=_JNP(XoLbY znafR3svzrLkPlX$9mbIy03q5m-n24MSb5i0nXNfpNw?uy6I=^pX>3;A`y>y+>s6MP`um$PnDOa@N7LxO+<;eu7R4b~m?X_1Ft?p>{&{`)n9# z^uEwnSWZlqWW0n5f6hSUy#Dm!_2<-Pv+rh5N}C?y&(&qnuQiz%MeRYRxmdOH_iu6M z=jd+}As%A+v;YM87KBbiQEZ*WH?62ib5%u_Hh0CXK3Hzr+MFk=@0>yGNwKtP%o!^U z$a3h|==+j9>4_bk4bh9xSSWUAy4ICz-L$rq{6#eg)Yu!Q{=nRS7~mri2s8r$Nmo{- zJkI62Ar5 zdKVEU9v`9Mh`@Xw`SBZRYUc)N=Na@xh-f}w5%Bi0hkSkuVFlHx99~VmN6(e35BKGn zrx^>WjH4`;wvKG8xS%T5(}_dtrjDe7+Sn1pgAP^6;PtSCkgL8ZA*(8}UxIq7T`hM-Rs23oZhcw&;yh45npGvJX!BaWeGAOnHC)z1=RZpYo+9pZ1qflOHuy3k19GWrT*hj{7_angQY;ZKFh;njFUBKhgoTg3TKqSr)&xgFzIz}+dM7iuGyx$tW}awD z)>48hisUIey^E;P)vwqZ9w4QsV;-(9T&&KtH3sjaWzdp(@G^vrHKjYw-$!IHpfW~= z0(j@FviOiwO;R&-XS-_Dkt}3*&PSFc`f01SZzlD_rzZW!;jJ%M&C%RRC(dCwx-g46 zGqZ58T{wo1CipNf)MOv~DPC3jQTN7mvWk;33?swN)p=Kha=Vn;WGOYcTx74&mNY4v zb8=ZzX)H;05AY+maoAq6HZW0GCXJphb6e*xli!^5?S!?X>$lhRr#Xg?J zc(JsIRx!2QYdZhd4ANI{>cvBu-Ysk zrS!m1@xBa}o$rB;K(3{(@F0 z_@Fz?fSxmf2%G_^e-P9GB>7Aob=HA_(O;44)O^AK8kU>)FciM1;GwE4l~9QfC(=?l z>=y+ZX4SBF6+%$1EY2g!?_8$#O?eqA!cR!944cCk@XbFyT< z^4a)v#9ed8D_`g`YT53z?MqeUrLLsQ$;ua`-caTJmf_DR*|%Atb^CZ>5;I%aQlRWy zhlLQ98N3J3HS#u*)aKJ|ztDKOWrn7=@w3LOe$+;%B~$h$e&52kt)KEosj&$(;yFPe zqZ2!VG|2nyo}MD{L7ddAJO!Jt>&Fyqc?1u_s@jV(+}ZIzrU>P&3_MX3zj8$EpdxZo z-fQgNe%{8}iA^|e2a|eO#7%_s;7QA3E(@oMBE8Wnx=oiTPlruq`1|w^&}Cg4A7wvC zjg88e%&JGs9m$G+2y#x(PTCu1%hX%5`8_4xnD#A|0nLS-MdZV{B1a2Z3Y-g`Y2OVd zr@KN3677h;dV}&F#x6n_mVZdBhbWl>%-&CX?X#uEhEqZhW1S{<$|{f<;i8)iD;r