diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..29f4ca7e1 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# 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** + +Our repo is all about learning. The `README` file is the cake, and the sample code is the cherry on top. A good contribution has succinct explanations supported by diagrams. Code is best introduced in chunks, weaved into the explanations where relevant. + +> When choosing between brevity and performance, err to the side of brevity as long as the time complexity of the particular implementation is the same. You can make a note afterwards suggesting a more performant way of doing things. + +**API Design Guidelines** + +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 are most welcome. + +### 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! diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..5c72ed5a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +### Brief Intro + + + +### More Details + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..c52564721 --- /dev/null +++ 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 + + + diff --git a/.gitignore b/.gitignore index 189605960..c2f483cba 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ DerivedData/ *.perspectivev3 *.xccheckout *.moved-aside -*.xcworkspace *.xcuserstate xcuserdata diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 000000000..6cb714110 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,25 @@ +cyclomatic_complexity: 12 +file_length: 550 +function_body_length: 80 +function_parameter_count: 8 +line_length: 150 +type_body_length: 300 +variable_name: + min_length: + error: 1 + warning: 1 + excluded: + - N + +disabled_rules: + - valid_docs + +custom_rules: + smiley_face: + name: "Smiley Face" + regex: '( :\))' + match_kinds: + - comment + - string + message: "A closing parenthesis smiley :) creates a half-hearted smile, and thus is not preferred. Use :]" + severity: warning diff --git a/3Sum and 4Sum/3Sum.playground/Contents.swift b/3Sum and 4Sum/3Sum.playground/Contents.swift new file mode 100644 index 000000000..d172aed1f --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/Contents.swift @@ -0,0 +1,67 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif + +extension Collection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a successor mapping to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be less than `endIndex` + func formUniqueIndex(after index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(after: &index) + } while index < endIndex && self[prev] == self[index] + } +} + +extension BidirectionalCollection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a predecessor that maps to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be greater than `startIndex`. + func formUniqueIndex(before index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(before: &index) + } while index > startIndex && self[prev] == self[index] + } +} + +func threeSum(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable { + let sorted = collection.sorted() + var ret: [[T.Element]] = [] + var l = sorted.startIndex + + ThreeSum: while l < sorted.endIndex { defer { sorted.formUniqueIndex(after: &l) } + var m = sorted.index(after: l) + var r = sorted.index(before: sorted.endIndex) + + TwoSum: while m < r && r < sorted.endIndex { + let sum = sorted[l] + sorted[m] + sorted[r] + if sum == target { + ret.append([sorted[l], sorted[m], sorted[r]]) + sorted.formUniqueIndex(after: &m) + sorted.formUniqueIndex(before: &r) + } else if sum < target { + sorted.formUniqueIndex(after: &m) + } else { + sorted.formUniqueIndex(before: &r) + } + } + } + + return ret +} + +// Answer: [[-1, 0, 1], [-1, -1, 2]] +threeSum([-1, 0, 1, 2, -1, -4], target: 0) + +// Answer: [[-1, -1, 2], [-1, 0, 1]] +threeSum([-1, -1, -1, -1, 2, 1, -4, 0], target: 0) + +// Answer: [[-1, -1, 2]] +threeSum([-1, -1, -1, -1, -1, -1, 2], target: 0) diff --git a/Fizz Buzz/FizzBuzz.playground/contents.xcplayground b/3Sum and 4Sum/3Sum.playground/contents.xcplayground similarity index 100% rename from Fizz Buzz/FizzBuzz.playground/contents.xcplayground rename to 3Sum and 4Sum/3Sum.playground/contents.xcplayground diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/3Sum and 4Sum/4Sum.playground/Contents.swift b/3Sum and 4Sum/4Sum.playground/Contents.swift new file mode 100644 index 000000000..37f75918c --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/Contents.swift @@ -0,0 +1,64 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif + +extension Collection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a successor mapping to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be less than `endIndex` + func formUniqueIndex(after index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(after: &index) + } while index < endIndex && self[prev] == self[index] + } +} + +extension BidirectionalCollection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a predecessor that maps to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be greater than `startIndex`. + func formUniqueIndex(before index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(before: &index) + } while index > startIndex && self[prev] == self[index] + } +} + +func fourSum(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable { + let sorted = collection.sorted() + var ret: [[T.Element]] = [] + + var l = sorted.startIndex + FourSum: while l < sorted.endIndex { defer { sorted.formUniqueIndex(after: &l) } + var ml = sorted.index(after: l) + + ThreeSum: while ml < sorted.endIndex { defer { sorted.formUniqueIndex(after: &ml) } + var mr = sorted.index(after: ml) + var r = sorted.index(before: sorted.endIndex) + + TwoSum: while mr < r && r < sorted.endIndex { + let sum = sorted[l] + sorted[ml] + sorted[mr] + sorted[r] + if sum == target { + ret.append([sorted[l], sorted[ml], sorted[mr], sorted[r]]) + sorted.formUniqueIndex(after: &mr) + sorted.formUniqueIndex(before: &r) + } else if sum < target { + sorted.formUniqueIndex(after: &mr) + } else { + sorted.formUniqueIndex(before: &r) + } + } + } + } + return ret +} + +// answer: [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]] +fourSum([1, 0, -1, 0, -2, 2], target: 0) diff --git a/3Sum and 4Sum/4Sum.playground/contents.xcplayground b/3Sum and 4Sum/4Sum.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/3Sum and 4Sum/README.md b/3Sum and 4Sum/README.md new file mode 100644 index 000000000..188f89109 --- /dev/null +++ b/3Sum and 4Sum/README.md @@ -0,0 +1,162 @@ +# 3Sum and 4Sum + +3Sum and 4Sum are extensions of a popular algorithm question, the [2Sum][5]. + +## 3Sum + +> Given an array of integers, find all subsets of the array with 3 values where the 3 values sum up to a target number. +> +> **Note**: The solution subsets must not contain duplicate triplets. +> +> For example, given the array [-1, 0, 1, 2, -1, -4], and the target **0**: +> The solution set is: [[-1, 0, 1], [-1, -1, 2]] // The two **-1** values in the array are considered to be distinct + +There are 2 key procedures in solving this algorithm. Sorting the array, and avoiding duplicates. + +### Sorting + +Sorting your input array allows for powerful assumptions: + +* duplicates are always adjacent to each other +* moving an index to the right increases the value, while moving an index to the left decreases the value + +You'll make use of these two rules to create an efficient algorithm. + +### Avoiding Duplicates + +Since you pre-sort the array, duplicates will be adjacent to each other. You just need to skip over duplicates by comparing adjacent values: + +```swift +extension Collection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a successor mapping to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be less than `endIndex` + func formUniqueIndex(after index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(after: &index) + } while index < endIndex && self[prev] == self[index] + } +} +``` + +A similar implementation is used to get the unique index *before* a given index: + +```swift +extension BidirectionalCollection where Element: Equatable { + + /// In a sorted collection, replaces the given index with a predecessor that maps to a unique element. + /// + /// - Parameter index: A valid index of the collection. `index` must be greater than `startIndex`. + func formUniqueIndex(before index: inout Index) { + var prev = index + repeat { + prev = index + formIndex(before: &index) + } while index > startIndex && self[prev] == self[index] + } +} +``` + +### Assembling the Subsets + +You'll keep track of 3 indices to represent the 3 numbers. The sum at any given moment is `array[l] + array[m] + array[r]`: + +```swift + m -> <- r +[-4, -1, -1, 0, 1, 2] +  l +``` + +The premise is quite straightforward (given that you're familiar with 2Sum). You'll iterate `l` through the array. For every iteration, you also apply the 2Sum algorithm to elements after `l`. You'll check the sum every time you moving the indices to check if you found match. Here's the algorithm: + +```swift +func threeSum(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable { + let sorted = collection.sorted() + var ret: [[T.Element]] = [] + var l = sorted.startIndex + + ThreeSum: while l < sorted.endIndex { defer { sorted.formUniqueIndex(after: &l) } + var m = sorted.index(after: l) + var r = sorted.index(before: sorted.endIndex) + + TwoSum: while m < r && r < sorted.endIndex { + let sum = sorted[l] + sorted[m] + sorted[r] + if sum == target { + ret.append([sorted[l], sorted[m], sorted[r]]) + sorted.formUniqueIndex(after: &m) + sorted.formUniqueIndex(before: &r) + } else if sum < target { + sorted.formUniqueIndex(after: &m) + } else { + sorted.formUniqueIndex(before: &r) + } + } + } + + return ret +} +``` + +## 4Sum + +> Given an array S of n integers, find all subsets of the array with 4 values where the 4 values sum up to a target number. +> +> **Note**: The solution set must not contain duplicate quadruplets. + +### Solution + +Foursum is a very straightforward extension to the threeSum algorithm. In threeSum, you kept track of 3 indices: + +```swift + m -> <- r +[-4, -1, -1, 0, 1, 2] +  l +``` + +For fourSum, you'll keep track of 4: + +```swift + mr -> <- r +[-4, -1, -1, 0, 1, 2] +  l ml -> +``` + +Here's the code for it (notice it is very similar to 3Sum): + +```swift +func fourSum(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable { + let sorted = collection.sorted() + var ret: [[T.Element]] = [] + + var l = sorted.startIndex + FourSum: while l < sorted.endIndex { defer { sorted.formUniqueIndex(after: &l) } + var ml = sorted.index(after: l) + + ThreeSum: while ml < sorted.endIndex { defer { sorted.formUniqueIndex(after: &ml) } + var mr = sorted.index(after: ml) + var r = sorted.index(before: sorted.endIndex) + + TwoSum: while mr < r && r < sorted.endIndex { + let sum = sorted[l] + sorted[ml] + sorted[mr] + sorted[r] + if sum == target { + ret.append([sorted[l], sorted[ml], sorted[mr], sorted[r]]) + sorted.formUniqueIndex(after: &mr) + sorted.formUniqueIndex(before: &r) + } else if sum < target { + sorted.formUniqueIndex(after: &mr) + } else { + sorted.formUniqueIndex(before: &r) + } + } + } + } + return ret +} +``` + +[5]: https://github.com/raywenderlich/swift-algorithm-club/tree/master/Two-Sum%20Problem + +*Written for the Swift Algorithm Club by Kai Chen and Kelvin Lau* diff --git a/A-Star/AStar.swift b/A-Star/AStar.swift new file mode 100644 index 000000000..41a9fac6c --- /dev/null +++ b/A-Star/AStar.swift @@ -0,0 +1,153 @@ +// Written by Alejandro Isaza. + +import Foundation + +public protocol Graph { + associatedtype Vertex: Hashable + associatedtype Edge: WeightedEdge where Edge.Vertex == Vertex + + /// Lists all edges going out from a vertex. + func edgesOutgoing(from vertex: Vertex) -> [Edge] +} + +public protocol WeightedEdge { + associatedtype Vertex + + /// The edge's cost. + var cost: Double { get } + + /// The target vertex. + var target: Vertex { get } +} + +public final class AStar { + /// The graph to search on. + public let graph: G + + /// The heuristic cost function that estimates the cost between two vertices. + /// + /// - Note: The heuristic function needs to always return a value that is lower-than or equal to the actual + /// cost for the resulting path of the A* search to be optimal. + public let heuristic: (G.Vertex, G.Vertex) -> Double + + /// Open list of nodes to expand. + private var open: HashedHeap> + + /// Closed list of vertices already expanded. + private var closed = Set() + + /// Actual vertex cost for vertices we already encountered (refered to as `g` on the literature). + private var costs = Dictionary() + + /// Store the previous node for each expanded node to recreate the path. + private var parents = Dictionary() + + /// Initializes `AStar` with a graph and a heuristic cost function. + public init(graph: G, heuristic: @escaping (G.Vertex, G.Vertex) -> Double) { + self.graph = graph + self.heuristic = heuristic + open = HashedHeap(sort: <) + } + + /// Finds an optimal path between `source` and `target`. + /// + /// - Precondition: both `source` and `target` belong to `graph`. + public func path(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + open.insert(Node(vertex: start, cost: 0, estimate: heuristic(start, target))) + while !open.isEmpty { + guard let node = open.remove() else { + break + } + costs[node.vertex] = node.cost + + if (node.vertex == target) { + let path = buildPath(start: start, target: target) + cleanup() + return path + } + + if !closed.contains(node.vertex) { + expand(node: node, target: target) + closed.insert(node.vertex) + } + } + + // No path found + return [] + } + + private func expand(node: Node, target: G.Vertex) { + let edges = graph.edgesOutgoing(from: node.vertex) + for edge in edges { + let g = cost(node.vertex) + edge.cost + if g < cost(edge.target) { + open.insert(Node(vertex: edge.target, cost: g, estimate: heuristic(edge.target, target))) + parents[edge.target] = node.vertex + } + } + } + + private func cost(_ vertex: G.Edge.Vertex) -> Double { + if let c = costs[vertex] { + return c + } + + let node = Node(vertex: vertex, cost: Double.greatestFiniteMagnitude, estimate: 0) + if let index = open.index(of: node) { + return open[index].cost + } + + return Double.greatestFiniteMagnitude + } + + private func buildPath(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + var path = Array() + path.append(target) + + var current = target + while current != start { + guard let parent = parents[current] else { + return [] // no path found + } + current = parent + path.append(current) + } + + return path.reversed() + } + + private func cleanup() { + open.removeAll() + closed.removeAll() + parents.removeAll() + } +} + +private struct Node: Hashable, Comparable { + /// The graph vertex. + var vertex: V + + /// The actual cost between the start vertex and this vertex. + var cost: Double + + /// Estimated (heuristic) cost betweent this vertex and the target vertex. + var estimate: Double + + public init(vertex: V, cost: Double, estimate: Double) { + self.vertex = vertex + self.cost = cost + self.estimate = estimate + } + + static func < (lhs: Node, rhs: Node) -> Bool { + return lhs.cost + lhs.estimate < rhs.cost + rhs.estimate + } + + static func == (lhs: Node, rhs: Node) -> Bool { + return lhs.vertex == rhs.vertex + } + + var hashValue: Int { + return vertex.hashValue + } +} diff --git a/A-Star/Images/graph.dot b/A-Star/Images/graph.dot new file mode 100644 index 000000000..941d66232 --- /dev/null +++ b/A-Star/Images/graph.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "h = 3" ] } + { rank = same; B [ label = "h = 2" ]; C [ label = "h = 2" ]; D [ label = "h = 2" ] } + { rank = same; E [ label = "h = 1" ]; F [ label = "h = 1" ]; G [ label = "h = 1" ] } + { H [ label = "h = 0", style = filled, color = green ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/graph.png b/A-Star/Images/graph.png new file mode 100644 index 000000000..c0a4b1cc8 Binary files /dev/null and b/A-Star/Images/graph.png differ diff --git a/A-Star/Images/step1.dot b/A-Star/Images/step1.dot new file mode 100644 index 000000000..5785aea4c --- /dev/null +++ b/A-Star/Images/step1.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = deepskyblue1 ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = \?\nh = 1" ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step1.png b/A-Star/Images/step1.png new file mode 100644 index 000000000..a983033a2 Binary files /dev/null and b/A-Star/Images/step1.png differ diff --git a/A-Star/Images/step2.dot b/A-Star/Images/step2.dot new file mode 100644 index 000000000..0c8a9d53d --- /dev/null +++ b/A-Star/Images/step2.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step2.png b/A-Star/Images/step2.png new file mode 100644 index 000000000..10b4300f4 Binary files /dev/null and b/A-Star/Images/step2.png differ diff --git a/A-Star/Images/step3.dot b/A-Star/Images/step3.dot new file mode 100644 index 000000000..32a75891d --- /dev/null +++ b/A-Star/Images/step3.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step3.png b/A-Star/Images/step3.png new file mode 100644 index 000000000..e195e7e8e Binary files /dev/null and b/A-Star/Images/step3.png differ diff --git a/A-Star/Images/step4.dot b/A-Star/Images/step4.dot new file mode 100644 index 000000000..16db76796 --- /dev/null +++ b/A-Star/Images/step4.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step4.png b/A-Star/Images/step4.png new file mode 100644 index 000000000..c07f34c80 Binary files /dev/null and b/A-Star/Images/step4.png differ diff --git a/A-Star/Images/step5.dot b/A-Star/Images/step5.dot new file mode 100644 index 000000000..2986b6a90 --- /dev/null +++ b/A-Star/Images/step5.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step5.png b/A-Star/Images/step5.png new file mode 100644 index 000000000..40a7008da Binary files /dev/null and b/A-Star/Images/step5.png differ diff --git a/A-Star/Images/step6.dot b/A-Star/Images/step6.dot new file mode 100644 index 000000000..b5e3179b6 --- /dev/null +++ b/A-Star/Images/step6.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ] } + { H [ label = "g = 3\nh = 0", style = filled, color = lightgrey ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step6.png b/A-Star/Images/step6.png new file mode 100644 index 000000000..9e7baef26 Binary files /dev/null and b/A-Star/Images/step6.png differ diff --git a/A-Star/Images/step7.dot b/A-Star/Images/step7.dot new file mode 100644 index 000000000..c5b26b6b3 --- /dev/null +++ b/A-Star/Images/step7.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightblue ] } + { H [ label = "g = 3\nh = 0", style = filled, color = deepskyblue1 ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step7.png b/A-Star/Images/step7.png new file mode 100644 index 000000000..0eedd638f Binary files /dev/null and b/A-Star/Images/step7.png differ diff --git a/A-Star/README.md b/A-Star/README.md new file mode 100644 index 000000000..b373d25fc --- /dev/null +++ b/A-Star/README.md @@ -0,0 +1,43 @@ +# A* + +A* (pronounced "ay star") is a heuristic best-first search algorithm. A* minimizes node expansions, therefore minimizing the search time, by using a heuristic function. The heuristic function gives an estimate of the distance between two vertices. For instance if you are searching for a path between two points in a city, you can estimate the actual street distance with the straight-line distance. + +A* works by expanding the most promising nodes first, according to the heuristic function. In the city example it would choose streets which go in the general direction of the target first and, only if those are dead ends, backtrack and try other streets. This speeds up search in most sitations. + +A* is optimal (it always find the shortest path) if the heuristic function is admissible. A heuristic function is admissible if it never overestimates the cost of reaching the goal. In the extreme case of the heuristic function always retuning `0` A* acts exactly the same as [Dijkstra's Algorithm](../Dijkstra). The closer the heuristic function is to the actual distance the faster the search. + +## Example + +Let's run through an example on this simple directed graph. We are going to assume that all edges have a cost of 1 and the heuristic function is going to be the column starting at goal and going back: + +![Graph](Images/graph.png) + +On the first step we expand the root node on the left (blue). We set the cost `g` to zero and add all neighbors to the open list (grey). + +![Step 1](Images/step1.png) + +We put the first node in the closed list (light blue) so that we don't try expanding it again if there were to be loops in the graph. Next we take the node on the open list with the smallest value of `g + h` where `g` is the current cost (0) plus the edge cost (1). Since all nodes in the open list have the same value we choose the top one. + +![Step 2](Images/step2.png) + +We repeat the process and pick the next node from the open list. In this case there are no new nodes to add to the open list. + +![Step 3](Images/step3.png) + +We expand the next node. One more node on the open list, but nothing exciting yet. + +![Step 4](Images/step4.png) + +Sicne the top and the bottom nodes have the same value we choose the top one. This is not a great choice but we could do better if we had a better heuristic function. + +![Step 5](Images/step5.png) + +Now we expand the bottom node because it has a smaller value than the middle node (2 + 1 < 3 + 1). + +![Step 6](Images/step6.png) + +And we finally reach the goal! We never even expanded that middle node. We didn't have to because its value is 4, which is equal to the total lenght of our solution and therefore guaranteed to not be part of the optimal solution. + +![Step 7](Images/step7.png) + +The final step is to backtrack from the goal node to buld the optimal path. diff --git a/A-Star/Tests/AStarTests.swift b/A-Star/Tests/AStarTests.swift new file mode 100755 index 000000000..87f674cd5 --- /dev/null +++ b/A-Star/Tests/AStarTests.swift @@ -0,0 +1,57 @@ +import Foundation +import XCTest + +struct GridGraph: Graph { + struct Vertex: Hashable { + var x: Int + var y: Int + + static func == (lhs: Vertex, rhs: Vertex) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + public var hashValue: Int { + return x.hashValue ^ y.hashValue + } + } + + struct Edge: WeightedEdge { + var cost: Double + var target: Vertex + } + + func edgesOutgoing(from vertex: Vertex) -> [Edge] { + return [ + Edge(cost: 1, target: Vertex(x: vertex.x - 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x + 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y - 1)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y + 1)), + ] + } +} + +class AStarTests: XCTestCase { + func testSameStartAndEnd() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 0, y: 0)) + XCTAssertEqual(path.count, 1) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + } + + func testDiagonal() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 10, y: 10)) + XCTAssertEqual(path.count, 21) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + XCTAssertEqual(path[20].x, 10) + XCTAssertEqual(path[20].y, 10) + } + + func manhattanDistance(_ s: GridGraph.Vertex, _ t: GridGraph.Vertex) -> Double { + return Double(abs(s.x - t.x) + abs(s.y - t.y)) + } +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..cacd1e5ae --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj @@ -0,0 +1,291 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099B1F8978AB00C7092B /* AStarTests.swift */; }; + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099D1F8978BB00C7092B /* AStar.swift */; }; + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099F1F89795100C7092B /* HashedHeap.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 611D099B1F8978AB00C7092B /* AStarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AStarTests.swift; sourceTree = ""; }; + 611D099D1F8978BB00C7092B /* AStar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AStar.swift; path = ../AStar.swift; sourceTree = ""; }; + 611D099F1F89795100C7092B /* HashedHeap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HashedHeap.swift; path = "../../Hashed Heap/HashedHeap.swift"; sourceTree = ""; }; + 7B2BBC801C779D720067B71D /* AStarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AStarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7B2BBC7D1C779D720067B71D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7B2BBC681C779D710067B71D = { + isa = PBXGroup; + children = ( + 7B2BBC831C779D720067B71D /* Tests */, + 7B2BBC721C779D710067B71D /* Products */, + ); + sourceTree = ""; + }; + 7B2BBC721C779D710067B71D /* Products */ = { + isa = PBXGroup; + children = ( + 7B2BBC801C779D720067B71D /* AStarTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 611D099F1F89795100C7092B /* HashedHeap.swift */, + 611D099D1F8978BB00C7092B /* AStar.swift */, + 611D099B1F8978AB00C7092B /* AStarTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* AStarTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AStarTests; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* AStarTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* AStarTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7B2BBC7E1C779D720067B71D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7B2BBC7C1C779D720067B71D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */, + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */, + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme new file mode 100644 index 000000000..5473b4c0c --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTreeTests/Info.plist b/A-Star/Tests/Info.plist similarity index 100% rename from Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTreeTests/Info.plist rename to A-Star/Tests/Info.plist diff --git a/AVL Tree/AVLTree.playground/Contents.swift b/AVL Tree/AVLTree.playground/Contents.swift index 140ec1292..34c1e6ddd 100644 --- a/AVL Tree/AVLTree.playground/Contents.swift +++ b/AVL Tree/AVLTree.playground/Contents.swift @@ -1,30 +1,28 @@ //: Playground - noun: a place where people can play + 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 minim = tree.root?.minimum()! // node 1 -var succ = minim!.successor()! // node 2 -succ = succ.successor()! // node 3 -succ = succ.successor()! // node 4 -succ = succ.successor()! // node 5 -succ.successor() // nil +let node = tree.search(input: 2) // "two" -tree.delete(2) +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 12befbe92..9f8695a83 100644 --- a/AVL Tree/AVLTree.playground/Sources/AVLTree.swift +++ b/AVL Tree/AVLTree.playground/Sources/AVLTree.swift @@ -23,71 +23,75 @@ public class TreeNode { public typealias Node = TreeNode - public var payload: Payload? - - private var key: Key - private var leftChild: Node? - private var rightChild: Node? - private var parent: Node? - private var balance = 0 - - public init(key: Key, payload: Payload?, leftChild: Node?, rightChild: Node?, parent: Node?) { + var payload: Payload? + + fileprivate var key: Key + internal var leftChild: Node? + internal var rightChild: 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 self.payload = payload self.leftChild = leftChild self.rightChild = rightChild self.parent = parent + self.height = height + + self.leftChild?.parent = self + self.rightChild?.parent = self } public convenience init(key: Key, payload: Payload?) { - self.init(key: key, payload: payload, leftChild: nil, rightChild: nil, parent: nil) + self.init(key: key, payload: payload, leftChild: nil, rightChild: nil, parent: nil, height: 1) } public convenience init(key: Key) { 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() { } } @@ -95,52 +99,32 @@ public class AVLTree { extension TreeNode { public func minimum() -> TreeNode? { - var curr: TreeNode? = self - while curr != nil && curr!.hasLeftChild { - curr = curr!.leftChild - } - return curr + return leftChild?.minimum() ?? self } - - public func successor() -> Node? { - if let right = rightChild { - return right.minimum() - } else if let parent = parent { - if isLeftChild { - return parent - } else { - parent.rightChild = nil - let result = parent.successor() - parent.rightChild = self - return result - } - } - return nil + + public func maximum() -> TreeNode? { + return rightChild?.maximum() ?? self } } 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) { - return result.payload - } else { - return nil - } + return search(key: input, node: root)?.payload } - 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 @@ -150,230 +134,231 @@ 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) + let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.leftChild = child - updateBalance(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) + let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.rightChild = child - updateBalance(child) + balance(node: child) } } } } -// MARK: - Deleting items +// MARK: - Balancing tree -extension TreeNode { - private func spliceout(){ - if isLeaf { - if isLeftChild { - parent!.leftChild = nil - } else if isRightChild { - parent!.rightChild = nil - } - } else if hasAnyChild { - if hasLeftChild { - parent!.leftChild = leftChild! +extension AVLTree { + 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: node.parent) + } + } + + 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?) { + guard let node = node else { + return + } + + 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: node) + if lrFactor > 1 { + // left-left or left-right + if lrDifference(node: node.leftChild) > 0 { + // left-left + nodes[0] = node + nodes[2] = node.leftChild + nodes[1] = nodes[2]?.leftChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[1]?.rightChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } else { - parent!.rightChild = rightChild! + // left-right + nodes[0] = node + nodes[1] = node.leftChild + nodes[2] = nodes[1]?.rightChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } - leftChild!.parent = parent! - } else { - if isLeftChild { - parent!.leftChild = rightChild! + } else if lrFactor < -1 { + // right-left or right-right + if lrDifference(node: node.rightChild) < 0 { + // right-right + nodes[1] = node + nodes[2] = node.rightChild + nodes[0] = nodes[2]?.rightChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[0]?.leftChild + subtrees[3] = nodes[0]?.rightChild } else { - parent!.rightChild = rightChild! + // right-left + nodes[1] = node + nodes[0] = node.rightChild + nodes[2] = nodes[0]?.leftChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } - rightChild!.parent = parent! + } else { + // Don't need to balance 'node', go for parent + balance(node: node.parent) + return } - } - private func replace(key: Key, _ payload: Payload?, _ leftChild: Node?, _ rightChild: Node?) { - self.key = key - self.payload = payload - self.leftChild = leftChild - self.rightChild = rightChild - - if hasLeftChild { - self.leftChild!.parent! = self + // nodes[2] is always the head + + if node.isRoot { + root = nodes[2] + root?.parent = nil + } else if node.isLeftChild { + nodeParent?.leftChild = nodes[2] + nodes[2]?.parent = nodeParent + } else if node.isRightChild { + nodeParent?.rightChild = nodes[2] + nodes[2]?.parent = nodeParent } - if hasRightChild { - self.rightChild!.parent! = self + + nodes[2]?.leftChild = nodes[1] + nodes[1]?.parent = nodes[2] + nodes[2]?.rightChild = nodes[0] + nodes[0]?.parent = nodes[2] + + nodes[1]?.leftChild = subtrees[0] + subtrees[0]?.parent = nodes[1] + nodes[1]?.rightChild = subtrees[1] + subtrees[1]?.parent = nodes[1] + + nodes[0]?.leftChild = subtrees[2] + subtrees[2]?.parent = nodes[0] + nodes[0]?.rightChild = subtrees[3] + subtrees[3]?.parent = nodes[0] + + updateHeightUpwards(node: nodes[1]) // Update height from left + updateHeightUpwards(node: nodes[0]) // Update height from right + + balance(node: nodes[2]?.parent) + } +} + +// MARK: - Displaying tree + +extension AVLTree { + fileprivate func display(node: Node?, level: Int) { + if let node = node { + display(node: node.rightChild, level: level + 1) + print("") + if node.isRoot { + print("Root -> ", terminator: "") + } + for _ in 0.. 1 || node.balance < -1 { - rebalance(node) - - } else if let parent = node.parent { - if node.isLeftChild { - parent.balance += 1 - } else if node.isRightChild { - parent.balance -= 1 - } - if parent.balance != 0 { - updateBalance(parent) - } - } - } - - private func rebalance(node: Node) { - if node.balance < 0 { - if let child = node.rightChild where child.balance > 0 { - rotateRight(child) - rotateLeft(node) + balance(node: parent) } else { - rotateLeft(node) + // at root + root = nil } - } else if node.balance > 0 { - if let child = node.leftChild where child.balance < 0 { - rotateLeft(child) - rotateRight(node) - } else { - rotateRight(node) + } else { + // Handle stem cases + if let replacement = node.leftChild?.maximum(), replacement !== node { + node.key = replacement.key + node.payload = replacement.payload + delete(node: replacement) + } else if let replacement = node.rightChild?.minimum(), replacement !== node { + node.key = replacement.key + node.payload = replacement.payload + delete(node: replacement) } } } - - private func rotateRight(node: Node) { - let newRoot = node.leftChild! - node.leftChild = newRoot.rightChild - - if let child = newRoot.rightChild { - child.parent = node - } - - newRoot.parent = node.parent - - if node.isRoot { - root = newRoot - } else if node.isRightChild { - node.parent!.rightChild = newRoot - } else if node.isLeftChild { - node.parent!.leftChild = newRoot - } - - newRoot.rightChild = node - node.parent = newRoot - node.balance = node.balance + 1 - min(newRoot.balance, 0) - newRoot.balance = newRoot.balance + 1 - max(node.balance, 0) - } - - private func rotateLeft(node: Node) { - let newRoot = node.rightChild! - node.rightChild = newRoot.leftChild - - if let child = newRoot.leftChild { - child.parent = node - } - - newRoot.parent = node.parent - - if node.isRoot { - root = newRoot - } else if node.isLeftChild { - node.parent!.leftChild = newRoot - } else if node.isRightChild { - node.parent!.rightChild = newRoot - } - - newRoot.leftChild = node - node.parent = newRoot - node.balance = node.balance + 1 - min(newRoot.balance, 0) - newRoot.balance = newRoot.balance + 1 - max(node.balance, 0) - } } // MARK: - Debugging extension TreeNode: CustomDebugStringConvertible { public var debugDescription: String { - var s = "key: \(key), payload: \(payload), balance: \(balance)" + var s = "key: \(key), payload: \(payload), height: \(height)" if let parent = parent { s += ", parent: \(parent.key)" } @@ -389,11 +374,7 @@ extension TreeNode: CustomDebugStringConvertible { extension AVLTree: CustomDebugStringConvertible { public var debugDescription: String { - if let root = root { - return root.debugDescription - } else { - return "[]" - } + return root?.debugDescription ?? "[]" } } @@ -413,10 +394,6 @@ extension TreeNode: CustomStringConvertible { extension AVLTree: CustomStringConvertible { public var description: String { - if let root = root { - return root.description - } else { - return "[]" - } + return root?.description ?? "[]" } } diff --git a/AVL Tree/AVLTree.playground/playground.xcworkspace/contents.xcworkspacedata b/AVL Tree/AVLTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/AVL Tree/AVLTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 @@ - - - - - diff --git a/AVL Tree/AVLTree.swift b/AVL Tree/AVLTree.swift index 12befbe92..04763f03b 100644 --- a/AVL Tree/AVLTree.swift +++ b/AVL Tree/AVLTree.swift @@ -22,71 +22,75 @@ public class TreeNode { public typealias Node = TreeNode - - public var payload: Payload? - - private var key: Key - private var leftChild: Node? - private var rightChild: Node? - private var parent: Node? - private var balance = 0 - public init(key: Key, payload: Payload?, leftChild: Node?, rightChild: Node?, parent: Node?) { + var payload: Payload? // Value held by the node + + fileprivate var key: Key // Node's name + internal var leftChild: Node? + internal var rightChild: 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 self.payload = payload self.leftChild = leftChild self.rightChild = rightChild self.parent = parent + self.height = height + + self.leftChild?.parent = self + self.rightChild?.parent = self } - + public convenience init(key: Key, payload: Payload?) { - self.init(key: key, payload: payload, leftChild: nil, rightChild: nil, parent: nil) + self.init(key: key, payload: payload, leftChild: nil, rightChild: nil, parent: nil, height: 1) } - + public convenience init(key: Key) { 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() { } } @@ -95,52 +99,32 @@ public class AVLTree { extension TreeNode { public func minimum() -> TreeNode? { - var curr: TreeNode? = self - while curr != nil && curr!.hasLeftChild { - curr = curr!.leftChild - } - return curr + return leftChild?.minimum() ?? self } - public func successor() -> Node? { - if let right = rightChild { - return right.minimum() - } else if let parent = parent { - if isLeftChild { - return parent - } else { - parent.rightChild = nil - let result = parent.successor() - parent.rightChild = self - return result - } - } - return nil + public func maximum() -> TreeNode? { + return rightChild?.maximum() ?? self } } 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) { - return result.payload - } else { - return nil - } + return search(key: input, node: root)?.payload } - - 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 @@ -150,222 +134,287 @@ 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) + let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.leftChild = child - updateBalance(child) + balance(node: child) } - } else { + } else if input != node.key { 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) + let child = Node(key: input, payload: payload, leftChild: nil, rightChild: nil, parent: node, height: 1) node.rightChild = child - updateBalance(child) + balance(node: child) } } } } -// MARK: - Deleting items +// MARK: - Balancing tree -extension TreeNode { - private func spliceout(){ - if isLeaf { - if isLeftChild { - parent!.leftChild = nil - } else if isRightChild { - parent!.rightChild = nil - } - } else if hasAnyChild { - if hasLeftChild { - parent!.leftChild = leftChild! +extension AVLTree { + 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: node.parent) + } + } + + 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?) { + guard let node = node else { + return + } + + 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: node) + if lrFactor > 1 { + // left-left or left-right + if lrDifference(node: node.leftChild) > 0 { + // left-left + nodes[0] = node + nodes[2] = node.leftChild + nodes[1] = nodes[2]?.leftChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[1]?.rightChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } else { - parent!.rightChild = rightChild! + // left-right + nodes[0] = node + nodes[1] = node.leftChild + nodes[2] = nodes[1]?.rightChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } - leftChild!.parent = parent! - } else { - if isLeftChild { - parent!.leftChild = rightChild! + } else if lrFactor < -1 { + // right-left or right-right + if lrDifference(node: node.rightChild) < 0 { + // right-right + nodes[1] = node + nodes[2] = node.rightChild + nodes[0] = nodes[2]?.rightChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[0]?.leftChild + subtrees[3] = nodes[0]?.rightChild } else { - parent!.rightChild = rightChild! + // right-left + nodes[1] = node + nodes[0] = node.rightChild + nodes[2] = nodes[0]?.leftChild + + subtrees[0] = nodes[1]?.leftChild + subtrees[1] = nodes[2]?.leftChild + subtrees[2] = nodes[2]?.rightChild + subtrees[3] = nodes[0]?.rightChild } - rightChild!.parent = parent! + } else { + // Don't need to balance 'node', go for parent + balance(node: node.parent) + return + } + + // nodes[2] is always the head + + if node.isRoot { + root = nodes[2] + root?.parent = nil + } else if node.isLeftChild { + nodeParent?.leftChild = nodes[2] + nodes[2]?.parent = nodeParent + } else if node.isRightChild { + nodeParent?.rightChild = nodes[2] + nodes[2]?.parent = nodeParent } + + nodes[2]?.leftChild = nodes[1] + nodes[1]?.parent = nodes[2] + nodes[2]?.rightChild = nodes[0] + nodes[0]?.parent = nodes[2] + + nodes[1]?.leftChild = subtrees[0] + subtrees[0]?.parent = nodes[1] + nodes[1]?.rightChild = subtrees[1] + subtrees[1]?.parent = nodes[1] + + nodes[0]?.leftChild = subtrees[2] + subtrees[2]?.parent = nodes[0] + nodes[0]?.rightChild = subtrees[3] + subtrees[3]?.parent = nodes[0] + + updateHeightUpwards(node: nodes[1]) // Update height from left + updateHeightUpwards(node: nodes[0]) // Update height from right + + balance(node: nodes[2]?.parent) } +} - private func replace(key: Key, _ payload: Payload?, _ leftChild: Node?, _ rightChild: Node?) { - self.key = key - self.payload = payload - self.leftChild = leftChild - self.rightChild = rightChild - - if hasLeftChild { - self.leftChild!.parent! = self +// MARK: - Displaying tree + +extension AVLTree { + fileprivate func display(node: Node?, level: Int) { + if let node = node { + display(node: node.rightChild, level: level + 1) + print("") + if node.isRoot { + print("Root -> ", terminator: "") + } + for _ in 0.. String { + var output = "" + if let node = node { + output = "\(inorder(node: node.leftChild)) \(print("\(node.key) ")) \(inorder(node: node.rightChild))" + } + return output + } + + public func preorder(node: Node?) -> String { + var output = "" + if let node = node { + output = "\(preorder(node: node.leftChild)) \(print("\(node.key) ")) \(preorder(node: node.rightChild))" } - if hasRightChild { - self.rightChild!.parent! = self + return output + } + + public func postorder(node: Node?) -> String { + var output = "" + if let node = node { + output = "\(postorder(node: node.leftChild)) \(print("\(node.key) ")) \(postorder(node: node.rightChild))" } + return output } } +// MARK: - Delete node + extension AVLTree { 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 } } - + private func delete(node: Node) { if node.isLeaf { - if node.isLeftChild { - node.parent!.leftChild = nil - } else if node.isRightChild { - node.parent!.rightChild = nil - } - } else if node.hasBothChildren { - let successor = node.successor()! - successor.spliceout() - node.key = successor.key - node.payload = successor.payload - - if node.hasAnyChild { - if node.hasBothChildren { - node.balance = max(node.leftChild!.balance, node.rightChild!.balance) + 1 - } else if node.hasRightChild { - node.balance = node.rightChild!.balance + 1 - } else if node.hasLeftChild { - node.balance = node.leftChild!.balance + 1 + // Just remove and balance up + if let parent = node.parent { + guard node.isLeftChild || node.isRightChild else { + // just in case + fatalError("Error: tree is invalid.") } - } - } else if node.hasLeftChild { - if node.isLeftChild { - node.leftChild!.parent = node.parent - node.parent!.leftChild = node.leftChild - node.balance = node.leftChild!.balance + 1 - } else if node.isRightChild { - node.leftChild!.parent = node.parent - node.parent!.rightChild = node.rightChild - node.balance = node.rightChild!.balance + 1 + + if node.isLeftChild { + parent.leftChild = nil + } else if node.isRightChild { + parent.rightChild = nil + } + + balance(node: parent) } else { - node.replace(node.leftChild!.key, node.leftChild!.payload, node.leftChild!.leftChild, node.leftChild!.rightChild) + // at root + root = nil } - } else if node.hasRightChild{ - if node.isRightChild{ - node.rightChild!.parent = node.parent - node.parent!.rightChild = node.rightChild - node.balance = node.rightChild!.balance + 1 - } else if node.isLeftChild{ - node.rightChild!.parent = node.parent - node.parent!.leftChild = node.leftChild - node.balance = node.leftChild!.balance + 1 - } else { - node.replace(node.rightChild!.key, node.rightChild!.payload, node.rightChild!.leftChild, node.rightChild!.rightChild) + } else { + // Handle stem cases + if let replacement = node.leftChild?.maximum(), replacement !== node { + node.key = replacement.key + node.payload = replacement.payload + delete(node: replacement) + } else if let replacement = node.rightChild?.minimum(), replacement !== node { + node.key = replacement.key + node.payload = replacement.payload + delete(node: replacement) } } } } -// MARK: - Balancing the tree +// MARK: - Advanced Stuff extension AVLTree { - private func updateBalance(node: Node) { - if node.balance > 1 || node.balance < -1 { - rebalance(node) - - } else if let parent = node.parent { - if node.isLeftChild { - parent.balance += 1 - } else if node.isRightChild { - parent.balance -= 1 + public func doInOrder(node: Node?, _ completion: (Node) -> Void) { + if let node = node { + doInOrder(node: node.leftChild) { lnode in + completion(lnode) } - if parent.balance != 0 { - updateBalance(parent) + completion(node) + doInOrder(node: node.rightChild) { rnode in + completion(rnode) } } } - - private func rebalance(node: Node) { - if node.balance < 0 { - if let child = node.rightChild where child.balance > 0 { - rotateRight(child) - rotateLeft(node) - } else { - rotateLeft(node) + + public func doInPreOrder(node: Node?, _ completion: (Node) -> Void) { + if let node = node { + completion(node) + doInPreOrder(node: node.leftChild) { lnode in + completion(lnode) } - } else if node.balance > 0 { - if let child = node.leftChild where child.balance < 0 { - rotateLeft(child) - rotateRight(node) - } else { - rotateRight(node) + doInPreOrder(node: node.rightChild) { rnode in + completion(rnode) } } } - - private func rotateRight(node: Node) { - let newRoot = node.leftChild! - node.leftChild = newRoot.rightChild - - if let child = newRoot.rightChild { - child.parent = node - } - - newRoot.parent = node.parent - - if node.isRoot { - root = newRoot - } else if node.isRightChild { - node.parent!.rightChild = newRoot - } else if node.isLeftChild { - node.parent!.leftChild = newRoot - } - - newRoot.rightChild = node - node.parent = newRoot - node.balance = node.balance + 1 - min(newRoot.balance, 0) - newRoot.balance = newRoot.balance + 1 - max(node.balance, 0) - } - private func rotateLeft(node: Node) { - let newRoot = node.rightChild! - node.rightChild = newRoot.leftChild - - if let child = newRoot.leftChild { - child.parent = node - } - - newRoot.parent = node.parent - - if node.isRoot { - root = newRoot - } else if node.isLeftChild { - node.parent!.leftChild = newRoot - } else if node.isRightChild { - node.parent!.rightChild = newRoot + public func doInPostOrder(node: Node?, _ completion: (Node) -> Void) { + if let node = node { + doInPostOrder(node: node.leftChild) { lnode in + completion(lnode) + } + doInPostOrder(node: node.rightChild) { rnode in + completion(rnode) + } + completion(node) } - - newRoot.leftChild = node - node.parent = newRoot - node.balance = node.balance + 1 - min(newRoot.balance, 0) - newRoot.balance = newRoot.balance + 1 - max(node.balance, 0) } } @@ -373,7 +422,7 @@ extension AVLTree { extension TreeNode: CustomDebugStringConvertible { public var debugDescription: String { - var s = "key: \(key), payload: \(payload), balance: \(balance)" + var s = "key: \(key), payload: \(payload), height: \(height)" if let parent = parent { s += ", parent: \(parent.key)" } @@ -389,11 +438,7 @@ extension TreeNode: CustomDebugStringConvertible { extension AVLTree: CustomDebugStringConvertible { public var debugDescription: String { - if let root = root { - return root.debugDescription - } else { - return "[]" - } + return root?.debugDescription ?? "[]" } } @@ -413,10 +458,6 @@ extension TreeNode: CustomStringConvertible { extension AVLTree: CustomStringConvertible { public var description: String { - if let root = root { - return root.description - } else { - return "[]" - } + return root?.description ?? "[]" } } diff --git a/AVL Tree/Images/RotationStep0.jpg b/AVL Tree/Images/RotationStep0.jpg new file mode 100644 index 000000000..f61f8804a Binary files /dev/null and b/AVL Tree/Images/RotationStep0.jpg differ diff --git a/AVL Tree/Images/RotationStep1.jpg b/AVL Tree/Images/RotationStep1.jpg new file mode 100644 index 000000000..953d35929 Binary files /dev/null and b/AVL Tree/Images/RotationStep1.jpg differ diff --git a/AVL Tree/Images/RotationStep2.jpg b/AVL Tree/Images/RotationStep2.jpg new file mode 100644 index 000000000..410c89536 Binary files /dev/null and b/AVL Tree/Images/RotationStep2.jpg differ diff --git a/AVL Tree/Images/RotationStep3.jpg b/AVL Tree/Images/RotationStep3.jpg new file mode 100644 index 000000000..921c0c4ba Binary files /dev/null and b/AVL Tree/Images/RotationStep3.jpg differ diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index 9e3a2cdc6..4e974ba71 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/) and 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: @@ -16,7 +16,7 @@ A balanced version of that tree would look like this: One way to make the binary search tree balanced is to insert the nodes in a totally random order. But that 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. The height of such a tree is guaranteed to be *log(n)* where *n* is the number nodes. On a balanced tree all insert, remove, and search operations take **O(log n)** time. That means fast. ;-) +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. The height of such a tree is guaranteed to be *log(n)* where *n* is the number nodes. On a balanced tree all insert, remove, and search operations take only **O(log n)** time. That means fast. ;-) ## Introducing the AVL tree @@ -32,7 +32,7 @@ As mentioned, in an AVL tree a node is balanced if its left and right subtree ha ![Balanced trees](Images/BalanceOK.png) -But these are trees that are unbalanced, because the height of the left subtree is too large compared to the right subtree: +But the following are trees that are unbalanced, because the height of the left subtree is too large compared to the right subtree: ![Unbalanced trees](Images/BalanceNotOK.png) @@ -43,29 +43,49 @@ 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. -TODO: describe with pictures how these rotations work +![Rotation0](Images/RotationStep0.jpg) -Insertion never needs more than 2 rotations. Removal might require up to *log(n)* rotations. +For the rotation we're using the terminology: +* *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 -## The code +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 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 -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 is 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. +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 + +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. -The interesting bits are in the following methods: +> **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. -- `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 [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 common. +AVL tree was the first self-balancing binary tree. These days, the [red-black tree](../Red-Black%20Tree/) seems to be more popular. -*Written for Swift Algorithm Club by Mike Taghavi and Matthijs Hollemans* +*Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) and [Matthijs Hollemans](https://github.com/hollance)* diff --git a/AVL Tree/Tests/AVLTreeTests.swift b/AVL Tree/Tests/AVLTreeTests.swift new file mode 100644 index 000000000..a9e932117 --- /dev/null +++ b/AVL Tree/Tests/AVLTreeTests.swift @@ -0,0 +1,191 @@ +// +// AVLTreeTestsTests.swift +// AVLTreeTestsTests +// +// Created by Barbara Rodeker on 2/19/16. +// Copyright © 2016 Swift Algorithm Club. All rights reserved. +// + +import XCTest +class AVLTreeTests: XCTestCase { + var tree: AVLTree? + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + override func setUp() { + super.setUp() + + tree = AVLTree() + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testAVLTreeBalancedAutoPopulate() { + self.tree?.autopopulateWithNodes(10) + + do { + try self.tree?.inOrderCheckBalanced(self.tree?.root) + } catch _ { + XCTFail("Tree is not balanced after autopopulate") + } + } + + func testAVLTreeBalancedInsert() { + self.tree?.autopopulateWithNodes(5) + + for i in 6...10 { + self.tree?.insert(key: i) + do { + try self.tree?.inOrderCheckBalanced(self.tree?.root) + } catch _ { + XCTFail("Tree is not balanced after inserting " + String(i)) + } + } + } + + func testAVLTreeBalancedDelete() { + self.tree?.autopopulateWithNodes(5) + + for i in 1...6 { + self.tree?.delete(key: i) + do { + try self.tree?.inOrderCheckBalanced(self.tree?.root) + } catch _ { + XCTFail("Tree is not balanced after deleting " + String(i)) + } + } + } + + func testEmptyInitialization() { + let tree = AVLTree() + + XCTAssertEqual(tree.size, 0) + XCTAssertNil(tree.root) + } + + func testSingleInsertionPerformance() { + self.measure { + self.tree?.insert(key: 5, payload: "E") + } + } + + func testMultipleInsertionsPerformance() { + self.measure { + self.tree?.autopopulateWithNodes(50) + } + } + + func testSearchExistentOnSmallTreePerformance() { + self.measure { + print(self.tree?.search(input: 2)) + } + } + + func testSearchExistentElementOnLargeTreePerformance() { + self.measure { + self.tree?.autopopulateWithNodes(500) + print(self.tree?.search(input: 400)) + } + } + + func testMinimumOnPopulatedTree() { + self.tree?.autopopulateWithNodes(500) + let min = self.tree?.root?.minimum() + XCTAssertNotNil(min, "Minimum function not working") + } + + func testMinimumOnSingleTreeNode() { + let treeNode = TreeNode(key: 1, payload: "A") + let min = treeNode.minimum() + + XCTAssertNotNil(min, "Minimum on single node should be returned") + XCTAssertEqual(min?.payload, treeNode.payload) + } + + func testDeleteExistentKey() { + self.tree?.delete(key: 1) + XCTAssertNil(self.tree?.search(input: 1), "Key should not exist anymore") + } + + func testDeleteNotExistentKey() { + 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(key: i, payload: "") + XCTAssertEqual(tree.size, i + 1, "Insert didn't update size correctly!") + } + } + + func testDelete() { + let permutations = [ + [5, 1, 4, 2, 3], + [2, 3, 1, 5, 4], + [4, 5, 3, 2, 1], + [3, 2, 5, 4, 1], + ] + + for p in permutations { + let tree = AVLTree() + + 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(key: i) + count -= 1 + XCTAssertEqual(tree.size, count, "Delete didn't update size correctly!") + } + } + } +} + +extension AVLTree where Key : SignedInteger { + func autopopulateWithNodes(_ count: Int) { + var k: Key = 1 + for _ in 0...count { + self.insert(key: k) + k = k + 1 + } + } +} + +enum AVLTreeError: Error { + case notBalanced +} + +extension AVLTree where Key : SignedInteger { + func height(_ node: Node?) -> Int { + if let node = node { + let lHeight = height(node.leftChild) + let rHeight = height(node.rightChild) + + return max(lHeight, rHeight) + 1 + } + return 0 + } + + func inOrderCheckBalanced(_ node: Node?) throws { + if let node = node { + guard abs(height(node.leftChild) - height(node.rightChild)) <= 1 else { + throw AVLTreeError.notBalanced + } + try inOrderCheckBalanced(node.leftChild) + try inOrderCheckBalanced(node.rightChild) + } + } +} diff --git a/Binary Search/BinarySearch Tests/BinarySearchTests/Info.plist b/AVL Tree/Tests/Info.plist similarity index 100% rename from Binary Search/BinarySearch Tests/BinarySearchTests/Info.plist rename to AVL Tree/Tests/Info.plist diff --git a/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e7c6e2989 --- /dev/null +++ b/AVL Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,275 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3C91C77A112003CECC7 /* TreeNodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3C71C77A112003CECC7 /* TreeNodeTests.swift */; }; + 7B80C3CA1C77A112003CECC7 /* AVLTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3C81C77A112003CECC7 /* AVLTreeTests.swift */; }; + 7B80C3CC1C77A120003CECC7 /* AVLTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CB1C77A120003CECC7 /* AVLTree.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; }; + 7B80C3C71C77A112003CECC7 /* TreeNodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeNodeTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3C81C77A112003CECC7 /* AVLTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVLTreeTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3CB1C77A120003CECC7 /* AVLTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AVLTree.swift; path = ../AVLTree.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 = ( + 7B80C3CB1C77A120003CECC7 /* AVLTree.swift */, + 7B80C3C81C77A112003CECC7 /* AVLTreeTests.swift */, + 7B80C3C71C77A112003CECC7 /* TreeNodeTests.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 = ( + 7B80C3CC1C77A120003CECC7 /* AVLTree.swift in Sources */, + 7B80C3C91C77A112003CECC7 /* TreeNodeTests.swift in Sources */, + 7B80C3CA1C77A112003CECC7 /* AVLTreeTests.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"; + SWIFT_VERSION = 4.0; + }; + 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"; + SWIFT_VERSION = 4.0; + }; + 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 = 4.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 = 4.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/AVL Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AVL Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/AVL Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/AVL Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AVL Tree/Tests/TreeNodeTests.swift b/AVL Tree/Tests/TreeNodeTests.swift new file mode 100644 index 000000000..dc393232c --- /dev/null +++ b/AVL Tree/Tests/TreeNodeTests.swift @@ -0,0 +1,88 @@ +// +// TreeNodeTest.swift +// AVLTreeTests +// +// Created by Barbara Rodeker on 2/19/16. +// Copyright © 2016 Swift Algorithm Club. All rights reserved. +// + +import XCTest + +class TreeNodeTests: XCTestCase { + + var root: TreeNode? + var left: TreeNode? + var right: TreeNode? + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + override func setUp() { + super.setUp() + + left = TreeNode(key: "Name", payload: "Left") + right = TreeNode(key: "Name", payload: "Right") + root = TreeNode(key: "Name", payload: "Root", leftChild: left, rightChild: right, parent: nil, height: 0) + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testSingleNodeCreationNOPayload() { + let treeNode = TreeNode(key: "Building") + XCTAssertNil(treeNode.payload, "Payload for this case should be nil") + } + + func testSingleNodeCreationWithPayload() { + XCTAssertNotNil(self.root!, "Payload for this case should not be nil") + } + + func testIsRoot() { + XCTAssertTrue(self.root!.isRoot) + } + + func testNotIsLeaf() { + XCTAssertFalse(self.root!.isLeaf, "root node is not leaf") + } + + func testNotIsLeftChild() { + XCTAssertFalse(self.root!.isLeftChild, "root node is not left child") + } + + func testNotIsRightChild() { + XCTAssertFalse(self.root!.isRightChild, "root node is not right child") + } + + func testIsLeftChild() { + XCTAssertTrue(self.left!.isLeftChild) + } + + func testIsRightChild() { + XCTAssertTrue(self.right!.isRightChild) + } + + func isLeaf() { + XCTAssertTrue(self.left!.isLeaf) + } + + func testHasAnyChild() { + XCTAssertTrue(self.root!.hasAnyChild) + } + + func testNotHasAnyChild() { + XCTAssertFalse(self.left!.hasAnyChild) + } + + func testHasBothChildren() { + XCTAssertTrue(self.root!.hasBothChildren) + } + + func testNotHasBothChildren() { + XCTAssertFalse(self.left!.hasBothChildren) + } + +} diff --git a/Algorithm Design.markdown b/Algorithm Design.markdown index d9376f82e..5d89cb05a 100644 --- a/Algorithm Design.markdown +++ b/Algorithm Design.markdown @@ -4,9 +4,9 @@ What to do when you're faced with a new problem and you need to find an algorith ### Is it similar to another problem? -One thing I like about [The Algorithm Design Manual](http://www.algorist.com) by Steven Skiena is that it includes a catalog of problems and solutions you can try. +If you can frame your problem in terms of another, more general problem, then you might be able to use an existing algorithm. Why reinvent the wheel? -If you can frame your problem in terms of another, more general problem, then you might be able to use an existing algorithm. +One thing I like about [The Algorithm Design Manual](http://www.algorist.com) by Steven Skiena is that it includes a catalog of problems and solutions you can try. (See also his [algorithm repository](http://www3.cs.stonybrook.edu/~algorith/).) ### It's OK to start with brute force @@ -14,10 +14,17 @@ Naive, brute force solutions are often too slow for practical use but they're a Once you have a brute force implementation you can use that to verify that any improvements you come up with are correct. -And if you only work with small datasets, then a brute force approach may actually be good enough on its own. +And if you only work with small datasets, then a brute force approach may actually be good enough on its own. Don't fall into the trap of premature optimization! ### Divide and conquer -A big problem is often just a whole bunch of much smaller problems. +>"When you change the way you look at things, the things you look at change."
+>Max Planck, Quantum theorist and Nobel Prize Winner -[More to come here] +Divide and conquer is a way of dealing with a large problem by breaking it down into bits and pieces and working your way up towards the solution. + +Instead of seeing the whole problem as a single, huge and complex task you divide the problem in relatively smaller problems that are easier to understand and deal with. + +You solve smaller problems and aggregate the solution until you are left with the solution only. At each step the problem at hand shrinks and the solution gets mature until you have the final correct solution. + +Solving the smaller task and applying the same solution repetitively ( or often times recursively) to other chunks give you the result in less time. diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift new file mode 100644 index 000000000..24c27cac8 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift @@ -0,0 +1,30 @@ +//: Playground - noun: a place where people can play + +import Graph +import APSP + +var graph = AdjacencyListGraph() + +let v1 = graph.createVertex("Montreal") +let v2 = graph.createVertex("New York") +let v3 = graph.createVertex("Boston") +let v4 = graph.createVertex("Portland") +let v5 = graph.createVertex("Portsmouth") + +graph.addDirectedEdge(v1, to: v2, withWeight: 3) +graph.addDirectedEdge(v1, to: v5, withWeight: -4) +graph.addDirectedEdge(v1, to: v3, withWeight: 8) + +graph.addDirectedEdge(v2, to: v4, withWeight: 1) +graph.addDirectedEdge(v2, to: v5, withWeight: 7) + +graph.addDirectedEdge(v3, to: v2, withWeight: 4) + +graph.addDirectedEdge(v4, to: v1, withWeight: 2) +graph.addDirectedEdge(v4, to: v3, withWeight: -5) + +graph.addDirectedEdge(v5, to: v4, withWeight: 6) + +let result = FloydWarshall.apply(graph) + +let path = result.path(fromVertex: v1, toVertex: v4, inGraph: graph) diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground new file mode 100644 index 000000000..d5a8d0e3f --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/playground.xcworkspace/contents.xcworkspacedata b/All-Pairs Shortest Paths/APSP/APSP.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/timeline.xctimeline b/All-Pairs Shortest Paths/APSP/APSP.playground/timeline.xctimeline new file mode 100644 index 000000000..c938ca857 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj new file mode 100644 index 000000000..dc8e509a1 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -0,0 +1,500 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 491AA37F1CE8C5C900A2E2C5 /* Graph.framework */; }; + 493D8DE31CDD2A1C0089795A /* APSPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DE21CDD2A1C0089795A /* APSPTests.swift */; }; + 493D8DF41CDD5B960089795A /* APSP.h in Headers */ = {isa = PBXBuildFile; fileRef = 493D8DF31CDD5B960089795A /* APSP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DD81CDC38C60089795A /* FloydWarshall.swift */; }; + 493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DDA1CDD29C80089795A /* Helpers.swift */; }; + 49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2791CDD93F400522D66 /* APSP.swift */; }; + 49BFA2801CDE742900522D66 /* APSP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 493D8DF11CDD5B960089795A /* APSP.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 49BFA2FD1CDF886B00522D66; + remoteInfo = Graph; + }; + 491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 49BFA3071CDF886B00522D66; + remoteInfo = GraphTests; + }; + 491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 49BFA2FC1CDF886B00522D66; + remoteInfo = Graph; + }; + 49BFA27E1CDE742700522D66 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 493D8D7E1CDC2DAE0089795A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 493D8DF01CDD5B960089795A; + remoteInfo = APSP; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Graph.xcodeproj; path = ../../Graph/Graph.xcodeproj; sourceTree = ""; }; + 493D8DD81CDC38C60089795A /* FloydWarshall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloydWarshall.swift; sourceTree = ""; }; + 493D8DDA1CDD29C80089795A /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; + 493D8DE01CDD2A1C0089795A /* APSPTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APSPTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 493D8DE21CDD2A1C0089795A /* APSPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APSPTests.swift; sourceTree = ""; }; + 493D8DE41CDD2A1C0089795A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 493D8DF11CDD5B960089795A /* APSP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = APSP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 493D8DF31CDD5B960089795A /* APSP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = APSP.h; sourceTree = ""; }; + 493D8DF51CDD5B960089795A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49BFA2791CDD93F400522D66 /* APSP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APSP.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 493D8DDD1CDD2A1C0089795A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA2801CDE742900522D66 /* APSP.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 493D8DED1CDD5B960089795A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 491AA37A1CE8C5C900A2E2C5 /* Products */ = { + isa = PBXGroup; + children = ( + 491AA37F1CE8C5C900A2E2C5 /* Graph.framework */, + 491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 493D8D7D1CDC2DAE0089795A = { + isa = PBXGroup; + children = ( + 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */, + 493D8D881CDC2DAE0089795A /* APSP */, + 493D8DE11CDD2A1C0089795A /* APSPTests */, + 493D8D871CDC2DAE0089795A /* Products */, + ); + sourceTree = ""; + }; + 493D8D871CDC2DAE0089795A /* Products */ = { + isa = PBXGroup; + children = ( + 493D8DE01CDD2A1C0089795A /* APSPTests.xctest */, + 493D8DF11CDD5B960089795A /* APSP.framework */, + ); + name = Products; + sourceTree = ""; + }; + 493D8D881CDC2DAE0089795A /* APSP */ = { + isa = PBXGroup; + children = ( + 493D8DF31CDD5B960089795A /* APSP.h */, + 49BFA2791CDD93F400522D66 /* APSP.swift */, + 493D8DD81CDC38C60089795A /* FloydWarshall.swift */, + 493D8DDA1CDD29C80089795A /* Helpers.swift */, + 493D8DF51CDD5B960089795A /* Info.plist */, + ); + path = APSP; + sourceTree = ""; + }; + 493D8DE11CDD2A1C0089795A /* APSPTests */ = { + isa = PBXGroup; + children = ( + 493D8DE21CDD2A1C0089795A /* APSPTests.swift */, + 493D8DE41CDD2A1C0089795A /* Info.plist */, + ); + path = APSPTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 493D8DEE1CDD5B960089795A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 493D8DF41CDD5B960089795A /* APSP.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 493D8DDF1CDD2A1C0089795A /* APSPTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 493D8DE51CDD2A1C0089795A /* Build configuration list for PBXNativeTarget "APSPTests" */; + buildPhases = ( + 493D8DDC1CDD2A1C0089795A /* Sources */, + 493D8DDD1CDD2A1C0089795A /* Frameworks */, + 493D8DDE1CDD2A1C0089795A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 49BFA27F1CDE742700522D66 /* PBXTargetDependency */, + ); + name = APSPTests; + productName = APSPTests; + productReference = 493D8DE01CDD2A1C0089795A /* APSPTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 493D8DF01CDD5B960089795A /* APSP */ = { + isa = PBXNativeTarget; + buildConfigurationList = 493D8DF61CDD5B960089795A /* Build configuration list for PBXNativeTarget "APSP" */; + buildPhases = ( + 493D8DEC1CDD5B960089795A /* Sources */, + 493D8DED1CDD5B960089795A /* Frameworks */, + 493D8DEE1CDD5B960089795A /* Headers */, + 493D8DEF1CDD5B960089795A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */, + ); + name = APSP; + productName = APSP; + productReference = 493D8DF11CDD5B960089795A /* APSP.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 493D8D7E1CDC2DAE0089795A /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 1010; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 493D8DDF1CDD2A1C0089795A = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 1010; + }; + 493D8DF01CDD5B960089795A = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 1010; + }; + }; + }; + buildConfigurationList = 493D8D811CDC2DAE0089795A /* Build configuration list for PBXProject "APSP" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 493D8D7D1CDC2DAE0089795A; + productRefGroup = 493D8D871CDC2DAE0089795A /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 491AA37A1CE8C5C900A2E2C5 /* Products */; + ProjectRef = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 493D8DDF1CDD2A1C0089795A /* APSPTests */, + 493D8DF01CDD5B960089795A /* APSP */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 491AA37F1CE8C5C900A2E2C5 /* Graph.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Graph.framework; + remoteRef = 491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = GraphTests.xctest; + remoteRef = 491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 493D8DDE1CDD2A1C0089795A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 493D8DEF1CDD5B960089795A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 493D8DDC1CDD2A1C0089795A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 493D8DE31CDD2A1C0089795A /* APSPTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 493D8DEC1CDD5B960089795A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */, + 493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */, + 493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Graph; + targetProxy = 491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */; + }; + 49BFA27F1CDE742700522D66 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 493D8DF01CDD5B960089795A /* APSP */; + targetProxy = 49BFA27E1CDE742700522D66 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 493D8D8B1CDC2DAE0089795A /* 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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; + }; + 493D8D8C1CDC2DAE0089795A /* 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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; + }; + 493D8DE61CDD2A1C0089795A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = APSPTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 493D8DE71CDD2A1C0089795A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = APSPTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; + 493D8DF71CDD5B960089795A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = APSP/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 493D8DF81CDD5B960089795A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = APSP/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 493D8D811CDC2DAE0089795A /* Build configuration list for PBXProject "APSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 493D8D8B1CDC2DAE0089795A /* Debug */, + 493D8D8C1CDC2DAE0089795A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 493D8DE51CDD2A1C0089795A /* Build configuration list for PBXNativeTarget "APSPTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 493D8DE61CDD2A1C0089795A /* Debug */, + 493D8DE71CDD2A1C0089795A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 493D8DF61CDD5B960089795A /* Build configuration list for PBXNativeTarget "APSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 493D8DF71CDD5B960089795A /* Debug */, + 493D8DF81CDD5B960089795A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 493D8D7E1CDC2DAE0089795A /* Project object */; +} diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + 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 new file mode 100644 index 000000000..944957d8f --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSPTests.xcscheme b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSPTests.xcscheme new file mode 100644 index 000000000..481baffd8 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSPTests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/contents.xcworkspacedata b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..615e34ecd --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/All-Pairs Shortest Paths/APSP/APSP/APSP.h b/All-Pairs Shortest Paths/APSP/APSP/APSP.h new file mode 100644 index 000000000..6936d5a21 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP/APSP.h @@ -0,0 +1,18 @@ +// +// APSP.h +// APSP +// +// Created by Andrew McKnight on 5/6/16. +// + +#import + +//! Project version number for APSP. +FOUNDATION_EXPORT double APSPVersionNumber; + +//! Project version string for APSP. +FOUNDATION_EXPORT const unsigned char APSPVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/All-Pairs Shortest Paths/APSP/APSP/APSP.swift b/All-Pairs Shortest Paths/APSP/APSP/APSP.swift new file mode 100644 index 000000000..dec7475bd --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP/APSP.swift @@ -0,0 +1,36 @@ +// +// Base.swift +// APSP +// +// Created by Andrew McKnight on 5/6/16. +// + +import Foundation +import Graph + +/** + `APSPAlgorithm` is a protocol for encapsulating an All-Pairs Shortest Paths algorithm. + It provides a single function `apply` that accepts a subclass of `AbstractGraph` and + returns an object conforming to `APSPResult`. + */ +public protocol APSPAlgorithm { + + associatedtype Q: Hashable + associatedtype P: APSPResult + + static func apply(_ graph: AbstractGraph) -> P + +} + +/** + `APSPResult` is a protocol defining functions `distance` and `path`, allowing for opaque + queries into the actual data structures that represent the APSP solution according to the algorithm used. + */ +public protocol APSPResult { + + associatedtype T: Hashable + + func distance(fromVertex from: Vertex, toVertex to: Vertex) -> Double? + func path(fromVertex from: Vertex, toVertex to: Vertex, inGraph graph: AbstractGraph) -> [T]? + +} diff --git a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift new file mode 100644 index 000000000..7bc78f326 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift @@ -0,0 +1,215 @@ +// +// FloydWarshall.swift +// APSP +// +// Created by Andrew McKnight on 5/5/16. +// + +import Foundation +import Graph + +private typealias Distances = [[Double]] +private typealias Predecessors = [[Int?]] +private typealias StepResult = (distances: Distances, predecessors: Predecessors) + +/** + Encapsulation of the Floyd-Warshall All-Pairs Shortest Paths algorithm, conforming to the `APSPAlgorithm` protocol. + + - 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 where T: Hashable { + + public typealias Q = T + public typealias P = FloydWarshallResult + + /** + Floyd-Warshall algorithm for computing all-pairs shortest paths in a weighted directed graph. + + - precondition: `graph` must have no negative weight cycles + - 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 { + + var previousDistance = constructInitialDistanceMatrix(graph) + var previousPredecessor = constructInitialPredecessorMatrix(previousDistance) + for intermediateIdx in 0 ..< graph.vertices.count { + let nextResult = nextStep(intermediateIdx, previousDistances: previousDistance, previousPredecessors: previousPredecessor, graph: graph) + previousDistance = nextResult.distances + previousPredecessor = nextResult.predecessors + +// // uncomment to see each new weight matrix +// print(" D(\(k)):\n") +// printMatrix(nextResult.distances) +// +// // uncomment to see each new predecessor matrix +// print(" ∏(\(k)):\n") +// printIntMatrix(nextResult.predecessors) + } + return FloydWarshallResult(weights: previousDistance, predecessors: previousPredecessor) + + } + + /** + For each iteration of `intermediateIdx`, perform the comparison for the dynamic algorith, + checking for each pair of start/end vertices, whether a path taken through another vertex + produces a shorter path. + + - complexity: `Θ(V^2)` time/space + - returns: a tuple containing the next distance matrix with weights of currently known + shortest paths and the corresponding predecessor matrix + */ + static fileprivate func nextStep(_ intermediateIdx: Int, previousDistances: Distances, + previousPredecessors: Predecessors, graph: AbstractGraph) -> StepResult { + + let vertexCount = graph.vertices.count + 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 { +// printMatrix(previousDistances, i: fromIdx, j: toIdx, k: intermediateIdx) // uncomment to see each comparison being made + let originalPathWeight = previousDistances[fromIdx][toIndex] + let newPathWeightBefore = previousDistances[fromIdx][intermediateIdx] + let newPathWeightAfter = previousDistances[intermediateIdx][toIndex] + + let minimum = min(originalPathWeight, newPathWeightBefore + newPathWeightAfter) + nextDistances[fromIdx][toIndex] = minimum + + var predecessor: Int? + if originalPathWeight <= newPathWeightBefore + newPathWeightAfter { + predecessor = previousPredecessors[fromIdx][toIndex] + } else { + predecessor = previousPredecessors[intermediateIdx][toIndex] + } + nextPredecessors[fromIdx][toIndex] = predecessor + } + } + return (nextDistances, nextPredecessors) + + } + + /** + We need to map the graph's weight domain onto the one required by the algorithm: the graph + stores either a weight as a `Double` or `nil` if no edge exists between two vertices, but + the algorithm needs a lack of an edge represented as ∞ for the `min` comparison to work correctly. + + - complexity: `Θ(V^2)` time/space + - returns: weighted adjacency matrix in form ready for processing with Floyd-Warshall + */ + static fileprivate func constructInitialDistanceMatrix(_ graph: AbstractGraph) -> Distances { + + let vertices = graph.vertices + + let vertexCount = graph.vertices.count + var distances = Array(repeating: Array(repeating: Double.infinity, count: vertexCount), count: vertexCount) + + for row in vertices { + for col in vertices { + let rowIdx = row.index + let colIdx = col.index + if rowIdx == colIdx { + distances[rowIdx][colIdx] = 0.0 + } else if let w = graph.weightFrom(row, to: col) { + distances[rowIdx][colIdx] = w + } + } + } + + return distances + + } + + /** + Make the initial predecessor index matrix. Initially each value is equal to it's row index, it's "from" index when querying into it. + + - complexity: `Θ(V^2)` time/space + */ + static fileprivate func constructInitialPredecessorMatrix(_ distances: Distances) -> Predecessors { + + let vertexCount = distances.count + var predecessors = Array(repeating: Array(repeating: nil, count: vertexCount), count: vertexCount) + + for fromIdx in 0 ..< vertexCount { + for toIdx in 0 ..< vertexCount { + if fromIdx != toIdx && distances[fromIdx][toIdx] < Double.infinity { + predecessors[fromIdx][toIdx] = fromIdx + } + } + } + + return predecessors + + } + +} + +/** + `FloydWarshallResult` encapsulates the result of the computation, namely the + minimized distance adjacency matrix, and the matrix of predecessor indices. + + 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 where T: Hashable { + + fileprivate var weights: Distances + fileprivate var predecessors: Predecessors + + /** + - returns: the total weight of the path from a starting vertex to a destination. + This value is the minimal connected weight between the two vertices, or `nil` if no path exists + - complexity: `Θ(1)` time/space + */ + public func distance(fromVertex from: Vertex, toVertex to: Vertex) -> Double? { + + return weights[from.index][to.index] + + } + + /** + - returns: the reconstructed path from a starting vertex to a destination, + as an array containing the data property of each vertex, or `nil` if no path exists + - complexity: `Θ(V)` time, `Θ(V^2)` space + */ + 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 + vertex.data + } + return pathValues + } + return nil + + } + + /** + The recursive component to rebuilding the shortest path between + two vertices using the predecessor matrix. + + - returns: the list of predecessors discovered so far + */ + fileprivate func recursePathFrom(fromVertex from: Vertex, toVertex to: Vertex, path: [Vertex], + inGraph graph: AbstractGraph) -> [Vertex]? { + + if from.index == to.index { + return [ from, to ] + } + + if let predecessor = predecessors[from.index][to.index] { + let predecessorVertex = graph.vertices[predecessor] + if predecessor == from.index { + let newPath = [ from, to ] + return newPath + } else { + let buildPath = recursePathFrom(fromVertex: from, toVertex: predecessorVertex, path: path, inGraph: graph) + let newPath = buildPath! + [ to ] + return newPath + } + } + + return nil + } + +} diff --git a/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift new file mode 100644 index 000000000..f590a6e50 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift @@ -0,0 +1,59 @@ +// +// Helpers.swift +// APSP +// +// Created by Andrew McKnight on 5/6/16. +// + +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) { + + if i >= 0 { + print(" k: \(k); i: \(i); j: \(j)\n") + } + + var grid = [String]() + + let n = matrix.count + for x in 0..en CFBundleExecutable $(EXECUTABLE_NAME) - CFBundleIconFile - CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion @@ -15,20 +13,14 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu + $(CURRENT_PROJECT_VERSION) NSPrincipalClass - NSApplication + diff --git a/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift new file mode 100644 index 000000000..ce0dfcf32 --- /dev/null +++ b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift @@ -0,0 +1,121 @@ +// +// APSPTests.swift +// APSPTests +// +// Created by Andrew McKnight on 5/6/16. +// + +import APSP +import Graph +import XCTest + +struct TestCase where T: Hashable { + + var from: Vertex + var to: Vertex + var expectedPath: [T] + var expectedDistance: Double + +} + +class APSPTests: XCTestCase { + /** + See Figure 25.1 of “Introduction to Algorithms” by Cormen et al, 3rd ed., pg 690 + */ + func testExampleFromBook() { + + let graph = AdjacencyMatrixGraph() + let v1 = graph.createVertex(1) + let v2 = graph.createVertex(2) + let v3 = graph.createVertex(3) + let v4 = graph.createVertex(4) + let v5 = graph.createVertex(5) + + graph.addDirectedEdge(v1, to: v2, withWeight: 3) + graph.addDirectedEdge(v1, to: v5, withWeight: -4) + graph.addDirectedEdge(v1, to: v3, withWeight: 8) + + graph.addDirectedEdge(v2, to: v4, withWeight: 1) + graph.addDirectedEdge(v2, to: v5, withWeight: 7) + + graph.addDirectedEdge(v3, to: v2, withWeight: 4) + + graph.addDirectedEdge(v4, to: v1, withWeight: 2) + graph.addDirectedEdge(v4, to: v3, withWeight: -5) + + graph.addDirectedEdge(v5, to: v4, withWeight: 6) + + let result = FloydWarshall.apply(graph) + + let cases = [ + TestCase(from: v1, to: v4, expectedPath: [1, 5, 4], expectedDistance: 2), + TestCase(from: v1, to: v5, expectedPath: [1, 5], expectedDistance: -4), + TestCase(from: v2, to: v1, expectedPath: [2, 4, 1], expectedDistance: 3), + TestCase(from: v2, to: v3, expectedPath: [2, 4, 3], expectedDistance: -4), + TestCase(from: v2, to: v4, expectedPath: [2, 4], expectedDistance: 1), + TestCase(from: v2, to: v5, expectedPath: [2, 4, 1, 5], expectedDistance: -1), + TestCase(from: v3, to: v1, expectedPath: [3, 2, 4, 1], expectedDistance: 7), + TestCase(from: v3, to: v2, expectedPath: [3, 2], expectedDistance: 4), + TestCase(from: v3, to: v4, expectedPath: [3, 2, 4], expectedDistance: 5), + TestCase(from: v3, to: v5, expectedPath: [3, 2, 4, 1, 5], expectedDistance: 3), + TestCase(from: v4, to: v1, expectedPath: [4, 1], expectedDistance: 2), + TestCase(from: v4, to: v2, expectedPath: [4, 3, 2], expectedDistance: -1), + TestCase(from: v4, to: v3, expectedPath: [4, 3], expectedDistance: -5), + TestCase(from: v4, to: v5, expectedPath: [4, 1, 5], expectedDistance: -2), + TestCase(from: v5, to: v1, expectedPath: [5, 4, 1], expectedDistance: 8), + TestCase(from: v5, to: v2, expectedPath: [5, 4, 3, 2], expectedDistance: 5), + TestCase(from: v5, to: v3, expectedPath: [5, 4, 3], expectedDistance: 1), + TestCase(from: v5, to: v4, expectedPath: [5, 4], expectedDistance: 6), + ] + + for testCase: TestCase in cases { + if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), + 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)") + } + } + + } + + func testExampleFromReadme() { + + let graph = AdjacencyMatrixGraph() + let v1 = graph.createVertex(1) + let v2 = graph.createVertex(2) + let v3 = graph.createVertex(3) + let v4 = graph.createVertex(4) + + graph.addDirectedEdge(v1, to: v2, withWeight: 4) + graph.addDirectedEdge(v1, to: v3, withWeight: 1) + graph.addDirectedEdge(v1, to: v4, withWeight: 3) + + graph.addDirectedEdge(v2, to: v3, withWeight: 8) + graph.addDirectedEdge(v2, to: v4, withWeight: -2) + + graph.addDirectedEdge(v3, to: v4, withWeight: -5) + + let result = FloydWarshall.apply(graph) + + let cases = [ + TestCase(from: v1, to: v2, expectedPath: [1, 2], expectedDistance: 4), + TestCase(from: v1, to: v3, expectedPath: [1, 3], expectedDistance: 1), + TestCase(from: v1, to: v4, expectedPath: [1, 3, 4], expectedDistance: -4), + + TestCase(from: v2, to: v3, expectedPath: [2, 3], expectedDistance: 8), + TestCase(from: v2, to: v4, expectedPath: [2, 4], expectedDistance: -2), + + TestCase(from: v3, to: v4, expectedPath: [3, 4], expectedDistance: -5), + ] + + for testCase: TestCase in cases { + if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), + 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)") + } + } + + } + +} diff --git a/Heap Sort/HeapSort Tests/HeapSortTests/Info.plist b/All-Pairs Shortest Paths/APSP/APSPTests/Info.plist similarity index 100% rename from Heap Sort/HeapSort Tests/HeapSortTests/Info.plist rename to All-Pairs Shortest Paths/APSP/APSPTests/Info.plist diff --git a/All-Pairs Shortest Paths/README.markdown b/All-Pairs Shortest Paths/README.markdown new file mode 100644 index 000000000..bbef6c64e --- /dev/null +++ b/All-Pairs Shortest Paths/README.markdown @@ -0,0 +1,76 @@ +# All-Pairs Shortest Paths + +The All-Pairs shortest path problem simultaneously computes the shortest path from each node in the graph to each other node, provided a path exists for each pair. In the naive approach, we could simply compute a single-source shortest path from each node to each other node. The number of shortest paths computed is then bound by `O(V^2)`, where `V` is the number of vertices in the graph. Because SSSP is also bounded by `O(V^2)`, the total running time for the naive approach would be `O(V^4)`. + +However, by applying a dynamic approach on the adjacency matrix of the graph, a running time of `O(V^3)` is achievable, using the `Floyd-Warshall` algorithm. Floyd-Warshall iterates through an adjacency matrix, and for each pair of start(`i`) and end(`j`) vertices it considers if the current distance between them is greater than a path taken through another vertex(`k`) in the graph (if paths `i` ~> `k` and `k` ~> `j` exist). It moves through an adjacency matrix for every vertex `k` applying its comparison for each pair (`i`, `j`), so for each `k` a new adjacency matrix `D(k)` is derived, where each value `d(k)[i][j]` is defined as: + + + +where `w[i][j]` is the weight of the edge connecting vertex `i` to vertex `j` in the graph's original adjacency matrix. + +When the algorithm memoizes each refined adjacency and predecessor matrix, its space complexity is `O(V^3)`, which can be optimised to `O(V^2)` by only memoizing the latest refinements. Reconstructing paths is a recursive procedure which requires `O(V)` time and `O(V^2)` space. + +# Example + +For the following weighted directed graph + + + +the adjacency matrix representation `w` is + + + +### Calculating shortest paths' weights + +At the beginning of the algorithm, `D(0)` is the same as `w`, with the following exceptions to accommodate the comparison function: + +1. vertices with no path connecting them have the `ø` replaced with `∞` +2. the diagonal has all `0`s + +Here are all the adjacency matrices derived when perform Floyd-Warshall on the above graph: + + + + + + + +with the last being the result, which tells for each pair of starting and ending vertices, the total weight of the shortest path connecting them. During the step where `k = 2`, the comparison that winds up changing the top right value from `2` to `-4` goes like this: + + k = 2, i = 0, j = 3 + d(k-1)[i][j] => d(1)[0][3] = 2 + d(k-1)[i][k] => d(1)[0][2] = 1 + d(k-1)[j][k] => d(1)[2][3] = -5 + +therefore `min(2, 2 + -5) => min(2, -4)` produces a new weight of `-4` for the element at `d(2)[0][3]`, meaning that the shortest known path 1 ~> 4 before this step was from 1 -> 2 -> 4 with a total weight of -2, and afterwards we discovered a shorter path from 1 -> 3 -> 4 with a total weight of -4. + +### Reconstructing shortest paths + +This algorithm finds only the lengths of the shortest paths between all pairs of nodes; a separate bookkeeping structure must be maintained to track predecessors' indices and reconstruct the shortest paths afterwards. The predecessor matrices at each step for the above graph follow: + + + + + + + +# Project Structure + +The provided xcworkspace allows working in the playground, which imports the APSP framework target from the xcodeproj. Build the framework target and rerun the playground to get started. There is also a test target in the xcodeproj. + +In the framework: + +- protocols for All-Pairs Shortest Paths algorithms and results structures +- an implementation of the Floyd-Warshall algorithm + +# TODO + +- Implement naive `O(V^4)` method for comparison +- Implement Johnson's algorithm for sparse graphs +- Implement other cool optimized versions + +# References + +Chapter 25 of Introduction to Algorithms, Third Edition by Cormen, Leiserson, Rivest and Stein [https://mitpress.mit.edu/books/introduction-algorithms](https://mitpress.mit.edu/books/introduction-algorithms) + +*Written for Swift Algorithm Club by [Andrew McKnight](https://github.com/armcknight)* diff --git a/All-Pairs Shortest Paths/img/d0.png b/All-Pairs Shortest Paths/img/d0.png new file mode 100644 index 000000000..4b0ea441c Binary files /dev/null and b/All-Pairs Shortest Paths/img/d0.png differ diff --git a/All-Pairs Shortest Paths/img/d1.png b/All-Pairs Shortest Paths/img/d1.png new file mode 100644 index 000000000..4ab5b4d84 Binary files /dev/null and b/All-Pairs Shortest Paths/img/d1.png differ diff --git a/All-Pairs Shortest Paths/img/d2.png b/All-Pairs Shortest Paths/img/d2.png new file mode 100644 index 000000000..b2f8b93ed Binary files /dev/null and b/All-Pairs Shortest Paths/img/d2.png differ diff --git a/All-Pairs Shortest Paths/img/d3.png b/All-Pairs Shortest Paths/img/d3.png new file mode 100644 index 000000000..f582c7b87 Binary files /dev/null and b/All-Pairs Shortest Paths/img/d3.png differ diff --git a/All-Pairs Shortest Paths/img/example_graph.png b/All-Pairs Shortest Paths/img/example_graph.png new file mode 100644 index 000000000..5d1a50acc Binary files /dev/null and b/All-Pairs Shortest Paths/img/example_graph.png differ diff --git a/All-Pairs Shortest Paths/img/original_adjacency_matrix.png b/All-Pairs Shortest Paths/img/original_adjacency_matrix.png new file mode 100644 index 000000000..8dcdd0237 Binary files /dev/null and b/All-Pairs Shortest Paths/img/original_adjacency_matrix.png differ diff --git a/All-Pairs Shortest Paths/img/pi0.png b/All-Pairs Shortest Paths/img/pi0.png new file mode 100644 index 000000000..097310068 Binary files /dev/null and b/All-Pairs Shortest Paths/img/pi0.png differ diff --git a/All-Pairs Shortest Paths/img/pi1.png b/All-Pairs Shortest Paths/img/pi1.png new file mode 100644 index 000000000..661d7ab5d Binary files /dev/null and b/All-Pairs Shortest Paths/img/pi1.png differ diff --git a/All-Pairs Shortest Paths/img/pi2.png b/All-Pairs Shortest Paths/img/pi2.png new file mode 100644 index 000000000..82e830a7e Binary files /dev/null and b/All-Pairs Shortest Paths/img/pi2.png differ diff --git a/All-Pairs Shortest Paths/img/pi3.png b/All-Pairs Shortest Paths/img/pi3.png new file mode 100644 index 000000000..c0b645ec3 Binary files /dev/null and b/All-Pairs Shortest Paths/img/pi3.png differ diff --git a/All-Pairs Shortest Paths/img/weight_comparison_formula.png b/All-Pairs Shortest Paths/img/weight_comparison_formula.png new file mode 100644 index 000000000..0a4dffeb2 Binary files /dev/null and b/All-Pairs Shortest Paths/img/weight_comparison_formula.png differ diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift new file mode 100644 index 000000000..d31d77540 --- /dev/null +++ b/Array2D/Array2D.playground/Contents.swift @@ -0,0 +1,65 @@ +/* + 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(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(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 + } + } +} + +// initialization +var matrix = Array2D(columns: 3, rows: 5, initialValue: 0) + +// makes an array of rows * columns elements all filled with zero +print(matrix.array) + +// setting numbers using subscript [x, y] +matrix[0, 0] = 1 +matrix[1, 0] = 2 + +matrix[0, 1] = 3 +matrix[1, 1] = 4 + +matrix[0, 2] = 5 +matrix[1, 2] = 6 + +matrix[0, 3] = 7 +matrix[1, 3] = 8 +matrix[2, 3] = 9 + +// now the numbers are set in the array +print(matrix.array) + +// print out the 2D array with a reference around the grid +for i in 0.. + + + \ No newline at end of file diff --git a/Array2D/Array2D.playground/playground.xcworkspace/contents.xcworkspacedata b/Array2D/Array2D.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Array2D/Array2D.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Array2D/Array2D.swift b/Array2D/Array2D.swift index ca84275f3..caff8373c 100644 --- a/Array2D/Array2D.swift +++ b/Array2D/Array2D.swift @@ -6,19 +6,23 @@ 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 { 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(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 32cde4d67..cf00638e1 100644 --- a/Array2D/README.markdown +++ b/Array2D/README.markdown @@ -1,14 +1,14 @@ # Array2D -In C and Objective-C you can write this, +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,33 +21,33 @@ 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]](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: +This looks complicated, but you can simplify it with a helper function: ```swift -func dim(count: Int, _ value: T) -> [T] { - return [T](count: count, repeatedValue: value) +func dim(_ count: Int, _ value: T) -> [T] { + return [T](repeating: value, count: count) } ``` -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,27 +59,31 @@ 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: +Instead, you can create your own type that acts like a 2-D array which is more convenient to use: ```swift 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 { 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(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 } } @@ -88,20 +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] ``` -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. +Or, you can change it: + +```swift +cookies[column, row] = newCookie +``` -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 by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Array2D/Tests/Array2DTests.swift b/Array2D/Tests/Array2DTests.swift new file mode 100644 index 000000000..b30769ac4 --- /dev/null +++ b/Array2D/Tests/Array2DTests.swift @@ -0,0 +1,78 @@ +// +// Array2DTest.swift +// algorithmclub +// +// Created by Barbara Rodeker on 2/16/16. +// Copyright © 2016 Swift Algorithm Club. All rights reserved. +// + +import XCTest + +class Array2DTest: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testIntegerArrayWithPositiveRowsAndColumns() { + let array = Array2D(columns: 3, rows: 2, initialValue: 0) + + XCTAssertEqual(array.columns, 3, "Column count setup failed") + XCTAssertEqual(array.rows, 2, "Rows count setup failed") + XCTAssertEqual(array[2, 1], 0, "Integer array: Initialization value is wrong") + } + + func testStringArrayWithPositiveRowsAndColumns() { + let array = Array2D(columns: 3, rows: 2, initialValue: "empty") + + XCTAssertEqual(array.columns, 3, "Column count setup failed") + XCTAssertEqual(array.rows, 2, "Rows count setup failed") + XCTAssertEqual(array[2, 1], "empty", "String array: Initialization value is wrong") + } + + func testCustomClassArrayWithPositiveRowsAndColumns() { + let array = Array2D(columns: 3, rows: 2, initialValue: TestElement(identifier: "pepe")) + + XCTAssertEqual(array.columns, 3, "Column count setup failed") + XCTAssertEqual(array.rows, 2, "Rows count setup failed") + XCTAssertEqual(array[2, 1], TestElement(identifier: "pepe"), "Custom Class array: Initialization value is wrong") + } + + func testPerformanceOnSmallArray() { + self.measure { + self.printArrayWith(columns: 2, rows: 2, inititalValue: 1) + } + } + + // func testPerformanceOnLargeArray() { + // self.measureBlock { + // self.printArrayWith(columns: 2000, rows: 2000, inititalValue: 1) + // } + // } + + fileprivate func printArrayWith(columns: Int, rows: Int, inititalValue: Int) { + let array = Array2D(columns: columns, rows: rows, initialValue: 4) + for r in 0.. Bool { + return lhs.identifier == rhs.identifier +} diff --git a/Heap/Heap Tests/HeapTests/Info.plist b/Array2D/Tests/Info.plist similarity index 100% rename from Heap/Heap Tests/HeapTests/Info.plist rename to Array2D/Tests/Info.plist diff --git a/Array2D/Tests/Tests.xcodeproj/project.pbxproj b/Array2D/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..af9b7c3b8 --- /dev/null +++ b/Array2D/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B2BBC901C779DAC0067B71D /* Array2DTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2BBC8F1C779DAC0067B71D /* Array2DTests.swift */; }; + 7B2BBC991C77A04F0067B71D /* Array2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2BBC981C77A04F0067B71D /* Array2D.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC8F1C779DAC0067B71D /* Array2DTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Array2DTests.swift; sourceTree = SOURCE_ROOT; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 7B2BBC981C77A04F0067B71D /* Array2D.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Array2D.swift; path = ../Array2D.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 = ( + 7B2BBC981C77A04F0067B71D /* Array2D.swift */, + 7B2BBC8F1C779DAC0067B71D /* Array2DTests.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 = ( + 7B2BBC901C779DAC0067B71D /* Array2DTests.swift in Sources */, + 7B2BBC991C77A04F0067B71D /* Array2D.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 = 4.2; + }; + 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 = 4.2; + }; + 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/Array2D/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Array2D/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Array2D/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Array2D/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift new file mode 100644 index 000000000..f6325513a --- /dev/null +++ b/B-Tree/BTree.playground/Contents.swift @@ -0,0 +1,27 @@ +//: Playground - noun: a place where people can play + +import Foundation + +// last checked with Xcode 10.0 + +let bTree = BTree(order: 1)! + +bTree.insert(1, for: 1) +bTree.insert(2, for: 2) +bTree.insert(3, for: 3) +bTree.insert(4, for: 4) + +bTree.value(for: 3) +bTree[3] + +bTree.remove(2) + +bTree.traverseKeysInOrder { key in + print(key) +} + +bTree.numberOfKeys + +bTree.order + +bTree.inorderArrayFromKeys diff --git a/B-Tree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift new file mode 100644 index 000000000..2ed0b2593 --- /dev/null +++ b/B-Tree/BTree.playground/Sources/BTree.swift @@ -0,0 +1,592 @@ +// 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 { + /** + * 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) + self.keys += keys + self.values += values + self.children = children + } +} + +// MARK: BTreeNode extesnion: Searching + +extension BTreeNode { + + /** + * 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 + 1) < keys.endIndex && keys[index] < key { + index = (index + 1) + } + + if key == keys[index] { + return values[index] + } else if key < keys[index] { + return children?[index].value(for: key) + } else { + return children?[(index + 1)].value(for: key) + } + } +} + +// MARK: BTreeNode extension: Traversals + +extension BTreeNode { + + /** + * 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.. owner.order * 2 { + split(child: children![index], atIndex: index) + } + } + } + + /** + * 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], at: index) + 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)]), + values: Array(child.values[child.values.indices.suffix(from: middleIndex)]) + ) + 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))] + ) + child.children!.removeSubrange(child.children!.indices.suffix(from: (middleIndex + 1))) + } + } +} + +// MARK: BTreeNode extension: Removal + +/** + * An enumeration to indicate a node's position according to another node. + * + * Possible values: + * - left + * - right + */ +private enum BTreeNodePosition { + case left + case right +} + +extension BTreeNode { + private var inorderPredecessor: BTreeNode { + if isLeaf { + return self + } else { + return children!.last!.inorderPredecessor + } + } + + /** + * Removes `key` and the value associated with it from the node + * or one of its descendants. + * + * - Parameters: + * - key: the key to be removed + */ + 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) + values.remove(at: index) + owner.numberOfKeys -= 1 + } else { + let predecessor = children![index].inorderPredecessor + keys[index] = predecessor.keys.last! + values[index] = predecessor.values.last! + children![index].remove(keys[index]) + if children![index].numberOfKeys < owner.order { + fix(childWithTooFewKeys: children![index], atIndex: index) + } + } + } else if key < keys[index] { + // We should go to left child... + + if let leftChild = children?[index] { + leftChild.remove(key) + if leftChild.numberOfKeys < owner.order { + fix(childWithTooFewKeys: leftChild, atIndex: index) + } + } else { + print("The key:\(key) is not in the tree.") + } + } else { + // We should go to right child... + + if let rightChild = children?[(index + 1)] { + rightChild.remove(key) + if rightChild.numberOfKeys < owner.order { + fix(childWithTooFewKeys: rightChild, atIndex: (index + 1)) + } + } else { + print("The key:\(key) is not in the tree") + } + } + } + + /** + * 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(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 { + move(keyAtIndex: index, to: child, from: children![(index + 1)], at: .right) + } else if (index - 1) >= 0 { + merge(child: child, atIndex: index, to: .left) + } else { + merge(child: child, atIndex: index, to: .right) + } + } + + /** + * 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[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(node.children!.last!, + 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) + keys[index] = node.keys.first! + values[index] = node.values.first! + node.keys.removeFirst() + node.values.removeFirst() + if !targetNode.isLeaf { + targetNode.children!.insert(node.children!.first!, + at: targetNode.children!.endIndex) + node.children!.removeFirst() + } + } + } + + /** + * 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: + // 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! + } + } + children!.remove(at: index) + } +} + +// MARK: BTreeNode extension: Conversion + +extension BTreeNode { + /** + * 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. + */ + public let order: Int + + /** + * The root node of the tree + */ + var rootNode: BTreeNode! + + fileprivate(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(owner: self) + } +} + +// MARK: BTree extension: Traversals + +extension BTree { + /** + * 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) + } +} + +// 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 value(for: key) + } +} + +// MARK: BTree extension: Value for Key + +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 func value(for key: Key) -> Value? { + guard rootNode.numberOfKeys > 0 else { + return nil + } + + return rootNode.value(for: key) + } +} + +// MARK: BTree extension: Insertion + +extension BTree { + /** + * 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( + owner: self, + keys: [rootNode.keys[middleIndexOfOldRoot]], + values: [rootNode.values[middleIndexOfOldRoot]], + children: [rootNode] + ) + 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)]), + values: Array(rootNode.values[rootNode.values.indices.suffix(from: middleIndexOfOldRoot)]) + ) + 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))] + ) + rootNode.children!.removeSubrange( + rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1)) + ) + } + + newRoot.children!.append(newRightChild) + rootNode = newRoot + } +} + +// MARK: BTree extension: Removal + +extension BTree { + /** + * Removes `key` and the value associated with it from the tree. + * + * - Parameters: + * - key: the key to remove + */ + public func remove(_ key: Key) { + guard rootNode.numberOfKeys > 0 else { + return + } + + rootNode.remove(key) + + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { + rootNode = rootNode.children!.first! + } + } +} + +// MARK: BTree extension: Conversion + +extension BTree { + /** + * 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. + */ + public var description: String { + return rootNode.description + } +} diff --git a/Boyer-Moore/BoyerMoore.playground/contents.xcplayground b/B-Tree/BTree.playground/contents.xcplayground similarity index 100% rename from Boyer-Moore/BoyerMoore.playground/contents.xcplayground rename to B-Tree/BTree.playground/contents.xcplayground diff --git a/B-Tree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata b/B-Tree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/B-Tree/BTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/BTree.swift b/B-Tree/BTree.swift new file mode 100644 index 000000000..2693eb308 --- /dev/null +++ b/B-Tree/BTree.swift @@ -0,0 +1,592 @@ +// 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 { + /** + * 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) + self.keys += keys + self.values += values + self.children = children + } +} + +// MARK: BTreeNode extesnion: Searching + +extension BTreeNode { + + /** + * 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 + 1) < keys.endIndex && keys[index] < key { + index = (index + 1) + } + + if key == keys[index] { + return values[index] + } else if key < keys[index] { + return children?[index].value(for: key) + } else { + return children?[(index + 1)].value(for: key) + } + } +} + +// MARK: BTreeNode extension: Travelsals + +extension BTreeNode { + + /** + * 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.. owner.order * 2 { + split(child: children![index], atIndex: index) + } + } + } + + /** + * 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], at: index) + 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)]), + values: Array(child.values[child.values.indices.suffix(from: middleIndex)]) + ) + 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))] + ) + child.children!.removeSubrange(child.children!.indices.suffix(from: (middleIndex + 1))) + } + } +} + +// MARK: BTreeNode extension: Removal + +/** + * An enumeration to indicate a node's position according to another node. + * + * Possible values: + * - left + * - right + */ +private enum BTreeNodePosition { + case left + case right +} + +extension BTreeNode { + private var inorderPredecessor: BTreeNode { + if isLeaf { + return self + } else { + return children!.last!.inorderPredecessor + } + } + + /** + * Removes `key` and the value associated with it from the node + * or one of its descendants. + * + * - Parameters: + * - key: the key to be removed + */ + 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) + values.remove(at: index) + owner.numberOfKeys -= 1 + } else { + let predecessor = children![index].inorderPredecessor + keys[index] = predecessor.keys.last! + values[index] = predecessor.values.last! + children![index].remove(keys[index]) + if children![index].numberOfKeys < owner.order { + fix(childWithTooFewKeys: children![index], atIndex: index) + } + } + } else if key < keys[index] { + // We should go to left child... + + if let leftChild = children?[index] { + leftChild.remove(key) + if leftChild.numberOfKeys < owner.order { + fix(childWithTooFewKeys: leftChild, atIndex: index) + } + } else { + print("The key:\(key) is not in the tree.") + } + } else { + // We should go to right child... + + if let rightChild = children?[(index + 1)] { + rightChild.remove(key) + if rightChild.numberOfKeys < owner.order { + fix(childWithTooFewKeys: rightChild, atIndex: (index + 1)) + } + } else { + print("The key:\(key) is not in the tree") + } + } + } + + /** + * 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(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 { + move(keyAtIndex: index, to: child, from: children![(index + 1)], at: .right) + } else if (index - 1) >= 0 { + merge(child: child, atIndex: index, to: .left) + } else { + merge(child: child, atIndex: index, to: .right) + } + } + + /** + * 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[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(node.children!.last!, + 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) + keys[index] = node.keys.first! + values[index] = node.values.first! + node.keys.removeFirst() + node.values.removeFirst() + if !targetNode.isLeaf { + targetNode.children!.insert(node.children!.first!, + at: targetNode.children!.endIndex) + node.children!.removeFirst() + } + } + } + + /** + * 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: + // 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! + } + } + children!.remove(at: index) + } +} + +// MARK: BTreeNode extension: Conversion + +extension BTreeNode { + /** + * 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. + */ + public let order: Int + + /** + * The root node of the tree + */ + var rootNode: BTreeNode! + + fileprivate(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(owner: self) + } +} + +// MARK: BTree extension: Travelsals + +extension BTree { + /** + * 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) + } +} + +// 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 value(for: key) + } +} + +// MARK: BTree extension: Value for Key + +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 func value(for key: Key) -> Value? { + guard rootNode.numberOfKeys > 0 else { + return nil + } + + return rootNode.value(for: key) + } +} + +// MARK: BTree extension: Insertion + +extension BTree { + /** + * 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( + owner: self, + keys: [rootNode.keys[middleIndexOfOldRoot]], + values: [rootNode.values[middleIndexOfOldRoot]], + children: [rootNode] + ) + 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)]), + values: Array(rootNode.values[rootNode.values.indices.suffix(from: middleIndexOfOldRoot)]) + ) + 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))] + ) + rootNode.children!.removeSubrange( + rootNode.children!.indices.suffix(from: (middleIndexOfOldRoot + 1)) + ) + } + + newRoot.children!.append(newRightChild) + rootNode = newRoot + } +} + +// MARK: BTree extension: Removal + +extension BTree { + /** + * Removes `key` and the value associated with it from the tree. + * + * - Parameters: + * - key: the key to remove + */ + public func remove(_ key: Key) { + guard rootNode.numberOfKeys > 0 else { + return + } + + rootNode.remove(key) + + if rootNode.numberOfKeys == 0 && !rootNode.isLeaf { + rootNode = rootNode.children!.first! + } + } +} + +// MARK: BTree extension: Conversion + +extension BTree { + /** + * 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. + */ + public var description: String { + return rootNode.description + } +} diff --git a/B-Tree/Images/BTree20.png b/B-Tree/Images/BTree20.png new file mode 100644 index 000000000..1a6a6a50e Binary files /dev/null and b/B-Tree/Images/BTree20.png differ diff --git a/B-Tree/Images/InsertionSplit.png b/B-Tree/Images/InsertionSplit.png new file mode 100644 index 000000000..2686b4df8 Binary files /dev/null and b/B-Tree/Images/InsertionSplit.png differ diff --git a/B-Tree/Images/MergingNodes.png b/B-Tree/Images/MergingNodes.png new file mode 100644 index 000000000..bdd94671b Binary files /dev/null and b/B-Tree/Images/MergingNodes.png differ diff --git a/B-Tree/Images/MovingKey.png b/B-Tree/Images/MovingKey.png new file mode 100644 index 000000000..17ebfd669 Binary files /dev/null and b/B-Tree/Images/MovingKey.png differ diff --git a/B-Tree/Images/Node.png b/B-Tree/Images/Node.png new file mode 100644 index 000000000..346f940bf Binary files /dev/null and b/B-Tree/Images/Node.png differ diff --git a/B-Tree/README.md b/B-Tree/README.md new file mode 100644 index 000000000..10a06853e --- /dev/null +++ b/B-Tree/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. + - 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. + +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 owner: BTree + + fileprivate 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 + +`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 + +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 `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 `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. + +## 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 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 child 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 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 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. + +![Merging Nodes](Images/MergingNodes.png) + +### The code + +- `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 `fix(childWithTooFewKeys:atIndex:)` method. + +- `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 + +[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/B-Tree/Tests/Tests.xcodeproj/project.pbxproj b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..66eb85190 --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,294 @@ +// !$*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 = 1000; + ORGANIZATIONNAME = "Viktor Szilárd Simkó"; + TargetAttributes = { + C66702771D0EEE25008CD769 = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1000; + }; + }; + }; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + 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"; + SWIFT_VERSION = 4.2; + }; + 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)"; + SWIFT_VERSION = 4.2; + }; + 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/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..d1555acfb --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/B-Tree/Tests/Tests/BTreeNodeTests.swift b/B-Tree/Tests/Tests/BTreeNodeTests.swift new file mode 100644 index 000000000..80de8b845 --- /dev/null +++ b/B-Tree/Tests/Tests/BTreeNodeTests.swift @@ -0,0 +1,58 @@ +// +// 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 owner = BTree(order: 2)! + var root: BTreeNode! + var leftChild: BTreeNode! + var rightChild: BTreeNode! + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + 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 new file mode 100644 index 000000000..69d7ce55d --- /dev/null +++ b/B-Tree/Tests/Tests/BTreeTests.swift @@ -0,0 +1,255 @@ +// +// 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! + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + 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) + } +} + +enum BTreeError: Error { + case tooManyNodes + case tooFewNodes +} + +extension BTreeNode { + func checkBalance(isRoot root: Bool) throws { + if numberOfKeys > owner.order * 2 { + throw BTreeError.tooManyNodes + } else if !root && numberOfKeys < owner.order { + throw BTreeError.tooFewNodes + } + + if !isLeaf { + for child in children! { + try child.checkBalance(isRoot: false) + } + } + } +} + +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/Insertion Sort/InsertionSort Tests/InsertionSortTests/Info.plist b/B-Tree/Tests/Tests/Info.plist similarity index 100% rename from Insertion Sort/InsertionSort Tests/InsertionSortTests/Info.plist rename to B-Tree/Tests/Tests/Info.plist diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 20c0d9dea..c3f020df2 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -14,11 +14,137 @@ Big-O | Name | Description **O(n log n)** | "linearithmic" | **Decent performance.** This is slightly worse than linear but not too bad. Example: the fastest general-purpose sorting algorithms. **O(n^2)** | quadratic | **Kinda slow.** If you have 100 items, this does 100^2 = 10,000 units of work. Doubling the number of items makes it four times slower (because 2 squared equals 4). Example: algorithms using nested loops, such as insertion sort. **O(n^3)** | cubic | **Poor performance.** If you have 100 items, this does 100^3 = 1,000,000 units of work. Doubling the input size makes it eight times slower. Example: matrix multiplication. -**O(2^n)** | exponential | **Very poor performance.** You want to avoid these kinds of algorithms, but sometimes you have no choice. Example: traveling salesperson problem. -**O(n!)** | factorial | **Intolerably slow.** It literally takes a million years to do anything. +**O(2^n)** | exponential | **Very poor performance.** You want to avoid these kinds of algorithms, but sometimes you have no choice. Adding just one bit to the input doubles the running time. Example: traveling salesperson problem. +**O(n!)** | factorial | **Intolerably slow.** It literally takes a million years to do anything. + + + +![Comparison of Big O computations](https://upload.wikimedia.org/wikipedia/commons/7/7e/Comparison_computational_complexity.svg) + + + +Below are some examples for each category of performance: + +**O(1)** + + The most common example with O(1) complexity is accessing an array index. + + ```swift + let value = array[5] + ``` + + Another example of O(1) is pushing and popping from Stack. + + +**O(log n)** + + ```swift + var j = 1 + while j < n { + // do constant time stuff + j *= 2 + } + ``` + + Instead of simply incrementing, 'j' is increased by 2 times itself in each run. + + Binary Search Algorithm is an example of O(log n) complexity. + + +**O(n)** + + ```swift + for i in stride(from: 0, to: n, by: 1) { + print(array[i]) + } + ``` + + Array Traversal and Linear Search are examples of O(n) complexity. + + +**O(n log n)** + + ```swift + for i in stride(from: 0, to: n, by: 1) { + var j = 1 + while j < n { + j *= 2 + // do constant time stuff + } + } + ``` + + OR + + ```swift + for i in stride(from: 0, to: n, by: 1) { + func index(after i: Int) -> Int? { // multiplies `i` by 2 until `i` >= `n` + return i < n ? i * 2 : nil + } + for j in sequence(first: 1, next: index(after:)) { + // do constant time stuff + } + } + ``` + + Merge Sort and Heap Sort are examples of O(n log n) complexity. + + +**O(n^2)** + + ```swift + for i in stride(from: 0, to: n, by: 1) { + for j in stride(from: 1, to: n, by: 1) { + // do constant time stuff + } + } + ``` + + Traversing a simple 2-D array and Bubble Sort are examples of O(n^2) complexity. + + +**O(n^3)** + + ```swift + for i in stride(from: 0, to: n, by: 1) { + for j in stride(from: 1, to: n, by: 1) { + for k in stride(from: 1, to: n, by: 1) { + // do constant time stuff + } + } + } + ``` + +**O(2^n)** + + Algorithms with running time O(2^N) are often recursive algorithms that solve a problem of size N by recursively solving two smaller problems of size N-1. + The following example prints all the moves necessary to solve the famous "Towers of Hanoi" problem for N disks. + + ```swift + func solveHanoi(n: Int, from: String, to: String, spare: String) { + guard n >= 1 else { return } + if n > 1 { + solveHanoi(n: n - 1, from: from, to: spare, spare: to) + solveHanoi(n: n - 1, from: spare, to: to, spare: from) + } + } + ``` + + +**O(n!)** + + The most trivial example of function that takes O(n!) time is given below. + + ```swift + func nFactFunc(n: Int) { + for i in stride(from: 0, to: n, by: 1) { + nFactFunc(n: n - 1) + } + } + ``` 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%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. diff --git a/Binary Search Tree/Images/DeleteTwoChildren.graffle b/Binary Search Tree/Images/DeleteTwoChildren.graffle index a03748077..a6a09877a 100644 Binary files a/Binary Search Tree/Images/DeleteTwoChildren.graffle and b/Binary Search Tree/Images/DeleteTwoChildren.graffle differ diff --git a/Binary Search Tree/Images/DeleteTwoChildren.png b/Binary Search Tree/Images/DeleteTwoChildren.png index c0a77aab1..1d941fe3c 100644 Binary files a/Binary Search Tree/Images/DeleteTwoChildren.png and b/Binary Search Tree/Images/DeleteTwoChildren.png differ diff --git a/Binary Search Tree/Images/MinimumMaximum.png b/Binary Search Tree/Images/MinimumMaximum.png index 70fe4ea7b..10b4e6352 100644 Binary files a/Binary Search Tree/Images/MinimumMaximum.png and b/Binary Search Tree/Images/MinimumMaximum.png differ diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index f08cc0ad1..57d1f4bff 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -1,67 +1,70 @@ # Binary Search Tree (BST) -A binary search tree is a special kind of [binary tree](../Binary Tree/) (a tree in which a node only has two children) that performs insertions and deletions such that the tree is always sorted. +> This topic has been tutorialized [here](https://www.raywenderlich.com/139821/swift-algorithm-club-swift-binary-search-tree-data-structure) -If you don't know what a tree is or what it is for, then [read this first](../Tree/). + +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 information about a tree, [read this first](../Tree/). ## "Always sorted" property -This is an example of a valid binary search tree: +Here is an example of a valid binary search tree: ![A binary search tree](Images/Tree1.png) 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 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 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.) +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 node, then at the node itself, and finally at the 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,27 +72,20 @@ 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 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) -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) -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 { @@ -140,41 +136,37 @@ 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 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 takes up more space. +> **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) { - 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 } } } @@ -182,11 +174,11 @@ A tree node by itself is pretty useless, so here is how you would add new nodes Like so many other tree operations, insertion is easiest to implement with recursion. We compare the new value to the values of the existing nodes and decide whether to add it to the left branch or the right branch. -If there is no more left or right child to look at, we create a new `BinarySearchTree` object for the new node and connect it to the tree by setting its `parent` property. +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) @@ -197,7 +189,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, then 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: @@ -206,7 +198,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) } } ``` @@ -221,7 +213,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 { @@ -243,15 +235,15 @@ When you do a `print(tree)`, you should get something like this: ((1) <- 2 -> (5)) <- 7 -> ((9) <- 10) -With some imagination, you should see now that this indeed corresponds to the following tree: +The root node is in the middle. With some imagination, you should see that this indeed corresponds to the following tree: ![The tree](Images/Tree2.png) -By the way, you may be wondering what happens when you insert duplicate items? We always insert those kinds of items 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()`: @@ -269,16 +261,16 @@ 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? { + public func search(_ value: T) -> BinarySearchTree? { var node: BinarySearchTree? = self - while case let n? = node { + while let n = node { if value < n.value { node = n.left } else if value > n.value { @@ -291,48 +283,48 @@ 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) tree.search(2) tree.search(7) -tree.search(6) // nil +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 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) } ``` -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) } @@ -347,14 +339,15 @@ 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 - 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 } ``` @@ -375,14 +368,14 @@ 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 -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 more readable by defining some helper functions. ```swift - private func reconnectParentToNode(node: BinarySearchTree?) { + private func reconnectParentTo(node: BinarySearchTree?) { if let parent = parent { if isLeftChild { parent.left = node @@ -394,96 +387,63 @@ 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`. +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 leftmost descendent of a node: +We also need a function that returns the minimum and maximum of a node: ```swift public func minimum() -> BinarySearchTree { var node = self - while case let next? = node.left { + while let next = node.left { node = next } 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 `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. - -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 { + while let next = node.right { node = next } return node } -``` -It returns the rightmost descendent of this 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`. +``` -Finally, we can write the code the remove a node from the tree: +The rest of the code is self-explanatory: ```swift - public func remove() { - if let left = left { - if let right = right { - let successor = right.minimum() // 1 - value = successor.value - successor.remove() - } else { - reconnectParentToNode(left) // 2 - } - } else if let right = right { // 3 - reconnectParentToNode(right) + @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 { + replacement = right.minimum() + } else if let left = left { + replacement = left.maximum() } else { - reconnectParentToNode(nil) // 4 + replacement = nil } - } -``` - -It doesn't look so scary after all. ;-) Here is what it does: - -1. 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, i.e. `right.minimum()`. -2. This node only has a left child. The left child replaces the node. + replacement?.remove() -3. This node only has a right child. The right child replaces the node. + // Place the replacement on current node's position + replacement?.right = right + replacement?.left = left + right?.parent = replacement + left?.parent = replacement + reconnectParentTo(node:replacement) -4. This node has no children. We just disconnect it from its parent. + // The current node is no longer part of the tree, so clean it up. + parent = nil + left = nil + right = nil -The only tricky situation here is `// 1`. Rather than deleting the current node, we give it the successor's value and remove the successor node instead. - -> **Note:** What would happen if you deleted the root node? Specifically, how would you know which node becomes the new root node? It turns out you don't have to worry about that because the root never actually gets deleted. We simply give it a new value. - -Try it out: - -```swift -if let node2 = tree.search(2) { - print(tree) // before - node2.remove() - print(tree) // after -} + return replacement + } ``` -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) - -But after `remove()` you get: - - ((1) <- 5) <- 7 -> ((9) <- 10) - -As you can see, node `5` has taken the place of `2`. In fact, if you do `print(node2)` you'll see that it now has the value `5`. We didn't actually remove the `node2` object, we just gave it a new value. - -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: @@ -500,7 +460,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: @@ -514,15 +474,15 @@ You can also calculate the *depth* of a node, which is the distance to the root. public func depth() -> Int { var node = self var edges = 0 - while case let parent? = node.parent { + while let parent = node.parent { node = parent - ++edges + edges += 1 } return edges } ``` -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) { @@ -532,11 +492,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: @@ -546,7 +506,7 @@ The `predecessor()` function returns the node whose value precedes the current v return left.maximum() } else { var node = self - while case let parent? = node.parent { + while let parent = node.parent { if parent.value < value { return parent } node = parent } @@ -555,11 +515,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? { @@ -567,7 +527,7 @@ The code for `successor()` works the exact same way but mirrored: return right.minimum() } else { var node = self - while case let parent? = node.parent { + while let parent = node.parent { if parent.value > value { return parent } node = parent } @@ -578,11 +538,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 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 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) { @@ -590,14 +550,14 @@ 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. You can check whether a tree is a valid binary search tree with the following method: ```swift - public func isBST(minValue minValue: T, maxValue: T) -> Bool { + public func isBST(minValue: T, maxValue: T) -> Bool { if value < minValue || value > maxValue { return false } let leftBST = left?.isBST(minValue: minValue, maxValue: value) ?? true let rightBST = right?.isBST(minValue: value, maxValue: maxValue) ?? true @@ -605,7 +565,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: @@ -620,9 +580,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 is how you can make a binary search tree using an enum: ```swift public enum BinarySearchTree { @@ -632,15 +594,15 @@ 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. - `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. That 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. -A usual, we'll implement most functionality recursively. We'll treat each case 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 { @@ -650,11 +612,11 @@ A usual, we'll implement most functionality recursively. We'll treat each case s case let .Node(left, _, right): return left.count + 1 + right.count } } - + public var height: Int { switch self { - case .Empty: return 0 - case .Leaf: return 1 + case .Empty: return -1 + case .Leaf: return 0 case let .Node(left, _, right): return 1 + max(left.height, right.height) } } @@ -667,7 +629,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) @@ -696,7 +658,7 @@ tree = tree.insert(9) tree = tree.insert(1) ``` -Notice that each time you insert something, you get back a completely new tree. 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: @@ -719,7 +681,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: @@ -729,7 +691,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 { @@ -744,21 +706,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 need to check 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! +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 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. To see examples, check [AVL tree](../AVL%20Tree) and [red-black tree](../Red-Black%20Tree). ## See also diff --git a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree.xcodeproj/project.pbxproj deleted file mode 100644 index d4ed37459..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B1BF9F11C678D630051C9A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BF9F01C678D630051C9A4 /* AppDelegate.swift */; }; - 7B1BF9F31C678D630051C9A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BF9F21C678D630051C9A4 /* Assets.xcassets */; }; - 7B1BF9F61C678D630051C9A4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BF9F41C678D630051C9A4 /* MainMenu.xib */; }; - 7B1BFA011C678D630051C9A4 /* BinarySearchTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA001C678D630051C9A4 /* BinarySearchTreeTests.swift */; }; - 7B1BFA0C1C678D820051C9A4 /* BinarySearchTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA0B1C678D820051C9A4 /* BinarySearchTree.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B1BF9FD1C678D630051C9A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B1BF9E51C678D630051C9A4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B1BF9EC1C678D630051C9A4; - remoteInfo = BinarySearchTree; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B1BF9ED1C678D630051C9A4 /* BinarySearchTree.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BinarySearchTree.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BF9F01C678D630051C9A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B1BF9F21C678D630051C9A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B1BF9F51C678D630051C9A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B1BF9F71C678D630051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BF9FC1C678D630051C9A4 /* BinarySearchTreeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BinarySearchTreeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA001C678D630051C9A4 /* BinarySearchTreeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeTests.swift; sourceTree = ""; }; - 7B1BFA021C678D630051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA0B1C678D820051C9A4 /* BinarySearchTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchTree.swift; path = ../../BinarySearchTree.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B1BF9EA1C678D630051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9F91C678D630051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B1BF9E41C678D630051C9A4 = { - isa = PBXGroup; - children = ( - 7B1BF9EF1C678D630051C9A4 /* BinarySearchTree */, - 7B1BF9FF1C678D630051C9A4 /* BinarySearchTreeTests */, - 7B1BF9EE1C678D630051C9A4 /* Products */, - ); - sourceTree = ""; - }; - 7B1BF9EE1C678D630051C9A4 /* Products */ = { - isa = PBXGroup; - children = ( - 7B1BF9ED1C678D630051C9A4 /* BinarySearchTree.app */, - 7B1BF9FC1C678D630051C9A4 /* BinarySearchTreeTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B1BF9EF1C678D630051C9A4 /* BinarySearchTree */ = { - isa = PBXGroup; - children = ( - 7B1BF9F01C678D630051C9A4 /* AppDelegate.swift */, - 7B1BF9F21C678D630051C9A4 /* Assets.xcassets */, - 7B1BFA0B1C678D820051C9A4 /* BinarySearchTree.swift */, - 7B1BF9F71C678D630051C9A4 /* Info.plist */, - 7B1BF9F41C678D630051C9A4 /* MainMenu.xib */, - ); - path = BinarySearchTree; - sourceTree = ""; - }; - 7B1BF9FF1C678D630051C9A4 /* BinarySearchTreeTests */ = { - isa = PBXGroup; - children = ( - 7B1BFA001C678D630051C9A4 /* BinarySearchTreeTests.swift */, - 7B1BFA021C678D630051C9A4 /* Info.plist */, - ); - path = BinarySearchTreeTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B1BF9EC1C678D630051C9A4 /* BinarySearchTree */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA051C678D630051C9A4 /* Build configuration list for PBXNativeTarget "BinarySearchTree" */; - buildPhases = ( - 7B1BF9E91C678D630051C9A4 /* Sources */, - 7B1BF9EA1C678D630051C9A4 /* Frameworks */, - 7B1BF9EB1C678D630051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = BinarySearchTree; - productName = BinarySearchTree; - productReference = 7B1BF9ED1C678D630051C9A4 /* BinarySearchTree.app */; - productType = "com.apple.product-type.application"; - }; - 7B1BF9FB1C678D630051C9A4 /* BinarySearchTreeTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA081C678D630051C9A4 /* Build configuration list for PBXNativeTarget "BinarySearchTreeTests" */; - buildPhases = ( - 7B1BF9F81C678D630051C9A4 /* Sources */, - 7B1BF9F91C678D630051C9A4 /* Frameworks */, - 7B1BF9FA1C678D630051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B1BF9FE1C678D630051C9A4 /* PBXTargetDependency */, - ); - name = BinarySearchTreeTests; - productName = BinarySearchTreeTests; - productReference = 7B1BF9FC1C678D630051C9A4 /* BinarySearchTreeTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B1BF9E51C678D630051C9A4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B1BF9EC1C678D630051C9A4 = { - CreatedOnToolsVersion = 7.2; - }; - 7B1BF9FB1C678D630051C9A4 = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B1BF9EC1C678D630051C9A4; - }; - }; - }; - buildConfigurationList = 7B1BF9E81C678D630051C9A4 /* Build configuration list for PBXProject "BinarySearchTree" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B1BF9E41C678D630051C9A4; - productRefGroup = 7B1BF9EE1C678D630051C9A4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B1BF9EC1C678D630051C9A4 /* BinarySearchTree */, - 7B1BF9FB1C678D630051C9A4 /* BinarySearchTreeTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B1BF9EB1C678D630051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BF9F31C678D630051C9A4 /* Assets.xcassets in Resources */, - 7B1BF9F61C678D630051C9A4 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9FA1C678D630051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B1BF9E91C678D630051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA0C1C678D820051C9A4 /* BinarySearchTree.swift in Sources */, - 7B1BF9F11C678D630051C9A4 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9F81C678D630051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA011C678D630051C9A4 /* BinarySearchTreeTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B1BF9FE1C678D630051C9A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B1BF9EC1C678D630051C9A4 /* BinarySearchTree */; - targetProxy = 7B1BF9FD1C678D630051C9A4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B1BF9F41C678D630051C9A4 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B1BF9F51C678D630051C9A4 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B1BFA031C678D630051C9A4 /* 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; - }; - 7B1BFA041C678D630051C9A4 /* 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; - }; - 7B1BFA061C678D630051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTree/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTree; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B1BFA071C678D630051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTree/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTree; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B1BFA091C678D630051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTreeTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTreeTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BinarySearchTree.app/Contents/MacOS/BinarySearchTree"; - }; - name = Debug; - }; - 7B1BFA0A1C678D630051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTreeTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTreeTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BinarySearchTree.app/Contents/MacOS/BinarySearchTree"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B1BF9E81C678D630051C9A4 /* Build configuration list for PBXProject "BinarySearchTree" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA031C678D630051C9A4 /* Debug */, - 7B1BFA041C678D630051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA051C678D630051C9A4 /* Build configuration list for PBXNativeTarget "BinarySearchTree" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA061C678D630051C9A4 /* Debug */, - 7B1BFA071C678D630051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA081C678D630051C9A4 /* Build configuration list for PBXNativeTarget "BinarySearchTreeTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA091C678D630051C9A4 /* Debug */, - 7B1BFA0A1C678D630051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B1BF9E51C678D630051C9A4 /* Project object */; -} diff --git a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/AppDelegate.swift b/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/AppDelegate.swift deleted file mode 100644 index d80dd0269..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// BinarySearchTree -// -// Created by Matthijs Hollemans on 07-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Base.lproj/MainMenu.xib b/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Base.lproj/MainMenu.xib deleted file mode 100644 index f7be413dc..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 7f982464a..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,21 +1,22 @@ //: 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) + +let toDelete = tree.search(value: 1) +toDelete?.remove() 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,9 +25,9 @@ tree.toArray() tree.minimum() tree.maximum() -if let node2 = tree.search(2) { +if let node2 = tree.search(value: 2) { node2.remove() - node2.value // this is now node "5" + node2 print(tree) } @@ -34,25 +35,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) { - // This makes it an invalid binary search tree because 100 is greater +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 f509195f9..2d0eb7e57 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 @@ -23,7 +23,7 @@ public class BinarySearchTree { precondition(array.count > 0) self.init(value: array.first!) for v in array.dropFirst() { - insert(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, 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 } } } @@ -101,37 +97,44 @@ extension BinarySearchTree { 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() { - if let left = left { - if let right = right { - // 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() - - // Rather than deleting the current node (which is problematic for the - // root node) we give it the successor's value and remove the successor. - value = successor.value - - // 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() - } else { - // This node only has a left child. The left child replaces the node. - reconnectParentToNode(left) - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - reconnectParentToNode(right) + @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 { + replacement = right.minimum() + } else if let left = left { + replacement = left.maximum() } else { - // This node has no children. We just disconnect it from its parent. - reconnectParentToNode(nil) + replacement = nil } + + replacement?.remove() + + // 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. + parent = nil + left = nil + right = nil + + return replacement } - private func reconnectParentToNode(node: BinarySearchTree?) { + private func reconnectParentTo(node: BinarySearchTree?) { if let parent = parent { if isLeftChild { parent.left = node @@ -152,7 +155,7 @@ extension BinarySearchTree { */ public func search(value: T) -> BinarySearchTree? { var node: BinarySearchTree? = self - while case let n? = node { + while let n = node { if value < n.value { node = n.left } else if value > n.value { @@ -176,9 +179,9 @@ extension BinarySearchTree { } } */ - + public func contains(value: T) -> Bool { - return search(value) != nil + return search(value: value) != nil } /* @@ -186,23 +189,23 @@ extension BinarySearchTree { */ public func minimum() -> BinarySearchTree { var node = self - while case let next? = node.left { + while 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 { + while 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. @@ -210,13 +213,13 @@ extension BinarySearchTree { public func depth() -> Int { var node = self var edges = 0 - while case let parent? = node.parent { + while let parent = node.parent { node = parent - ++edges + 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). @@ -232,12 +235,12 @@ extension BinarySearchTree { /* Finds the node whose value precedes our value in sorted order. */ - public func predecessor() -> BinarySearchTree? { + public func predecessor() -> BinarySearchTree? { if let left = left { return left.maximum() } else { var node = self - while case let parent? = node.parent { + while let parent = node.parent { if parent.value < value { return parent } node = parent } @@ -248,12 +251,12 @@ extension BinarySearchTree { /* Finds the node whose value succeeds our value in sorted order. */ - public func successor() -> BinarySearchTree? { + public func successor() -> BinarySearchTree? { if let right = right { return right.minimum() } else { var node = self - while case let parent? = node.parent { + while let parent = node.parent { if parent.value > value { return parent } node = parent } @@ -265,32 +268,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 } } @@ -299,7 +302,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 @@ -321,24 +324,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 +// } +//} diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/timeline.xctimeline b/Binary Search Tree/Solution 1/BinarySearchTree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.swift b/Binary Search Tree/Solution 1/BinarySearchTree.swift deleted file mode 100644 index f509195f9..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree.swift +++ /dev/null @@ -1,344 +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. - Performance: runs in O(h) time, where h is the height of the tree. - */ - public func remove() { - if let left = left { - if let right = right { - // 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() - - // Rather than deleting the current node (which is problematic for the - // root node) we give it the successor's value and remove the successor. - value = successor.value - - // 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() - } else { - // This node only has a left child. The left child replaces the node. - reconnectParentToNode(left) - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - reconnectParentToNode(right) - } else { - // This node has no children. We just disconnect it from its parent. - reconnectParentToNode(nil) - } - } - - 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 - } - 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/BinarySearchTree Tests/BinarySearchTreeTests/BinarySearchTreeTests.swift b/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift similarity index 69% rename from Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTreeTests/BinarySearchTreeTests.swift rename to Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift index a23c3de5f..30749d8e4 100755 --- a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTreeTests/BinarySearchTreeTests.swift +++ b/Binary Search Tree/Solution 1/Tests/BinarySearchTreeTests.swift @@ -1,6 +1,5 @@ import Foundation import XCTest -@testable import BinarySearchTree class BinarySearchTreeTest: XCTestCase { func testRootNode() { @@ -18,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) @@ -27,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) @@ -46,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) @@ -85,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]) } @@ -109,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]) @@ -119,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) @@ -128,26 +127,29 @@ 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) - node4.remove() + let replacement1 = node4.remove() XCTAssertNil(node5.left) + XCTAssertNil(replacement1) - node5.remove() + let replacement2 = node5.remove() XCTAssertNil(tree.left) + XCTAssertNil(replacement2) - node10.remove() + let replacement3 = node10.remove() XCTAssertNil(tree.right) + XCTAssertNil(replacement3) XCTAssertEqual(tree.count, 1) XCTAssertEqual(tree.toArray(), [8]) @@ -156,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) @@ -169,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) @@ -186,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) @@ -199,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) @@ -216,43 +218,49 @@ 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) XCTAssertTrue(node5 === node6.parent) - node5.remove() - XCTAssertTrue(tree.left === node5) - XCTAssertTrue(tree === node5.parent) - XCTAssertTrue(node5.left === node4) - XCTAssertTrue(node5 === node4.parent) + let replacement1 = node5.remove() + XCTAssertTrue(replacement1 === node6) + XCTAssertTrue(tree.left === node6) + XCTAssertTrue(tree === node6.parent) + XCTAssertTrue(node6.left === node4) + XCTAssertTrue(node6 === node4.parent) + XCTAssertNil(node5.left) XCTAssertNil(node5.right) + XCTAssertNil(node5.parent) XCTAssertNil(node4.left) XCTAssertNil(node4.right) - XCTAssertEqual(node5.value, 6) + XCTAssertNotNil(node4.parent) 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) XCTAssertTrue(node10 === node11.parent) - node10.remove() - XCTAssertTrue(tree.right === node10) - XCTAssertTrue(tree === node10.parent) - XCTAssertTrue(node10.left === node9) - XCTAssertTrue(node10 === node9.parent) + let replacement2 = node10.remove() + XCTAssertTrue(replacement2 === node11) + XCTAssertTrue(tree.right === node11) + XCTAssertTrue(tree === node11.parent) + XCTAssertTrue(node11.left === node9) + XCTAssertTrue(node11 === node9.parent) + XCTAssertNil(node10.left) XCTAssertNil(node10.right) + XCTAssertNil(node10.parent) XCTAssertNil(node9.left) XCTAssertNil(node9.right) - XCTAssertEqual(node10.value, 11) + XCTAssertNotNil(node9.parent) XCTAssertEqual(tree.count, 5) XCTAssertEqual(tree.toArray(), [4, 6, 8, 9, 11]) } @@ -260,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) @@ -274,33 +283,44 @@ class BinarySearchTreeTest: XCTestCase { XCTAssertTrue(node11.right === node15) XCTAssertTrue(node11 === node15.parent) - node10.remove() - XCTAssertTrue(tree.right === node10) - XCTAssertTrue(tree === node10.parent) - XCTAssertTrue(node10.left === node9) - XCTAssertTrue(node10 === node9.parent) - XCTAssertTrue(node10.right === node20) - XCTAssertTrue(node10 === node20.parent) - XCTAssertTrue(node20.left === node15) - XCTAssertTrue(node20 === node15.parent) + let replacement = node10.remove() + XCTAssertTrue(replacement === node11) + XCTAssertTrue(tree.right === node11) + XCTAssertTrue(tree === node11.parent) + XCTAssertTrue(node11.left === node9) + XCTAssertTrue(node11 === node9.parent) + XCTAssertTrue(node11.right === node20) + XCTAssertTrue(node11 === node20.parent) + XCTAssertTrue(node20.left === node13) + XCTAssertTrue(node20 === node13.parent) XCTAssertNil(node20.right) - XCTAssertEqual(node10.value, 11) + XCTAssertNil(node10.left) + XCTAssertNil(node10.right) + XCTAssertNil(node10.parent) XCTAssertEqual(tree.count, 8) XCTAssertEqual(tree.toArray(), [4, 5, 8, 9, 11, 13, 15, 20]) } func testRemoveRoot() { let tree = BinarySearchTree(array: [8, 5, 10, 4, 9, 20, 11, 15, 13]) - tree.remove() - XCTAssertEqual(tree.value, 9) - XCTAssertEqual(tree.count, 8) - XCTAssertEqual(tree.toArray(), [4, 5, 9, 10, 11, 13, 15, 20]) + let node9 = tree.search(value: 9)! + + let newRoot = tree.remove() + XCTAssertTrue(newRoot === node9) + XCTAssertEqual(newRoot!.value, 9) + XCTAssertEqual(newRoot!.count, 8) + XCTAssertEqual(newRoot!.toArray(), [4, 5, 9, 10, 11, 13, 15, 20]) + + // The old root is a subtree of a single element. + XCTAssertEqual(tree.value, 8) + XCTAssertEqual(tree.count, 1) + XCTAssertEqual(tree.toArray(), [8]) } 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) @@ -312,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/Linked List/LinkedList Tests/LinkedListTests/Info.plist b/Binary Search Tree/Solution 1/Tests/Info.plist similarity index 100% rename from Linked List/LinkedList Tests/LinkedListTests/Info.plist rename to Binary Search Tree/Solution 1/Tests/Info.plist diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d7c687e0c --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,287 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 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; }; + 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 = 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 = ( + 9E5A58B81E304C3100DAB3BB /* BinarySearchTree.swift */, + 7B80C3D91C77A323003CECC7 /* BinarySearchTreeTests.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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 7B80C3DA1C77A323003CECC7 /* BinarySearchTreeTests.swift in Sources */, + 9E5A58B91E304C3100DAB3BB /* BinarySearchTree.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_COMPILATION_MODE = wholemodule; + }; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/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 + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift index 217cb489e..2b5dcc341 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/Contents.swift @@ -1,14 +1,14 @@ //: 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) -tree = tree.insert(2) -tree = tree.insert(5) -tree = tree.insert(10) -tree = tree.insert(9) -tree = tree.insert(1) +var tree = BinarySearchTree.leaf(7) +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 d370eb691..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,105 +4,105 @@ 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) } } - + /* Inserts a new element into the tree. Performance: runs in O(h) time, where h is the height of the tree. */ public func insert(newValue: T) -> BinarySearchTree { switch self { - case .Empty: - return .Leaf(newValue) - - case .Leaf(let value): + case .empty: + return .leaf(newValue) + + 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: newValue), value, right) } else { - return .Node(left, value, right.insert(newValue)) + return .node(left, value, right.insert(newValue: newValue)) } } } - + /* 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(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) + return left.search(x: x) } else if y < x { - return right.search(x) + return right.search(x: x) } else { return self } } } - + public func contains(x: T) -> Bool { - return search(x) != nil + return search(x: x) != nil } - + /* Returns the leftmost descendent. O(h) time. */ 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 } - + /* Returns the rightmost descendent. O(h) time. */ 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.playground/playground.xcworkspace/contents.xcworkspacedata b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/timeline.xctimeline b/Binary Search Tree/Solution 2/BinarySearchTree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.swift b/Binary Search Tree/Solution 2/BinarySearchTree.swift index d370eb691..23b1c8aca 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.swift @@ -4,64 +4,64 @@ 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 -1 + case .leaf: return 0 + case let .node(left, _, right): return 1 + max(left.height, right.height) } } - + /* Inserts a new element into the tree. Performance: runs in O(h) time, where h is the height of the tree. */ public func insert(newValue: T) -> BinarySearchTree { switch self { - case .Empty: - return .Leaf(newValue) - - case .Leaf(let value): + case .empty: + return .leaf(newValue) + + 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)) } } } - + /* 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(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 { @@ -71,38 +71,38 @@ public enum BinarySearchTree { } } } - + public func contains(x: T) -> Bool { return search(x) != nil } - + /* Returns the leftmost descendent. O(h) time. */ 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 } - + /* Returns the rightmost descendent. O(h) time. */ 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/BinarySearch Tests/BinarySearch.xcodeproj/project.pbxproj b/Binary Search/BinarySearch Tests/BinarySearch.xcodeproj/project.pbxproj deleted file mode 100644 index b5493845f..000000000 --- a/Binary Search/BinarySearch Tests/BinarySearch.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18DFF11C5BF66F005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18DFF01C5BF66F005A2B8E /* AppDelegate.swift */; }; - 7B18DFF31C5BF66F005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18DFF21C5BF66F005A2B8E /* Assets.xcassets */; }; - 7B18DFF61C5BF66F005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18DFF41C5BF66F005A2B8E /* MainMenu.xib */; }; - 7B18E0011C5BF66F005A2B8E /* BinarySearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0001C5BF66F005A2B8E /* BinarySearchTests.swift */; }; - 7B18E00C1C5BF6B2005A2B8E /* BinarySearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E00B1C5BF6B2005A2B8E /* BinarySearch.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18DFFD1C5BF66F005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18DFE51C5BF66F005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18DFEC1C5BF66F005A2B8E; - remoteInfo = BinarySearch; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18DFED1C5BF66F005A2B8E /* BinarySearch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BinarySearch.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18DFF01C5BF66F005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18DFF21C5BF66F005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18DFF51C5BF66F005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18DFF71C5BF66F005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18DFFC1C5BF66F005A2B8E /* BinarySearchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BinarySearchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0001C5BF66F005A2B8E /* BinarySearchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinarySearchTests.swift; sourceTree = ""; }; - 7B18E0021C5BF66F005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E00B1C5BF6B2005A2B8E /* BinarySearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearch.swift; path = ../../BinarySearch.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18DFEA1C5BF66F005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFF91C5BF66F005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18DFE41C5BF66F005A2B8E = { - isa = PBXGroup; - children = ( - 7B18DFEF1C5BF66F005A2B8E /* BinarySearch */, - 7B18DFFF1C5BF66F005A2B8E /* BinarySearchTests */, - 7B18DFEE1C5BF66F005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18DFEE1C5BF66F005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18DFED1C5BF66F005A2B8E /* BinarySearch.app */, - 7B18DFFC1C5BF66F005A2B8E /* BinarySearchTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18DFEF1C5BF66F005A2B8E /* BinarySearch */ = { - isa = PBXGroup; - children = ( - 7B18DFF01C5BF66F005A2B8E /* AppDelegate.swift */, - 7B18DFF21C5BF66F005A2B8E /* Assets.xcassets */, - 7B18E00B1C5BF6B2005A2B8E /* BinarySearch.swift */, - 7B18DFF71C5BF66F005A2B8E /* Info.plist */, - 7B18DFF41C5BF66F005A2B8E /* MainMenu.xib */, - ); - path = BinarySearch; - sourceTree = ""; - }; - 7B18DFFF1C5BF66F005A2B8E /* BinarySearchTests */ = { - isa = PBXGroup; - children = ( - 7B18E0001C5BF66F005A2B8E /* BinarySearchTests.swift */, - 7B18E0021C5BF66F005A2B8E /* Info.plist */, - ); - path = BinarySearchTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18DFEC1C5BF66F005A2B8E /* BinarySearch */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0051C5BF66F005A2B8E /* Build configuration list for PBXNativeTarget "BinarySearch" */; - buildPhases = ( - 7B18DFE91C5BF66F005A2B8E /* Sources */, - 7B18DFEA1C5BF66F005A2B8E /* Frameworks */, - 7B18DFEB1C5BF66F005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = BinarySearch; - productName = BinarySearch; - productReference = 7B18DFED1C5BF66F005A2B8E /* BinarySearch.app */; - productType = "com.apple.product-type.application"; - }; - 7B18DFFB1C5BF66F005A2B8E /* BinarySearchTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0081C5BF66F005A2B8E /* Build configuration list for PBXNativeTarget "BinarySearchTests" */; - buildPhases = ( - 7B18DFF81C5BF66F005A2B8E /* Sources */, - 7B18DFF91C5BF66F005A2B8E /* Frameworks */, - 7B18DFFA1C5BF66F005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18DFFE1C5BF66F005A2B8E /* PBXTargetDependency */, - ); - name = BinarySearchTests; - productName = BinarySearchTests; - productReference = 7B18DFFC1C5BF66F005A2B8E /* BinarySearchTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18DFE51C5BF66F005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18DFEC1C5BF66F005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18DFFB1C5BF66F005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18DFEC1C5BF66F005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18DFE81C5BF66F005A2B8E /* Build configuration list for PBXProject "BinarySearch" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18DFE41C5BF66F005A2B8E; - productRefGroup = 7B18DFEE1C5BF66F005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18DFEC1C5BF66F005A2B8E /* BinarySearch */, - 7B18DFFB1C5BF66F005A2B8E /* BinarySearchTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18DFEB1C5BF66F005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18DFF31C5BF66F005A2B8E /* Assets.xcassets in Resources */, - 7B18DFF61C5BF66F005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFFA1C5BF66F005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18DFE91C5BF66F005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E00C1C5BF6B2005A2B8E /* BinarySearch.swift in Sources */, - 7B18DFF11C5BF66F005A2B8E /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFF81C5BF66F005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0011C5BF66F005A2B8E /* BinarySearchTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18DFFE1C5BF66F005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18DFEC1C5BF66F005A2B8E /* BinarySearch */; - targetProxy = 7B18DFFD1C5BF66F005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18DFF41C5BF66F005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18DFF51C5BF66F005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E0031C5BF66F005A2B8E /* 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; - }; - 7B18E0041C5BF66F005A2B8E /* 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; - }; - 7B18E0061C5BF66F005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearch/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearch; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0071C5BF66F005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearch/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearch; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0091C5BF66F005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BinarySearch.app/Contents/MacOS/BinarySearch"; - }; - name = Debug; - }; - 7B18E00A1C5BF66F005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = BinarySearchTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.BinarySearchTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BinarySearch.app/Contents/MacOS/BinarySearch"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18DFE81C5BF66F005A2B8E /* Build configuration list for PBXProject "BinarySearch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0031C5BF66F005A2B8E /* Debug */, - 7B18E0041C5BF66F005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0051C5BF66F005A2B8E /* Build configuration list for PBXNativeTarget "BinarySearch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0061C5BF66F005A2B8E /* Debug */, - 7B18E0071C5BF66F005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0081C5BF66F005A2B8E /* Build configuration list for PBXNativeTarget "BinarySearchTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0091C5BF66F005A2B8E /* Debug */, - 7B18E00A1C5BF66F005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18DFE51C5BF66F005A2B8E /* Project object */; -} diff --git a/Binary Search/BinarySearch Tests/BinarySearch/AppDelegate.swift b/Binary Search/BinarySearch Tests/BinarySearch/AppDelegate.swift deleted file mode 100644 index f3db7bc62..000000000 --- a/Binary Search/BinarySearch Tests/BinarySearch/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// BinarySearch -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Binary Search/BinarySearch Tests/BinarySearch/Assets.xcassets/AppIcon.appiconset/Contents.json b/Binary Search/BinarySearch Tests/BinarySearch/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Binary Search/BinarySearch Tests/BinarySearch/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/Binary Search/BinarySearch Tests/BinarySearch/Base.lproj/MainMenu.xib b/Binary Search/BinarySearch Tests/BinarySearch/Base.lproj/MainMenu.xib deleted file mode 100644 index ee7982efd..000000000 --- a/Binary Search/BinarySearch Tests/BinarySearch/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Binary Search/BinarySearch.playground/Contents.swift b/Binary Search/BinarySearch.playground/Contents.swift index fdfd37d8f..f673f25c4 100644 --- a/Binary Search/BinarySearch.playground/Contents.swift +++ b/Binary Search/BinarySearch.playground/Contents.swift @@ -4,52 +4,15 @@ 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() - -/* - 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 - } - } -} +let sorted = numbers.sorted() +// Using recursive solution 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.. - + \ No newline at end of file diff --git a/Binary Search/BinarySearch.playground/timeline.xctimeline b/Binary Search/BinarySearch.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Binary Search/BinarySearch.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - 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 792b15c4a..0cecce6cf 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -4,24 +4,24 @@ Goal: Quickly find an element in an array. Let's say you have an array of numbers and you want to determine whether a specific number is in that array, and if so, at which index. -In most cases, Swift's `indexOf()` function is good enough for that: +In most cases, Swift's `Collection.index(of:)` function is good enough for that: ```swift let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 41, 23] -numbers.indexOf(43) // returns 15 +numbers.index(of: 43) // returns 15 ``` -The built-in `indexOf()` function performs a [linear search](../Linear Search/). In code that looks something like this: +The built-in `Collection.index(of:)` function performs a [linear search](../Linear%20Search/). In code that looks something like this: ```swift -func linearSearch(a: [T], _ key: T) -> Int? { - for i in 0 ..< a.count { - if a[i] == key { - return i +func linearSearch(_ a: [T], _ key: T) -> Int? { + for i in 0 ..< a.count { + if a[i] == key { + return i + } } - } - return nil + return nil } ``` @@ -31,7 +31,7 @@ And you'd use it like this: linearSearch(numbers, 43) // returns 15 ``` -So what's the problem? `linearSearch()` loops through the entire array from the beginning until it finds the element you're looking for. In the worst case, the value isn't in the array and all that work is done for nothing. +So what's the problem? `linearSearch()` loops through the entire array from the beginning, until it finds the element you're looking for. In the worst case, the value isn't even in the array and all that work is done for nothing. On average, the linear search algorithm needs to look at half the values in the array. If your array is large enough, this starts to become very slow! @@ -41,12 +41,12 @@ The classic way to speed this up is to use a *binary search*. The trick is to ke For an array of size `n`, the performance is not **O(n)** as with linear search but only **O(log n)**. To put that in perspective, binary search on an array with 1,000,000 elements only takes about 20 steps to find what you're looking for, because `log_2(1,000,000) = 19.9`. And for an array with a billion elements it only takes 30 steps. (Then again, when was the last time you used an array with a billion items?) -Sounds great, but there is one downside to using binary search: the array must be sorted. In practice, this usually isn't a problem. +Sounds great, but there is a downside to using binary search: the array must be sorted. In practice, this usually isn't a problem. 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. -- 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 less-than or greater-than comparison. +- 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,28 +57,28 @@ 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? { - if range.startIndex >= range.endIndex { - // If we get here, then the search key is not present in the array. - return nil +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.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 + // 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 + } } - } } ``` @@ -92,11 +92,9 @@ binarySearch(numbers, key: 43, range: 0 ..< numbers.count) // gives 13 Note that the `numbers` array is sorted. The binary search algorithm does not work otherwise! -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. +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, 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 @@ -111,10 +109,10 @@ 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. @@ -124,18 +122,18 @@ In the next figure, the `*` shows the middle item. As you can see, the number of 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, since that only contains numbers smaller than `29`. Hence, the search key must be in the right half somewhere (or not in the array at all). +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 ] @@ -167,13 +165,13 @@ 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 ] * -And now we're done. The search key equals the array element we're looking at, so we've finally found what we were looking for. Number `43` is at array index `13`. w00t! +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 look 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` and 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 = (start + end) / 2`. This contains a subtle bug that only appears with very large arrays, because `start + end` 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 @@ -182,19 +180,20 @@ 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? { - var range = 0..(_ 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 + return nil } ``` @@ -214,4 +213,4 @@ Is it a problem that the array must be sorted first? It depends. Keep in mind th See also [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm). -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Binary Search/BinarySearch Tests/BinarySearchTests/BinarySearchTests.swift b/Binary Search/Tests/BinarySearchTests.swift similarity index 97% rename from Binary Search/BinarySearch Tests/BinarySearchTests/BinarySearchTests.swift rename to Binary Search/Tests/BinarySearchTests.swift index d626e475d..35ad9559b 100755 --- a/Binary Search/BinarySearch Tests/BinarySearchTests/BinarySearchTests.swift +++ b/Binary Search/Tests/BinarySearchTests.swift @@ -1,6 +1,5 @@ import Foundation import XCTest -@testable import BinarySearch class BinarySearchTest: XCTestCase { var searchList = [Int]() diff --git a/Priority Queue/PriorityQueue Tests/PriorityQueueTests/Info.plist b/Binary Search/Tests/Info.plist similarity index 100% rename from Priority Queue/PriorityQueue Tests/PriorityQueueTests/Info.plist rename to Binary Search/Tests/Info.plist diff --git a/Binary Search/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..6e29252ec --- /dev/null +++ b/Binary Search/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3CE1C77A256003CECC7 /* BinarySearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CD1C77A256003CECC7 /* BinarySearchTests.swift */; }; + 7B80C3D01C77A263003CECC7 /* BinarySearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CF1C77A263003CECC7 /* BinarySearch.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 /* 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; }; +/* 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 = ( + 7B80C3CF1C77A263003CECC7 /* BinarySearch.swift */, + 7B80C3CD1C77A256003CECC7 /* BinarySearchTests.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 = ( + 7B80C3D01C77A263003CECC7 /* BinarySearch.swift in Sources */, + 7B80C3CE1C77A256003CECC7 /* BinarySearchTests.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/Binary Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Binary Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Binary Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Binary Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index 5470f9741..b0bff577a 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,62 +17,58 @@ public indirect enum BinaryTree { extension BinaryTree: CustomStringConvertible { public var description: String { switch self { - case let .Node(left, value, right): - return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" - case .Empty: + case let .node(left, value, right): + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" + case .empty: return "" } } } - - // 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 - - extension BinaryTree { - public func traverseInOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { - left.traverseInOrder(process) + public func traverseInOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - - public func traversePreOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + + 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) { - if case let .Node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + + public func traversePostOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } diff --git a/Binary Tree/BinaryTree.playground/contents.xcplayground b/Binary Tree/BinaryTree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Binary Tree/BinaryTree.playground/contents.xcplayground +++ b/Binary Tree/BinaryTree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Binary Tree/BinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Binary Tree/BinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Binary Tree/BinaryTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Tree/BinaryTree.playground/timeline.xctimeline b/Binary Tree/BinaryTree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Binary Tree/BinaryTree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Binary Tree/BinaryTree.swift b/Binary Tree/BinaryTree.swift index 9f1b80393..6146880b4 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,36 +20,46 @@ public indirect enum BinaryTree { extension BinaryTree: CustomStringConvertible { public var description: String { switch self { - case let .Node(left, value, right): - return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]" - case .Empty: + case let .node(left, value, right): + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" + case .empty: return "" } } } extension BinaryTree { - public func traverseInOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { - left.traverseInOrder(process) + public func traverseInOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - - public func traversePreOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + + 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) { - if case let .Node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + + public func traversePostOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } } + +extension BinaryTree { + func invert() -> BinaryTree { + if case let .node(left, value, right) = self { + return .node(right.invert(), value, left.invert()) + } else { + return .empty + } + } +} diff --git a/Binary Tree/README.markdown b/Binary Tree/README.markdown index ed829ec0c..8ce398804 100644 --- a/Binary Tree/README.markdown +++ b/Binary Tree/README.markdown @@ -4,11 +4,11 @@ A binary tree is a [tree](../Tree/) where each node has 0, 1, or 2 children. Thi ![A binary tree](Images/BinaryTree.png) -The child nodes are usually called the "left" child and the "right" child. If a node doesn't have any children, it's called a *leaf* node. The *root* is the node at the very top of the tree (programmers like their trees upside down). +The child nodes are usually called the *left* child and the *right* child. If a node doesn't have any children, it's called a *leaf* node. The *root* is the node at the very top of the tree (programmers like their trees upside down). 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))`: @@ -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,9 @@ 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): - return "value: \(value), left = [" + left.description + "], right = [" - + right.description + "]" - case .Empty: + case let .node(left, value, right): + return "value: \(value), left = [\(left.description)], right = [\(right.description)]" + case .empty: return "" } } @@ -92,9 +91,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 } } @@ -104,33 +103,33 @@ On the tree from the example, `tree.count` should be 12. Something you often need to do with trees is traverse them, i.e. look at all the nodes in some order. There are three ways to traverse a binary tree: -1. *In-order* (or *depth-first*): first look at the left child node, then at the node itself, and finally at the 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 last. +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 at its left and right children. +3. *Post-order*: first look at the left and right children and process the node itself last. Here is how you'd implement that: ```swift - public func traverseInOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { - left.traverseInOrder(process) + public func traverseInOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traverseInOrder(process: process) process(value) - right.traverseInOrder(process) + right.traverseInOrder(process: process) } } - public func traversePreOrder(@noescape process: T -> Void) { - if case let .Node(left, value, right) = self { + 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) { - if case let .Node(left, value, right) = self { - left.traversePostOrder(process) - right.traversePostOrder(process) + public func traversePostOrder(process: (T) -> Void) { + if case let .node(left, value, right) = self { + left.traversePostOrder(process: process) + right.traversePostOrder(process: process) process(value) } } diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 3cb56ccbb..70d5ca5e8 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -4,8 +4,8 @@ var bits = BitSet(size: 140) // Initially, it looks like all zeros: -// 0000000000000000000000000000000000000000000000000000000000000000 -// 0000000000000000000000000000000000000000000000000000000000000000 +// 0000000000000000000000000000000000000000000000000000000000000000 +// 0000000000000000000000000000000000000000000000000000000000000000 // 0000000000000000000000000000000000000000000000000000000000000000 print(bits) @@ -29,9 +29,6 @@ print(bits) print("") - - - // Bitwise operations var a = BitSet(size: 4) @@ -63,15 +60,12 @@ c.cardinality // 4 print("") print(~a) // 0111000000000000000000000000000000000000000000000000000000000000 print(~b) // 1101110000000000000000000000000000000000000000000000000000000000 -print(~c) // 0101110000000000000000000000000000000000000000000000000000000000 +print(~c) // 0101110000000000000000000000000000000000000000000000000000000000 (~a).cardinality // 3 (~b).cardinality // 5 (~c).cardinality // 4 - - - var z = BitSet(size: 66) z.all0() // true z.all1() // false @@ -93,8 +87,25 @@ z.all1() // true z[65] = false z.all1() // false - - - //var bigBits = BitSet(size: 10000) //print(bigBits) + +var smallBitSet = BitSet(size: 16) +smallBitSet[5] = true +smallBitSet[10] = true +print(smallBitSet >> 3) +print(smallBitSet << 6) // one bit shifts off the end + +var bigBitSet = BitSet( size: 120 ) +bigBitSet[1] = true +bigBitSet[3] = true +bigBitSet[7] = true +bigBitSet[32] = true +bigBitSet[55] = true +bigBitSet[64] = true +bigBitSet[80] = true +print(bigBitSet) +print(bigBitSet << 32) +print(bigBitSet << 64) +print(bigBitSet >> 32) +print(bigBitSet >> 64) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index e54bf9cc8..258bce457 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -9,9 +9,9 @@ public struct BitSet { We store the bits in a list of unsigned 64-bit integers. The first entry, `words[0]`, is the least significant word. */ - private let N = 64 + fileprivate let N = 64 public typealias Word = UInt64 - 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 @@ -41,7 +41,7 @@ public struct BitSet { // Set the highest bit that's still valid. let mask = 1 << Word(63 - diff) // Subtract 1 to turn it into a mask, and add the high bit back in. - return mask | (mask - 1) + return (Word)(mask | (mask - 1)) } else { return allOnes } @@ -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 } @@ -112,7 +112,7 @@ public struct BitSet { while x != 0 { let y = x & ~(x - 1) // find lowest 1-bit x = x ^ y // and erase it - ++count + count += 1 } } return count @@ -148,7 +148,7 @@ public struct BitSet { extension BitSet: Equatable { } -public func ==(lhs: BitSet, rhs: BitSet) -> Bool { +public func == (lhs: BitSet, rhs: BitSet) -> Bool { return lhs.words == rhs.words } @@ -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 { 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 } @@ -184,7 +184,7 @@ private func copyLargest(lhs: BitSet, _ rhs: BitSet) -> BitSet { That will strip off the higher bits from the larger BitSet when doing &. */ -public func &(lhs: BitSet, rhs: BitSet) -> BitSet { +public func & (lhs: BitSet, rhs: BitSet) -> BitSet { let m = max(lhs.size, rhs.size) var out = BitSet(size: m) let n = min(lhs.words.count, rhs.words.count) @@ -194,7 +194,7 @@ public func &(lhs: BitSet, rhs: BitSet) -> BitSet { return out } -public func |(lhs: BitSet, rhs: BitSet) -> BitSet { +public func | (lhs: BitSet, rhs: BitSet) -> BitSet { var out = copyLargest(lhs, rhs) let n = min(lhs.words.count, rhs.words.count) for i in 0.. BitSet { return out } -public func ^(lhs: BitSet, rhs: BitSet) -> BitSet { +public func ^ (lhs: BitSet, rhs: BitSet) -> BitSet { var out = copyLargest(lhs, rhs) let n = min(lhs.words.count, rhs.words.count) for i in 0.. BitSet { return out } -prefix public func ~(rhs: BitSet) -> BitSet { +prefix public func ~ (rhs: BitSet) -> BitSet { var out = BitSet(size: rhs.size) for i in 0.. BitSet { return out } +// MARK: - Bit shift operations + +/* + Note: For bitshift operations, the assumption is that any bits that are + shifted off the end of the end of the declared size are not still set. + In other words, we are maintaining the original number of bits. + */ + +public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { + var out = lhs + let offset = numBitsLeft / lhs.N + let shift = numBitsLeft % lhs.N + for i in 0..= 0) { + out.words[i] = lhs.words[i - offset] << shift + } + if (i - offset - 1 >= 0) { + out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + if (i + offset + 1 < lhs.words.count) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + // MARK: - Debugging extension UInt64 { diff --git a/Bit Set/BitSet.playground/contents.xcplayground b/Bit Set/BitSet.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Bit Set/BitSet.playground/contents.xcplayground +++ b/Bit Set/BitSet.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bit Set/BitSet.playground/playground.xcworkspace/contents.xcworkspacedata b/Bit Set/BitSet.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bit Set/BitSet.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bit Set/BitSet.playground/timeline.xctimeline b/Bit Set/BitSet.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Bit Set/BitSet.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift deleted file mode 100644 index e54bf9cc8..000000000 --- a/Bit Set/BitSet.swift +++ /dev/null @@ -1,247 +0,0 @@ -/* - A fixed-size sequence of n bits. Bits have indices 0 to n-1. -*/ -public struct BitSet { - /* How many bits this object can hold. */ - private(set) public var size: Int - - /* - We store the bits in a list of unsigned 64-bit integers. - The first entry, `words[0]`, is the least significant word. - */ - private let N = 64 - public typealias Word = UInt64 - private(set) public var words: [Word] - - private let allOnes = ~Word() - - /* Creates a bit set that can hold `size` bits. All bits are initially 0. */ - public init(size: Int) { - precondition(size > 0) - self.size = size - - // Round up the count to the next multiple of 64. - let n = (size + (N-1)) / N - words = .init(count: n, repeatedValue: 0) - } - - /* Converts a bit index into an array index and a mask inside the word. */ - private func indexOf(i: Int) -> (Int, Word) { - precondition(i >= 0) - precondition(i < size) - let o = i / N - let m = Word(i - o*N) - return (o, 1 << m) - } - - /* Returns a mask that has 1s for all bits that are in the last word. */ - private func lastWordMask() -> Word { - let diff = words.count*N - size - if diff > 0 { - // Set the highest bit that's still valid. - let mask = 1 << Word(63 - diff) - // Subtract 1 to turn it into a mask, and add the high bit back in. - return mask | (mask - 1) - } else { - return allOnes - } - } - - /* - If the size is not a multiple of N, then we have to clear out the bits - that we're not using, or bitwise operations between two differently sized - BitSets will go wrong. - */ - private mutating func clearUnusedBits() { - words[words.count - 1] &= lastWordMask() - } - - /* So you can write bitset[99] = ... */ - public subscript(i: Int) -> Bool { - get { return isSet(i) } - set { if newValue { set(i) } else { clear(i) } } - } - - /* Sets the bit at the specified index to 1. */ - public mutating func set(i: Int) { - let (j, m) = indexOf(i) - words[j] |= m - } - - /* Sets all the bits to 1. */ - public mutating func setAll() { - for i in 0.. Bool { - let (j, m) = indexOf(i) - words[j] ^= m - return (words[j] & m) != 0 - } - - /* Determines whether the bit at the specific index is 1 (true) or 0 (false). */ - public func isSet(i: Int) -> Bool { - let (j, m) = indexOf(i) - return (words[j] & m) != 0 - } - - /* - Returns the number of bits that are 1. Time complexity is O(s) where s is - the number of 1-bits. - */ - public var cardinality: Int { - var count = 0 - for var x in words { - while x != 0 { - let y = x & ~(x - 1) // find lowest 1-bit - x = x ^ y // and erase it - ++count - } - } - return count - } - - /* Checks if all the bits are set. */ - public func all1() -> Bool { - for i in 0.. Bool { - for x in words { - if x != 0 { return true } - } - return false - } - - /* Checks if none of the bits are set. */ - public func all0() -> Bool { - for x in words { - if x != 0 { return false } - } - return true - } -} - -// MARK: - Equality - -extension BitSet: Equatable { -} - -public func ==(lhs: BitSet, rhs: BitSet) -> Bool { - return lhs.words == rhs.words -} - -// MARK: - Hashing - -extension BitSet: Hashable { - /* Based on the hashing code from Java's BitSet. */ - public var hashValue: Int { - var h = Word(1234) - for i in words.count.stride(to: 0, by: -1) { - h ^= words[i - 1] &* Word(i) - } - return Int((h >> 32) ^ h) - } -} - -// MARK: - Bitwise operations - -extension BitSet: BitwiseOperationsType { - public static var allZeros: BitSet { - return BitSet(size: 64) - } -} - -private func copyLargest(lhs: BitSet, _ rhs: BitSet) -> BitSet { - return (lhs.words.count > rhs.words.count) ? lhs : rhs -} - -/* - Note: In all of these bitwise operations, lhs and rhs are allowed to have a - different number of bits. The new BitSet always has the larger size. - The extra bits that get added to the smaller BitSet are considered to be 0. - That will strip off the higher bits from the larger BitSet when doing &. -*/ - -public func &(lhs: BitSet, rhs: BitSet) -> BitSet { - let m = max(lhs.size, rhs.size) - var out = BitSet(size: m) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = BitSet(size: rhs.size) - for i in 0.. String { - var s = "" - var n = self - for _ in 1...64 { - s += ((n & 1 == 1) ? "1" : "0") - n >>= 1 - } - return s - } -} - -extension BitSet: CustomStringConvertible { - public var description: String { - var s = "" - for x in words { - s += x.bitsToString() + " " - } - return s - } -} diff --git a/Bit Set/README.markdown b/Bit Set/README.markdown index 380463d33..365950d06 100644 --- a/Bit Set/README.markdown +++ b/Bit Set/README.markdown @@ -10,7 +10,7 @@ Since manipulating individual bits is a little tricky, you can use `BitSet` to h ## The code -A bit set is simply a wrapper around an array. The array doesn't store individual bits but larger integers that we call the "words". The `BitSet` maps the bits to the right word. +A bit set is simply a wrapper around an array. The array doesn't store individual bits but larger integers called the "words". The main job of `BitSet` is to map the bits to the right word. ```swift public struct BitSet { @@ -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) } ``` @@ -38,16 +38,16 @@ If you write, var bits = BitSet(size: 140) ``` -then the `BitSet` allocates an array of three words. Each word holds 64 bits and therefore three words can hold 192 bits. We only use 140 of those bits so we're wasting a bit of space (but of course we can never use less than a whole word.) +then the `BitSet` allocates an array of three words. Each word has 64 bits and therefore three words can hold 192 bits. We only use 140 of those bits so we're wasting a bit of space (but of course we can never use less than a whole word). -> **Note:** The first entry in the `words` array is the least-significant word, so these words are stored in little endian order. +> **Note:** The first entry in the `words` array is the least-significant word, so these words are stored in little endian order in the array. ## Looking up the bits 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 @@ -56,9 +56,9 @@ Most of the operations on `BitSet` take the index of the bit as a parameter, so } ``` -The `indexOf()` function returns the array index of the word, as well as a "mask" that shows where the bit sits inside that word. +The `indexOf()` function returns the array index of the word, as well as a "mask" that shows exactly where the bit sits inside that word. -For example, `indexOf(2)` returns the tuple `(0, 4)` because bit 2 is in the first word (index 0). The mask is 4. In binary that looks like: +For example, `indexOf(2)` returns the tuple `(0, 4)` because bit 2 is in the first word (index 0). The mask is 4. In binary the mask looks like the following: 0010000000000000000000000000000000000000000000000000000000000000 @@ -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,18 +88,18 @@ 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 } ``` -Instead of a bitwise OR we now do a bitwise AND with the inverse of the mask. So if the mask was `00100000...0`, then the inverse is `11011111...1`. All the bits are 1, except for the bit we want to set to 0. Due to the way `&` works, this leaves all other bits alone and only changes that one to 0. +Instead of a bitwise OR we now do a bitwise AND with the inverse of the mask. So if the mask was `00100000...0`, then the inverse is `11011111...1`. All the bits are 1, except for the bit we want to set to 0. Due to the way `&` works, this leaves all other bits alone and only changes that single bit to 0. 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,26 +170,26 @@ 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. -Setting those "leftover" bits to 0 is what the `clearUnusedBits()` helper function does. If the size is not a multiple of `N` (i.e. 64), then we have to clear out the bits that we're not using. If we don't do this, bitwise operations between two differently sized `BitSet`s will go wrong (an example follows). +Setting those "leftover" bits to 0 is what the `clearUnusedBits()` helper function does. If the `BitSet`'s size is not a multiple of `N` (i.e. 64), then we have to clear out the bits that we're not using. If we don't do this, bitwise operations between two differently sized `BitSet`s will go wrong (an example follows). 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 } @@ -209,17 +209,17 @@ Here's what it does, step-by-step: 1) `diff` is the number of "leftover" bits. In the above example that is 52 because `3*64 - 140 = 52`. -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: +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`. @@ -230,13 +230,13 @@ An example of where this is important is when you combine two `BitSet`s of diffe 10001111 size=4 00100011 size=8 -The first one only uses the first 4 bits; the second one uses 8 bits. The first one should really be `10000000` but let's pretend we forgot to clear out those 1's. Then a bitwise or between the two results in: +The first one only uses the first 4 bits; the second one uses 8 bits. The first one should really be `10000000` but let's pretend we forgot to clear out those 1's at the end. Then a bitwise OR between the two results in: 10001111 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! @@ -299,7 +299,7 @@ To count the number of bits that are set to 1 we could scan through the entire a } ``` -When you write `x & ~(x - 1)`, it gives you a new value with a single bit set. This is the lowest bit that is one. For example take this 8-bit value (again, I'm showing this with the least significant bit on the left): +When you write `x & ~(x - 1)`, it gives you a new value with only a single bit set. This is the lowest bit that is one. For example take this 8-bit value (again, I'm showing this with the least significant bit on the left): 00101101 @@ -325,7 +325,93 @@ The only value they have in common is the lowest (or least significant) 1-bit. T -------- XOR 00001101 -We keep repeating this until the value consists of all zeros. The time complexity is **O(s)** where **s** is the number of 1-bits. +This is the original value but with the lowest 1-bit removed. + +We keep repeating this process until the value consists of all zeros. The time complexity is **O(s)** where **s** is the number of 1-bits. + +## Bit Shift Operations + +Bit shifts are a common and very useful mechanism when dealing with bitsets. Here is the right-shift function: + +``` +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + + if (i + offset + 1 < lhs.words.count) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} +``` + +Let's start with this line: + +```swift +for i in 0..> 10 + +I've grouped each part of the number by word to make it easier to see what happens. The for-loop goes from least significant word to most significant. So for index zero we're want to know what bits will make up our least significant word. Let's calculate our offset and shift values: + + offset = 10 / 8 = 1 (remember this is integer division) + shift = 10 % 8 = 2 + +So we consult the word at offset 1 to get some of our bits: + + 11000000 >> 2 = 00110000 + +And we get the rest of them from the word one further away: + + 01000010 << (8 - 2) = 10000000 + +And we bitwise OR these together to get our least significant term + + 00110000 + 10000000 + -------- OR + 10110000 + +We repeat this for the 2nd least significant term and obtain: + + 00010000 + +The last term can't get any bits because they are past the end of our number so those are all zeros. Our result is: + + 00000000 00010000 10110000 ## See also diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift new file mode 100644 index 000000000..8ed808a06 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -0,0 +1,82 @@ +//: Playground - noun: a place where people can play + +public class BloomFilter { + fileprivate var array: [Bool] + private var hashFunctions: [(T) -> Int] + + public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) + self.hashFunctions = hashFunctions + } + + private func computeHashes(_ value: T) -> [Int] { + return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } + } + + public func insert(_ element: T) { + for hashValue in computeHashes(element) { + array[hashValue] = true + } + } + + public func insert(_ values: [T]) { + for value in values { + insert(value) + } + } + + public func query(_ value: T) -> Bool { + let hashValues = computeHashes(value) + + // Map hashes to indices in the Bloom Filter + let results = hashValues.map { hashValue in array[hashValue] } + + // All values must be 'true' for the query to return true + + // This does NOT imply that the value is in the Bloom filter, + // 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, { $0 && $1 }) + return exists + } + + public func isEmpty() -> Bool { + // As soon as the reduction hits a 'true' value, the && condition will fail. + return array.reduce(true) { prev, next in prev && !next } + } +} + +/* Two hash functions, adapted from http://www.cse.yorku.ca/~oz/hash.html */ + +func djb2(x: String) -> Int { + var hash = 5381 + for char in x { + hash = ((hash << 5) &+ hash) &+ char.hashValue + } + return Int(hash) +} + +func sdbm(x: String) -> Int { + var hash = 0 + for char in x { + hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash + } + return Int(hash) +} + +/* A simple test */ + +let bloom = BloomFilter(size: 17, hashFunctions: [djb2, sdbm]) + +bloom.insert("Hello world!") +print(bloom.array) + +bloom.query("Hello world!") // true +bloom.query("Hello WORLD") // false + +bloom.insert("Bloom Filterz") +print(bloom.array) + +bloom.query("Bloom Filterz") // true +bloom.query("Hello WORLD") // false or true: It may return true due to a false positive, but it's not guaranteed. diff --git a/Bloom Filter/BloomFilter.playground/contents.xcplayground b/Bloom Filter/BloomFilter.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Bloom Filter/BloomFilter.playground/playground.xcworkspace/contents.xcworkspacedata b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/BloomFilter.swift b/Bloom Filter/BloomFilter.swift new file mode 100644 index 000000000..56c3be328 --- /dev/null +++ b/Bloom Filter/BloomFilter.swift @@ -0,0 +1,46 @@ +public class BloomFilter { + private var array: [Bool] + private var hashFunctions: [(T) -> Int] + + public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) + self.hashFunctions = hashFunctions + } + + private func computeHashes(_ value: T) -> [Int] { + return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } + } + + public func insert(_ element: T) { + for hashValue in computeHashes(element) { + array[hashValue] = true + } + } + + public func insert(_ values: [T]) { + for value in values { + insert(value) + } + } + + public func query(_ value: T) -> Bool { + let hashValues = computeHashes(value) + + // Map hashes to indices in the Bloom Filter + let results = hashValues.map { hashValue in array[hashValue] } + + // All values must be 'true' for the query to return true + + // This does NOT imply that the value is in the Bloom filter, + // 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, { $0 && $1 }) + return exists + } + + public func isEmpty() -> Bool { + // As soon as the reduction hits a 'true' value, the && condition will fail. + return array.reduce(true) { prev, next in prev && !next } + } +} diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown new file mode 100644 index 000000000..5f2ede069 --- /dev/null +++ b/Bloom Filter/README.markdown @@ -0,0 +1,130 @@ +# Bloom Filter + +## Introduction + +A Bloom Filter is a space-efficient data structure that tells you whether or not an element is present in a set. + +This is a probabilistic data structure: a query to a Bloom filter either returns `false`, meaning the element is definitely not in the set, or `true`, meaning that the element *might* be in the set. + +There is a small probability of false positives, where the element isn't actually in the set even though the query returned `true`. But there will never any false negatives: you're guaranteed that if the query returns `false`, then the element really isn't in the set. + +So a Bloom Filter tells you, "definitely not" or "probably yes". + +At first, this may not seem too useful. However, it's important in applications like cache filtering and data synchronization. + +An advantage of the Bloom Filter over a hash table is that the former maintains constant memory usage and constant-time insert and search. For sets with a large number of elements, the performance difference between a hash table and a Bloom Filter is significant, and it is a viable option if you do not need the guarantee of no false positives. + +> **Note:** Unlike a hash table, the Bloom Filter does not store the actual objects. It just remembers what objects you’ve seen (with a degree of uncertainty) and which ones you haven’t. + +## Inserting objects into the set + +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. + +For example, let's say this is our array of bits. We have 17 bits and initially they are all `0` or false: + + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + +Now we want to insert the string `"Hello world!"` into the Bloom Filter. We apply two hash functions to this string. The first one gives the value 1999532104120917762. We map this hash value to an index into our array by taking the modulo of the array length: `1999532104120917762 % 17 = 4`. This means we set the bit at index 4 to `1` or true: + + [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + +Then we hash the original string again but this time with a different hash function. It gives the hash value 9211818684948223801. Modulo 17 that is 12, and we set the bit at index 12 to `1` as well: + + [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ] + +These two 1-bits are enough to tell the Bloom Filter that it now contains the string `"Hello world!"`. Of course, it doesn't contain the actual string, so you can't ask the Bloom Filter, "give me a list of all the objects you contain". All it has is a bunch of ones and zeros. + +## Querying the set + +Querying, similarly to inserting, is accomplished by first hashing the expected value, which gives several array indices, and then checking to see if all of the bits at those indices are `1`. If even one of the bits is not `1`, the element could not have been inserted and the query returns `false`. If all the bits are `1`, the query returns `true`. + +For example, if we query for the string `"Hello WORLD"`, then the first hash function returns 5383892684077141175, which modulo 17 is 12. That bit is `1`. But the second hash function gives 5625257205398334446, which maps to array index 9. That bit is `0`. This means the string `"Hello WORLD"` is not in the filter and the query returns `false`. + +The fact that the first hash function mapped to a `1` bit is a coincidence (it has nothing to do with the fact that both strings start with `"Hello "`). Too many such coincidences can lead to "collisions". If there are collisions, the query may erroneously return `true` even though the element was not inserted -- bringing about the issue with false positives mentioned earlier. + +Let's say we insert some other element, `"Bloom Filterz"`, which sets bits 7 and 9. Now the array looks like this: + + [ 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0 ] + +If you query for `"Hello WORLD"` again, the filter sees that bit 12 is true and bit 9 is now true as well. It reports that `"Hello WORLD"` is indeed present in the set, even though it isn't... because we never inserted that particular string. It's a false positive. This example shows why a Bloom Filter will never say, "definitely yes", only "probably yes". + +You can fix such issues by using an array with more bits and using additional hash functions. Of course, the more hash functions you use the slower the Bloom Filter will be. So you have to strike a balance. + +Deletion is not possible with a Bloom Filter, since any one bit might belong to multiple elements. Once you add an element, it's in there for good. + +Performance of a Bloom Filter is **O(k)** where **k** is the number of hashing functions. + +## 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. + +```swift +public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + self.array = [Bool](repeating: false, count: size) + self.hashFunctions = hashFunctions +} +``` + +Several hash functions should be specified at initialization. Which hash functions you use will depend on the datatypes of the elements you'll be adding to the set. You can see some examples in the playground and the tests -- the `djb2` and `sdbm` hash functions for strings. + +Insertion just flips the required bits to `true`: + +```swift +public func insert(_ element: T) { + for hashValue in computeHashes(element) { + array[hashValue] = true + } +} +``` + +This uses the `computeHashes()` function, which loops through the specified `hashFunctions` and returns an array of indices: + +```swift +private func computeHashes(_ value: T) -> [Int] { + return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) } +} +``` + +And querying checks to make sure the bits at the hashed values are `true`: + +```swift +public func query(_ value: T) -> Bool { + let hashValues = computeHashes(value) + let results = hashValues.map() { hashValue in array[hashValue] } + 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. + +## Another approach + +In the previous section, you learnt about how using multiple different hash functions can help reduce the chance of collisions in the bloom filter. However, good hash functions are difficult to design. A simple alternative to multiple hash functions is to use a set of random numbers. + +As an example, let's say a bloom filter wants to hash each element 15 times during insertion. Instead of using 15 different hash functions, you can rely on just one hash function. The hash value can then be combined with 15 different values to form the indices for flipping. This bloom filter would initialize a set of 15 random numbers ahead of time and use these values during each insertion. + +``` +hash("Hello world!") >> hash(987654321) // would flip bit 8 +hash("Hello world!") >> hash(123456789) // would flip bit 2 +``` + +Since Swift 4.2, `Hasher` is now included in the Standard library, which is designed to reduce multiple hashes to a single hash in an efficient manner. This makes combining the hashes trivial. + +``` +private func computeHashes(_ value: T) -> [Int] { + return randomSeeds.map() { seed in + let hasher = Hasher() + hasher.combine(seed) + hasher.combine(value) + let hashValue = hasher.finalize() + return abs(hashValue % array.count) + } +} +``` + +If you want to learn more about this approach, you can read about the [Hasher documentation](https://developer.apple.com/documentation/swift/hasher) or Soroush Khanlou's [Swift 4.2 Bloom filter](http://khanlou.com/2018/09/bloom-filters/) implementation. + +*Written for Swift Algorithm Club by Jamil Dhanani. Edited by Matthijs Hollemans. Updated by Bruno Scheele.* diff --git a/Bloom Filter/Tests/BloomFilterTests.swift b/Bloom Filter/Tests/BloomFilterTests.swift new file mode 100644 index 000000000..d88ec0a31 --- /dev/null +++ b/Bloom Filter/Tests/BloomFilterTests.swift @@ -0,0 +1,80 @@ +import XCTest + +/* Two hash functions, adapted from + http://www.cse.yorku.ca/~oz/hash.html */ + +func djb2(_ x: String) -> Int { + var hash = 5381 + + for char in x { + hash = ((hash << 5) &+ hash) &+ char.hashValue + } + + return Int(hash) +} + +func sdbm(_ x: String) -> Int { + var hash = 0 + + for char in x { + hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash + } + + return Int(hash) +} + +class BloomFilterTests: XCTestCase { + func testSwift4(){ + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + func testSingleHashFunction() { + let bloom = BloomFilter(hashFunctions: [djb2]) + + bloom.insert("Hello world!") + + let result_good = bloom.query("Hello world!") + let result_bad = bloom.query("Hello world") + + XCTAssertTrue(result_good) + XCTAssertFalse(result_bad) + } + + func testEmptyFilter() { + let bloom = BloomFilter(hashFunctions: [djb2]) + + let empty = bloom.isEmpty() + + XCTAssertTrue(empty) + } + + func testMultipleHashFunctions() { + let bloom = BloomFilter(hashFunctions: [djb2, sdbm]) + + bloom.insert("Hello world!") + + let result_good = bloom.query("Hello world!") + let result_bad = bloom.query("Hello world") + + XCTAssertTrue(result_good) + XCTAssertFalse(result_bad) + } + + func testFalsePositive() { + let bloom = BloomFilter(size: 5, hashFunctions: [djb2, sdbm]) + + bloom.insert(["hello", "elloh", "llohe", "lohel", "ohell"]) + + print("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. + + XCTAssertTrue(query) + } +} diff --git a/Queue/Queue Tests/QueueTests/Info.plist b/Bloom Filter/Tests/Info.plist similarity index 100% rename from Queue/Queue Tests/QueueTests/Info.plist rename to Bloom Filter/Tests/Info.plist diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..f0649ba26 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,287 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3D01C77A263003CECC7 /* BloomFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CF1C77A263003CECC7 /* BloomFilter.swift */; }; + 7B95D1E41C861DAA00760793 /* BloomFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B95D1E31C861DAA00760793 /* BloomFilterTests.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; }; + 7B80C3CF1C77A263003CECC7 /* BloomFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BloomFilter.swift; path = ../BloomFilter.swift; sourceTree = SOURCE_ROOT; }; + 7B95D1E31C861DAA00760793 /* BloomFilterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BloomFilterTests.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 = ( + 7B80C3CF1C77A263003CECC7 /* BloomFilter.swift */, + 7B95D1E31C861DAA00760793 /* BloomFilterTests.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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 7B80C3D01C77A263003CECC7 /* BloomFilter.swift in Sources */, + 7B95D1E41C861DAA00760793 /* BloomFilterTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + 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 = 4.2; + }; + 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 = 4.2; + }; + 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/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift new file mode 100644 index 000000000..d6204abec --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift @@ -0,0 +1,98 @@ +struct Message: Comparable, CustomStringConvertible { + let name: String + let priority: Int + + var description: String { + return "\(name):\(priority)" + } +} + +func == (m1: Message, m2: Message) -> Bool { + return m1.priority == m2.priority +} + +func < (m1: Message, m2: Message) -> Bool { + return m1.priority < m2.priority +} + +let queue = BoundedPriorityQueue(maxElements: 5) +queue.count + +queue.enqueue(Message(name: "hello", priority: 100)) +queue.count +queue.peek() +print(queue) + +queue.enqueue(Message(name: "there", priority: 99)) +queue.count +queue.peek() +print(queue) + +queue.enqueue(Message(name: "world", priority: 150)) +queue.count +queue.peek() +print(queue) + +queue.enqueue(Message(name: "swift", priority: 110)) +queue.count +queue.peek() +print(queue) + +queue.enqueue(Message(name: "is", priority: 30)) +queue.count +queue.peek() +print(queue) + +// At this point, the queue is: +// + +// Try to insert an item with a really low priority. This should not get added. +queue.enqueue(Message(name: "very", priority: -1)) +queue.count // 5 +queue.peek() +print(queue) // still same as before + +// Try to insert an item with medium priority. This gets added and the lowest +// priority item is removed. +queue.enqueue(Message(name: "cool", priority: 120)) +queue.count +queue.peek() +print(queue) + +// Try to insert an item with very high priority. This gets added and the +// lowest priority item is removed. +queue.enqueue(Message(name: "!!!", priority: 500)) +queue.count +queue.peek() +print(queue) + +// Test dequeuing +queue.dequeue() +queue.count +queue.peek() +print(queue) + +queue.dequeue() +queue.count +queue.peek() +print(queue) + +queue.dequeue() +queue.count +queue.peek() +print(queue) + +queue.dequeue() +queue.count +queue.peek() +print(queue) + +queue.dequeue() +queue.count +queue.peek() +print(queue) + +queue.dequeue() +queue.count +queue.peek() +print(queue) diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift new file mode 100644 index 000000000..b94863afc --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Sources/BoundedPriorityQueue.swift @@ -0,0 +1,137 @@ +public class LinkedListNode { + var value: T + var next: LinkedListNode? + var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } +} + +public class BoundedPriorityQueue { + fileprivate typealias Node = LinkedListNode + + private(set) public var count = 0 + fileprivate var head: Node? + private var tail: Node? + private var maxElements: Int + + public init(maxElements: Int) { + self.maxElements = maxElements + } + + public var isEmpty: Bool { + return count == 0 + } + + public func peek() -> T? { + return head?.value + } + + 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. + if node.next == nil { + tail = node + } + + // If the queue is full, then remove an element from the back. + count += 1 + if count > maxElements { + removeLeastImportantElement() + } + } + } + + 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, + // then there's no reason to insert the new value. + if count == maxElements && previous.next == nil { + print("Queue is full and priority of new object is too small") + return nil + } + + // Put the new node in between previous and previous.next (if exists). + let node = Node(value: value) + node.next = previous.next + previous.next?.previous = node + previous.next = node + node.previous = previous + return node + + } else if let first = head { + // Have to insert at the head, so shift the existing head up once place. + head = Node(value: value) + head!.next = first + first.previous = head + return head + + } else { + // This is the very first item in the queue. + head = Node(value: value) + return head + } + } + + /* 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? { + var node = head + var prev: Node? = nil + + while let current = node, value < current.value { + prev = node + node = current.next + } + return prev + } + + private func removeLeastImportantElement() { + if let last = tail { + tail = last.previous + tail?.next = nil + count -= 1 + } + + // Note: Instead of using a tail pointer, we could just scan from the new + // node until the end. Then nodes also don't need a previous pointer. But + // this is much slower on large lists. + } + + public func dequeue() -> T? { + if let first = head { + count -= 1 + if count == 0 { + head = nil + tail = nil + } else { + head = first.next + head!.previous = nil + } + return first.value + } else { + return nil + } + } +} + +extension LinkedListNode: CustomStringConvertible { + public var description: String { + return "\(value)" + } +} + +extension BoundedPriorityQueue: CustomStringConvertible { + public var description: String { + var s = "<" + var node = head + while let current = node { + s += "\(current), " + node = current.next + } + return s + ">" + } +} diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground new file mode 100644 index 000000000..69d154d1e --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/contents.xcworkspacedata b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bounded Priority Queue/BoundedPriorityQueue.swift b/Bounded Priority Queue/BoundedPriorityQueue.swift new file mode 100644 index 000000000..d882a7698 --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.swift @@ -0,0 +1,137 @@ +open class LinkedListNode { + var value: T + var next: LinkedListNode? + var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } +} + +open class BoundedPriorityQueue { + fileprivate typealias Node = LinkedListNode + + 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 + } + + open var isEmpty: Bool { + return count == 0 + } + + open func peek() -> T? { + return head?.value + } + + 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. + if node.next == nil { + tail = node + } + + // If the queue is full, then remove an element from the back. + count += 1 + if count > maxElements { + removeLeastImportantElement() + } + } + } + + 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, + // then there's no reason to insert the new value. + if count == maxElements && previous.next == nil { + print("Queue is full and priority of new object is too small") + return nil + } + + // Put the new node in between previous and previous.next (if exists). + let node = Node(value: value) + node.next = previous.next + previous.next?.previous = node + previous.next = node + node.previous = previous + return node + + } else if let first = head { + // Have to insert at the head, so shift the existing head up once place. + head = Node(value: value) + head!.next = first + first.previous = head + return head + + } else { + // This is the very first item in the queue. + head = Node(value: value) + return head + } + } + + /* 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. */ + fileprivate func findInsertionPoint(_ value: T) -> Node? { + var node = head + var prev: Node? = nil + + while let current = node, value < current.value { + prev = node + node = current.next + } + return prev + } + + fileprivate func removeLeastImportantElement() { + if let last = tail { + tail = last.previous + tail?.next = nil + count -= 1 + } + + // Note: Instead of using a tail pointer, we could just scan from the new + // node until the end. Then nodes also don't need a previous pointer. But + // this is much slower on large lists. + } + + open func dequeue() -> T? { + if let first = head { + count -= 1 + if count == 0 { + head = nil + tail = nil + } else { + head = first.next + head!.previous = nil + } + return first.value + } else { + return nil + } + } +} + +extension LinkedListNode: CustomStringConvertible { + public var description: String { + return "\(value)" + } +} + +extension BoundedPriorityQueue: CustomStringConvertible { + public var description: String { + var s = "<" + var node = head + while let current = node { + s += "\(current), " + node = current.next + } + return s + ">" + } +} diff --git a/Bounded Priority Queue/README.markdown b/Bounded Priority Queue/README.markdown new file mode 100644 index 000000000..8cbaa85b2 --- /dev/null +++ b/Bounded Priority Queue/README.markdown @@ -0,0 +1,160 @@ +# Bounded Priority 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 + +Suppose we have a bounded-priority-queue with maximum size 5 that has the following values and priorities: + +``` +Value: [ A, B, C, D, E ] +Priority: [ 4.6, 3.2, 1.33, 0.25, 0.1 ] +``` + +Here, we consider the object with the highest priority value to be the most important (so this is a *max-priority* queue). The larger the priority value, the more we care about the object. So `A` is more important than `B`, `B` is more important than `C`, and so on. + +Now we want to insert the element `F` with priority `0.4` into this bounded priority queue. Because the queue has maximum size 5, this will insert the element `F` but then evict the lowest-priority element (`E`), yielding the updated queue: + +``` +Value: [ A, B, C, F, D ] +Priority: [ 4.6, 3.2, 1.33, 0.4, 0.25 ] +``` + +`F` is inserted between `C` and `D` because of its priority value. It's less important than `C` but more important than `D`. + +Suppose that we wish to insert the element `G` with priority 0.1 into this BPQ. Because `G`'s priority value is less than the minimum-priority element in the queue, upon inserting `G` it will immediately be evicted. In other words, inserting an element into a BPQ with priority less than the minimum-priority element of the BPQ has no effect. + +## Implementation + +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: + +```swift +public class BoundedPriorityQueue { + private typealias Node = LinkedListNode + + private(set) public var count = 0 + fileprivate var head: Node? + private var tail: Node? + private var maxElements: Int + + public init(maxElements: Int) { + self.maxElements = maxElements + } + + public var isEmpty: Bool { + return count == 0 + } + + public func peek() -> T? { + return head?.value + } +``` + +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) { + 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. + if node.next == nil { + tail = node + } + + // If the queue is full, then remove an element from the back. + count += 1 + if count > maxElements { + removeLeastImportantElement() + } + } +} + +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, + // then there's no reason to insert the new value. + if count == maxElements && previous.next == nil { + print("Queue is full and priority of new object is too small") + return nil + } + + // Put the new node in between previous and previous.next (if exists). + let node = Node(value: value) + node.next = previous.next + previous.next?.previous = node + previous.next = node + node.previous = previous + return node + + } else if let first = head { + // Have to insert at the head, so shift the existing head up once place. + head = Node(value: value) + head!.next = first + first.previous = head + return head + + } else { + // This is the very first item in the queue. + head = Node(value: value) + return head + } +} + +/* 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? { + var node = head + var prev: Node? = nil + + while let current = node where value < current.value { + prev = node + node = current.next + } + return prev +} + +private func removeLeastImportantElement() { + if let last = tail { + tail = last.previous + tail?.next = nil + count -= 1 + } + + // Note: Instead of using a tail pointer, we could just scan from the new + // node until the end. Then nodes also don't need a previous pointer. But + // this is much slower on large lists. +} +``` + +We first check if the queue already has the maximum number of elements. If so, and the new priority value is less than the `tail` element's priority value, then there is no room for this new element and we return without inserting it. + +If the new value is acceptable, then we search through the list to find the proper insertion location and update the `next` and `previous` pointers. + +Lastly, if the queue has now reached the maximum number of elements, then we `dequeue()` the one with the largest priority value. + +By keeping the most important element at the front of the list, it makes dequeueing very easy: + +```swift +public func dequeue() -> T? { + if let first = head { + count -= 1 + if count == 0 { + head = nil + tail = nil + } else { + head = first.next + head!.previous = nil + } + return first.value + } else { + return nil + } +} +``` + +This simply removes the `head` element from the list and returns it. + +*Written for Swift Algorithm Club by John Gill and Matthijs Hollemans* diff --git a/Bounded Priority Queue/Tests/BoundedPriorityQueueTests.swift b/Bounded Priority Queue/Tests/BoundedPriorityQueueTests.swift new file mode 100644 index 000000000..b248c17ad --- /dev/null +++ b/Bounded Priority Queue/Tests/BoundedPriorityQueueTests.swift @@ -0,0 +1,121 @@ +// +// BoundedPriorityQueueTests.swift +// +// Created by John Gill on 2/28/16. +// + +import Foundation +import XCTest + +private struct Message: Comparable { + let name: String + let priority: Int +} + +private func == (m1: Message, m2: Message) -> Bool { + return m1.priority == m2.priority +} + +private func < (m1: Message, m2: Message) -> Bool { + return m1.priority < m2.priority +} + +private func > (m1: Message, m2: Message) -> Bool { + return m1.priority > m2.priority +} + +class BoundedPriorityQueueTest: XCTestCase { + func testEmpty() { + let queue = BoundedPriorityQueue(maxElements: 5) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.dequeue()) + } + + func testOneElement() { + let queue = BoundedPriorityQueue(maxElements: 5) + + queue.enqueue(Message(name: "hello", priority: 100)) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 1) + + let result = queue.dequeue() + XCTAssertEqual(result!.priority, 100) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + } + + func testMaxElements() { + let queue = BoundedPriorityQueue(maxElements: 5) + XCTAssertTrue(queue.isEmpty) + + queue.enqueue(Message(name: "john", priority: 100)) + XCTAssertEqual(queue.count, 1) + XCTAssertEqual(queue.peek()?.priority, 100) + + queue.enqueue(Message(name: "james", priority: 200)) + XCTAssertEqual(queue.count, 2) + XCTAssertEqual(queue.peek()?.priority, 200) + + queue.enqueue(Message(name: "mark", priority: 300)) + XCTAssertEqual(queue.count, 3) + XCTAssertEqual(queue.peek()?.priority, 300) + + queue.enqueue(Message(name: "ken", priority: 400)) + XCTAssertEqual(queue.count, 4) + XCTAssertEqual(queue.peek()?.priority, 400) + + queue.enqueue(Message(name: "thomas", priority: 500)) + XCTAssertEqual(queue.count, 5) + XCTAssertEqual(queue.peek()?.priority, 500) + + queue.enqueue(Message(name: "melanie", priority: 550)) + XCTAssertEqual(queue.count, 5) + XCTAssertEqual(queue.peek()?.priority, 550) + + queue.enqueue(Message(name: "lily", priority: 450)) + XCTAssertEqual(queue.count, 5) + XCTAssertEqual(queue.peek()?.priority, 550) + + queue.enqueue(Message(name: "fred", priority: 350)) + XCTAssertEqual(queue.count, 5) + XCTAssertEqual(queue.peek()?.priority, 550) + + queue.enqueue(Message(name: "rachel", priority: 50)) + XCTAssertEqual(queue.count, 5) + XCTAssertEqual(queue.peek()?.priority, 550) + + var result = queue.dequeue() + XCTAssertEqual(result!.priority, 550) + XCTAssertEqual(queue.count, 4) + + result = queue.dequeue() + XCTAssertEqual(result!.priority, 500) + XCTAssertEqual(queue.count, 3) + + result = queue.dequeue() + XCTAssertEqual(result!.priority, 450) + XCTAssertEqual(queue.count, 2) + + queue.enqueue(Message(name: "ryan", priority: 150)) + XCTAssertEqual(queue.count, 3) + XCTAssertEqual(queue.peek()?.priority, 400) + + result = queue.dequeue() + XCTAssertEqual(result!.priority, 400) + XCTAssertEqual(queue.count, 2) + + result = queue.dequeue() + XCTAssertEqual(result!.priority, 350) + XCTAssertEqual(queue.count, 1) + + result = queue.dequeue() + XCTAssertEqual(result!.priority, 150) + XCTAssertEqual(queue.count, 0) + + result = queue.dequeue() + XCTAssertNil(result) + XCTAssertEqual(queue.count, 0) + XCTAssertTrue(queue.isEmpty) + } +} diff --git a/Quicksort/Quicksort Tests/QuicksortTests/Info.plist b/Bounded Priority Queue/Tests/Info.plist similarity index 100% rename from Quicksort/Quicksort Tests/QuicksortTests/Info.plist rename to Bounded Priority Queue/Tests/Info.plist diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..11f907b47 --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,300 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B810B5B11C83E3B200450324 /* BoundedPriorityQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B810B5B01C83E3B200450324 /* BoundedPriorityQueueTests.swift */; }; + B8F635A81C83E4270060805E /* BoundedPriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F635A71C83E4270060805E /* BoundedPriorityQueue.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B80004B31C83E342001FE2D7 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B80004B81C83E342001FE2D7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + B810B5B01C83E3B200450324 /* BoundedPriorityQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoundedPriorityQueueTests.swift; sourceTree = SOURCE_ROOT; }; + B8F635A71C83E4270060805E /* BoundedPriorityQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoundedPriorityQueue.swift; path = ../BoundedPriorityQueue.swift; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B80004B01C83E342001FE2D7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B80004A81C83E324001FE2D7 = { + isa = PBXGroup; + children = ( + B80004B51C83E342001FE2D7 /* Tests */, + B80004B41C83E342001FE2D7 /* Products */, + ); + sourceTree = ""; + }; + B80004B41C83E342001FE2D7 /* Products */ = { + isa = PBXGroup; + children = ( + B80004B31C83E342001FE2D7 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + B80004B51C83E342001FE2D7 /* Tests */ = { + isa = PBXGroup; + children = ( + B8F635A71C83E4270060805E /* BoundedPriorityQueue.swift */, + B810B5B01C83E3B200450324 /* BoundedPriorityQueueTests.swift */, + B80004B81C83E342001FE2D7 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B80004B21C83E342001FE2D7 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B80004B91C83E342001FE2D7 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + B80004AF1C83E342001FE2D7 /* Sources */, + B80004B11C83E342001FE2D7 /* Resources */, + B80004B01C83E342001FE2D7 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = B80004B31C83E342001FE2D7 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B80004A91C83E324001FE2D7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0820; + TargetAttributes = { + B80004B21C83E342001FE2D7 = { + CreatedOnToolsVersion = 7.2.1; + LastSwiftMigration = 1000; + }; + }; + }; + buildConfigurationList = B80004AC1C83E324001FE2D7 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = B80004A81C83E324001FE2D7; + productRefGroup = B80004B41C83E342001FE2D7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B80004B21C83E342001FE2D7 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B80004B11C83E342001FE2D7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B80004AF1C83E342001FE2D7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B810B5B11C83E3B200450324 /* BoundedPriorityQueueTests.swift in Sources */, + B8F635A81C83E4270060805E /* BoundedPriorityQueue.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 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; + }; + B80004BA1C83E342001FE2D7 /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + 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; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.alvahouse322.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + B80004BB1C83E342001FE2D7 /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = 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 = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.alvahouse322.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B80004AC1C83E324001FE2D7 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B80004AD1C83E324001FE2D7 /* Debug */, + B80004AE1C83E324001FE2D7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B80004B91C83E342001FE2D7 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B80004BA1C83E342001FE2D7 /* Debug */, + B80004BB1C83E342001FE2D7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B80004A91C83E324001FE2D7 /* Project object */; +} diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8bb763edd --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift new file mode 100644 index 000000000..933cbc4ac --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -0,0 +1,88 @@ +//: 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 index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + // Cache the length of the search pattern because we're going to + // use it a few times and it's expensive to calculate. + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } + + // Make the skip table. This table determines how far we skip ahead + // when a character from the pattern is found. + var skipTable = [Character: Int]() + for (i, c) in pattern.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 + } +} + +// A few simple tests + +let str = "Hello, World" +str.index(of: "World") // 7 + +let animals = "🐶🐔🐷🐮🐱" +animals.index(of: "🐮") // 6 + +let lorem = "Lorem ipsum dolor sit amet" +lorem.index(of: "sit", usingHorspoolImprovement: true) // 18 diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/contents.xcplayground b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/contents.xcworkspacedata b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline new file mode 100644 index 000000000..2688d72c1 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift new file mode 100644 index 000000000..481b7d483 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -0,0 +1,75 @@ +/* + 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 index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + // Cache the length of the search pattern because we're going to + // use it a few times and it's expensive to calculate. + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } + + // Make the skip table. This table determines how far we skip ahead + // when a character from the pattern is found. + var skipTable = [Character: Int]() + for (i, c) in pattern.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 + } +} diff --git a/Boyer-Moore-Horspool/README.markdown b/Boyer-Moore-Horspool/README.markdown new file mode 100644 index 000000000..8879d8df6 --- /dev/null +++ b/Boyer-Moore-Horspool/README.markdown @@ -0,0 +1,230 @@ +# Boyer-Moore String Search + +> This topic has been tutorialized [here](https://www.raywenderlich.com/163964/swift-algorithm-club-booyer-moore-string-search-algorithm) + + +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: +let s = "Hello, World" +s.indexOf(pattern: "World") + +// Output: + 7 + +// Input: +let animals = "🐶🐔🐷🐮🐱" +animals.indexOf(pattern: "🐮") + +// Output: + 6 +``` + +> **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%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. + +Here's how you could write it in Swift: + +```swift +extension String { + func index(of pattern: String) -> Index? { + // Cache the length of the search pattern because we're going to + // use it a few times and it's expensive to calculate. + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } + + // Make the skip table. This table determines how far we skip ahead + // when a character from the pattern is found. + var skipTable = [Character: Int]() + for (i, c) in pattern.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 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, limitedBy: endIndex) ?? endIndex + } + } + 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: + +``` +source string: Hello, World +search pattern: World + ^ +``` + +There are three possibilities: + +1. The two characters are equal. You've found a possible match. + +2. The characters are not equal, but the source character does appear in the search pattern elsewhere. + +3. The source character does not appear in the search pattern at all. + +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 + ^ +``` + +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 + ^ +``` + +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 +``` + +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. + +> **Note:** If the search pattern consists of only a few characters, it's faster to do a brute-force search. There's a trade-off between the time it takes to build the skip table and doing brute-force for short patterns. + +Credits: This code is based on the article ["Faster String Searches" by Costas Menico](http://www.drdobbs.com/database/faster-string-searches/184408171) from Dr Dobb's magazine, July 1989 -- Yes, 1989! Sometimes it's useful to keep those old magazines around. + +See also: [a detailed analysis](http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/bmen.htm) of the algorithm. + +## Boyer-Moore-Horspool algorithm + +A variation on the above algorithm is the [Boyer-Moore-Horspool algorithm](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm). + +Like the regular Boyer-Moore algorithm, it uses the `skipTable` to skip ahead a number of characters. The difference is in how we check partial matches. In the above version, if a partial match is found but it's not a complete match, we skip ahead by just one character. In this revised version, we also use the skip table in that situation. + +Here's an implementation of the Boyer-Moore-Horspool algorithm: + +```swift +extension String { + func index(of pattern: String) -> Index? { + // Cache the length of the search pattern because we're going to + // use it a few times and it's expensive to calculate. + let patternLength = pattern.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.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 } + + // 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 + } +} +``` + +In practice, the Horspool version of the algorithm tends to perform a little better than the original. However, it depends on the tradeoffs you're willing to make. + +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üß_, [Matías Mazzei](https://github.com/mmazzei). diff --git a/Boyer-Moore-Horspool/Tests/BoyerMooreHorspoolTests.swift b/Boyer-Moore-Horspool/Tests/BoyerMooreHorspoolTests.swift new file mode 100644 index 000000000..3924494c7 --- /dev/null +++ b/Boyer-Moore-Horspool/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-Horspool/Tests/BoyerMooreTests.swift b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift new file mode 100755 index 000000000..436173127 --- /dev/null +++ b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift @@ -0,0 +1,95 @@ +// +// 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.index(of: pattern, usingHorspoolImprovement: useHorspoolImprovement) + XCTAssertNil(index) + } + + func assert(pattern: String, existsIn string: String) { + let index = string.index(of: pattern, usingHorspoolImprovement: useHorspoolImprovement) + XCTAssertNotNil(index) + + let startIndex = index! + let endIndex = string.index(index!, offsetBy: pattern.count) + let match = String(string[startIndex.. + + + + diff --git a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Boyer-Moore/BoyerMoore.playground/Contents.swift b/Boyer-Moore/BoyerMoore.playground/Contents.swift deleted file mode 100644 index bba6e0fb6..000000000 --- a/Boyer-Moore/BoyerMoore.playground/Contents.swift +++ /dev/null @@ -1,49 +0,0 @@ -//: 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.enumerate() { - skipTable[c] = patternLength - i - 1 - } - - let p = pattern.endIndex.predecessor() - let lastChar = pattern[p] - var i = self.startIndex.advancedBy(patternLength - 1) - - 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 - } - - while i < self.endIndex { - let c = self[i] - if c == lastChar { - if let k = backwards() { return k } - i = i.successor() - } else { - i = i.advancedBy(skipTable[c] ?? patternLength) - } - } - return nil - } -} - -// A few simple tests - -let s = "Hello, World" -s.indexOf("World") // 7 - -// Input: -let animals = "🐶🐔🐷🐮🐱" -animals.indexOf("🐮") // 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 @@ - - - - - diff --git a/Boyer-Moore/BoyerMoore.swift b/Boyer-Moore/BoyerMoore.swift deleted file mode 100644 index 50aa88048..000000000 --- a/Boyer-Moore/BoyerMoore.swift +++ /dev/null @@ -1,69 +0,0 @@ -/* - 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 <= 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) - } - } - return nil - } -} diff --git a/Boyer-Moore/README.markdown b/Boyer-Moore/README.markdown deleted file mode 100644 index 7050442e2..000000000 --- a/Boyer-Moore/README.markdown +++ /dev/null @@ -1,167 +0,0 @@ -# Boyer-Moore String Search - -How would you go about writing a string search algorithm in pure Swift if you were not allowed to import Foundation and could not use `NSString`'s `rangeOfString()` method? - -The goal is 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: -let s = "Hello, World" -s.indexOf("World") - -// Output: - 7 - -// Input: -let animals = "🐶🐔🐷🐮🐱" -animals.indexOf("🐮") - -// Output: - 6 -``` - -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. - -First, 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() - } - } - if found { - return i - } - } - return nil - } -} -``` - -This looks at each character in the source string in turn. If the character equals the first character of the search pattern, then the inner loop checks whether the rest of the pattern matches. If no match is found, the outer loop continues where it left off. This repeats until a complete match is found or the end of the source string is reached. - -The brute-force approach works OK, but it's not very efficient (or pretty). As it turns out, you don't need to look at *every* character from the source string -- you can often skip ahead multiple characters. - -That 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. - -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.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) - } - } - 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: - - source string: Hello, World - search pattern: World - ^ - -There are three possibilities: - -1. The two characters are equal. You've found a possible match. - -2. The characters are not equal, but the source character does appear in the search pattern elsewhere. - -3. The source character does not appear in the search pattern at all. - -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 - ^ - -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 - ^ - -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 - -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. - -A caveat: If the search pattern consists of only a few characters, it's faster to do a brute-force search. There's a trade-off between the time it takes to build the skip table and doing brute-force for short patterns. - -Credits: This code is based on the article ["Faster String Searches" by Costas Menico](http://www.drdobbs.com/database/faster-string-searches/184408171) from Dr Dobb's magazine, July 1989 -- Yes, 1989! Sometimes it's useful to keep those old magazines around. - -*Written by Matthijs Hollemans* 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 new file mode 100644 index 000000000..cf22ebb25 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift @@ -0,0 +1,45 @@ + +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var queue = Queue() + queue.enqueue(source) + + var nodesExplored = [source.label] + source.visited = true + + while let node = queue.dequeue() { + for edge in node.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + queue.enqueue(neighborNode) + neighborNode.visited = true + nodesExplored.append(neighborNode.label) + } + } + } + + return nodesExplored +} + +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeD) +graph.addEdge(nodeB, neighbor: nodeE) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeG) +graph.addEdge(nodeE, neighbor: nodeH) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeG) + +let nodesExplored = breadthFirstSearch(graph, source: nodeA) +print(nodesExplored) diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift new file mode 100644 index 000000000..7c841be30 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Edge.swift @@ -0,0 +1,11 @@ +public class Edge: Equatable { + public var neighbor: Node + + public init(_ neighbor: Node) { + self.neighbor = neighbor + } +} + +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 new file mode 100644 index 000000000..0343120f8 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift @@ -0,0 +1,55 @@ +public class Graph: CustomStringConvertible, Equatable { + public private(set) var nodes: [Node] + + public init() { + self.nodes = [] + } + + @discardableResult 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) + 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(node.label) + } + + 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) + } + } + + return duplicated + } +} + +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 new file mode 100644 index 000000000..48fc952e3 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Node.swift @@ -0,0 +1,32 @@ +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))" + } + 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 }!) + } +} + +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 new file mode 100644 index 000000000..3d98f801c --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + private var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground new file mode 100644 index 000000000..f635e9804 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/BreadthFirstSearch.swift b/Breadth-First Search/BreadthFirstSearch.swift new file mode 100644 index 000000000..75508682a --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.swift @@ -0,0 +1,20 @@ +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var queue = Queue() + queue.enqueue(source) + + var nodesExplored = [source.label] + source.visited = true + + while let current = queue.dequeue() { + for edge in current.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + queue.enqueue(neighborNode) + neighborNode.visited = true + nodesExplored.append(neighborNode.label) + } + } + } + + return nodesExplored +} diff --git a/Breadth-First Search/Images/AnimatedExample.gif b/Breadth-First Search/Images/AnimatedExample.gif new file mode 100644 index 000000000..8f57028c7 Binary files /dev/null and b/Breadth-First Search/Images/AnimatedExample.gif differ diff --git a/Breadth-First Search/Images/AnimatedExample.graffle b/Breadth-First Search/Images/AnimatedExample.graffle new file mode 100644 index 000000000..a025cb6fa Binary files /dev/null and b/Breadth-First Search/Images/AnimatedExample.graffle differ diff --git a/Breadth-First Search/Images/AnimatedExample.psd b/Breadth-First Search/Images/AnimatedExample.psd new file mode 100644 index 000000000..836fb9247 Binary files /dev/null and b/Breadth-First Search/Images/AnimatedExample.psd differ diff --git a/Breadth-First Search/Images/TraversalTree.graffle b/Breadth-First Search/Images/TraversalTree.graffle new file mode 100644 index 000000000..3de9f1a68 Binary files /dev/null and b/Breadth-First Search/Images/TraversalTree.graffle differ diff --git a/Breadth-First Search/Images/TraversalTree.png b/Breadth-First Search/Images/TraversalTree.png new file mode 100644 index 000000000..4029285d7 Binary files /dev/null and b/Breadth-First Search/Images/TraversalTree.png differ diff --git a/Breadth-First Search/README.markdown b/Breadth-First Search/README.markdown new file mode 100644 index 000000000..097f4278d --- /dev/null +++ b/Breadth-First Search/README.markdown @@ -0,0 +1,157 @@ +# Breadth-First Search + +> This topic has been tutorialized [here](https://www.raywenderlich.com/155801/swift-algorithm-club-swift-breadth-first-search) + + +Breadth-first search (BFS) is an algorithm for traversing or searching [tree](../Tree/) or [graph](../Graph/) data structures. It starts at a source node and explores the immediate neighbor nodes first, before moving to the next level neighbors. + +Breadth-first search can be used on both directed and undirected graphs. + +## Animated example + +Here's how breadth-first search works on a graph: + +![Animated example of a breadth-first search](Images/AnimatedExample.gif) + +When we visit a node, we color it black. We also put its neighbor nodes into a [queue](../Queue/). In the animation the nodes that are enqueued but not visited yet are shown in gray. + +Let's follow the animated example. We start with the source node `A` and add it to a queue. In the animation this is shown as node `A` becoming gray. + +```swift +queue.enqueue(A) +``` + +The queue is now `[ A ]`. The idea is that, as long as there are nodes in the queue, we visit the node that's at the front of the queue, and enqueue its immediate neighbor nodes if they have not been visited yet. + +To start traversing the graph, we pull the first node off the queue, `A`, and color it black. Then we enqueue its two neighbor nodes `B` and `C`. This colors them gray. + +```swift +queue.dequeue() // A +queue.enqueue(B) +queue.enqueue(C) +``` + +The queue is now `[ B, C ]`. We dequeue `B`, and enqueue `B`'s neighbor nodes `D` and `E`. + +```swift +queue.dequeue() // B +queue.enqueue(D) +queue.enqueue(E) +``` + +The queue is now `[ C, D, E ]`. Dequeue `C`, and enqueue `C`'s neighbor nodes `F` and `G`. + +```swift +queue.dequeue() // C +queue.enqueue(F) +queue.enqueue(G) +``` + +The queue is now `[ D, E, F, G ]`. Dequeue `D`, which has no neighbor nodes. + +```swift +queue.dequeue() // D +``` + +The queue is now `[ E, F, G ]`. Dequeue `E` and enqueue its single neighbor node `H`. Note that `B` is also a neighbor for `E` but we've already visited `B`, so we're not adding it to the queue again. + +```swift +queue.dequeue() // E +queue.enqueue(H) +``` + +The queue is now `[ F, G, H ]`. Dequeue `F`, which has no unvisited neighbor nodes. + +```swift +queue.dequeue() // F +``` + +The queue is now `[ G, H ]`. Dequeue `G`, which has no unvisited neighbor nodes. + +```swift +queue.dequeue() // G +``` + +The queue is now `[ H ]`. Dequeue `H`, which has no unvisited neighbor nodes. + +```swift +queue.dequeue() // H +``` + +The queue is now empty, meaning that all nodes have been explored. The order in which the nodes were explored is `A`, `B`, `C`, `D`, `E`, `F`, `G`, `H`. + +We can show this as a tree: + +![The BFS tree](Images/TraversalTree.png) + +The parent of a node is the one that "discovered" that node. The root of the tree is the node you started the breadth-first search from. + +For an unweighted graph, this tree defines a shortest path from the starting node to every other node in the tree. So breadth-first search is one way to find the shortest path between two nodes in a graph. + +## The code + +Simple implementation of breadth-first search using a queue: + +```swift +func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var queue = Queue() + queue.enqueue(source) + + var nodesExplored = [source.label] + source.visited = true + + while let node = queue.dequeue() { + for edge in node.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + queue.enqueue(neighborNode) + neighborNode.visited = true + nodesExplored.append(neighborNode.label) + } + } + } + + return nodesExplored +} +``` + +While there are nodes in the queue, we visit the first one and then enqueue its immediate neighbors if they haven't been visited yet. + +Put this code in a playground and test it like so: + +```swift +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeD) +graph.addEdge(nodeB, neighbor: nodeE) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeG) +graph.addEdge(nodeE, neighbor: nodeH) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeG) + +let nodesExplored = breadthFirstSearch(graph, source: nodeA) +print(nodesExplored) +``` + +This will output: `["a", "b", "c", "d", "e", "f", "g", "h"]` + +## What is BFS good for? + +Breadth-first search can be used to solve many problems. A small selection: + +* Computing the [shortest path](../Shortest%20Path%20(Unweighted)/) between a source node and each of the other nodes (only for unweighted graphs). +* Calculating the [minimum spanning tree](../Minimum%20Spanning%20Tree%20(Unweighted)/) on an unweighted graph. + +*Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* diff --git a/Breadth-First Search/Tests/BreadthFirstSearchTests.swift b/Breadth-First Search/Tests/BreadthFirstSearchTests.swift new file mode 100755 index 000000000..b5e3adac6 --- /dev/null +++ b/Breadth-First Search/Tests/BreadthFirstSearchTests.swift @@ -0,0 +1,85 @@ +import XCTest + +class BreadthFirstSearchTests: XCTestCase { + + func testExploringTree() { + 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") + + tree.addEdge(nodeA, neighbor: nodeB) + tree.addEdge(nodeA, neighbor: nodeC) + tree.addEdge(nodeB, neighbor: nodeD) + tree.addEdge(nodeB, neighbor: nodeE) + tree.addEdge(nodeC, neighbor: nodeF) + tree.addEdge(nodeC, neighbor: nodeG) + tree.addEdge(nodeE, neighbor: nodeH) + + let nodesExplored = breadthFirstSearch(tree, source: nodeA) + + XCTAssertEqual(nodesExplored, ["a", "b", "c", "d", "e", "f", "g", "h"]) + } + + func testExploringGraph() { + 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") + + graph.addEdge(nodeA, neighbor: nodeB) + graph.addEdge(nodeA, neighbor: nodeH) + graph.addEdge(nodeB, neighbor: nodeA) + graph.addEdge(nodeB, neighbor: nodeC) + graph.addEdge(nodeB, neighbor: nodeH) + graph.addEdge(nodeC, neighbor: nodeB) + graph.addEdge(nodeC, neighbor: nodeD) + graph.addEdge(nodeC, neighbor: nodeF) + graph.addEdge(nodeC, neighbor: nodeI) + graph.addEdge(nodeD, neighbor: nodeC) + graph.addEdge(nodeD, neighbor: nodeE) + graph.addEdge(nodeD, neighbor: nodeF) + graph.addEdge(nodeE, neighbor: nodeD) + graph.addEdge(nodeE, neighbor: nodeF) + graph.addEdge(nodeF, neighbor: nodeC) + graph.addEdge(nodeF, neighbor: nodeD) + graph.addEdge(nodeF, neighbor: nodeE) + graph.addEdge(nodeF, neighbor: nodeG) + graph.addEdge(nodeG, neighbor: nodeF) + graph.addEdge(nodeG, neighbor: nodeH) + graph.addEdge(nodeG, neighbor: nodeI) + graph.addEdge(nodeH, neighbor: nodeA) + graph.addEdge(nodeH, neighbor: nodeB) + graph.addEdge(nodeH, neighbor: nodeG) + graph.addEdge(nodeH, neighbor: nodeI) + graph.addEdge(nodeI, neighbor: nodeC) + graph.addEdge(nodeI, neighbor: nodeG) + graph.addEdge(nodeI, neighbor: nodeH) + + let nodesExplored = breadthFirstSearch(graph, source: nodeA) + + XCTAssertEqual(nodesExplored, ["a", "b", "h", "c", "g", "i", "d", "f", "e"]) + } + + func testExploringGraphWithASingleNode() { + let graph = Graph() + let node = graph.addNode("a") + + let nodesExplored = breadthFirstSearch(graph, source: node) + + XCTAssertEqual(nodesExplored, ["a"]) + } +} diff --git a/Breadth-First Search/Tests/Graph.swift b/Breadth-First Search/Tests/Graph.swift new file mode 100644 index 000000000..a8c34b3f6 --- /dev/null +++ b/Breadth-First Search/Tests/Graph.swift @@ -0,0 +1,106 @@ +// MARK: - Edge + +public class Edge: Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + 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))" + } + 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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + 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})]" + } + } + 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) + } + + 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) + } + } + + return duplicated + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Selection Sort/SelectionSort Tests/SelectionSortTests/Info.plist b/Breadth-First Search/Tests/Info.plist similarity index 100% rename from Selection Sort/SelectionSort Tests/SelectionSortTests/Info.plist rename to Breadth-First Search/Tests/Info.plist diff --git a/Breadth-First Search/Tests/Queue.swift b/Breadth-First Search/Tests/Queue.swift new file mode 100644 index 000000000..3d98f801c --- /dev/null +++ b/Breadth-First Search/Tests/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + private var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a7f04e00a --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,295 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 83F9C9681C84437C00B3A87F /* BreadthFirstSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9651C84437C00B3A87F /* BreadthFirstSearch.swift */; }; + 83F9C96C1C8443E800B3A87F /* BreadthFirstSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */; }; + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9701C84449D00B3A87F /* Queue.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; }; + 83F9C9651C84437C00B3A87F /* BreadthFirstSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BreadthFirstSearch.swift; path = ../BreadthFirstSearch.swift; sourceTree = SOURCE_ROOT; }; + 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BreadthFirstSearchTests.swift; sourceTree = SOURCE_ROOT; }; + 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = SOURCE_ROOT; }; + 83F9C9701C84449D00B3A87F /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.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 = ( + 83F9C9651C84437C00B3A87F /* BreadthFirstSearch.swift */, + 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */, + 83F9C96E1C84449D00B3A87F /* Graph.swift */, + 83F9C9701C84449D00B3A87F /* Queue.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + 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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */, + 83F9C9681C84437C00B3A87F /* BreadthFirstSearch.swift in Sources */, + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */, + 83F9C96C1C8443E800B3A87F /* BreadthFirstSearchTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + 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/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift new file mode 100644 index 000000000..003a87e8f --- /dev/null +++ b/Brute-Force String Search/BruteForceStringSearch.playground/Contents.swift @@ -0,0 +1,36 @@ +//: Playground - noun: a place where people can play + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +extension String { + 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 + } + } + return nil + } +} + +// A few simple tests + +let s = "Hello, World" +s.indexOf("World") // 7 + +let animals = "🐶🐔🐷🐮🐱" +animals.indexOf("🐮") // 6 diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/contents.xcplayground b/Brute-Force String Search/BruteForceStringSearch.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Brute-Force String Search/BruteForceStringSearch.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Brute-Force String Search/BruteForceStringSearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Brute-Force String Search/BruteForceStringSearch.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Brute-Force String Search/BruteForceStringSearch.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Brute-Force String Search/BruteForceStringSearch.swift b/Brute-Force String Search/BruteForceStringSearch.swift new file mode 100644 index 000000000..016292304 --- /dev/null +++ b/Brute-Force String Search/BruteForceStringSearch.swift @@ -0,0 +1,23 @@ +/* + Brute-force string search +*/ +extension String { + 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 + } + } + return nil + } +} diff --git a/Brute-Force String Search/README.markdown b/Brute-Force String Search/README.markdown new file mode 100644 index 000000000..599fe75ea --- /dev/null +++ b/Brute-Force String Search/README.markdown @@ -0,0 +1,56 @@ +# Brute-Force String Search + +How would you go about writing a string search algorithm in pure Swift if you were not allowed to import Foundation and could not use `NSString`'s `rangeOfString()` method? + +The goal is 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: +let s = "Hello, World" +s.indexOf("World") + +// Output: + 7 + +// Input: +let animals = "🐶🐔🐷🐮🐱" +animals.indexOf("🐮") + +// Output: + 6 +``` + +> **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. + +Here is a brute-force solution: + +```swift +extension String { + 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 + } + } + return nil + } +} +``` + +This looks at each character in the source string in turn. If the character equals the first character of the search pattern, then the inner loop checks whether the rest of the pattern matches. If no match is found, the outer loop continues where it left off. This repeats until a complete match is found or the end of the source string is reached. + +The brute-force approach works OK, but it's not very efficient (or pretty). It should work fine on small strings, though. For a smarter algorithm that works better with large chunks of text, check out [Boyer-Moore](../Boyer-Moore-Horspool) string search. + +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift new file mode 100644 index 000000000..6188a0763 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -0,0 +1,8 @@ +import Foundation + +var array = [4,2,1,3] + +print("before:",array) +print("after:", bubbleSort(array)) +print("after:", bubbleSort(array, <)) +print("after:", bubbleSort(array, >)) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift new file mode 100644 index 000000000..09e01542b --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -0,0 +1,46 @@ +// +// BubbleSort.swift +// +// Created by Julio Brazil on 1/10/18. +// +// 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 + +/// Performs the bubble sort algorithm in the array +/// +/// - Parameter elements: a array of elements that implement the Comparable protocol +/// - Returns: an array with the same elements but in order +public func bubbleSort (_ elements: [T]) -> [T] where T: Comparable { + return bubbleSort(elements, <) +} + +public func bubbleSort (_ elements: [T], _ comparison: (T,T) -> Bool) -> [T] { + var array = elements + + for i in 0.. + + + \ No newline at end of file diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 1c3d89798..211a5aefa 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,4 +1,127 @@ # Bubble Sort -This is a horrible algorithm. There is no reason why you should have to know it. +Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. +##### Runtime: +- Average: O(N^2) +- Worst: O(N^2) + +##### Memory: +- O(1) + +### Implementation: + +The implementation will not be shown as the average and worst runtimes show that this is a very inefficient algorithm. However, having a grasp of the concept will help you understand the basics of simple sorting algorithms. + +Bubble sort is a very simple sorting algorithm, it consists in comparing pairs of adjacent elements in the array, if the first element is larger, swap them, otherwise, you do nothing and go for the next comparison. +This is accomplished by looking through the array `n` times, `n` being the amount of elements in the array. + +![animated gif of the bubble sort algorithm](https://s3.amazonaws.com/codecademy-content/programs/tdd-js/articles/BubbleSort.gif) + +This GIF shows a inverted implementation than + +#### Example +Let us take the array `[5, 1, 4, 2, 8]`, and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. + +##### First Pass +[ **5 1** 4 2 8 ] -> [ **1 5** 4 2 8 ], Here, algorithm compares the first two elements, and swaps since 5 > 1. + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] +Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted. + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] + +This is the same for the forth and fifth passes. + +#### Code +```swift +for i in 0.. [ **1 5** 4 2 8 ], Swaps since 5 > 1 + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +*by the end of the first pass, the last element is guaranteed to be the largest* + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ], As the first loop has occured once, the inner loop stops here, not comparing 5 with 8 + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] again, stoping one comparison short + +##### Fourth Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +There is no Fifth pass + +#### Conclusion + +Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Merge%20Sort), that not only is better performing, has a similar degree of dificulty to implement. + +*Updated for the Swift Algorithm Club by Julio Brazil* + +##### Supporting Links +[Code Pumpkin](https://codepumpkin.com/bubble-sort/) +[Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) +[GeeksforGeeks](https://www.geeksforgeeks.org/bubble-sort/) diff --git a/Bucket Sort/BucketSort.playground/Contents.swift b/Bucket Sort/BucketSort.playground/Contents.swift new file mode 100644 index 000000000..e862f8bb1 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/Contents.swift @@ -0,0 +1,42 @@ +// +// BucketSort.playground +// +// Created by Barbara Rodeker on 4/4/16. +// +// 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. +// +// + +////////////////////////////////////// +// MARK: Extensions +////////////////////////////////////// + +extension Int: IntConvertible, Sortable { + public func toInt() -> Int { + return self + } +} + +////////////////////////////////////// +// MARK: Playing code +////////////////////////////////////// + +let input = [1, 2, 4, 6, 10, 5] +var buckets = [Bucket(capacity: 15), Bucket(capacity: 15), Bucket(capacity: 15)] + +let sortedElements = bucketSort(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 new file mode 100644 index 000000000..64408eca4 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift @@ -0,0 +1,171 @@ +// +// BucketSort.swift +// +// Created by Barbara Rodeker on 4/4/16. +// +// 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. +// +// + +////////////////////////////////////// +// MARK: Main algorithm +////////////////////////////////////// + +/** + Performs bucket sort algorithm on the given input elements. + [Bucket Sort Algorithm Reference](https://en.wikipedia.org/wiki/Bucket_sort) + + - Parameter elements: Array of Sortable elements + - Parameter distributor: Performs the distribution of each element of a bucket + - Parameter sorter: Performs the sorting inside each bucket, after all the elements are distributed + - Parameter buckets: An array of buckets + + - Returns: A new array with sorted elements + */ + +public func bucketSort(_ elements: [T], distributor: Distributor, sorter: Sorter, buckets: [Bucket]) -> [T] { + precondition(allPositiveNumbers(elements)) + precondition(enoughSpaceInBuckets(buckets, elements: elements)) + + var bucketsCopy = buckets + for elem in elements { + distributor.distribute(elem, buckets: &bucketsCopy) + } + + var results = [T]() + + for bucket in bucketsCopy { + results += bucket.sort(sorter) + } + + return results +} + +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.max()?.toInt() + let totalCapacity = buckets.count * (buckets.first?.capacity)! + + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max +} + +////////////////////////////////////// +// MARK: Distributor +////////////////////////////////////// + +public protocol Distributor { + func distribute(_ element: T, buckets: inout [Bucket]) +} + +/* + * An example of a simple distribution function that send every elements to + * the bucket representing the range in which it fits.An + * + * If the range of values to sort is 0..<49 i.e, there could be 5 buckets of capacity = 10 + * So every element will be classified by the ranges: + * + * - 0 ..< 10 + * - 10 ..< 20 + * - 20 ..< 30 + * - 30 ..< 40 + * - 40 ..< 50 + * + * By following the formula: element / capacity = #ofBucket + */ +public struct RangeDistributor: Distributor { + + public init() {} + + 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) + } +} + +////////////////////////////////////// +// MARK: Sortable +////////////////////////////////////// + +public protocol IntConvertible { + func toInt() -> Int +} + +public protocol Sortable: IntConvertible, Comparable { +} + +////////////////////////////////////// +// MARK: Sorter +////////////////////////////////////// + +public protocol Sorter { + func sort(_ items: [T]) -> [T] +} + +public struct InsertionSorter: Sorter { + + public init() {} + + public func sort(_ items: [T]) -> [T] { + var results = items + 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 + } + } + return results + } +} + +////////////////////////////////////// +// MARK: Bucket +////////////////////////////////////// + +public struct Bucket { + var elements: [T] + let capacity: Int + + public init(capacity: Int) { + self.capacity = capacity + elements = [T]() + } + + public mutating func add(_ item: T) { + if elements.count < capacity { + elements.append(item) + } + } + + public func sort(_ algorithm: Sorter) -> [T] { + return algorithm.sort(elements) + } +} + diff --git a/Bucket Sort/BucketSort.playground/contents.xcplayground b/Bucket Sort/BucketSort.playground/contents.xcplayground new file mode 100644 index 000000000..9f5f2f40c --- /dev/null +++ b/Bucket Sort/BucketSort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Bucket Sort/BucketSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift new file mode 100644 index 000000000..4c2abd372 --- /dev/null +++ b/Bucket Sort/BucketSort.swift @@ -0,0 +1,170 @@ +// +// BucketSort.swift +// +// Created by Barbara Rodeker on 4/4/16. +// +// 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. +// +// + +////////////////////////////////////// +// MARK: Main algorithm +////////////////////////////////////// + +/** + Performs bucket sort algorithm on the given input elements. + [Bucket Sort Algorithm Reference](https://en.wikipedia.org/wiki/Bucket_sort) + + - Parameter elements: Array of Sortable elements + - Parameter distributor: Performs the distribution of each element of a bucket + - Parameter sorter: Performs the sorting inside each bucket, after all the elements are distributed + - Parameter buckets: An array of buckets + + - Returns: A new array with sorted elements + */ + +public func bucketSort(_ elements: [T], distributor: Distributor, sorter: Sorter, buckets: [Bucket]) -> [T] { + precondition(allPositiveNumbers(elements)) + precondition(enoughSpaceInBuckets(buckets, elements: elements)) + + var bucketsCopy = buckets + for elem in elements { + distributor.distribute(elem, buckets: &bucketsCopy) + } + + var results = [T]() + + for bucket in bucketsCopy { + results += bucket.sort(sorter) + } + + return results +} + +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.max()?.toInt() + let totalCapacity = buckets.count * (buckets.first?.capacity)! + + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max +} + +////////////////////////////////////// +// MARK: Distributor +////////////////////////////////////// + +public protocol Distributor { + func distribute(_ element: T, buckets: inout [Bucket]) +} + +/* + * An example of a simple distribution function that send every elements to + * the bucket representing the range in which it fits.An + * + * If the range of values to sort is 0..<49 i.e, there could be 5 buckets of capacity = 10 + * So every element will be classified by the ranges: + * + * - 0 ..< 10 + * - 10 ..< 20 + * - 20 ..< 30 + * - 30 ..< 40 + * - 40 ..< 50 + * + * By following the formula: element / capacity = #ofBucket + */ +public struct RangeDistributor: Distributor { + + public init() {} + + 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) + } +} + +////////////////////////////////////// +// MARK: Sortable +////////////////////////////////////// + +public protocol IntConvertible { + func toInt() -> Int +} + +public protocol Sortable: IntConvertible, Comparable { +} + +////////////////////////////////////// +// MARK: Sorter +////////////////////////////////////// + +public protocol Sorter { + func sort(_ items: [T]) -> [T] +} + +public struct InsertionSorter: Sorter { + + public init() {} + + public func sort(_ items: [T]) -> [T] { + var results = items + 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 + } + } + return results + } +} + +////////////////////////////////////// +// MARK: Bucket +////////////////////////////////////// + +public struct Bucket { + var elements: [T] + let capacity: Int + + public init(capacity: Int) { + self.capacity = capacity + elements = [T]() + } + + public mutating func add(_ item: T) { + if elements.count < capacity { + elements.append(item) + } + } + + public func sort(_ algorithm: Sorter) -> [T] { + return algorithm.sort(elements) + } +} diff --git a/Bucket Sort/Docs/BucketSort.png b/Bucket Sort/Docs/BucketSort.png new file mode 100644 index 000000000..7e154b439 Binary files /dev/null and b/Bucket Sort/Docs/BucketSort.png differ diff --git a/Bucket Sort/README.markdown b/Bucket Sort/README.markdown new file mode 100644 index 000000000..f2708d71e --- /dev/null +++ b/Bucket Sort/README.markdown @@ -0,0 +1,259 @@ +# Bucket Sort + +Bucket Sort, also known as Bin Sort, is a distributed sorting algorithm, which sort elements from an array by performing these steps: + +1) Distribute the elements into buckets or bins. +2) Sort each bucket individually. +3) Merge the buckets in order to produce a sorted array as the result. + +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) | + +Where **n** = the number of elements and **k** is the number of buckets. + +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)**. + +## Pseudocode + +A [pseudocode](https://en.wikipedia.org/wiki/Bucket_sort#Pseudocode) of the algorithm can be as follows: + + function bucketSort(array, n) is + buckets ← new array of n empty lists + for i = 0 to (length(array)-1) do + insert array[i] into buckets[msbits(array[i], k)] + for i = 0 to n - 1 do + nextSort(buckets[i]); + return the concatenation of buckets[0], ...., buckets[n-1] + + +## Graphically explained + +1) Distribute elements in buckets: + +![distribution step](https://upload.wikimedia.org/wikipedia/commons/6/61/Bucket_sort_1.png) + +2) Sorting inside every bucket and merging: + +![sorting each bucket and merge](https://upload.wikimedia.org/wikipedia/commons/3/39/Bucket_sort_2.png) + +## An example + +### Input + +Suppose we have the following list of elements: `[2, 56, 4, 77, 26, 98, 55]`. Let's use 10 buckets. To determine the capacity of each bucket we need to know the *maximum element value*, in this case `98`. + +So the buckets are: + +* `bucket 1`: from 0 to 9 +* `bucket 2`: from 10 to 19 +* `bucket 3`: from 20 to 29 +* and so on. + +### Distribution + +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` +4. Apply the distribution function to `77`. `bucketNumber = (77 / 10) + 1 = 8` +5. Apply the distribution function to `26`. `bucketNumber = (26 / 10) + 1 = 3` +6. Apply the distribution function to `98`. `bucketNumber = (98 / 10) + 1 = 10` +7. Apply the distribution function to `55`. `bucketNumber = (55 / 10) + 1 = 6` + +Our buckets will be filled now: + +**1** : `[2, 4]` +**2** : `[]` +**3** : `[26]` +**4** : `[]` +**5** : `[]` +**6** : `[55, 56]` +**7** : `[]` +**8** : `[77]` +**9** : `[]` +**10** : `[98]` + +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 + +Finally we go through all the buckets and put the elements back in the list: + + `[2, 4, 26, 55, 56, 77, 98]` + + +## Swift implementation + +Here is a diagram that shows the functions, data structures and protocols for our bucker sort implementation: + +![classes](Docs/BucketSort.png) + +#### Main function + +`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, + buckets: [Bucket]) -> [T] { + precondition(allPositiveNumbers(elements)) + precondition(enoughSpaceInBuckets(buckets, elements: elements)) + + var bucketsCopy = buckets + for elem in elements { + distributor.distribute(elem, buckets: &bucketsCopy) + } + + var results = [T]() + + for bucket in bucketsCopy { + results += bucket.sort(sorter) + } + + return results +} +``` + +#### Bucket + +```swift +public struct Bucket { + var elements: [T] + let capacity: Int + + public init(capacity: Int) { + self.capacity = capacity + elements = [T]() + } + + public mutating func add(item: T) { + if (elements.count < capacity) { + elements.append(item) + } + } + + public func sort(algorithm: Sorter) -> [T] { + return algorithm.sort(elements) + } +} +``` + +#### Sortable + +```swift +public protocol Sortable: IntConvertible, Comparable { +} +``` + +#### IntConvertible + +The algorithm is designed to sort integers, so all the elements to be sorted should be mapped to an integer value. + +```swift +public protocol IntConvertible { + func toInt() -> Int +} +``` + +#### Sorter + +```swift +public protocol Sorter { + func sort(items: [T]) -> [T] +} +``` + +#### Distributor + +```swift +public protocol Distributor { + func distribute(element: T, inout buckets: [Bucket]) +} +``` + +### Custom Sorter and Distributor + +The current implementation make use of the following implementations for *Sorter* and *Distributor*. + +*Sorter* + +```swift +public struct InsertionSorter: Sorter { + public func sort(items: [T]) -> [T] { + var results = items + 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 + } + } + return results + } +} +``` + +*Distributor* + +```swift +/* + * An example of a simple distribution function that send every elements to + * the bucket representing the range in which it fits. + * + * If the range of values to sort is 0..<49 i.e, there could be 5 buckets of capacity = 10 + * So every element will be classified by the ranges: + * + * - 0 ..< 10 + * - 10 ..< 20 + * - 20 ..< 30 + * - 30 ..< 40 + * - 40 ..< 50 + * + * By following the formula: element / capacity = #ofBucket + */ +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) + } +} +``` + +### Make your own version + +By reusing this code and implementing your own *Sorter* and *Distributor* you can experiment with different versions. + +## Other variations of Bucket Sort + +The following are some of the variation to the general [Bucket Sort](https://en.wikipedia.org/wiki/Bucket_sort) implemented here: + +- [Proxmap Sort](https://en.wikipedia.org/wiki/Bucket_sort#ProxmapSort) +- [Histogram Sort](https://en.wikipedia.org/wiki/Bucket_sort#Histogram_sort) +- [Postman Sort](https://en.wikipedia.org/wiki/Bucket_sort#Postman.27s_sort) +- [Shuffle Sort](https://en.wikipedia.org/wiki/Bucket_sort#Shuffle_sort) + +*Written for Swift Algorithm Club by Barbara Rodeker. Images from Wikipedia. Updated by Bruno Scheele.* diff --git a/Shell Sort/ShellSort Tests/ShellSortTests/Info.plist b/Bucket Sort/Tests/Info.plist similarity index 100% rename from Shell Sort/ShellSort Tests/ShellSortTests/Info.plist rename to Bucket Sort/Tests/Info.plist diff --git a/Bucket Sort/Tests/Tests.swift b/Bucket Sort/Tests/Tests.swift new file mode 100644 index 000000000..1a06c92b5 --- /dev/null +++ b/Bucket Sort/Tests/Tests.swift @@ -0,0 +1,97 @@ +// +// TestTests.swift +// TestTests +// +// Created by Barbara Rodeker on 4/5/16. +// Copyright © 2016 Barbara M. Rodeker. All rights reserved. +// + +import XCTest + +class TestTests: XCTestCase { + + var smallArray: [Int]? + + let total = 400 + let maximum = 1000 + var largeArray: [Int]? + + var sparsedArray: [Int]? + + override func setUp() { + super.setUp() + + smallArray = [8, 3, 33, 0, 12, 8, 2, 18] + + largeArray = [Int]() + for _ in 0.. [Int] { + + let value = (elements.max()?.toInt())! + 1 + let capacityRequired = Int( ceil( Double(value) / Double(totalBuckets) ) ) + + var buckets = [Bucket]() + for _ in 0..(capacity: capacityRequired)) + } + + let results = bucketSort(smallArray!, distributor: RangeDistributor(), sorter: InsertionSorter(), buckets: buckets) + return results + } + + func isSorted(_ array: [Int]) -> Bool { + + var index = 0 + var sorted = true + while index < (array.count - 1) && sorted { + if array[index] > array[index+1] { + sorted = false + } + index += 1 + } + + return sorted + } +} + +////////////////////////////////////// +// MARK: Extensions +////////////////////////////////////// + +extension Int: IntConvertible, Sortable { + public func toInt() -> Int { + return self + } +} diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..6df507720 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,290 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 76E90BEB1CBFB317009E04FE /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E90BEA1CBFB317009E04FE /* Tests.swift */; }; + 76E90BED1CBFB322009E04FE /* BucketSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E90BEC1CBFB322009E04FE /* BucketSort.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 76E90BEA1CBFB317009E04FE /* Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = SOURCE_ROOT; }; + 76E90BEC1CBFB322009E04FE /* BucketSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BucketSort.swift; path = ../BucketSort.swift; sourceTree = SOURCE_ROOT; }; + 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; }; +/* 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 = ( + 76E90BEA1CBFB317009E04FE /* Tests.swift */, + 76E90BEC1CBFB322009E04FE /* BucketSort.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 = 0730; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + 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 = ( + 76E90BEB1CBFB317009E04FE /* Tests.swift in Sources */, + 76E90BED1CBFB322009E04FE /* BucketSort.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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 = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "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/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Closest Pair/ClosestPair.playground/Contents.swift b/Closest Pair/ClosestPair.playground/Contents.swift new file mode 100644 index 000000000..c11c1770b --- /dev/null +++ b/Closest Pair/ClosestPair.playground/Contents.swift @@ -0,0 +1,224 @@ +//Created by Ahmed Nader (github: AhmedNader42) on 4/4/18. + +func ClosestPairOf(points: [Point]) -> (minimum:Double, firstPoint:Point, secondPoint:Point) { + var innerPoints = mergeSort(points, sortAccording : true) + let result = ClosestPair(&innerPoints, innerPoints.count) + return (result.minValue, result.firstPoint, result.secondPoint) +} + +func ClosestPair(_ p : inout [Point],_ n : Int) -> (minValue: Double,firstPoint: Point,secondPoint: Point) +{ + // Brute force if only 3 points (To end recursion) + if n <= 3 + { + var i=0, j = i+1 + var minDist = Double.infinity + var newFirst:Point? = nil + var newSecond:Point? = nil + while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } + + if temp < min + { + min = temp; + first = tempFirst + second = tempSecond + } + return (min, first, second) +} + + + + +// MergeSort the array (Taken from Swift Algorithms Club with +// minor addition) +// sortAccodrding : true -> x, false -> y. +func mergeSort(_ array: [Point], sortAccording : Bool) -> [Point] { + guard array.count > 1 else { return array } + let middleIndex = array.count / 2 + let leftArray = mergeSort(Array(array[0.. [Point] { + + var compare : (Point, Point) -> Bool + + // Choose to compare with X or Y. + if sortAccording + { + compare = { p1,p2 in + return p1.x < p2.x + } + } + else + { + compare = { p1, p2 in + return p1.y < p2.y + } + } + + var leftIndex = 0 + var rightIndex = 0 + var orderedPile = [Point]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } + + while true { + guard leftIndex < leftPile.endIndex else { + orderedPile.append(contentsOf: rightPile[rightIndex.. Double +{ + let equation:Double = (((a.x-b.x)*(a.x-b.x))) + (((a.y-b.y)*(a.y-b.y))) + return equation.squareRoot() +} + + +var a = Point(0,2) +var b = Point(6,67) +var c = Point(43,71) +var d = Point(1000,1000) +var e = Point(39,107) +var f = Point(2000,2000) +var g = Point(3000,3000) +var h = Point(4000,4000) + + +var points = [a,b,c,d,e,f,g,h] +let endResult = ClosestPairOf(points: points) +print("Minimum Distance : \(endResult.minimum), The two points : (\(endResult.firstPoint.x ),\(endResult.firstPoint.y)), (\(endResult.secondPoint.x),\(endResult.secondPoint.y))") + diff --git a/Closest Pair/ClosestPair.playground/contents.xcplayground b/Closest Pair/ClosestPair.playground/contents.xcplayground new file mode 100644 index 000000000..a93d4844a --- /dev/null +++ b/Closest Pair/ClosestPair.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..82b130340 Binary files /dev/null and b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Closest Pair/Images/1200px-Closest_pair_of_points.png b/Closest Pair/Images/1200px-Closest_pair_of_points.png new file mode 100644 index 000000000..cf61a3eff Binary files /dev/null and b/Closest Pair/Images/1200px-Closest_pair_of_points.png differ diff --git a/Closest Pair/Images/Case.png b/Closest Pair/Images/Case.png new file mode 100644 index 000000000..20b171a1a Binary files /dev/null and b/Closest Pair/Images/Case.png differ diff --git a/Closest Pair/Images/Strip.png b/Closest Pair/Images/Strip.png new file mode 100644 index 000000000..b0193a127 Binary files /dev/null and b/Closest Pair/Images/Strip.png differ diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown new file mode 100644 index 000000000..a4de4a28b --- /dev/null +++ b/Closest Pair/README.markdown @@ -0,0 +1,88 @@ +# ClosestPair + +Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. + +![Given points and we're required to find the two red ones](Images/1200px-Closest_pair_of_points.png) + +As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? + +Here is the main algorithm (Steps) we'll follow. + +- Sort the array according to their position on the X-axis so that they are sorted in the array as they are naturally in math. + +```swift +var innerPoints = mergeSort(points, sortAccording : true) +``` + +- Divide the points into two arrays Left, Right and keep dividing until you reach to only having 3 points in your array. + +- The base case is you have less than 3 points compare those against each other (Brute force) then return the minimum distance you found and the two points. + +- Now we get the first observation in the below image, There could be 2 points both very close to each other and indeed those two are the closest pair but since our algorithm so far divides from the middle + +```swift +let line:Double = (p[mid].x + p[mid+1].x)/2 +``` + +and just recursively calls itself until it reaches the base case we don't detect those points. + +![ Points lying near the division line](Images/Case.png) + +- To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip + +```swift +var strip = [Point]() +var i=0, j = 0 +while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } +``` + +- Of course not every time you end up with the same shape but this is the worst case and it's rare to happen so in reality you end up with far less points valid for comparison and this is why the algorithm gets performance in addition to the sorting tricks we did. + +- Compare the points in the strip and if you find a smaller distance replace the current one with it. + + +So this is the rundown of how the algorithm works and you could see the fun little math tricks used to optimize this and we end up with O(nlogn) complexity mainly because of the sorting. + + +## See also + +See the playground to play around with the implementation of the algorithm + +[Wikipedia](https://en.wikipedia.org/wiki/Closest_pair_of_points_problem) + +*Written for Swift Algorithm Club by [Ahmed Nader](https://github.com/ahmednader42)* diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift new file mode 100644 index 000000000..1f7723838 --- /dev/null +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -0,0 +1,18 @@ +// Comb Sort Function +// Created by Stephen Rutstein +// 7-16-2016 + +import Foundation + +// 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](repeating: 0, count: 1000) +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/Sources/Comb Sort.swift b/Comb Sort/Comb Sort.playground/Sources/Comb Sort.swift new file mode 100644 index 000000000..559fe47e8 --- /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] { + copy.swapAt(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.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..bd37fed42 --- /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 + +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] { + copy.swapAt(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/README.markdown b/Comb Sort/README.markdown new file mode 100644 index 000000000..20c939307 --- /dev/null +++ b/Comb Sort/README.markdown @@ -0,0 +1,79 @@ +# 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 polynomial -- O(n^2). At best though, Comb Sort +performs at O(n logn) time complexity -- loglinear. This creates a drastic improvement over Bubble Sort's performance. + +Similar to Bubble Sort, the space complexity for Comb Sort is constant -- O(1). +This is extremely space efficient as it sorts the array in place. + + +## 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)* diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift new file mode 100644 index 000000000..1d83af002 --- /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..4582b3f2d --- /dev/null +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,295 @@ +// !$*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 = 1000; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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"; + SWIFT_VERSION = 4.2; + }; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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"; + SWIFT_VERSION = 4.2; + }; + 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 = 4.2; + }; + 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 = 4.2; + }; + 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..48faa2df7 --- /dev/null +++ b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Combinatorics/Combinatorics.playground/Contents.swift b/Combinatorics/Combinatorics.playground/Contents.swift index bd7c174a3..2daa5f22f 100644 --- a/Combinatorics/Combinatorics.playground/Contents.swift +++ b/Combinatorics/Combinatorics.playground/Contents.swift @@ -1,7 +1,12 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + /* Calculates n! */ -func factorial(n: Int) -> Int { +func factorial(_ n: Int) -> Int { var n = n var result = 1 while n > 1 { @@ -14,13 +19,11 @@ func factorial(n: Int) -> Int { factorial(5) 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 { + 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) { + Prints out all the permutations of the given array. + Original algorithm by Niklaus Wirth. + See also Dr.Dobb's Magazine June 1993, Algorithm Alley + */ +func permuteWirth(_ a: [T], _ n: Int) { if n == 0 { print(a) // display the current permutation } else { var a = a permuteWirth(a, n - 1) for i in 0.. Int { + 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, 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))") } +/* + 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, choose k: Int) -> Int { + var result = 1 + for i in 0.. { let columns: Int let rows: Int private var array: [T] - + 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 { get { return array[row*columns + column] } set { array[row*columns + column] = newValue } @@ -137,31 +148,32 @@ struct Array2D { } /* - Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose - k things out of n possibilities. - - Thanks to the dynamic programming, this algorithm from Skiena allows for - the calculation of much larger numbers, at the cost of temporary storage - space for the cached values. -*/ -func binomialCoefficient(n: Int, _ k: Int) -> Int { - var bc = Array2D(columns: n + 1, rows: n + 1, initialValue: 0) - + Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose + k things out of n possibilities. + + Thanks to the dynamic programming, this algorithm from Skiena allows for + the calculation of much larger numbers, at the cost of temporary storage + space for the cached values. + */ + +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 - bc[i, i] = 1 + bc[i][0] = 1 + bc[i][i] = 1 } - + if n > 0 { for i in 1...n { for j in 1.. + + + + diff --git a/Combinatorics/Combinatorics.playground/timeline.xctimeline b/Combinatorics/Combinatorics.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Combinatorics/Combinatorics.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Combinatorics/Combinatorics.swift b/Combinatorics/Combinatorics.swift deleted file mode 100644 index a204f7252..000000000 --- a/Combinatorics/Combinatorics.swift +++ /dev/null @@ -1,106 +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. - - Thanks to the dynamic programming, this algorithm from Skiena allows for - the calculation of much larger numbers, at the cost of temporary storage - space for the cached values. -*/ -func binomialCoefficient(n: Int, _ k: Int) -> Int { - var bc = Array2D(columns: n + 1, rows: n + 1, initialValue: 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 { @@ -47,7 +47,7 @@ factorial(5) // returns 120 Note that `factorial(20)` is the largest number you can calculate with this function, or you'll get integer overflow. -Let's say that from that collection of five letters you want to choose only 3 elements. How many possible ways can you do this? Well, that works the same way as before, except that you stop after the third letter. So now the number of possibilities is `5 x 4 x 3 = 60`. +Let's say that from that collection of five letters you want to choose only 3 elements. How many possible ways can you do this? Well, that works the same way as before, except that you stop after the third letter. So now the number of possibilities is `5 * 4 * 3 = 60`. The formula for this is: @@ -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) { - if n == 0 { - print(a) // display the current permutation - } else { - var a = a - permuteWirth(a, n - 1) - for i in 0..(_ 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 { +func combinations(_ n: Int, choose k: Int) -> Int { return permutations(n, k) / factorial(k) } ``` @@ -297,22 +299,58 @@ 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. + +There's a faster approach to calculate `C(n, k)` in **O(k)** time and **O(1)** extra space. The idea behind it is that the formula for `C(n, k)` is: + + n! n * (n - 1) * ... * 1 + C(n, k) = ------------- = ------------------------------------------ + (n - k)! * k! (n - k) * (n - k - 1) * ... * 1 * k! + +After the reduction of fractions, we get the following formula: + + n * (n - 1) * ... * (n - k + 1) (n - 0) * (n - 1) * ... * (n - k + 1) + C(n, k) = --------------------------------------- = ----------------------------------------- + k! (0 + 1) * (1 + 1) * ... * (k - 1 + 1) + +We can implement this formula as follows: + +```swift +func quickBinomialCoefficient(_ n: Int, choose k: Int) -> Int { + var result = 1 + for i in 0.. Int { - var bc = Array2D(columns: n + 1, rows: n + 1, initialValue: 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 - bc[i, i] = 1 + bc[i][0] = 1 + bc[i][i] = 1 } if n > 0 { for i in 1...n { for j in 1.. + + + + diff --git a/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8f04a0f51 --- /dev/null +++ b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Convex Hull/Convex Hull/AppDelegate.swift b/Convex Hull/Convex Hull/AppDelegate.swift new file mode 100644 index 000000000..9bc61ff96 --- /dev/null +++ b/Convex Hull/Convex Hull/AppDelegate.swift @@ -0,0 +1,54 @@ +// +// 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..d8db8d65f --- /dev/null +++ b/Convex Hull/Convex Hull/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "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" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "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..e75c73ed0 --- /dev/null +++ b/Convex Hull/Convex Hull/View.swift @@ -0,0 +1,178 @@ +// +// 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) + generateRandomPoints() + quickHull(points: points) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func generateRandomPoints() { + 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 + var maxDist: CGFloat = -1 + var maxPoint: CGPoint = pts.first! + + for p in pts { // for every point check the distance from our line + let dist = distance(from: p, to: (p1, p2)) + 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) + } + + func distance(from p: CGPoint, to line: (CGPoint, CGPoint)) -> CGFloat { + // If line.0 and line.1 are the same point, they don't define a line (and, besides, + // would cause division by zero in the distance formula). Return the distance between + // line.0 and point p instead. + if line.0 == line.1 { + return sqrt(pow(p.x - line.0.x, 2) + pow(p.y - line.0.y, 2)) + } + + // from Deza, Michel Marie; Deza, Elena (2013), Encyclopedia of Distances (2nd ed.), Springer, p. 86, ISBN 9783642309588 + return abs((line.1.y - line.0.y) * p.x + - (line.1.x - line.0.x) * p.y + + line.1.x * line.0.y + - line.1.y * line.0.x) + / sqrt(pow(line.1.y - line.0.y, 2) + pow(line.1.x - line.0.x, 2)) + } + + 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..3036a4138 --- /dev/null +++ b/Convex Hull/README.md @@ -0,0 +1,51 @@ +# Convex Hull + +Given a group of points on a plane. The Convex Hull algorithm calculates the shape (made up from the points itself) containing all these points. It can also be used on a collection of points of different dimensions. This implementation however covers points on a plane. It essentially calculates the lines between points which together contain all points. In comparing different solutions to this problem we can describe each algorithm in terms of it's big-O time complexity. + +There are multiple Convex Hull algorithms but this solution is called Quickhull, is comes from the work of both W. Eddy in 1977 and also separately A. Bykat in 1978, this algorithm has an expected time complexity of O(n log n), but it's worst-case time-complexity can be O(n^2) . With average conditions the algorithm has ok efficiency, but it's time-complexity can start to become more exponential in cases of high symmetry or where there are points lying on the circumference of a circle for example. + +## 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 first find the two points A and B with the minimum(A) and the maximum(B) x-coordinates (as these will obviously be part of the hull). +- Use the line formed by the two points to divide the set in two subsets of points, which will be processed recursively. +- Determine the point, on one side of the line, with the maximum distance from the line. The two points found before along with this one form a triangle. +- The points lying inside of that triangle cannot be part of the convex hull and can therefore be ignored in the next steps. +- Repeat the previous two steps on the two lines formed by the triangle (not the initial line). +- Keep on doing so on until no more points are left, the recursion has come to an end and the points selected constitute the convex hull. + + +Our function will have the following defininition: + +`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.* diff --git a/Convex Hull/Tests/Info.plist b/Convex Hull/Tests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/Convex Hull/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Convex Hull/Tests/Tests.swift b/Convex Hull/Tests/Tests.swift new file mode 100644 index 000000000..411424479 --- /dev/null +++ b/Convex Hull/Tests/Tests.swift @@ -0,0 +1,36 @@ +// +// Tests.swift +// Tests +// +// Created by Matthew Nespor on 10/7/17. +// Copyright © 2017 Workmoose. All rights reserved. +// + +import XCTest + +class Tests: XCTestCase { + func testHorizontalInitialLine() { + let view = View() + let excludedPoint = CGPoint(x: 146, y: 284) + let includedPoints = [ + CGPoint(x: 353, y: 22), + CGPoint(x: 22, y: 22), + CGPoint(x: 157, y: 447), + ] + + view.points = [CGPoint]() + view.convexHull = [CGPoint]() + view.points.append(contentsOf: includedPoints) + view.points.append(excludedPoint) + view.points.sort { (a: CGPoint, b: CGPoint) -> Bool in + return a.x < b.x + } + + view.quickHull(points: view.points) + + assert(includedPoints.filter({ view.convexHull.contains($0) }).count == 3, + "\(includedPoints) should have been included") + assert(!view.convexHull.contains(excludedPoint), + "\(excludedPoint) should have been excluded") + } +} diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index 3a7ea9713..6ab4c00f3 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,12 +1,11 @@ -//: Playground - noun: a place where people can play -func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -14,13 +13,13 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { } return low } - - func rightBoundary() -> Int { + + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -28,16 +27,14 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { } return low } - - return rightBoundary() - leftBoundary() -} + return rightBoundary - leftBoundary +} // Simple test let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) - +countOccurrences(of: 3, in: a) // Test with arrays of random size and contents (see debug output) @@ -53,7 +50,7 @@ func createArray() -> [Int] { } } } - return a.sort(<) + return a.sorted() } for _ in 0..<10 { @@ -62,6 +59,6 @@ for _ in 0..<10 { // Note: we also test -1 and 6 to check the edge cases. for k in -1...6 { - print("\t\(k): \(countOccurrencesOfKey(k, inArray: a))") + print("\t\(k): \(countOccurrences(of: k, in: a))") } } diff --git a/Count Occurrences/CountOccurrences.playground/playground.xcworkspace/contents.xcworkspacedata b/Count Occurrences/CountOccurrences.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Count Occurrences/CountOccurrences.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Count Occurrences/CountOccurrences.playground/timeline.xctimeline b/Count Occurrences/CountOccurrences.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Count Occurrences/CountOccurrences.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Count Occurrences/CountOccurrences.swift b/Count Occurrences/CountOccurrences.swift index 57c75c735..532e3810e 100644 --- a/Count Occurrences/CountOccurrences.swift +++ b/Count Occurrences/CountOccurrences.swift @@ -1,14 +1,15 @@ -/* - Counts the number of times a value appears in an array in O(lg n) time. - The array must be sorted from low to high. -*/ -func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +/// Counts the number of times a value appears in an array in O(log n) time. The array must be sorted from low to high. +/// +/// - Parameter key: the key to be searched for in the array +/// - Parameter array: the array to search +/// - Returns: the count of occurences of the key in the given array +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -17,12 +18,12 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -31,5 +32,5 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index d22609025..8e935ea58 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -2,15 +2,15 @@ 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. This 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: [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -If we want to know how often the value `3` occurs, we can do a binary search for `3`. That could give us any of these four indices: +If we want to know how often the value `3` occurs, we can do a regular binary search for `3`. That could give us any of these four indices: [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] * * * * @@ -22,10 +22,10 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] < key { @@ -36,10 +36,10 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { } return low } - - func rightBoundary() -> Int { + + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] > key { @@ -50,22 +50,22 @@ func countOccurrencesOfKey(key: Int, inArray a: [Int]) -> Int { } return low } - - return rightBoundary() - leftBoundary() + + return rightBoundary - leftBoundary } ``` -Notice that the helper functions `leftBoundary()` and `rightBoundary()` are very similar to the binary search algorithm. The big difference is that they don't stop when they find the search key, but keep going. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: ```swift let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) // returns 4 +countOccurrences(of: 3, in: a) // returns 4 ``` -Remember: If you use your own array, make sure it is sorted first! +> **Remember:** If you use your own array, make sure it is sorted first! Let's walk through the example. The array is: @@ -111,10 +111,10 @@ Now let's start over and try to find the right boundary. This is very similar, s The right boundary is at index 7. The difference between the two boundaries is 7 - 3 = 4, so the number `3` occurs four times in this array. -Each binary search took 4 steps, so in total this algorithm took 8 steps. Not a big gain on an array of only 12 items, but the bigger the array, the more efficient this algorithm becomes. For a sorted array with 1,000,000 items, it only takes 2x20 = 40 steps to count the number of occurrences for any particular value. +Each binary search took 4 steps, so in total this algorithm took 8 steps. Not a big gain on an array of only 12 items, but the bigger the array, the more efficient this algorithm becomes. For a sorted array with 1,000,000 items, it only takes 2 x 20 = 40 steps to count the number of occurrences for any particular value. -By the way, if the value you're looking for is not in the array, then `rightBoundary()` and `leftBoundary()` return the same value and so the difference between them is 0. +By the way, if the value you're looking for is not in the array, then `rightBoundary` and `leftBoundary` return the same value and so the difference between them is 0. This is an example of how you can modify the basic binary search to solve other algorithmic problems as well. Of course, it does require that the array is sorted. -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/CounterClockWise/CounterClockWise.playground/Contents.swift b/CounterClockWise/CounterClockWise.playground/Contents.swift new file mode 100644 index 000000000..ffa91ecbb --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/Contents.swift @@ -0,0 +1,76 @@ +/* + CounterClockWise(CCW) Algorithm + The user cross-multiplies corresponding coordinates to find the area encompassing the polygon, + and subtracts it from the surrounding polygon to find the area of the polygon within. + This code is based on the "Shoelace formula" by Carl Friedrich Gauss + https://en.wikipedia.org/wiki/Shoelace_formula + */ + +import Foundation + +// MARK : Point struct for defining 2-D coordinate(x,y) +public struct Point{ + // Coordinate(x,y) + var x: Int + var y: Int + + public init(x: Int ,y: Int){ + self.x = x + self.y = y + } +} + +// MARK : Function that determine the area of a simple polygon whose vertices are described +// by their Cartesian coordinates in the plane. +func ccw(points: [Point]) -> Int{ + let polygon = points.count + var orientation = 0 + + // Take the first x-coordinate and multiply it by the second y-value, + // then take the second x-coordinate and multiply it by the third y-value, + // and repeat as many times until it is done for all wanted points. + for i in 0.. 0 : CounterClockWise + } +} + +// A few simple tests + + +// Triangle +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise + +// Quadrilateral +var p4 = Point(x: 5, y: 8) +var p5 = Point(x: 2, y: 3) +var p6 = Point(x: 6, y: 1) +var p7 = Point(x: 9, y: 3) + +print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise + +// Pentagon +var p8 = Point(x: 5, y: 11) +var p9 = Point(x: 3, y: 4) +var p10 = Point(x: 5, y: 6) +var p11 = Point(x: 9, y: 5) +var p12 = Point(x: 12, y: 8) + +print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise diff --git a/CounterClockWise/CounterClockWise.playground/contents.xcplayground b/CounterClockWise/CounterClockWise.playground/contents.xcplayground new file mode 100644 index 000000000..9f5f2f40c --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/CounterClockWise/CounterClockWise.swift b/CounterClockWise/CounterClockWise.swift new file mode 100644 index 000000000..07c422ea5 --- /dev/null +++ b/CounterClockWise/CounterClockWise.swift @@ -0,0 +1,50 @@ +/* + CounterClockWise(CCW) Algorithm + The user cross-multiplies corresponding coordinates to find the area encompassing the polygon, + and subtracts it from the surrounding polygon to find the area of the polygon within. + This code is based on the "Shoelace formula" by Carl Friedrich Gauss + https://en.wikipedia.org/wiki/Shoelace_formula + */ + + +import Foundation + +// MARK : Point struct for defining 2-D coordinate(x,y) +public struct Point{ + // Coordinate(x,y) + var x: Int + var y: Int + + public init(x: Int ,y: Int){ + self.x = x + self.y = y + } +} + +// MARK : Function that determine the area of a simple polygon whose vertices are described +// by their Cartesian coordinates in the plane. +func ccw(points: [Point]) -> Int{ + let polygon = points.count + var orientation = 0 + + // Take the first x-coordinate and multiply it by the second y-value, + // then take the second x-coordinate and multiply it by the third y-value, + // and repeat as many times until it is done for all wanted points. + for i in 0.. 0 : CounterClockWise + } +} diff --git a/CounterClockWise/Images/Pentagon_img.png b/CounterClockWise/Images/Pentagon_img.png new file mode 100644 index 000000000..44d858303 Binary files /dev/null and b/CounterClockWise/Images/Pentagon_img.png differ diff --git a/CounterClockWise/Images/Quadrilateral_img.jpg b/CounterClockWise/Images/Quadrilateral_img.jpg new file mode 100644 index 000000000..b48d7ee5a Binary files /dev/null and b/CounterClockWise/Images/Quadrilateral_img.jpg differ diff --git a/CounterClockWise/Images/Shoelace.png b/CounterClockWise/Images/Shoelace.png new file mode 100644 index 000000000..2691ec129 Binary files /dev/null and b/CounterClockWise/Images/Shoelace.png differ diff --git a/CounterClockWise/Images/Triangle_img.jpg b/CounterClockWise/Images/Triangle_img.jpg new file mode 100644 index 000000000..8a010ca15 Binary files /dev/null and b/CounterClockWise/Images/Triangle_img.jpg differ diff --git a/CounterClockWise/Images/pentagon.png b/CounterClockWise/Images/pentagon.png new file mode 100644 index 000000000..063c77900 Binary files /dev/null and b/CounterClockWise/Images/pentagon.png differ diff --git a/CounterClockWise/Images/quadrilateral.png b/CounterClockWise/Images/quadrilateral.png new file mode 100644 index 000000000..139d09778 Binary files /dev/null and b/CounterClockWise/Images/quadrilateral.png differ diff --git a/CounterClockWise/Images/triangle.png b/CounterClockWise/Images/triangle.png new file mode 100644 index 000000000..67e8b453f Binary files /dev/null and b/CounterClockWise/Images/triangle.png differ diff --git a/CounterClockWise/README.md b/CounterClockWise/README.md new file mode 100644 index 000000000..2d15eba53 --- /dev/null +++ b/CounterClockWise/README.md @@ -0,0 +1,118 @@ +# CounterClockWise + +Goal : Determine what direction to take when multiple points are given. + +CounterClockWise(CCW) is based on [Shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula#Examples) by Carl Friedrich Gauss. + + + +1. Take the first x-coordinate and multiply it by the second y-value, then take the second x-coordinate and multiply it by the third y-value, and repeat as many times until it is done for all wanted points. +2. If the points are labeled sequentially in the counterclockwise direction, then the sum of the above determinants is positive and the absolute value signs can be omitted if they are labeled in the clockwise direction, the sum of the determinants will be negative. This is because the formula can be viewed as a special case of [Green's theorem](https://en.wikipedia.org/wiki/Green%27s_theorem). + +![Shoelace](./Images/Shoelace.png) + + + +Here's an implementation in Swift that should be easy to understand: + +```swift +func ccw(points: [Point]) -> Int{ + let polygon = points.count + var orientation = 0 + + for i in 0.. 0 : CounterClockWise + } +} +``` + +Put this code in a playground and test it like so: + +```swift +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise +``` + +Here's how it works. When given an `[Photo]`, `ccw(points:)` calculates the direction of the given points according to the Shoelaces formula. + + + +`orientation` is less than 0, the direction is clockwise. + +`orientation` is equal to 0, the direction is parallel. + +`orientation` is greater than 0, the direction is counterclockwise. + + + +## An example + +**In Triangle** + +```swift +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise +``` + +![triangle](./Images/Triangle_img.jpg) + +![triangleExpression](./Images/triangle.png) + + + +**In Quadrilateral** + +```swift +var p4 = Point(x: 5, y: 8) +var p5 = Point(x: 2, y: 3) +var p6 = Point(x: 6, y: 1) +var p7 = Point(x: 9, y: 3) + +print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise +``` + +![Quadrilateral](./Images/Quadrilateral_img.jpg) + +![triangleExpression](./Images/quadrilateral.png) + + + +**In Pentagon** + +```swift +var p8 = Point(x: 5, y: 11) +var p9 = Point(x: 3, y: 4) +var p10 = Point(x: 5, y: 6) +var p11 = Point(x: 9, y: 5) +var p12 = Point(x: 12, y: 8) + +print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise +``` + +![triangle](./Images/Pentagon_img.png) + +![triangleExpression](./Images/pentagon.png) + + + +You probably won't need to use the CCW in any real-world problems, but it's cool to play around with geometry algorithm. The formula was described by Meister (1724-1788) in 1769 and by Gauss in 1795. It can be verified by dividing the polygon into triangles, and can be considered to be a special case of Green's theorem. + + + +*Written for Swift Algorithm Club by TaeJoong Yoon* diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift new file mode 100644 index 000000000..99178f85d --- /dev/null +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -0,0 +1,45 @@ +//: Playground - noun: a place where people can play + +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.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 + // Loop through the array in reverse to keep the stability of the new array + // i.e. 7, is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 + var sortedArray = [Int](repeating: 0, count: array.count) + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] + countArray[element] -= 1 + sortedArray[countArray[element]] = element + } + + return sortedArray +} + +try countingSort(array: [10, 9, 8, 7, 1, 2, 7, 3]) + diff --git a/Counting Sort/CountingSort.playground/contents.xcplayground b/Counting Sort/CountingSort.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Counting Sort/CountingSort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Counting Sort/CountingSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Counting Sort/CountingSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Counting Sort/CountingSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Counting Sort/CountingSort.swift b/Counting Sort/CountingSort.swift new file mode 100644 index 000000000..68dcf5c0d --- /dev/null +++ b/Counting Sort/CountingSort.swift @@ -0,0 +1,41 @@ +// +// Sort.swift +// test +// +// Created by Kauserali on 11/04/16. +// Copyright © 2016 Ali Hafizji. All rights reserved. +// + +func countingSort(_ array: [Int])-> [Int] { + guard array.count > 0 else {return []} + + // 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 + // Loop through the array in reverse to keep the stability of the new sorted array + // (For Example: 7 is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 + var sortedArray = [Int](repeating: 0, count: array.count) + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] + countArray[element] -= 1 + sortedArray[countArray[element]] = element + } + return sortedArray +} diff --git a/Counting Sort/README.markdown b/Counting Sort/README.markdown new file mode 100644 index 000000000..93d6635bd --- /dev/null +++ b/Counting Sort/README.markdown @@ -0,0 +1,82 @@ +# Counting Sort + +Counting sort is an algorithm for sorting a collection of objects according to keys that are small integers. It operates by counting the number of objects that have each distinct key values, and using arithmetic on those counts to determine the positions of each key value in the output sequence. + +## Example + +To understand the algorithm let's walk through a small example. + +Consider the array: `[ 10, 9, 8, 7, 1, 2, 7, 3 ]` + +### Step 1: + +The first step is to count the total number of occurrences for each item in the array. The output for the first step would be a new array that looks as follows: + +``` +Index 0 1 2 3 4 5 6 7 8 9 10 +Count 0 1 1 1 0 0 0 2 1 1 1 +``` + +Here is the code to accomplish this: + +```swift + let maxElement = array.max() ?? 0 + + var countArray = [Int](repeating: 0, count: Int(maxElement + 1)) + for element in array { + countArray[element] += 1 + } +``` + +### Step 2: + +In this step the algorithm tries to determine the number of elements that are placed before each element. Since, you already know the total occurrences for each element you can use this information to your advantage. The way it works is to sum up the previous counts and store them at each index. + +The count array would be as follows: + +``` +Index 0 1 2 3 4 5 6 7 8 9 10 +Count 0 1 2 3 3 3 3 5 6 7 8 +``` + +The code for step 2 is: + +```swift + for index in 1 ..< countArray.count { + let sum = countArray[index] + countArray[index - 1] + countArray[index] = sum + } +``` + +### Step 3: + +This is the last step in the algorithm. Each element in the original array is placed at the position defined by the output of step 2. For example, the number 10 would be placed at an index of 7 in the output array. Also, as you place the elements you need to reduce the count by 1 as those many elements are reduced from the array. +We also have to loop through the array in reverse to keep the stability of the new sorted array. +For Example: 7 is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6. + +The final output would be: + +``` +Index 0 1 2 3 4 5 6 7 +Output 1 2 3 7 7 8 9 10 +``` + +Here is the code for this final step: + +```swift + var sortedArray = [Int](repeating: 0, count: array.count) + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] + countArray[element] -= 1 + sortedArray[countArray[element]] = element + } + return sortedArray +``` + +## Performance + +The algorithm uses simple loops to sort a collection. Hence, the time to run the entire algorithm is **O(n+k)** where **O(n)** represents the loops that are required to initialize the output arrays and **O(k)** is the loop required to create the count array. + +The algorithm uses arrays of length **n + 1** and **n**, so the total space required is **O(2n)**. Hence for collections where the keys are scattered in a dense area along the number line it can be space efficient. + +*Written for Swift Algorithm Club by Ali Hafizji* diff --git a/Counting Sort/Tests/CountingSortTest.swift b/Counting Sort/Tests/CountingSortTest.swift new file mode 100644 index 000000000..d8d73fc76 --- /dev/null +++ b/Counting Sort/Tests/CountingSortTest.swift @@ -0,0 +1,24 @@ +// +// CountingSort.swift +// CountingSort +// +// Created by Kauserali on 11/04/16. +// +// + +import XCTest + +class CountingSort: XCTestCase { + + func testCountingSort() { + let sequence = [10, 8, 1, 2, 5, 8] + let sortedSequence = [1, 2, 5, 8, 8, 10] + + do { + let afterCountingSort = try countingSort(sequence) + XCTAssertEqual(afterCountingSort, sortedSequence) + } catch { + XCTFail("") + } + } +} diff --git a/Stack/Stack Tests/StackTests/Info.plist b/Counting Sort/Tests/Info.plist similarity index 100% rename from Stack/Stack Tests/StackTests/Info.plist rename to Counting Sort/Tests/Info.plist diff --git a/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..aaa6c1b6b --- /dev/null +++ b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,270 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B74638C1CBCCC3C006DB977 /* CountingSortTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B74638B1CBCCC3C006DB977 /* CountingSortTest.swift */; }; + 7B80C3D81C77A313003CECC7 /* CountingSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3D71C77A313003CECC7 /* CountingSort.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; }; + 7B74638B1CBCCC3C006DB977 /* CountingSortTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CountingSortTest.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3D71C77A313003CECC7 /* CountingSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CountingSort.swift; path = ../CountingSort.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 = ( + 7B80C3D71C77A313003CECC7 /* CountingSort.swift */, + 7B74638B1CBCCC3C006DB977 /* CountingSortTest.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 = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + 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 = ( + 7B74638C1CBCCC3C006DB977 /* CountingSortTest.swift in Sources */, + 7B80C3D81C77A313003CECC7 /* CountingSort.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 = 5.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 = 5.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/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..dfcf6de42 --- /dev/null +++ b/Counting Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Depth-First Search/DepthFirstSearch.playground/Edge.o b/Depth-First Search/DepthFirstSearch.playground/Edge.o new file mode 100644 index 000000000..ab1e89b3a Binary files /dev/null and b/Depth-First Search/DepthFirstSearch.playground/Edge.o differ diff --git a/Depth-First Search/DepthFirstSearch.playground/Graph.o b/Depth-First Search/DepthFirstSearch.playground/Graph.o new file mode 100644 index 000000000..dde35fb0f Binary files /dev/null and b/Depth-First Search/DepthFirstSearch.playground/Graph.o differ diff --git a/Depth-First Search/DepthFirstSearch.playground/Node.o b/Depth-First Search/DepthFirstSearch.playground/Node.o new file mode 100644 index 000000000..1090b3a9c Binary files /dev/null and b/Depth-First Search/DepthFirstSearch.playground/Node.o differ 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 new file mode 100644 index 000000000..c83f52af8 --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift @@ -0,0 +1,37 @@ +// last checked with Xcode 10.1 + +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var nodesExplored = [source.label] + source.visited = true + + for edge in source.neighbors { + if !edge.neighbor.visited { + nodesExplored += depthFirstSearch(graph, source: edge.neighbor) + } + } + return nodesExplored +} + +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeD) +graph.addEdge(nodeB, neighbor: nodeE) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeG) +graph.addEdge(nodeE, neighbor: nodeH) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeG) + +let nodesExplored = depthFirstSearch(graph, source: nodeA) +print(nodesExplored) diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift new file mode 100644 index 000000000..40e769aae --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Edge.swift @@ -0,0 +1,11 @@ +public class Edge: Equatable { + public var neighbor: Node + + public init(_ neighbor: Node) { + self.neighbor = neighbor + } +} + +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 new file mode 100644 index 000000000..48b8feed5 --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift @@ -0,0 +1,56 @@ +public class Graph: CustomStringConvertible, Equatable { + public private(set) var nodes: [Node] + + public init() { + self.nodes = [] + } + + @discardableResult + 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) + 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(node.label) + } + + 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) + } + } + + return duplicated + } +} + +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 new file mode 100644 index 000000000..bab55c371 --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Node.swift @@ -0,0 +1,32 @@ +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))" + } + 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 }!) + } +} + +public func == (_ lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} diff --git a/Depth-First Search/DepthFirstSearch.playground/contents.xcplayground b/Depth-First Search/DepthFirstSearch.playground/contents.xcplayground new file mode 100644 index 000000000..5ed29117b --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Depth-First Search/DepthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Depth-First Search/DepthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Depth-First Search/DepthFirstSearch.swift b/Depth-First Search/DepthFirstSearch.swift new file mode 100644 index 000000000..04e84cb66 --- /dev/null +++ b/Depth-First Search/DepthFirstSearch.swift @@ -0,0 +1,11 @@ +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var nodesExplored = [source.label] + source.visited = true + + for edge in source.neighbors { + if !edge.neighbor.visited { + nodesExplored += depthFirstSearch(graph, source: edge.neighbor) + } + } + return nodesExplored +} diff --git a/Depth-First Search/Images/AnimatedExample.gif b/Depth-First Search/Images/AnimatedExample.gif new file mode 100644 index 000000000..6769f5b59 Binary files /dev/null and b/Depth-First Search/Images/AnimatedExample.gif differ diff --git a/Depth-First Search/Images/AnimatedExample.graffle b/Depth-First Search/Images/AnimatedExample.graffle new file mode 100644 index 000000000..fb91dd9ca Binary files /dev/null and b/Depth-First Search/Images/AnimatedExample.graffle differ diff --git a/Depth-First Search/Images/AnimatedExample.psd b/Depth-First Search/Images/AnimatedExample.psd new file mode 100644 index 000000000..4da97c2a3 Binary files /dev/null and b/Depth-First Search/Images/AnimatedExample.psd differ diff --git a/Depth-First Search/Images/TraversalTree.graffle b/Depth-First Search/Images/TraversalTree.graffle new file mode 100644 index 000000000..d40812e4a Binary files /dev/null and b/Depth-First Search/Images/TraversalTree.graffle differ diff --git a/Depth-First Search/Images/TraversalTree.png b/Depth-First Search/Images/TraversalTree.png new file mode 100644 index 000000000..bff2070dd Binary files /dev/null and b/Depth-First Search/Images/TraversalTree.png differ diff --git a/Depth-First Search/README.markdown b/Depth-First Search/README.markdown new file mode 100644 index 000000000..67030346b --- /dev/null +++ b/Depth-First Search/README.markdown @@ -0,0 +1,86 @@ +# Depth-First Search + +> This topic has been tutorialized [here](https://www.raywenderlich.com/157949/swift-algorithm-club-depth-first-search) + +Depth-first search (DFS) is an algorithm for traversing or searching [tree](../Tree/) or [graph](../Graph/) data structures. It starts at a source node and explores as far as possible along each branch before backtracking. + +Depth-first search can be used on both directed and undirected graphs. + +## Animated example + +Here's how depth-first search works on a graph: + +![Animated example](Images/AnimatedExample.gif) + +Let's say we start the search from node `A`. In depth-first search we look at the starting node's first neighbor and visit that. In the example that is node `B`. Then we look at node `B`'s first neighbor and visit it. This is node `D`. Since `D` doesn't have any unvisited neighbors of its own, we backtrack to node `B` and go to its other neighbor `E`. And so on, until we've visited all the nodes in the graph. + +Each time we visit the first neighbor and keep going until there's nowhere left to go, and then we backtrack to a point where there are again nodes to visit. When we've backtracked all the way to node `A`, the search is complete. + +For the example, the nodes were visited in the order `A`, `B`, `D`, `E`, `H`, `F`, `G`, `C`. + +The depth-first search process can also be visualized as a tree: + +![Traversal tree](Images/TraversalTree.png) + +The parent of a node is the one that "discovered" that node. The root of the tree is the node you started the depth-first search from. Whenever there's a branch, that's where we backtracked. + +## The code + +Simple recursive implementation of depth-first search: + +```swift +func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { + var nodesExplored = [source.label] + source.visited = true + + for edge in source.neighbors { + if !edge.neighbor.visited { + nodesExplored += depthFirstSearch(graph, source: edge.neighbor) + } + } + return nodesExplored +} +``` + +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: + +```swift +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeD) +graph.addEdge(nodeB, neighbor: nodeE) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeG) +graph.addEdge(nodeE, neighbor: nodeH) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeG) + +let nodesExplored = depthFirstSearch(graph, source: nodeA) +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%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! + +*Written for Swift Algorithm Club by Paulo Tanaka and Matthijs Hollemans* diff --git a/Depth-First Search/Tests/DepthFirstSearchTests.swift b/Depth-First Search/Tests/DepthFirstSearchTests.swift new file mode 100755 index 000000000..5fb450190 --- /dev/null +++ b/Depth-First Search/Tests/DepthFirstSearchTests.swift @@ -0,0 +1,91 @@ +import XCTest + +class DepthFirstSearchTests: XCTestCase { + + func testSwift4(){ + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + func testExploringTree() { + 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") + + tree.addEdge(nodeA, neighbor: nodeB) + tree.addEdge(nodeA, neighbor: nodeC) + tree.addEdge(nodeB, neighbor: nodeD) + tree.addEdge(nodeB, neighbor: nodeE) + tree.addEdge(nodeC, neighbor: nodeF) + tree.addEdge(nodeC, neighbor: nodeG) + tree.addEdge(nodeE, neighbor: nodeH) + + let nodesExplored = depthFirstSearch(tree, source: nodeA) + + XCTAssertEqual(nodesExplored, ["a", "b", "d", "e", "h", "c", "f", "g"]) + } + + func testExploringDigraph() { + let digraph = Graph() + + let nodeA = digraph.addNode("a") + let nodeB = digraph.addNode("b") + let nodeC = digraph.addNode("c") + let nodeD = digraph.addNode("d") + let nodeE = digraph.addNode("e") + let nodeF = digraph.addNode("f") + let nodeG = digraph.addNode("g") + let nodeH = digraph.addNode("h") + let nodeI = digraph.addNode("i") + + digraph.addEdge(nodeA, neighbor: nodeB) + digraph.addEdge(nodeA, neighbor: nodeH) + digraph.addEdge(nodeB, neighbor: nodeA) + digraph.addEdge(nodeB, neighbor: nodeC) + digraph.addEdge(nodeB, neighbor: nodeH) + digraph.addEdge(nodeC, neighbor: nodeB) + digraph.addEdge(nodeC, neighbor: nodeD) + digraph.addEdge(nodeC, neighbor: nodeF) + digraph.addEdge(nodeC, neighbor: nodeI) + digraph.addEdge(nodeD, neighbor: nodeC) + digraph.addEdge(nodeD, neighbor: nodeE) + digraph.addEdge(nodeD, neighbor: nodeF) + digraph.addEdge(nodeE, neighbor: nodeD) + digraph.addEdge(nodeE, neighbor: nodeF) + digraph.addEdge(nodeF, neighbor: nodeC) + digraph.addEdge(nodeF, neighbor: nodeD) + digraph.addEdge(nodeF, neighbor: nodeE) + digraph.addEdge(nodeF, neighbor: nodeG) + digraph.addEdge(nodeG, neighbor: nodeF) + digraph.addEdge(nodeG, neighbor: nodeH) + digraph.addEdge(nodeG, neighbor: nodeI) + digraph.addEdge(nodeH, neighbor: nodeA) + digraph.addEdge(nodeH, neighbor: nodeB) + digraph.addEdge(nodeH, neighbor: nodeG) + digraph.addEdge(nodeH, neighbor: nodeI) + digraph.addEdge(nodeI, neighbor: nodeC) + digraph.addEdge(nodeI, neighbor: nodeG) + digraph.addEdge(nodeI, neighbor: nodeH) + + let nodesExplored = depthFirstSearch(digraph, source: nodeA) + + XCTAssertEqual(nodesExplored, ["a", "b", "c", "d", "e", "f", "g", "h", "i"]) + } + + func testExploringDigraphWithASingleNode() { + let digraph = Graph() + let node = digraph.addNode("a") + + let nodesExplored = depthFirstSearch(digraph, source: node) + + XCTAssertEqual(nodesExplored, ["a"]) + } +} diff --git a/Depth-First Search/Tests/Graph.swift b/Depth-First Search/Tests/Graph.swift new file mode 100644 index 000000000..a52b3c419 --- /dev/null +++ b/Depth-First Search/Tests/Graph.swift @@ -0,0 +1,106 @@ +// MARK: - Edge + +open class Edge: Equatable { + open var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} + +// MARK: - Node + +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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} + +// MARK: - Graph + +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})]" + } + } + 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(node.label) + } + + 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) + } + } + + return duplicated + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Depth-First Search/Tests/Info.plist b/Depth-First Search/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Depth-First Search/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/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..2b433bd96 --- /dev/null +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,278 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 83F9C96C1C8443E800B3A87F /* DepthFirstSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */; }; + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; + FFC6E11E1C8656D10046BA79 /* DepthFirstSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.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; }; + 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepthFirstSearchTests.swift; sourceTree = SOURCE_ROOT; }; + 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = SOURCE_ROOT; }; + FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DepthFirstSearch.swift; path = ../DepthFirstSearch.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 = ( + 83F9C96E1C84449D00B3A87F /* Graph.swift */, + 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */, + FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.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 = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; + }; + }; + }; + 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 = ( + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */, + FFC6E11E1C8656D10046BA79 /* DepthFirstSearch.swift in Sources */, + 83F9C96C1C8443E800B3A87F /* DepthFirstSearchTests.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"; + SWIFT_VERSION = 4.0; + }; + 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"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + 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/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..4462aede0 --- /dev/null +++ b/Depth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Deque/Deque-Optimized.swift b/Deque/Deque-Optimized.swift new file mode 100644 index 000000000..4eea01f1a --- /dev/null +++ b/Deque/Deque-Optimized.swift @@ -0,0 +1,81 @@ +/* + Deque (pronounced "deck"), a double-ended queue + + All enqueuing and dequeuing operations are O(1). +*/ +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 + } + + 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) { + if head == 0 { + capacity *= 2 + let emptySpace = [T?](repeating: nil, count: capacity) + array.insert(contentsOf: emptySpace, at: 0) + head = capacity + } + + head -= 1 + array[head] = element + } + + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + + array[head] = nil + head += 1 + + if capacity >= originalCapacity && head >= capacity*2 { + let amountToRemove = capacity + capacity/2 + array.removeFirst(amountToRemove) + head -= amountToRemove + capacity /= 2 + } + return element + } + + public mutating func dequeueBack() -> T? { + if isEmpty { + return nil + } else { + return array.removeLast() + } + } + + public func peekFront() -> T? { + if isEmpty { + return nil + } else { + return array[head] + } + } + + public func peekBack() -> T? { + if isEmpty { + return nil + } else { + return array.last! + } + } +} diff --git a/Deque/Deque.swift b/Deque/Deque-Simple.swift similarity index 85% rename from Deque/Deque.swift rename to Deque/Deque-Simple.swift index c1b2489a7..fc0fcb2b2 100644 --- a/Deque/Deque.swift +++ b/Deque/Deque-Simple.swift @@ -2,7 +2,7 @@ Deque (pronounced "deck"), a double-ended queue This particular implementation is simple but not very efficient. Several - operations are O(n). A more efficient implementation would use a doubly + operations are O(n). A more efficient implementation would use a doubly linked list or a circular buffer. */ public struct Deque { @@ -16,12 +16,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/Contents.swift b/Deque/Deque.playground/Contents.swift index e3cedd706..9e7b22c02 100644 --- a/Deque/Deque.playground/Contents.swift +++ b/Deque/Deque.playground/Contents.swift @@ -2,23 +2,23 @@ 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) { + + 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? { if isEmpty { return nil @@ -26,7 +26,7 @@ public struct Deque { return array.removeFirst() } } - + public mutating func dequeueBack() -> T? { if isEmpty { return nil @@ -34,11 +34,11 @@ public struct Deque { return array.removeLast() } } - + public func peekFront() -> T? { return array.first } - + public func peekBack() -> T? { return array.last } diff --git a/Deque/Deque.playground/playground.xcworkspace/contents.xcworkspacedata b/Deque/Deque.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Deque/Deque.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 8ccaf8361..f3172e16e 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -2,30 +2,30 @@ A double-ended queue. For some reason this is pronounced as "deck". -A regular [queue](../Queue/) adds new elements to the back and dequeues from the front. The deque also allows enqueuing at the front and dequeuing from the back, and peeking at both ends. +A regular [queue](../Queue/) adds elements to the back and removes from the front. The deque also allows enqueuing at the front and dequeuing from the back, and peeking at both ends. 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) { + + 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? { if isEmpty { return nil @@ -33,7 +33,7 @@ public struct Deque { return array.removeFirst() } } - + public mutating func dequeueBack() -> T? { if isEmpty { return nil @@ -41,18 +41,18 @@ public struct Deque { return array.removeLast() } } - + public func peekFront() -> T? { return array.first } - + public func peekBack() -> T? { return array.last } } ``` -This uses an array internally. Enqueuing and dequeuing is simply a matter of adding and removing items from the front or back of the array. +This uses an array internally. Enqueuing and dequeuing are simply a matter of adding and removing items from the front or back of the array. An example of how to use it in a playground: @@ -71,7 +71,239 @@ 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 implementation would use a [doubly linked list](../Linked List/), a [circular buffer](../Ring Buffer/), or two [stacks](../Stack/) facing opposite directions. + +## 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: + + [ 1, 2, 3, 4 ] + +Then `dequeue()` will remove `1` from the array and the elements `2`, `3`, and `4`, are shifted one position to the front: + + [ 2, 3, 4 ] + +This is an **O(n)** operation because all array elements need to be moved by one position in the computer's memory. + +Likewise, inserting an element at the front of the array is expensive because it requires that all other elements must be shifted one position to the back. So `enqueueFront(5)` will change the array to be: + + [ 5, 2, 3, 4 ] + +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. + +Our initial array `[ 1, 2, 3, 4]` actually looks like this in memory: + + [ 1, 2, 3, 4, x, x, x ] + +where the `x`s denote additional positions in the array that are not being used yet. Calling `enqueue(6)` simply copies the new item into the next unused spot: + + [ 1, 2, 3, 4, 6, x, x ] + +The `dequeueBack()` function uses `array.removeLast()` to delete that item. This does not shrink the array's memory but only decrements `array.count` by one. There are no expensive memory copies involved here. So operations at the back of the array are fast, **O(1)**. + +It is possible the array runs out of free spots at the back. In that case, Swift will allocate a new, larger array and copy over all the data. This is an **O(n)** operation but because it only happens once in a while, adding new elements at the end of an array is still **O(1)** on average. + +Of course, we can use this same trick at the *beginning* of the array. That will make our deque efficient too for operations at the front of the queue. Our array will look like this: + + [ x, x, x, 1, 2, 3, 4, x, x, x ] + +There is now also a chunk of free space at the start of the array, which allows adding or removing elements at the front of the queue to be **O(1)** as well. + +Here is the new version of `Deque`: + +```swift +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 + } + + 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 + } + + public mutating func dequeue() -> T? { + // this is explained below + } + + public mutating func dequeueBack() -> T? { + if isEmpty { + return nil + } else { + return array.removeLast() + } + } + + public func peekFront() -> T? { + if isEmpty { + return nil + } else { + return array[head] + } + } + + public func peekBack() -> T? { + if isEmpty { + return nil + } else { + return array.last! + } + } +} +``` + +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 `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. + + [ x, x, x, x, x, x, x, x, x, x ] + | + head + +To enqueue an object at the front, we move `head` one position to the left and then copy the new object into the array at index `head`. For example, `enqueueFront(5)` gives: + + [ x, x, x, x, x, x, x, x, x, 5 ] + | + head + +Followed by `enqueueFront(7)`: + + [ x, x, x, x, x, x, x, x, 7, 5 ] + | + head + +And so on... the `head` keeps moving to the left and always points at the first item in the queue. `enqueueFront()` is now **O(1)** because it only involves copying a value into the array, a constant-time operation. + +Here is the code: + +```swift + public mutating func enqueueFront(element: T) { + head -= 1 + array[head] = element + } +``` + +Appending to the back of the queue has not changed (it's the exact same code as before). For example, `enqueue(1)` gives: + + [ x, x, x, x, x, x, x, x, 7, 5, 1, x, x, x, x, x, x, x, x, x ] + | + head + +Notice how the array has resized itself. There was no room to add the `1`, so Swift decided to make the array larger and add a number of empty spots to the end. If you enqueue another object, it gets added to the next empty spot in the back. For example, `enqueue(2)`: + + [ x, x, x, x, x, x, x, x, 7, 5, 1, 2, x, x, x, x, x, x, x, x ] + | + 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. + +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: + +```swift + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + + array[head] = nil + head += 1 + + return element + } +``` + +There is one tiny problem... If you enqueue a lot of objects at the front, you're going to run out of empty spots at the front at some point. When this happens at the back of the array, Swift automatically resizes it. But at the front of the array we have to handle this situation ourselves, with some extra logic in `enqueueFront()`: + +```swift + public mutating func enqueueFront(element: T) { + if head == 0 { + capacity *= 2 + let emptySpace = [T?](repeating: nil, count: capacity) + array.insert(contentsOf: emptySpace, at: 0) + head = capacity + } + + head -= 1 + array[head] = element + } +``` + +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. + +We have to do something similar for `dequeue()`. If you mostly enqueue a lot of elements at the back and mostly dequeue from the front, then you may end up with an array that looks as follows: + + [ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, 1, 2, 3 ] + | + head + +Those empty spots at the front only get used when you call `enqueueFront()`. But if enqueuing objects at the front happens only rarely, this leaves a lot of wasted space. So let's add some code to `dequeue()` to clean this up: + +```swift + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + + array[head] = nil + head += 1 + + if capacity >= originalCapacity && head >= capacity*2 { + let amountToRemove = capacity + capacity/2 + array.removeFirst(amountToRemove) + head -= amountToRemove + capacity /= 2 + } + return element + } +``` + +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:** The 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 ] + | | + capacity head + +becomes after trimming: + + [ x, x, x, x, x, 1, 2, 3 ] + | + head + capacity + +This way we can strike a balance between fast enqueuing and dequeuing at the front and keeping the memory requirements reasonable. + +> **Note:** We don't perform trimming on very small arrays. It's not worth it for saving just a few bytes of memory. + +## See also + +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) *Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift new file mode 100644 index 000000000..7c7f1a4b0 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -0,0 +1,80 @@ +//: Playground - noun: a place where people can play +import Foundation + +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 + newSet.remove(vertex) + let offset = Int(arc4random_uniform(UInt32(newSet.count))) + let index = newSet.index(newSet.startIndex, offsetBy: offset) + 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) + +//decide which vertex will be the starting one +let startVertex = randomVertex() + +let startTime = Date() + +//ask algorithm to find shortest paths from start vertex to all others +dijkstra.findShortestPaths(from: startVertex) + +let endTime = Date() + +print("calculation time is = \((endTime.timeIntervalSince(startTime))) sec") + +//printing results +let destinationVertex = randomVertex(except: startVertex) +print(destinationVertex.pathLengthFromStart) +var pathVerticesFromStartString: [String] = [] +for vertex in destinationVertex.pathVerticesFromStart { + pathVerticesFromStartString.append(vertex.identifier) +} + +print(pathVerticesFromStartString.joined(separator: "->")) + + diff --git a/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift new file mode 100644 index 000000000..8cda797dd --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Dijkstra.swift @@ -0,0 +1,41 @@ +import Foundation + +public class Dijkstra { + private var totalVertices: Set + + public init(vertices: Set) { + totalVertices = vertices + } + + private func clearCache() { + totalVertices.forEach { $0.clearCache() } + } + + 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 { + currentVertices.remove(vertex) + let filteredNeighbors = vertex.neighbors.filter { currentVertices.contains($0.0) } + for neighbor in filteredNeighbors { + let neighborVertex = neighbor.0 + let weight = neighbor.1 + + let theoreticNewWeight = vertex.pathLengthFromStart + weight + if theoreticNewWeight < neighborVertex.pathLengthFromStart { + neighborVertex.pathLengthFromStart = theoreticNewWeight + neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart + neighborVertex.pathVerticesFromStart.append(neighborVertex) + } + } + if currentVertices.isEmpty { + currentVertex = nil + break + } + currentVertex = currentVertices.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..a3587e04e --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/Sources/Vertex.swift @@ -0,0 +1,30 @@ +import Foundation + +open class Vertex { + + open var identifier: String + open var neighbors: [(Vertex, Double)] = [] + open var pathLengthFromStart = Double.infinity + open var pathVerticesFromStart: [Vertex] = [] + + public init(identifier: String) { + self.identifier = identifier + } + + open func clearCache() { + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] + } +} + +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 + } +} 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/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Dijkstra Algorithm/Images/DirectedGraph.png b/Dijkstra Algorithm/Images/DirectedGraph.png new file mode 100644 index 000000000..67db49958 Binary files /dev/null and b/Dijkstra Algorithm/Images/DirectedGraph.png differ diff --git a/Dijkstra Algorithm/Images/Vertices.png b/Dijkstra Algorithm/Images/Vertices.png new file mode 100644 index 000000000..09b2ad2c0 Binary files /dev/null and b/Dijkstra Algorithm/Images/Vertices.png differ diff --git a/Dijkstra Algorithm/Images/WeightedDirectedGraph.png b/Dijkstra Algorithm/Images/WeightedDirectedGraph.png new file mode 100644 index 000000000..542c698e1 Binary files /dev/null and b/Dijkstra Algorithm/Images/WeightedDirectedGraph.png differ diff --git a/Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png b/Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png new file mode 100644 index 000000000..b2bb3e8e2 Binary files /dev/null and b/Dijkstra Algorithm/Images/WeightedDirectedGraphFinal.png differ diff --git a/Dijkstra Algorithm/Images/WeightedUndirectedGraph.png b/Dijkstra Algorithm/Images/WeightedUndirectedGraph.png new file mode 100644 index 000000000..2f26b74d4 Binary files /dev/null and b/Dijkstra Algorithm/Images/WeightedUndirectedGraph.png differ diff --git a/Dijkstra Algorithm/Images/image1.png b/Dijkstra Algorithm/Images/image1.png new file mode 100644 index 000000000..aabe0969e Binary files /dev/null and b/Dijkstra Algorithm/Images/image1.png differ diff --git a/Dijkstra Algorithm/Images/image2.png b/Dijkstra Algorithm/Images/image2.png new file mode 100644 index 000000000..d4c4d94da Binary files /dev/null and b/Dijkstra Algorithm/Images/image2.png differ diff --git a/Dijkstra Algorithm/Images/image3.png b/Dijkstra Algorithm/Images/image3.png new file mode 100644 index 000000000..493048ab7 Binary files /dev/null and b/Dijkstra Algorithm/Images/image3.png differ diff --git a/Dijkstra Algorithm/Images/image4.png b/Dijkstra Algorithm/Images/image4.png new file mode 100644 index 000000000..9c47aaaaf Binary files /dev/null and b/Dijkstra Algorithm/Images/image4.png differ diff --git a/Dijkstra Algorithm/Images/image5.png b/Dijkstra Algorithm/Images/image5.png new file mode 100644 index 000000000..249465444 Binary files /dev/null and b/Dijkstra Algorithm/Images/image5.png differ diff --git a/Dijkstra Algorithm/Images/image6.png b/Dijkstra Algorithm/Images/image6.png new file mode 100644 index 000000000..a2c7c7689 Binary files /dev/null and b/Dijkstra Algorithm/Images/image6.png differ diff --git a/Dijkstra Algorithm/Images/image7.png b/Dijkstra Algorithm/Images/image7.png new file mode 100644 index 000000000..dd91cab0b Binary files /dev/null and b/Dijkstra Algorithm/Images/image7.png differ diff --git a/Dijkstra Algorithm/README.md b/Dijkstra Algorithm/README.md new file mode 100644 index 000000000..4bc719598 --- /dev/null +++ b/Dijkstra Algorithm/README.md @@ -0,0 +1,317 @@ +# Weighted graph general concepts + +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 has a direction, i.e. vertex, where it starts and vertex, where it ends. But remember a 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 undirected 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. + +# The Dijkstra's algorithm +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. + +The best example is a road network. If you want 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 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 checks all of its neighbours. If the current vertex path length from the start plus an edge weight to a neighbour less than the neighbour current path length from the start than it assigns new path length from the start to the neighbour. +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** game/tutorial to improve your understanding of the algorithm's flow. Besides, below is step by step algorithm's description. + +A short sidenote. The Swift Algorithm Club also contains the A* algorithm, which essentially is a faster version of Dijkstra's algorithm for which the only extra prerequisite is you have to know where the destination is located. + +## Example +Let's imagine that 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 a graph that connects your house with all these stores. So, you know what to do :) + +### Initialisation + +When the algorithm starts to work initial graph looks like this: + + + +The table below represents 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 | [ ] | [ ] | [ ] | [ ] | [ ] | + +>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 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 | +|:------------------------- |:---:|:---:|:---:|:---:|:---:| +| Visited | F | F | F | F | F | +| Path Length From Start | 0 | inf | inf | inf | inf | +| Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | + +Great, now our graph is initialised and we can pass it to the Dijkstra's algorithm, let's start! + +Let's follow the algorithm's cycle and pick the first vertex which neighbours we want to check. +All our vertices are not visited but there is only one has the smallest path length from start. It is A. This vertex is the 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 | +|:------------------------- |:---:|:---:|:---:|:---:|:---:| +| Visited | T | F | F | F | F | +| Path Length From Start | 0 | inf | inf | inf | inf | +| Path Vertices From Start | [A] | [ ] | [ ] | [ ] | [ ] | + +### Step 1 + +Then we check all of its neighbours. +If checking vertex path length from start + edge weight is smaller than neighbour's path length from start then we set neighbour'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 | +|:------------------------- |:----------:|:----------:|:----------:|:----------:|:----------:| +| 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] | + +### Step 3 + + + +| | 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 ] | + +### Step 4 + + + +| | 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 ] | + +### Step 5 + + + +| | 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 ] | + + +## Code implementation +First of all, let’s 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 usecases + //when you firstly initialize all vertices without neighbours. And then on next iteration you set up their neighbours. So, initially neighbours is an empty array. + //Array contains tuples (Vertex, Double). Vertex is a neighbour and Double is as edge weight to that neighbour. + open var neighbours: [(Vertex, Double)] = [] + + //As it was mentioned in the 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 the algorithm execution. + open var pathLengthFromStart = Double.infinity + + //This array contains 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 the 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 and recalculate paths then we will simply clear graph vertices' cashes. + open func clearCache() { + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] + } +} +``` + +As every vertex should be unique it is useful to make them Hashable and according Equatable. We use an 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 realisation 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. + 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 the shortest path from startVertex, + //we need to clear vertices cache just to be sure that out graph is clean. + //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 an 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 { + + //Next 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) + + //filteredNeighbours is an array that contains current vertex neighbours which aren't yet visited + let filteredNeighbours = vertex.neighbours.filter { totalVertices.contains($0.0) } + + //Let's iterate through them + for neighbour in filteredNeighbours { + //These variable are more representative, than neighbour.0 or neighbour.1 + let neighbourVertex = neighbour.0 + let weight = neighbour.1 + + //Here we calculate new weight, that we can offer to neighbour. + let theoreticNewWeight = vertex.pathLengthFromStart + weight + + //If it is smaller than neighbour's current pathLengthFromStart + //Then we perform this code + if theoreticNewWeight < neighbourVertex.pathLengthFromStart { + + //set new pathLengthFromStart + neighbourVertex.pathLengthFromStart = theoreticNewWeight + + //set new pathVerticesFromStart + neighbourVertex.pathVerticesFromStart = vertex.pathVerticesFromStart + + //append current vertex to neighbour's pathVerticesFromStart + neighbourVertex.pathVerticesFromStart.append(neighbourVertex) + } + } + + //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 a random graph. + +Also there is a **VisualizedDijkstra.playground**. Use it to figure out the algorithm's flow in real (slowed :)) time. + +It is up to you how to implement some specific parts of the 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 + +This repository contains two playgrounds: +* To understand how does this algorithm works, I created **VisualizedDijkstra.playground.** It works in auto and interactive modes. Moreover, there are play/pause/stop buttons. +* If you need only realisation of the algorithm without visualisation 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) + +# Credits + +WWDC 2017 Scholarship Project (Rejected) created by [Taras Nikulin](https://github.com/crabman448) diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift new file mode 100644 index 000000000..de6b49834 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift @@ -0,0 +1,58 @@ +/*: + ## 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 000000000..12a5d4922 Binary files /dev/null and b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Pause.png differ diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png new file mode 100644 index 000000000..3ab955629 Binary files /dev/null and b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Start.png differ diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png new file mode 100644 index 000000000..b74585cbe Binary files /dev/null and b/Dijkstra Algorithm/VisualizedDijkstra.playground/Resources/Stop.png differ 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..d827d3924 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/EdgeRepresentation.swift @@ -0,0 +1,109 @@ +import UIKit + +public class EdgeRepresentation { + 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 = graphColors.defaultEdgeColor + label.clipsToBounds = true + label.adjustsFontSizeToFitWidth = true + label.layer.cornerRadius = arcDiameter / 2 + label.text = "" + + let shapeLayer = MyShapeLayer() + shapeLayer.path = path.cgPath + 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() { + layer.strokeColor = graphColors.checkingColor.cgColor + label.backgroundColor = graphColors.checkingColor + } + + public func setDefaultColor() { + layer.strokeColor = graphColors.defaultEdgeColor.cgColor + label.backgroundColor = graphColors.defaultEdgeColor + } + + public func setText(text: String) { + label.text = text + } +} + +extension EdgeRepresentation: Equatable { + public static func ==(lhs: EdgeRepresentation, rhs: EdgeRepresentation) -> Bool { + 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 new file mode 100644 index 000000000..a63655dd9 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/ErrorView.swift @@ -0,0 +1,31 @@ +import UIKit + +public class ErrorView: UIView { + private var label: UILabel! + + public override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + backgroundColor = UIColor(red: 242/255, green: 156/255, blue: 84/255, alpha: 1) + layer.cornerRadius = 10 + + 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) { + 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..33bf4a515 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/CustomUI/MyShapeLayer.swift @@ -0,0 +1,6 @@ +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..819fcfc5c --- /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) + commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + 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 new file mode 100644 index 000000000..e785e120b --- /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) + backgroundColor = graphColors.defaultVertexColor + layer.cornerRadius = frame.width / 2 + clipsToBounds = true + setupIdLabel() + setupPathLengthFromStartLabel() + } + + private func setupIdLabel() { + let x: CGFloat = frame.width * 0.2 + let y: CGFloat = 0 + let width: CGFloat = frame.width * 0.6 + let height: CGFloat = frame.height / 2 + let idLabelFrame = CGRect(x: x, y: y, width: width, height: height) + + idLabel = UILabel(frame: idLabelFrame) + idLabel.textAlignment = .center + idLabel.adjustsFontSizeToFitWidth = true + addSubview(idLabel) + } + + private func setupPathLengthFromStartLabel() { + 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) + + pathLengthLabel = UILabel(frame: pathLengthLabelFrame) + pathLengthLabel.textAlignment = .center + pathLengthLabel.adjustsFontSizeToFitWidth = true + addSubview(pathLengthLabel) + } + + public func setIdLabel(text: String) { + idLabel.text = text + } + + public func setPathLengthLabel(text: String) { + pathLengthLabel.text = text + } + + public func setLabelsTextColor(color: UIColor) { + idLabel.textColor = color + 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..447b3dbe1 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Graph.swift @@ -0,0 +1,310 @@ +import Foundation +import UIKit + +public enum GraphState { + case initial + case autoVisualization + case interactiveVisualization + case parsing + case completed +} + +public class Graph { + 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 = false + public var stopVisualization = false + public var startVertex: Vertex? + public var interactiveNeighborCheckAnimationDuration: Double = 1.8 { + didSet { + _interactiveOneSleepDuration = UInt32(interactiveNeighborCheckAnimationDuration * 1000000.0 / 3.0) + } + } + private var _interactiveOneSleepDuration: UInt32 = 600000 + + public var visualizationNeighborCheckAnimationDuration: Double = 2.25 { + didSet { + _visualizationOneSleepDuration = UInt32(visualizationNeighborCheckAnimationDuration * 1000000.0 / 3.0) + } + } + private var _visualizationOneSleepDuration: UInt32 = 750000 + + public var vertices: Set { + return _vertices + } + + public init(verticesCount: UInt) { + self.verticesCount = verticesCount + } + + public func removeGraph() { + _vertices.removeAll() + startVertex = nil + } + + public func createNewGraph() { + guard _vertices.isEmpty, startVertex == nil else { + assertionFailure("Clear graph before creating new one") + return + } + 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() { + _vertices.forEach { $0.clearCache() } + } + + public func reset() { + for vertex in _vertices { + vertex.clearCache() + } + } + + private func createNotConnectedVertices() { + for i 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] + } + + private func setVertexLevels() { + _vertices.forEach { $0.clearLevelInfo() } + guard let startVertex = 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) { + guard let startVertex = self.startVertex else { + assertionFailure("start vertex is nil") + return + } + clearCache() + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) + var currentVertex: Vertex? = startVertex + + var totalVertices = _vertices + + breakableLoop: while let vertex = currentVertex { + totalVertices.remove(vertex) + while pauseVisualization == true { + if stopVisualization == true { + break breakableLoop + } + } + if stopVisualization == true { + break breakableLoop + } + DispatchQueue.main.async { + vertex.setVisitedColor() + } + usleep(750000) + vertex.visited = true + let filteredEdges = vertex.edges.filter { !$0.neighbor.visited } + for edge in filteredEdges { + let neighbor = edge.neighbor + let weight = edge.weight + let edgeRepresentation = edge.edgeRepresentation + + while pauseVisualization == true { + if stopVisualization == true { + break breakableLoop + } + } + if stopVisualization == true { + break breakableLoop + } + DispatchQueue.main.async { + edgeRepresentation?.setCheckingColor() + neighbor.setCheckingPathColor() + self.delegate?.willCompareVertices(startVertexPathLength: vertex.pathLengthFromStart, + edgePathLength: weight, + endVertexPathLength: neighbor.pathLengthFromStart) + } + usleep(_visualizationOneSleepDuration) + + + let theoreticNewWeight = vertex.pathLengthFromStart + weight + + if theoreticNewWeight < neighbor.pathLengthFromStart { + while pauseVisualization == true { + if stopVisualization == true { + break breakableLoop + } + } + if stopVisualization == true { + break breakableLoop + } + neighbor.pathLengthFromStart = theoreticNewWeight + neighbor.pathVerticesFromStart = vertex.pathVerticesFromStart + neighbor.pathVerticesFromStart.append(neighbor) + } + usleep(_visualizationOneSleepDuration) + + DispatchQueue.main.async { + self.delegate?.didFinishCompare() + edge.edgeRepresentation?.setDefaultColor() + edge.neighbor.setDefaultColor() + } + usleep(_visualizationOneSleepDuration) + } + if totalVertices.isEmpty { + currentVertex = nil + break + } + currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } + } + if 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 nextVertices.contains(vertex) { + delegate?.willStartVertexNeighborsChecking() + state = .parsing + 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..ec4f74705 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/GraphView.swift @@ -0,0 +1,244 @@ +import UIKit + +public class GraphView: UIView { + private var graph: Graph + private var panningView: VertexView? = nil + private var graphColors = GraphColors.sharedInstance + + 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) { + fatalError("init(coder:) has not been implemented") + + } + + public func removeGraph() { + for vertex in graph.vertices { + if let view = vertex.view { + view.removeFromSuperview() + vertex.view = nil + } + } + for vertex in graph.vertices { + for edge in vertex.edges { + if let edgeRepresentation = edge.edgeRepresentation { + edgeRepresentation.layer.removeFromSuperlayer() + edgeRepresentation.label.removeFromSuperview() + edge.edgeRepresentation = nil + } + } + } + } + + public func createNewGraph() { + setupVertexViews() + setupEdgeRepresentations() + addGraph() + } + + public func reset() { + for vertex in graph.vertices { + vertex.edges.forEach { $0.edgeRepresentation?.setDefaultColor() } + vertex.setDefaultColor() + } + } + + private func addGraph() { + for vertex in graph.vertices { + for edge in vertex.edges { + if let edgeRepresentation = edge.edgeRepresentation { + layer.addSublayer(edgeRepresentation.layer) + addSubview(edgeRepresentation.label) + } + } + } + for vertex in graph.vertices { + if let view = vertex.view { + addSubview(view) + } + } + } + + private func setupVertexViews() { + var level = 0 + var buildViewQueue = [graph.startVertex!] + let itemWidth: CGFloat = 40 + while !buildViewQueue.isEmpty { + let levelItemsCount = CGFloat(buildViewQueue.count) + let xStep = (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(didTapVertex(sender:)), for: .touchUpInside) + let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(recognizer:))) + vertex.view?.addGestureRecognizer(panGesture) + } + level += 1 + buildViewQueue = 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 panningView != nil { + if 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) + } + } + } + panningView = vertexView + case .changed: + 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) >= frame.width + || (vertexView.frame.origin.y + vertexView.frame.height + translation.y) >= frame.height { + break + } + 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 = path(fromEdgeRepresentation: edgeRepresentation, movingVertex: vertex, translation: translation, outPath: false) + edgeRepresentation.layer.path = newPath + CATransaction.commit() + + } + + 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 = 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: + movingVertexInputEdges = [] + movingVertexOutputEdges = [] + 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] = [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..f18ec3114 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/SimpleObjects/Vertex.swift @@ -0,0 +1,63 @@ +import UIKit + +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 { + self.view?.setPathLengthLabel(text: "\(self.pathLengthFromStart)") + } + } + } + + public init(identifier: String) { + self.identifier = identifier + } + + public func clearCache() { + pathLengthFromStart = Double.infinity + pathVerticesFromStart = [] + visited = false + } + + public func clearLevelInfo() { + level = 0 + levelChecked = false + } + + public func setVisitedColor() { + view?.backgroundColor = graphColors.visitedColor + view?.setLabelsTextColor(color: UIColor.white) + } + + public func setCheckingPathColor() { + view?.backgroundColor = graphColors.checkingColor + } + + public func setDefaultColor() { + 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 new file mode 100644 index 000000000..9a169b8c7 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -0,0 +1,322 @@ +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.sharedInstance + + public override init(frame: CGRect) { + super.init(frame: frame) + self.frame = frame + backgroundColor = graphColors.mainWindowBackgroundColor + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func configure(graph: Graph) { + self.graph = graph + 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, 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: 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: 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: 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: center.x - 65, y: 56, width: 30, height: 30) + startButton = UIButton(frame: frame) + let playImage = UIImage(named: "Start.png") + startButton.setImage(playImage, for: .normal) + startButton.isEnabled = false + startButton.addTarget(self, action: #selector(didTapStartButton), for: .touchUpInside) + } + + private func configurePauseButton() { + let frame = CGRect(x: center.x - 15, y: 56, width: 30, height: 30) + pauseButton = UIButton(frame: frame) + let pauseImage = UIImage(named: "Pause.png") + pauseButton.setImage(pauseImage, for: .normal) + pauseButton.isEnabled = false + pauseButton.addTarget(self, action: #selector(didTapPauseButton), for: .touchUpInside) + } + + private func configureStopButton() { + let frame = CGRect(x: center.x + 35, y: 56, width: 30, height: 30) + stopButton = UIButton(frame: frame) + let stopImage = UIImage(named: "Stop.png") + 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: center.x - 125, y: 96) + let frame = CGRect(origin: origin, size: size) + 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: center.x - 25, y: 100) + let activityIndicatorFrame = CGRect(origin: origin, size: size) + activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) + activityIndicator.style = .whiteLarge + } + + @objc private func createGraphButtonTap() { + comparisonLabel.text = "" + graphView.removeGraph() + graph.removeGraph() + graph.createNewGraph() + graphView.createNewGraph() + graph.state = .initial + } + + @objc private func startVisualizationButtonDidTap() { + 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() + } + 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() { + 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() + } + + guard let startVertex = graph.startVertex else { + assertionFailure("startVertex is nil") + return + } + startVertex.pathLengthFromStart = 0 + startVertex.pathVerticesFromStart.append(startVertex) + graph.state = .parsing + graph.parseNeighborsFor(vertex: startVertex) { + self.graph.state = .interactiveVisualization + DispatchQueue.main.async { + self.comparisonLabel.text = "Pick next vertex" + } + } + } + + @objc private func didTapStartButton() { + startButton.isEnabled = false + pauseButton.isEnabled = true + DispatchQueue.global(qos: .utility).async { + self.graph.pauseVisualization = false + } + } + + @objc private func didTapPauseButton() { + startButton.isEnabled = true + pauseButton.isEnabled = false + DispatchQueue.global(qos: .utility).async { + self.graph.pauseVisualization = true + } + } + + @objc private func didTapStopButton() { + 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() { + 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) { + 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() { + graph.state = .completed + setButtonsToInitialState() + comparisonLabel.text = "Completed!" + } + + public func didTapWrongVertex() { + if !subviews.contains { $0 is ErrorView } { + 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() { + graph.state = .initial + graph.stopVisualization = false + graph.pauseVisualization = false + graphView.reset() + graph.reset() + setButtonsToInitialState() + 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/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj new file mode 100755 index 000000000..7699219de --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -0,0 +1,223 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + OBJ_18 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* main.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 232D7939216F76F700831A74 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + OBJ_12 /* DiningPhilosophers */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = DiningPhilosophers; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + OBJ_9 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + OBJ_19 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + OBJ_11 /* Products */ = { + isa = PBXGroup; + children = ( + OBJ_12 /* DiningPhilosophers */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_5 = { + isa = PBXGroup; + children = ( + 232D7939216F76F700831A74 /* README.md */, + OBJ_6 /* Package.swift */, + OBJ_7 /* Sources */, + OBJ_11 /* Products */, + ); + sourceTree = ""; + }; + OBJ_7 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* DiningPhilosophers */, + ); + path = Sources; + sourceTree = ""; + }; + OBJ_8 /* DiningPhilosophers */ = { + isa = PBXGroup; + children = ( + OBJ_9 /* main.swift */, + ); + name = DiningPhilosophers; + path = Sources; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + OBJ_13 /* DiningPhilosophers */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_14 /* Build configuration list for PBXNativeTarget "DiningPhilosophers" */; + buildPhases = ( + OBJ_17 /* Sources */, + OBJ_19 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DiningPhilosophers; + productName = DiningPhilosophers; + productReference = OBJ_12 /* DiningPhilosophers */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 9999; + TargetAttributes = { + OBJ_13 = { + LastSwiftMigration = 1000; + }; + }; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "DiningPhilosophers" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = OBJ_5; + productRefGroup = OBJ_11 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + OBJ_13 /* DiningPhilosophers */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + OBJ_17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_18 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + OBJ_15 /* Debug */ = { + 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 = 4.2; + TARGET_NAME = DiningPhilosophers; + }; + name = Debug; + }; + OBJ_16 /* Release */ = { + 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 = 4.2; + TARGET_NAME = DiningPhilosophers; + }; + name = Release; + }; + OBJ_3 /* Debug */ = { + 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 /* Release */ = { + 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; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + OBJ_14 /* Build configuration list for PBXNativeTarget "DiningPhilosophers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_15 /* Debug */, + OBJ_16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_2 /* Build configuration list for PBXProject "DiningPhilosophers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} 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/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + 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..aed9dfe59 --- /dev/null +++ b/DiningPhilosophers/README.md @@ -0,0 +1,60 @@ +# Dining Philosophers +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 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 uses the GCD Dispatch and Semaphores 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. 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. + +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 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 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). + +# 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. 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 it will solve an arbitrarily large problem. + +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. + +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 the GCD and Semaphore technique that can be built on both macOS and Linux. + +The code is based on a ForkPair struct used for holding an array of DispatchSemaphore and a Philosopher struct for associate a couple of forks to each Philosopher. + +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 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 + +Written for Swift Algorithm Club by Jacopo Mangiavacchi +Swift 4.2 check by Bruno Scheele diff --git a/DiningPhilosophers/Sources/main.swift b/DiningPhilosophers/Sources/main.swift new file mode 100755 index 000000000..f473e76fb --- /dev/null +++ b/DiningPhilosophers/Sources/main.swift @@ -0,0 +1,105 @@ +// +// Swift Dining philosophers problem Algorithm +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +// +// Created by Jacopo Mangiavacchi on 11/02/16. +// +// + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) + print("Hello, Swift 4!") +#endif + +import Dispatch + +let numberOfPhilosophers = 4 + +struct 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() + } +} + +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 Philosopher: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + forkPair.pickUp() + print("Start Eating Philosopher: \(philosopherIndex)") + //sleep(1000) + print("Releasing lock for Philosopher: \(philosopherIndex) Left:\(leftIndex) Right:\(rightIndex)") + forkPair.putDown() + } + } +} + +// 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.. Int { + guard numberOfEggs != 0 && numberOfFloors != 0 else { return 0 } + guard numberOfEggs != 1 && numberOfFloors != 1 else { return 1 } + + var eggFloor: [[Int]] = .init(repeating: .init(repeating: 0, count: numberOfFloors + 1), count: numberOfEggs + 1) + var attempts = 0 + + for floorNumber in stride(from: 0, through: numberOfFloors, by: 1) { + eggFloor[1][floorNumber] = floorNumber + } + eggFloor[2][1] = 1 + + for eggNumber in stride(from: 2, through: numberOfEggs, by: 1) { + for floorNumber in stride(from: 2, through: numberOfFloors, by: 1) { + eggFloor[eggNumber][floorNumber] = Int.max + for visitingFloor in stride(from: 1, through: floorNumber, by: 1) { + attempts = 1 + max(eggFloor[eggNumber - 1][visitingFloor - 1], eggFloor[eggNumber][floorNumber - visitingFloor]) + + if attempts < eggFloor[eggNumber][floorNumber] { + eggFloor[eggNumber][floorNumber] = attempts + } + } + } + } + + return eggFloor[numberOfEggs][numberOfFloors] +} 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.playground/playground.xcworkspace/contents.xcworkspacedata b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/Egg Drop Problem/EggDrop.swift b/Egg Drop Problem/EggDrop.swift new file mode 100644 index 000000000..db1e48b95 --- /dev/null +++ b/Egg Drop Problem/EggDrop.swift @@ -0,0 +1,39 @@ +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{ //edge case: When either number of eggs or number of floors is 1, answer is 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 + } + 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] = 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 + //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] +} + +//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/README.markdown b/Egg Drop Problem/README.markdown new file mode 100644 index 000000000..416984193 --- /dev/null +++ b/Egg Drop Problem/README.markdown @@ -0,0 +1,72 @@ +# Egg Drop + +The *egg drop* problem is an interview question popularized by Google. The premise is simple; You're given a task to evaluate the *shatter resistance* of unknown objects by dropping them at a certain height. For simplicity, you test this by going inside a multi-story building and performing tests by dropping the objects out the window and onto the ground: + +![building with eggs being dropped](images/eggdrop.png) + +Your goal is to find out the **minimum** height that causes the object to shatter. Consider the trivial case you're given **1** object to obtain the results with. Since you've only got one sample for testing, you need to play it safe by performing drop tests starting with the bottom floor and working your way up: + +![dropping from first floor](images/eggdrop2.png) + +If the object is incredibly resilient, and you may need to do the testing on the world's tallest building - the [Burj Khalifa](https://en.wikipedia.org/wiki/Burj_Khalifa). With **163** floors, that's a lot of climbing. Let's assume you complain, and your employer hears your plight. You are now given *several* samples to work with. How can you make use of these extra samples to expedite your testing process? The problem for this situation is popularized as the **egg drop** problem. + +## Description + +You're in a building with **m** floors and you are given **n** eggs. What is the minimum number of attempts it will take to find out the floor that breaks the egg? + +For convenience, here are a few rules to keep in mind: + +- 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, then it would break if dropped from a higher floor. +- If an egg survives, then it would survive a shorter fall. + +## 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 are two eggs and one floor, it takes one attempt + +```swift +for var floorNumber in (0..<(numberOfFloors+1)){ +eggFloor[1][floorNumber] = floorNumber //base case 1: if there's only one egg, it takes 'numberOfFloors' attempts +} + +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 + +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. + +*Written for the Swift Algorithm Club by Arkalyk Akash. Revisions and additions by Kelvin Lau* diff --git a/Egg Drop Problem/images/eggdrop.png b/Egg Drop Problem/images/eggdrop.png new file mode 100644 index 000000000..9acfc2b76 Binary files /dev/null and b/Egg Drop Problem/images/eggdrop.png differ diff --git a/Egg Drop Problem/images/eggdrop2.png b/Egg Drop Problem/images/eggdrop2.png new file mode 100644 index 000000000..b342321bb Binary files /dev/null and b/Egg Drop Problem/images/eggdrop2.png differ diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift new file mode 100644 index 000000000..44c2440d5 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift @@ -0,0 +1,46 @@ +//: Playground - noun: a place where people can play + +func printTree(_ root: BinaryNode?) { + guard let root = root else { + return + } + + let leftVal = root.left == nil ? "nil" : root.left!.val + let rightVal = root.right == nil ? "nil" : root.right!.val + + print("val: \(root.val) left: \(leftVal) right: \(rightVal)") + + printTree(root.left) + printTree(root.right) +} + +let coder = BinaryNodeCoder() + +let node1 = BinaryNode("a") +let node2 = BinaryNode("b") +let node3 = BinaryNode("c") +let node4 = BinaryNode("d") +let node5 = BinaryNode("e") + +node1.left = node2 +node1.right = node3 +node3.left = node4 +node3.right = node5 + +let encodeStr = try coder.encode(node1) +print(encodeStr) +// "a b # # c d # # e # #" + + +let root: BinaryNode = coder.decode(from: encodeStr)! +print("Tree:") +printTree(root) +/* + Tree: + val: a left: b right: c + val: b left: nil right: nil + val: c left: d right: e + val: d left: nil right: nil + val: e left: nil right: nil + */ + diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift new file mode 100644 index 000000000..10bb277f5 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift @@ -0,0 +1,95 @@ +// +// EncodeAndDecodeTree.swift +// +// +// Created by Kai Chen on 19/07/2017. +// +// + +import Foundation + +protocol BinaryNodeEncoder { + func encode(_ node: BinaryNode?) throws -> String +} + +protocol BinaryNodeDecoder { + func decode(from string: String) -> BinaryNode? +} + +public class BinaryNodeCoder: BinaryNodeEncoder, BinaryNodeDecoder { + + // MARK: Private + + private let separator: Character = "," + private let nilNode = "X" + + private func decode(from array: inout [String]) -> BinaryNode? { + guard !array.isEmpty else { + return nil + } + + let value = array.removeLast() + + guard value != nilNode, let val = value as? T else { + return nil + } + + let node = BinaryNode(val) + node.left = decode(from: &array) + node.right = decode(from: &array) + + return node + } + + // MARK: Public + + public init() {} + + public func encode(_ node: BinaryNode?) throws -> String { + var str = "" + node?.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) + } + + return str + } + + public func decode(from string: String) -> BinaryNode? { + var components = string.split(separator: separator).reversed().map(String.init) + return decode(from: &components) + } +} + +public class BinaryNode { + public var val: Element + public var left: BinaryNode? + public var right: BinaryNode? + + public init(_ val: Element, left: BinaryNode? = nil, right: BinaryNode? = nil) { + self.val = val + self.left = left + self.right = right + } + + public func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(val) + + if let left = left { + try left.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + + if let right = right { + try right.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + } +} diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground b/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.swift new file mode 100644 index 000000000..6ec8a3046 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.swift @@ -0,0 +1,95 @@ +// +// EncodeAndDecodeTree.swift +// +// +// Created by Kai Chen on 19/07/2017. +// +// + +import Foundation + +protocol BinaryNodeEncoder { + func encode(_ node: BinaryNode?) throws -> String +} + +protocol BinaryNodeDecoder { + func decode(from string: String) -> BinaryNode? +} + +public class BinaryNodeCoder: BinaryNodeEncoder, BinaryNodeDecoder { + + // MARK: Private + + private let separator: Character = "," + private let nilNode = "X" + + private func decode(from array: inout [String]) -> BinaryNode? { + guard !array.isEmpty else { + return nil + } + + let value = array.removeLast() + + guard value != nilNode, let val = value as? T else { + return nil + } + + let node = BinaryNode(val) + node.left = decode(from: &array) + node.right = decode(from: &array) + + return node + } + + // MARK: Public + + public init() {} + + public func encode(_ node: BinaryNode?) throws -> String { + var str = "" + node?.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) + } + + return str + } + + public func decode(from string: String) -> BinaryNode? { + var components = string.split(separator: separator).reversed().map(String.init) + return decode(from: &components) + } +} + +public class BinaryNode { + public var val: Element + public var left: BinaryNode? + public var right: BinaryNode? + + public init(_ val: Element, left: BinaryNode? = nil, right: BinaryNode? = nil) { + self.val = val + self.left = left + self.right = right + } + + public func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(val) + + if let left = left { + try left.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + + if let right = right { + try right.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + } +} diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md new file mode 100644 index 000000000..b60e0a504 --- /dev/null +++ b/Encode and Decode Tree/readme.md @@ -0,0 +1,199 @@ +# Encode and Decode Binary Tree + +> **Note**: The prerequisite for this article is an understanding of how [binary trees](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Tree) work. + +Trees are complex structures. Unlike linear collections such as arrays or linked lists, trees are *non-linear* and each element in a tree has positional information such as the *parent-child* relationship between nodes. When you want to send a tree structure to your backend, you need to send the data of each node, and a way to represent the parent-child relationship for each node. + +Your strategy in how you choose to represent this information is called your **encoding** strategy. The opposite of that - changing your encoded data back to its original form - is your **decoding** strategy. + +There are many ways to encode a tree and decode a tree. The important thing to keep in mind is that encoding and decoding strategies are closely related. The way you choose to encode a tree directly affects how you might decode a tree. + +Encoding and decoding are synonyms to *serializing* and *deserializing* trees. + +As a reference, the following code represents the typical `Node` type of a binary tree: + +```swift +class BinaryNode { + var data: Element + var leftChild: BinaryNode? + var rightChild: BinaryNode? + + // ... (rest of the implementation) +} +``` + +Your encoding and decoding methods will reside in the `BinaryNodeEncoder` and `BinaryNodeDecoder` classes: + +```swift +class BinaryNodeCoder { + + // transforms nodes into string representation + func encode(_ node: BinaryNode) throws -> String where T: Encodable { + + } + + // transforms string into `BinaryNode` representation + func decode(from string: String) + throws -> BinaryNode where T: Decodable { + + } +} +``` + +## Encoding + +As mentioned before, there are different ways to do encoding. For no particular reason, you'll opt for the following rules: + +1. The result of the encoding will be a `String` object. +2. You'll encode using *pre-order* traversal. + +Here's an example of this operation in code: + +```swift +fileprivate extension BinaryNode { + + // 1 + func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(data) + + if let leftChild = leftChild { + try leftChild.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + + if let rightChild = rightChild { + try rightChild.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + } +} + +class BinaryNodeCoder { + + // 2 + private var separator: String { return "," } + + // 3 + private var nilNode: String { return "X" } + + // 4 + func encode(_ node: BinaryNode) -> String { + var str = "" + node.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) + } + return str + } + + // ... +} +``` + +Here's a high level overview of the above code: + +2. `separator` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `separator`, you can't tell. + +3. `nilNode` is used to identify empty children. This a necesssary piece of information to retain in order to rebuild the tree later. + +4. `encode` returns a `String` representation of the `BinaryNode`. For example: "ba,nana,nil" represents a tree with two nodes - "ba" and "nana" - in pre-order format. + +## Decoding + +Your decoding strategy is the exact opposite of your encoding strategy. You'll take an encoded string, and turn it back into your binary tree. + +Your encoding strategy followed the following rules: + +1. The result of the encoding will be a `String` object. +2. You'll encode using *pre-order* traversal. + +The implementation also added a few important details: + +* node values are separated by `,` +* `nil` children are denoted by the `nil` string + +These details will shape your `decode` operation. Here's a possible implementation: + +```swift + +class BinaryNodeCoder { + + // ... + + // 1 + func decode(_ string: String) -> BinaryNode? { + let components = encoded.lazy.split(separator: separator).reversed().map(String.init) + return decode(from: components) + } + + // 2 + private func decode(from array: inout [String]) -> BinaryNode? { + guard !array.isEmpty else { return nil } + let value = array.removeLast() + guard value != "\(nilNode)" else { return nil } + + let node = AVLNode(value: value) + node.leftChild = decode(from: &array) + node.rightChild = decode(from: &array) + return node + } +} +``` + +Here's a high level overview of the above code: + +1. Takes a `String`, and uses `split` to partition the contents of `string` into an array based on the `separator` defined in the encoding step. The result is first `reversed`, and then mapped to a `String`. The `reverse` step is an optimization for the next function, allowing us to use `array.removeLast()` instead of `array.removeFirst()`. + +2. Using an array as a stack, you recursively decode each node. The array keeps track of sequence of nodes and progress. + +Here's an example output of a tree undergoing the encoding and decoding process: + +``` +Original Tree + + ┌──8423 + ┌──8391 + │ └──nil +┌──7838 +│ │ ┌──4936 +│ └──3924 +│ └──2506 +830 +│ ┌──701 +└──202 + └──169 + +Encoded tree: 830,202,169,X,X,701,X,X,7838,3924,2506,X,X,4936,X,X,8391,X,8423,X,X, + +Decoded tree + + ┌──8423 + ┌──8391 + │ └──nil +┌──7838 +│ │ ┌──4936 +│ └──3924 +│ └──2506 +830 +│ ┌──701 +└──202 + └──169 + ``` + +Notice the original tree and decoded tree are identical. + +## Further Reading & References + +- [LeetCode](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/description/) + +*Written for the Swift Algorithm Club by Kai Chen & Kelvin Lau* + + + diff --git a/Fixed Size Array/FixedSizeArray.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift similarity index 63% rename from Fixed Size Array/FixedSizeArray.swift rename to Fixed Size Array/FixedSizeArray.playground/Contents.swift index 270222230..616f8443d 100644 --- a/Fixed Size Array/FixedSizeArray.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -1,8 +1,10 @@ -/* - An unordered array with a maximum size. +//: Playground - noun: a place where people can play - Performance is always O(1). -*/ +/* + An unordered array with a maximum size. + + Performance is always O(1). + */ struct FixedSizeArray { private var maxSize: Int private var defaultValue: T @@ -12,7 +14,7 @@ struct FixedSizeArray { init(maxSize: Int, defaultValue: T) { self.maxSize = maxSize self.defaultValue = defaultValue - self.array = [T](count: maxSize, repeatedValue: defaultValue) + self.array = [T](repeating: defaultValue, count: maxSize) } subscript(index: Int) -> T { @@ -21,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 @@ -44,3 +46,11 @@ struct FixedSizeArray { count = 0 } } + +var array = FixedSizeArray(maxSize: 5, defaultValue: 0) +array.append(4) +array.append(2) +array[1] +array.removeAt(index: 0) +array.removeAll() + diff --git a/Fixed Size Array/FixedSizeArray.playground/contents.xcplayground b/Fixed Size Array/FixedSizeArray.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Fixed Size Array/FixedSizeArray.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ 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..31fc7c826 --- /dev/null +++ b/Fixed Size Array/FixedSizeArray.playground/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Fixed Size Array/README.markdown b/Fixed Size Array/README.markdown index ec72852a8..e9eade140 100644 --- a/Fixed Size Array/README.markdown +++ b/Fixed Size Array/README.markdown @@ -1,11 +1,11 @@ # Fixed-Size Arrays -Early programming languages didn't have very fancy arrays. You'd create the array with a specific size and from that moment on it would never grow or shrink. Even the standard arrays in C and Objective-C are still of this type. +Early programming languages didn't have very fancy arrays. You'd create the array with a specific size and from that moment on it would never grow or shrink. Even the standard arrays in C and Objective-C are still of this type. -When you define an array like this, +When you define an array like so, int myArray[10]; - + the compiler allocates one contiguous block of memory that can hold 40 bytes (assuming an `int` is 4 bytes): ![An array with room for 10 elements](Images/array.png) @@ -14,7 +14,7 @@ That's your array. It will always be this size. If you need to fit more than 10 To get an array that grows when it gets full you need to use a [dynamic array](https://en.wikipedia.org/wiki/Dynamic_array) object such as `NSMutableArray` in Objective-C or `std::vector` in C++, or a language like Swift whose arrays increase their capacity as needed. -A big downside of the old-style arrays is that they need to be big enough or you run out of space. But if they are too big you're wasting memory. And you need to be careful about security flaws and crashes due to buffer overflows. In summary, fixed-size arrays are not flexible and they leave no room for error. +A major downside of the old-style arrays is that they need to be big enough or you run out of space. But if they are too big you're wasting memory. And you need to be careful about security flaws and crashes due to buffer overflows. In summary, fixed-size arrays are not flexible and they leave no room for error. That said, **I like fixed-size arrays** because they are simple, fast, and predictable. @@ -38,29 +38,29 @@ These two operations have complexity **O(1)**, meaning the time it takes to perf For an array that can grow, appending is more involved: if the array is full, new memory must be allocated and the old contents copied over to the new memory buffer. On average, appending is still an **O(1)** operation, but what goes on under the hood is less predictable. -The expensive operations are inserting and deleting. When you insert an element somewhere that's not at the end, it requires moving up the remainder of the array by one position. That involves a relatively costly memory copy operation: +The expensive operations are inserting and deleting. When you insert an element somewhere that's not at the end, it requires moving up the remainder of the array by one position. That involves a relatively costly memory copy operation. For example, inserting the value `7` in the middle of the array: ![Insert requires a memory copy](Images/insert.png) -If your code was using any indexes into the array beyond the insertion point, these indexes are now referring to the wrong objects. +If your code was using any indexes into the array beyond the insertion point, these indexes are now referring to the wrong objects. Deleting requires a copy the other way around: ![Delete also requires a memory copy](Images/delete.png) -This, by the way, is also true for `NSMutableArray` or Swift arrays. Inserting and deleting are **O(n)** operations -- the larger the array is the more time it takes. +This, by the way, is also true for `NSMutableArray` or Swift arrays. Inserting and deleting are **O(n)** operations -- the larger the array the more time it takes. 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] } @@ -87,7 +87,7 @@ This copies the last element on top of the element you want to remove, and then This is why the array is not sorted. To avoid an expensive copy of a potentially large portion of the array we copy just one element, but that does change the order of the elements. -There are now two copies of element "6" in the array, but what was previously the last element is no longer part of the active array. It's just junk data -- the next time you append an new element, this old version of "6" will be overwritten. +There are now two copies of element `6` in the array, but what was previously the last element is no longer part of the active array. It's just junk data -- the next time you append an new element, this old version of `6` will be overwritten. Under these two constraints -- a limit on the number of elements and an unsorted array -- fixed-size arrays are still perfectly suitable for use in modern software. @@ -99,26 +99,26 @@ 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](count: maxSize, repeatedValue: 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) { + + 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 @@ -127,6 +127,13 @@ struct FixedSizeArray { array[count] = defaultValue return result } + + mutating func removeAll() { + for i in 0..= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" - } - - if result.isEmpty { - result += "\(i)" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - print(result) - } } -fizzBuzz(100) +fizzBuzz(15) 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..bf753e648 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,19 +1,21 @@ -func fizzBuzz(numberOfTurns: Int) { - for i in 1...numberOfTurns { - var result = "" +// Last checked with Xcode Version 11.4.1 (11E503a) - if i % 3 == 0 { - result += "Fizz" +func fizzBuzz(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" - } - - if result.isEmpty { - result += "\(i)" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - print(result) - } -} +} \ No newline at end of file diff --git a/Fizz Buzz/README.markdown b/Fizz Buzz/README.markdown index 066cbe2de..be516bd46 100644 --- a/Fizz Buzz/README.markdown +++ b/Fizz Buzz/README.markdown @@ -16,47 +16,51 @@ The modulus operator `%` is the key to solving fizz buzz. The modulus operator returns the remainder after an integer division. Here is an example of the modulus operator: -| Division | Division Result | Modulus | Modulus Result | -| ------------- | -------------------------- | --------------- | ---------------:| -| 1 `/` 3 | `0` with a remainder of 3 | 1 `%` 3 | `3` | -| 5 `/` 3 | `1` with a remainder of 2 | 5 `%` 3 | `2` | -| 16 `/` 3 | `5` with a remainder of 1 | 16 `%` 3 | `1` | +| Division | Division Result | Modulus | Modulus Result| +| ----------- | --------------------- | ------------- | :-----------: | +| 1 / 3 | 0 with a remainder of 3 | 1 % 3 | 1 | +| 5 / 3 | 1 with a remainder of 2 | 5 % 3 | 2 | +| 16 / 3 | 5 with a remainder of 1 | 16 % 3 | 1 | A common approach to determine if a number is even or odd is to use the modulus operator: -| Modulus | Result | Swift Code | Swift Code Result | Comment | -| ------------- | ---------------:| ------------------------------- | -----------------:| --------------------------------------------- | -| 6 `%` 2 | 0 | `let isEven = number % 2 == 0` | `true` | If a number is divisible by 2 it is `even` | -| 5 `%` 2 | 1 | `let isOdd = number % 2 != 0` | `true` | If a number is not divisible by 2 it is `odd` | +| Modulus | Result | Swift Code | Swift Code
Result | Comment | +| -------- | :-----:| -------------------------------- | :----------------:| --------------------------------------------- | +| 6 % 2 | 0 | `let isEven = (number % 2 == 0)` | `true` | If a number is divisible by 2 it is *even* | +| 5 % 2 | 1 | `let isOdd = (number % 2 != 0)` | `true` | If a number is not divisible by 2 it is *odd* | -Now we can use the modulus operator `%` to solve fizz buzz. +Alternatively, Swift's built in function .isMultiple(of:) can be used, i.e. 6.isMultiple(of: 2) will return true, 5.isMultiple(of: 2) will return false + +## Solving fizz buzz + +Now we can use the modulus operator `%` or .isMultiple(of:) method to solve fizz buzz. Finding numbers divisible by three: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 `%` 3 | `1` | `1 % 3 == 0` | `false` | -| 2 `%` 3 | `2` | `2 % 3 == 0` | `false` | -| 3 `%` 3 | `0` | `3 % 3 == 0` | `true` | -| 4 `%` 3 | `1` | `4 % 3 == 0` | `false` | +| Modulus | Modulus
Result | Swift Code
using Modulo | Swift Code
using .isMultiple(of:) | Swift Code
Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | ------------------- | +|1 % 3 | 1 | `1 % 3 == 0` | `1.isMultiple(of: 3)` | `false` | +|2 % 3 | 2 | `2 % 3 == 0` | `2.isMultiple(of: 3)` | `false` | +|3 % 3 | 0 | `3 % 3 == 0` | `3.isMultiple(of: 3)` | `true` | +|4 % 3 | 1 | `4 % 3 == 0` | `4.isMultiple(of: 3)` | `false` | Finding numbers divisible by five: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 `%` 5 | `1` | `1 % 5 == 0` | `false` | -| 2 `%` 5 | `2` | `2 % 5 == 0` | `false` | -| 3 `%` 5 | `3` | `3 % 5 == 0` | `false` | -| 4 `%` 5 | `4` | `4 % 5 == 0` | `false` | -| 5 `%` 5 | `0` | `5 % 5 == 0` | `true` | -| 6 `%` 5 | `1` | `6 % 5 == 0` | `false` | +| Modulus | Modulus
Result | Swift Code
using Modulo | Swift Code
using .isMultiple(of:) | Swift Code
Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | -------------------- | +| 1 % 5 | 1 | `1 % 5 == 0` | `1.isMultiple(of: 5)` | `false` | +| 2 % 5 | 2 | `2 % 5 == 0` | `2.isMultiple(of: 5)` | `false` | +| 3 % 5 | 3 | `3 % 5 == 0` | `3.isMultiple(of: 5)` | `false` | +| 4 % 5 | 4 | `4 % 5 == 0` | `4.isMultiple(of: 5)` | `false` | +| 5 % 5 | 0 | `5 % 5 == 0` | `5.isMultiple(of: 5)` | `true` | +| 6 % 5 | 1 | `6 % 5 == 0` | `6.isMultiple(of: 5)` | `false` | ## The code -Here is a simple implementation in Swift: +Here is a simple implementation in Swift using Modulus approach ```swift -func fizzBuzz(numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { var result = "" @@ -77,13 +81,57 @@ func fizzBuzz(numberOfTurns: Int) { } ``` -Put this code in a playground and test it like so: +Here is simple implementation in Swift using .isMultiple(of:) and switch statement ```swift -fizzBuzz(15) // This will output 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz +func fizzBuzz(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return + } + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } + } +} ``` + +Put either code in a playground and test it like so: + +```swift +fizzBuzz(15) +``` + +This will output: + +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +Fizz Buzz + ## See also [Fizz buzz on Wikipedia](https://en.wikipedia.org/wiki/Fizz_buzz) -*Written by [Chris Pilcher](https://github.com/chris-pilcher)* +*Originally written by [Chris Pilcher](https://github.com/chris-pilcher)*
+*Updated by [Lance Rettberg](https://github.com/l-rettberg)* diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index ab18c9a05..bb8d49055 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,26 +1,21 @@ -//: Playground - noun: a place where people can play - -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 -} +gcd(52, 39) // 13 +gcd(228, 36) // 12 +gcd(51357, 3819) // 57 +gcd(841, 299) // 1 -func lcm(m: Int, _ n: Int) -> Int { - return m*n / gcd(m, n) -} +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 +gcd(841, 299, using: gcdRecursiveEuklid) // 1 -gcd(39, 52) // 13 -gcd(36, 228) // 12 -gcd(3819, 51357) // 57 -gcd(841, 299) // 1 +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +gcd(841, 299, using: gcdBinaryRecursiveStein) // 1 -lcm(2, 3) // 6 -lcm(10, 8) // 40 +do { + try lcm(2, 3) // 6 + try lcm(10, 8, using: gcdRecursiveEuklid) // 40 +} catch { + dump(error) +} diff --git a/GCD/GCD.playground/Sources/GCD.swift b/GCD/GCD.playground/Sources/GCD.swift new file mode 100644 index 000000000..4eb0c7621 --- /dev/null +++ b/GCD/GCD.playground/Sources/GCD.swift @@ -0,0 +1,143 @@ +/* + Finds the largest positive integer that divides both + m and n without a remainder. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Parameter using: The used algorithm to calculate the gcd. + If nothing provided, the Iterative Euclidean + algorithm is used. + - Returns: The natural gcd of m and n. + */ +public func gcd(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) -> Int { + return gcdAlgorithm(m, n) +} + +/* + Iterative approach based on the Euclidean algorithm. + The Euclidean algorithm is based on the principle that the greatest + common divisor of two numbers does not change if the larger number + is replaced by its difference with the smaller number. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n. + */ +public func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} + +/* + Recursive approach based on the Euclidean algorithm. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n. + - Note: The recursive version makes only tail recursive calls. + Most compilers for imperative languages do not optimize these. + The swift compiler as well as the obj-c compiler is able to do + optimizations for tail recursive calls, even though it still ends + up to be the same in terms of complexity. That said, tail call + elimination is not mutually exclusive to recursion. + */ +public func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } +} + +/* + The binary GCD algorithm, also known as Stein's algorithm, + is an algorithm that computes the greatest common divisor of two + nonnegative integers. Stein's algorithm uses simpler arithmetic + operations than the conventional Euclidean algorithm; it replaces + division with arithmetic shifts, comparisons, and subtraction. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Complexity: worst case O(n^2), where n is the number of bits + in the larger of the two numbers. Although each step reduces + at least one of the operands by at least a factor of 2, + the subtract and shift operations take linear time for very + large integers + */ +public func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} + +/* + Finds an easy solution for the gcd. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: A natural gcd of m and n if possible. + - Note: It might be relevant for different usecases to + try finding an easy solution for the GCD calculation + before even starting more difficult operations. + */ +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil +} + + +public enum LCMError: Error { + case divisionByZero +} + +/* + Calculates the lcm for two given numbers using a specified gcd algorithm. + + - Parameter m: First natural number. + - Parameter n: Second natural number. + - Parameter using: The used gcd algorithm to calculate the lcm. + If nothing provided, the Iterative Euclidean + algorithm is used. + - Throws: Can throw a `divisionByZero` error if one of the given + attributes turns out to be zero or less. + - Returns: The least common multiplier of the two attributes as + an unsigned integer + */ +public func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { + guard m & n != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n +} diff --git a/GCD/GCD.playground/playground.xcworkspace/contents.xcworkspacedata b/GCD/GCD.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/GCD/GCD.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GCD/GCD.playground/timeline.xctimeline b/GCD/GCD.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/GCD/GCD.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/GCD/GCD.swift b/GCD/GCD.swift deleted file mode 100644 index 222f8284e..000000000 --- a/GCD/GCD.swift +++ /dev/null @@ -1,22 +0,0 @@ -/* - Euclid's algorithm for finding the greatest common divisor -*/ -func gcd(m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b -} - -/* - Returns the least common multiple of two numbers. -*/ -func lcm(m: Int, _ n: Int) -> Int { - return m*n / gcd(m, n) -} diff --git a/GCD/README.markdown b/GCD/README.markdown index 63cd9afa4..4c459eff0 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -1,14 +1,19 @@ # Greatest Common Divisor -The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. +The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. The GCD.swift file contains three different algorithms of how to calculate the greatest common divisor. +For example, `gcd(39, 52) = 13` because 13 divides 39 (`39 / 13 = 3`) as well as 52 (`52 / 13 = 4`). But there is no larger number than 13 that divides them both. +You've probably had to learn about this in school at some point. :-) -For example, `gcd(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. +You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euklid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. -You've probably had to learn about this in school at some point. :-) +## Different Algorithms -The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +This example includes three different algorithms to find the same result. + +### Iterative Euklidean -There is a smarter way to calculate the GCD: Euclid's algorithm. The big idea here is that, +The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +There is a smarter way to calculate the GCD: Euklid's algorithm. The big idea here is that, gcd(a, b) = gcd(b, a % b) @@ -17,37 +22,58 @@ where `a % b` calculates the remainder of `a` divided by `b`. Here is an implementation of this idea in Swift: ```swift -func gcd(m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b } ``` Put it in a playground and try it out with these examples: ```swift -gcd(39, 52) // 13 -gcd(36, 228) // 12 -gcd(3819, 51357) // 57 +gcd(52, 39, using: gcdIterativeEuklid) // 13 +gcd(228, 36, using: gcdIterativeEuklid) // 12 +gcd(51357, 3819, using: gcdIterativeEuklid) // 57 +``` + +### Recursive Euklidean + +Here is a slightly different implementation of Euklid's algorithm. Unlike the first version this doesn't use a `while` loop, but leverages recursion. + +```swift +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } +} ``` -Let's step through the third example: +Put it in a playground and compare it with the results of the iterative Eulidean gcd. They should return the same results: + +```swift +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 +``` - gcd(3819, 51357) +The `max()` and `min()` at the top of the function make sure we always divide the larger number by the smaller one. -It's convenient to have the larger number first, so we swap them. That's what the `max()` and `min()` are for at the top of the function. We now have: +Let's step through the third example using the *recursive Euklidean algorithm* here: gcd(51357, 3819) -According to Euclid's rule, this is equivalent to: +According to Euklid's rule, this is equivalent to, gcd(3819, 51357 % 3819) = gcd(3819, 1710) @@ -55,17 +81,17 @@ because the remainder of `51357 % 3819` is `1710`. If you work out this division So `gcd(51357, 3819)` is the same as `gcd(3819, 1710)`. That's useful because we can keep simplifying: - gcd(3819, 1710) = gcd(1710, 3819 % 1710) = - gcd(1710, 399) = gcd(399, 1710 % 399) = - gcd(399, 114) = gcd(114, 399 % 114) = - gcd(114, 57) = gcd(57, 114 % 57) = + gcd(3819, 1710) = gcd(1710, 3819 % 1710) = + gcd(1710, 399) = gcd(399, 1710 % 399) = + gcd(399, 114) = gcd(114, 399 % 114) = + gcd(114, 57) = gcd(57, 114 % 57) = gcd(57, 0) And now can't divide any further. The remainder of `114 / 57` is zero because `114 = 57 * 2` exactly. That means we've found the answer: gcd(3819, 51357) = gcd(57, 0) = 57 -So in each step of Euclid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. +So in each step of Euklid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. By the way, it's also possible that two numbers have a GCD of 1. They are said to be *relatively prime*. This happens when there is no number that divides them both, for example: @@ -73,25 +99,82 @@ By the way, it's also possible that two numbers have a GCD of 1. They are said t gcd(841, 299) // 1 ``` -## Least Common Multiple +### Binary Recursive Stein + +The binary GCD algorithm, also known as Stein's algorithm, is an algorithm that computes the greatest common divisor of two nonnegative integers. Stein's algorithm is very similar to the recursive Eulidean algorithm, but uses arithmetical operations, which are simpler for computers to perform, than the conventional Euclidean algorithm does. It replaces division with arithmetic shifts, comparisons, and subtraction. + +```swift +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} +``` + +Depending on your application and your input expectations, it might be reasonable to also search for an "easy solution" using the other gcd implementations: + +```swift +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil +} + +``` + +Put it in a playground and compare it with the results of the other gcd implementations: + +```swift +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +``` + +### Least Common Multiple -An idea related to the GCD is the *least common multiple* or LCM. +Another algorithm related to the GCD is the *least common multiple* or LCM. -The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. +The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and an optional specification which GCD algorithm is used. -For example: `lcm(2, 3) = 6` because 6 can be divided by 2 and also by 3. +For example: `lcm(2, 3, using: gcdRecursiveEuklid) = 6` , which tells us that 6 is the smallest number that can be devided by 2 as well as 3. -We can calculate the LCM using Euclid's algorithm too: +We can calculate the LCM using Euklid's algorithm too: - a * b - lcm(a, b) = --------- - gcd(a, b) +a * b +lcm(a, b) = --------- +gcd(a, b) In code: ```swift -func lcm(m: Int, _ n: Int) -> Int { - return m*n / gcd(m, n) +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { +guard (m & n) != 0 else { throw LCMError.divisionByZero } +return m / gcdAlgorithm(m, n) * n } ``` @@ -101,6 +184,11 @@ And to try it out in a playground: lcm(10, 8) // 40 ``` -You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euclid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. +## Discussion + +While these algorithms all calculate the same result, comparing their plane complexity might not be enough to decide for one of them, though. The original iterative Euklidean algorithm is easier to understand. The recursive Euklidean and Stein's algorithm, while being generally faster, their runtime is heavily dependend on the environment they are running on. +_If a fast calculation of the gcd is necessary, a runtime comparison for the specific platform and compiler optimization level should be done for the rekursive Euklidean and Stein's algorithm._ *Written for Swift Algorithm Club by Matthijs Hollemans* + +*Extended by Simon C. Krüger* diff --git a/Genetic/README.markdown b/Genetic/README.markdown new file mode 100644 index 000000000..5dc4747f2 --- /dev/null +++ b/Genetic/README.markdown @@ -0,0 +1,312 @@ +# Genetic Algorthim + +## What is it? + +A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), crossover and mutation. To understand more, let's walk through these processes in terms of biology: + +### Selection +>**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. + +In other words, survival of the fittest. Organisms that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank individuals and give them a better chance for reproduction. + +### Crossover +>**Chromosomal crossover** (or crossing over) is the exchange of genetic material between homologous chromosomes that results in recombinant chromosomes during sexual reproduction [Wikipedia](https://en.wikipedia.org/wiki/Chromosomal_crossover) + +Simply reproduction. A generation will be a mixed representation of the previous generation, with offspring taking DNA from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. + +### Mutation +>**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) + +The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a population in order to introduce fitness variance. + +### Resources: +* [Genetic Algorithms in Search Optimization, and Machine Learning](https://www.amazon.com/Genetic-Algorithms-Optimization-Machine-Learning/dp/0201157675/ref=sr_1_sc_1?ie=UTF8&qid=1520628364&sr=8-1-spell&keywords=Genetic+Algortithms+in+search) +* [Wikipedia](https://en.wikipedia.org/wiki/Genetic_algorithm) +* [My Original Gist](https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba) + +## The Code + +### Problem +For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. + +We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. + +### Define the Universe + +Before we dive into the core processes we need to set up our "universe". First let's define a lexicon, a set of everything that exists in our universe. + +```swift +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +``` + +To make things easier, we are actually going to work in [Unicode values](https://en.wikipedia.org/wiki/List_of_Unicode_characters), so let's define a String extension to help with that. + +```swift +extension String { + var unicodeArray: [UInt8] { + return [UInt8](self.utf8) + } +} +``` + + Now, let's define a few global variables for the universe: + * `OPTIMAL`: This is the end goal and what we will be using to rate fitness. In the real world this will not exist + * `DNA_SIZE`: The length of the string in our population. Organisms need to be similar + * `POP_SIZE`: Size of each generation + * `MAX_GENERATIONS`: Max number of generations, script will stop when it reach 5000 if the optimal value is not found + * `MUTATION_CHANCE`: The chance in which a random nucleotide can mutate (`1/MUTATION_CHANCE`) + + ```swift +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray +let DNA_SIZE = OPTIMAL.count +let POP_SIZE = 50 +let GENERATIONS = 5000 +let MUTATION_CHANCE = 100 + ``` + + ### Population Zero + +Before selecting, crossover and mutation, we need a population to start with. Now that we have the universe defined we can write that function: + + ```swift + func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + guard lexicon.count > 1 else { return [] } + var pop = [[UInt8]]() + + (0.. Int { + guard dna.count == optimal.count else { return -1 } + var fitness = 0 + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) + } + return fitness +} +``` + +The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one unicode value off from the optimal (`H->G`). + +This example is very simple, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using a GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. In our example we will reach our goal, a fitness of 0. + +The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or be unable to reproduce. + +Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. A certain "branch" of evolution may beat out the current fittest solution at a later time. This may be ok depending on the problem, but to keep this educational we will go with the bio-inspired way. + +With all that, here is our weight choice function: + +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + + for item in items { + if n < item.weight { + return item + } + n = n - item.weight + } + return items[1] +} + + +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `Double.random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. + +## Mutation + +The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution. + +```swift +func mutate(lexicon: [UInt8], dna: [UInt8], mutationChance: Int) -> [UInt8] { + var outputDna = dna + (0.. [UInt8] { + let pos = Int.random(in: 0..?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray + +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// Size of each generation +let POP_SIZE = 50 + +// Max number of generations, script will stop when it reaches 5000 if the optimal value is not found +let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + var pop = [[UInt8]]() + + (0.. Int { + var fitness = 0 + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) + } + return fitness +} + +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + + for item in items { + if n < item.weight { + return item + } + n = n - item.weight + } + return items[1] +} + +func mutate(lexicon: [UInt8], dna: [UInt8], mutationChance: Int) -> [UInt8] { + var outputDna = dna + (0.. [UInt8] { + let pos = Int.random(in: 0.. + + + \ No newline at end of file diff --git a/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Genetic/gen.swift b/Genetic/gen.swift new file mode 100644 index 000000000..a61e61785 --- /dev/null +++ b/Genetic/gen.swift @@ -0,0 +1,148 @@ +//: Playground - noun: a place where people can play + +import Foundation + +extension String { + var unicodeArray: [UInt8] { + return [UInt8](self.utf8) + } +} + + +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray + +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// size of each generation +let POP_SIZE = 50 + +// max number of generations, script will stop when it reach 5000 if the optimal value is not found +let MAX_GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + +func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] +} + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + var pop = [[UInt8]]() + + (0.. Int { + var fitness = 0 + (0...dna.count-1).forEach { c in + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} + +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for item in items { + if n < item.weight { + return item + } + n = n - item.weight + } + return items[1] +} + +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { + var outputDna = dna + + (0.. [UInt8] { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) +} + +func main() { + + // generate the starting random population + var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) + // print("population: \(population), dnaSize: \(DNA_SIZE) ") + var fittest = [UInt8]() + + for generation in 0...MAX_GENERATIONS { + + var weightedPopulation = [(dna:[UInt8], weight:Double)]() + + // calulcated the fitness of each individual in the population + // and add it to the weight population (weighted = 1.0/fitness) + for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + + let pair = ( individual, fitnessValue == 0 ? 1.0 : Double(100/POP_SIZE)/Double( fitnessValue ) ) + + weightedPopulation.append(pair) + } + + population = [] + + // create a new generation using the individuals in the origional population + (0...POP_SIZE).forEach { _ in + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE) + + // append to the population and mutate + population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) + } + + fittest = population[0] + var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + + // parse the population for the fittest string + population.forEach { indv in + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } + } + if minFitness == 0 { break; } + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + + } + print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") +} + +main() diff --git a/Graph/Graph.playground/Contents.swift b/Graph/Graph.playground/Contents.swift new file mode 100644 index 000000000..fde396e64 --- /dev/null +++ b/Graph/Graph.playground/Contents.swift @@ -0,0 +1,41 @@ +import Graph + +for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { + + let v1 = graph.createVertex(1) + let v2 = graph.createVertex(2) + let v3 = graph.createVertex(3) + let v4 = graph.createVertex(4) + let v5 = graph.createVertex(5) + + // Set up a cycle like so: + // v5 + // ^ + // | (3.2) + // | + // v1 ---(1)---> v2 ---(1)---> v3 ---(4.5)---> v4 + // ^ | + // | V + // ---------<-----------<---------(2.8)----<----| + + graph.addDirectedEdge(v1, to: v2, withWeight: 1.0) + graph.addDirectedEdge(v2, to: v3, withWeight: 1.0) + graph.addDirectedEdge(v3, to: v4, withWeight: 4.5) + graph.addDirectedEdge(v4, to: v1, withWeight: 2.8) + graph.addDirectedEdge(v2, to: v5, withWeight: 3.2) + + // Returns the weight of the edge from v1 to v2 (1.0) + graph.weightFrom(v1, to: v2) + + // Returns the weight of the edge from v1 to v3 (nil, since there is not an edge) + graph.weightFrom(v1, to: v3) + + // Returns the weight of the edge from v3 to v4 (4.5) + graph.weightFrom(v3, to: v4) + + // Returns the weight of the edge from v4 to v1 (2.8) + graph.weightFrom(v4, to: v1) + + print(graph) + print() // separate by a newline +} diff --git a/Graph/Graph.playground/contents.xcplayground b/Graph/Graph.playground/contents.xcplayground new file mode 100644 index 000000000..50ce46d0b --- /dev/null +++ b/Graph/Graph.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Graph/Graph.playground/playground.xcworkspace/contents.xcworkspacedata b/Graph/Graph.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Graph/Graph.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph.playground/timeline.xctimeline b/Graph/Graph.playground/timeline.xctimeline new file mode 100644 index 000000000..59717856a --- /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 new file mode 100644 index 000000000..790f6ac18 --- /dev/null +++ b/Graph/Graph.xcodeproj/project.pbxproj @@ -0,0 +1,454 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 491AA3761CE6B81C00A2E2C5 /* AdjacencyListGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491AA3751CE6B81C00A2E2C5 /* AdjacencyListGraph.swift */; }; + 491AA3781CE6B82E00A2E2C5 /* AdjacencyMatrixGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491AA3771CE6B82E00A2E2C5 /* AdjacencyMatrixGraph.swift */; }; + 49BFA3011CDF886B00522D66 /* Graph.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BFA3001CDF886B00522D66 /* Graph.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49BFA3081CDF886B00522D66 /* Graph.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49BFA2FD1CDF886B00522D66 /* Graph.framework */; }; + 49BFA30D1CDF886B00522D66 /* GraphTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA30C1CDF886B00522D66 /* GraphTests.swift */; }; + 49BFA3181CDF887E00522D66 /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA3171CDF887E00522D66 /* Graph.swift */; }; + 49BFA3271CDF899400522D66 /* Edge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA3261CDF899400522D66 /* Edge.swift */; }; + 49BFA32F1CDF89FC00522D66 /* Vertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA32E1CDF89FC00522D66 /* Vertex.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 49BFA3091CDF886B00522D66 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 49BFA2F41CDF886B00522D66 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 49BFA2FC1CDF886B00522D66; + remoteInfo = Graph; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 491AA3751CE6B81C00A2E2C5 /* AdjacencyListGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdjacencyListGraph.swift; sourceTree = ""; }; + 491AA3771CE6B82E00A2E2C5 /* AdjacencyMatrixGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdjacencyMatrixGraph.swift; sourceTree = ""; }; + 49BFA2FD1CDF886B00522D66 /* Graph.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Graph.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 49BFA3001CDF886B00522D66 /* Graph.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Graph.h; sourceTree = ""; }; + 49BFA3021CDF886B00522D66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49BFA3071CDF886B00522D66 /* GraphTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GraphTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 49BFA30C1CDF886B00522D66 /* GraphTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphTests.swift; sourceTree = ""; }; + 49BFA30E1CDF886B00522D66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49BFA3171CDF887E00522D66 /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = ""; }; + 49BFA3261CDF899400522D66 /* Edge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Edge.swift; sourceTree = ""; }; + 49BFA32E1CDF89FC00522D66 /* Vertex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vertex.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 49BFA2F91CDF886B00522D66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA3041CDF886B00522D66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA3081CDF886B00522D66 /* Graph.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 49BFA2F31CDF886B00522D66 = { + isa = PBXGroup; + children = ( + 49BFA2FF1CDF886B00522D66 /* Graph */, + 49BFA30B1CDF886B00522D66 /* GraphTests */, + 49BFA2FE1CDF886B00522D66 /* Products */, + ); + sourceTree = ""; + }; + 49BFA2FE1CDF886B00522D66 /* Products */ = { + isa = PBXGroup; + children = ( + 49BFA2FD1CDF886B00522D66 /* Graph.framework */, + 49BFA3071CDF886B00522D66 /* GraphTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 49BFA2FF1CDF886B00522D66 /* Graph */ = { + isa = PBXGroup; + children = ( + 49BFA3001CDF886B00522D66 /* Graph.h */, + 49BFA3021CDF886B00522D66 /* Info.plist */, + 49BFA3261CDF899400522D66 /* Edge.swift */, + 49BFA32E1CDF89FC00522D66 /* Vertex.swift */, + 49BFA3171CDF887E00522D66 /* Graph.swift */, + 491AA3751CE6B81C00A2E2C5 /* AdjacencyListGraph.swift */, + 491AA3771CE6B82E00A2E2C5 /* AdjacencyMatrixGraph.swift */, + ); + path = Graph; + sourceTree = ""; + }; + 49BFA30B1CDF886B00522D66 /* GraphTests */ = { + isa = PBXGroup; + children = ( + 49BFA30C1CDF886B00522D66 /* GraphTests.swift */, + 49BFA30E1CDF886B00522D66 /* Info.plist */, + ); + path = GraphTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 49BFA2FA1CDF886B00522D66 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA3011CDF886B00522D66 /* Graph.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 49BFA2FC1CDF886B00522D66 /* Graph */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49BFA3111CDF886B00522D66 /* Build configuration list for PBXNativeTarget "Graph" */; + buildPhases = ( + 49BFA2F81CDF886B00522D66 /* Sources */, + 49BFA2F91CDF886B00522D66 /* Frameworks */, + 49BFA2FA1CDF886B00522D66 /* Headers */, + 49BFA2FB1CDF886B00522D66 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Graph; + productName = Graph; + productReference = 49BFA2FD1CDF886B00522D66 /* Graph.framework */; + productType = "com.apple.product-type.framework"; + }; + 49BFA3061CDF886B00522D66 /* GraphTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49BFA3141CDF886B00522D66 /* Build configuration list for PBXNativeTarget "GraphTests" */; + buildPhases = ( + 49BFA3031CDF886B00522D66 /* Sources */, + 49BFA3041CDF886B00522D66 /* Frameworks */, + 49BFA3051CDF886B00522D66 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 49BFA30A1CDF886B00522D66 /* PBXTargetDependency */, + ); + name = GraphTests; + productName = GraphTests; + productReference = 49BFA3071CDF886B00522D66 /* GraphTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 49BFA2F41CDF886B00522D66 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 49BFA2FC1CDF886B00522D66 = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0900; + }; + 49BFA3061CDF886B00522D66 = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 49BFA2F71CDF886B00522D66 /* Build configuration list for PBXProject "Graph" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 49BFA2F31CDF886B00522D66; + productRefGroup = 49BFA2FE1CDF886B00522D66 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 49BFA2FC1CDF886B00522D66 /* Graph */, + 49BFA3061CDF886B00522D66 /* GraphTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 49BFA2FB1CDF886B00522D66 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA3051CDF886B00522D66 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 49BFA2F81CDF886B00522D66 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 491AA3761CE6B81C00A2E2C5 /* AdjacencyListGraph.swift in Sources */, + 49BFA3271CDF899400522D66 /* Edge.swift in Sources */, + 491AA3781CE6B82E00A2E2C5 /* AdjacencyMatrixGraph.swift in Sources */, + 49BFA3181CDF887E00522D66 /* Graph.swift in Sources */, + 49BFA32F1CDF89FC00522D66 /* Vertex.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA3031CDF886B00522D66 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA30D1CDF886B00522D66 /* GraphTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 49BFA30A1CDF886B00522D66 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 49BFA2FC1CDF886B00522D66 /* Graph */; + targetProxy = 49BFA3091CDF886B00522D66 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 49BFA30F1CDF886B00522D66 /* 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 49BFA3101CDF886B00522D66 /* 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 49BFA3121CDF886B00522D66 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Graph/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.Graph"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 49BFA3131CDF886B00522D66 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Graph/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.Graph"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; + 49BFA3151CDF886B00522D66 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = GraphTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.GraphTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 49BFA3161CDF886B00522D66 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = GraphTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.GraphTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 49BFA2F71CDF886B00522D66 /* Build configuration list for PBXProject "Graph" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA30F1CDF886B00522D66 /* Debug */, + 49BFA3101CDF886B00522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 49BFA3111CDF886B00522D66 /* Build configuration list for PBXNativeTarget "Graph" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA3121CDF886B00522D66 /* Debug */, + 49BFA3131CDF886B00522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 49BFA3141CDF886B00522D66 /* Build configuration list for PBXNativeTarget "GraphTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA3151CDF886B00522D66 /* Debug */, + 49BFA3161CDF886B00522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 49BFA2F41CDF886B00522D66 /* Project object */; +} diff --git a/Graph/Graph.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Graph/Graph.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..94b2795e2 --- /dev/null +++ b/Graph/Graph.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme new file mode 100644 index 000000000..84c688e66 --- /dev/null +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/GraphTests.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/GraphTests.xcscheme new file mode 100644 index 000000000..7aa65b0e4 --- /dev/null +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/GraphTests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Graph/Graph.xcworkspace/contents.xcworkspacedata b/Graph/Graph.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..eea257206 --- /dev/null +++ b/Graph/Graph.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Graph/Graph.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Graph/Graph.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Graph/Graph/AdjacencyListGraph.swift b/Graph/Graph/AdjacencyListGraph.swift new file mode 100644 index 000000000..a24e732e7 --- /dev/null +++ b/Graph/Graph/AdjacencyListGraph.swift @@ -0,0 +1,131 @@ +// +// AdjacencyListGraph.swift +// Graph +// +// Created by Andrew McKnight on 5/13/16. +// + +import Foundation + +private class EdgeList where T: Hashable { + + var vertex: Vertex + var edges: [Edge]? + + init(vertex: Vertex) { + self.vertex = vertex + } + + func addEdge(_ edge: Edge) { + edges?.append(edge) + } + +} + +open class AdjacencyListGraph: AbstractGraph where T: Hashable { + + fileprivate var adjacencyList: [EdgeList] = [] + + public required init() { + super.init() + } + + public required init(fromGraph graph: AbstractGraph) { + super.init(fromGraph: graph) + } + + open override var vertices: [Vertex] { + var vertices = [Vertex]() + for edgeList in adjacencyList { + vertices.append(edgeList.vertex) + } + return vertices + } + + open override var edges: [Edge] { + var allEdges = Set>() + for edgeList in adjacencyList { + guard let edges = edgeList.edges else { + continue + } + + for edge in edges { + allEdges.insert(edge) + } + } + return Array(allEdges) + } + + 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 + } + + 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 != nil { + edgeList.addEdge(edge) + } else { + edgeList.edges = [edge] + } + } + + 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) + } + + open override func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + guard let edges = adjacencyList[sourceVertex.index].edges else { + return nil + } + + for edge: Edge in edges { + if edge.to == destinationVertex { + return edge.weight + } + } + + return nil + } + + open override func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { + return adjacencyList[sourceVertex.index].edges ?? [] + } + + open override var description: String { + var rows = [String]() + for edgeList in adjacencyList { + + 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) + } + + 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 new file mode 100644 index 000000000..4d3ae9731 --- /dev/null +++ b/Graph/Graph/AdjacencyMatrixGraph.swift @@ -0,0 +1,112 @@ +// +// AdjacencyMatrixGraph.swift +// Graph +// +// Created by Andrew McKnight on 5/13/16. +// + +import Foundation + +open class AdjacencyMatrixGraph: AbstractGraph where T: Hashable { + + // If adjacencyMatrix[i][j] is not nil, then there is an edge from + // vertex i to vertex j. + fileprivate var adjacencyMatrix: [[Double?]] = [] + fileprivate var _vertices: [Vertex] = [] + + public required init() { + super.init() + } + + public required init(fromGraph graph: AbstractGraph) { + super.init(fromGraph: graph) + } + + open override var vertices: [Vertex] { + return _vertices + } + + open override var edges: [Edge] { + 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 + } + + // Adds a new vertex to the matrix. + // 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 + 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: adjacencyMatrix.count) + + // 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?](repeating: nil, count: adjacencyMatrix.count + 1) + adjacencyMatrix.append(newRow) + + _vertices.append(vertex) + + return vertex + } + + open override func addDirectedEdge(_ from: Vertex, to: Vertex, withWeight weight: Double?) { + adjacencyMatrix[from.index][to.index] = weight + } + + 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) + } + + open override func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + return adjacencyMatrix[sourceVertex.index][destinationVertex.index] + } + + open override func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { + var outEdges = [Edge]() + let fromIndex = sourceVertex.index + for column in 0..: Equatable where T: Hashable { + + public let from: Vertex + public let to: Vertex + + public let weight: Double? + +} + +extension Edge: CustomStringConvertible { + + public var description: String { + guard let unwrappedWeight = weight else { + return "\(from.description) -> \(to.description)" + } + return "\(from.description) -(\(unwrappedWeight))-> \(to.description)" + } + +} + +extension Edge: Hashable { + + public func hash(into hasher: inout Hasher) { + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } + +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + guard lhs.from == rhs.from else { + return false + } + + guard lhs.to == rhs.to else { + return false + } + + guard lhs.weight == rhs.weight else { + return false + } + + return true +} diff --git a/Graph/Graph/Graph.h b/Graph/Graph/Graph.h new file mode 100644 index 000000000..085103b23 --- /dev/null +++ b/Graph/Graph/Graph.h @@ -0,0 +1,18 @@ +// +// Graph.h +// Graph +// +// Created by Andrew McKnight on 5/8/16. +// + +#import + +//! Project version number for Graph. +FOUNDATION_EXPORT double GraphVersionNumber; + +//! Project version string for Graph. +FOUNDATION_EXPORT const unsigned char GraphVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Graph/Graph/Graph.swift b/Graph/Graph/Graph.swift new file mode 100644 index 000000000..ddae4eddd --- /dev/null +++ b/Graph/Graph/Graph.swift @@ -0,0 +1,56 @@ +// +// Graph.swift +// Graph +// +// Created by Andrew McKnight on 5/8/16. +// + +import Foundation + +open class AbstractGraph: CustomStringConvertible where T: Hashable { + + public required init() {} + + public required init(fromGraph graph: AbstractGraph) { + for edge in graph.edges { + let from = createVertex(edge.from.data) + let to = createVertex(edge.to.data) + + addDirectedEdge(from, to: to, withWeight: edge.weight) + } + } + + open var description: String { + fatalError("abstract property accessed") + } + + open var vertices: [Vertex] { + fatalError("abstract property accessed") + } + + open var edges: [Edge] { + fatalError("abstract property accessed") + } + + // Adds a new vertex to the matrix. + // Performance: possibly O(n^2) because of the resizing of the matrix. + open func createVertex(_ data: T) -> Vertex { + fatalError("abstract function called") + } + + open func addDirectedEdge(_ from: Vertex, to: Vertex, withWeight weight: Double?) { + fatalError("abstract function called") + } + + open func addUndirectedEdge(_ vertices: (Vertex, Vertex), withWeight weight: Double?) { + fatalError("abstract function called") + } + + open func weightFrom(_ sourceVertex: Vertex, to destinationVertex: Vertex) -> Double? { + fatalError("abstract function called") + } + + open func edgesFrom(_ sourceVertex: Vertex) -> [Edge] { + fatalError("abstract function called") + } +} diff --git a/Heap Sort/HeapSort Tests/HeapSort/Info.plist b/Graph/Graph/Info.plist similarity index 67% rename from Heap Sort/HeapSort Tests/HeapSort/Info.plist rename to Graph/Graph/Info.plist index 0dca3caa8..d3de8eefb 100644 --- a/Heap Sort/HeapSort Tests/HeapSort/Info.plist +++ b/Graph/Graph/Info.plist @@ -6,8 +6,6 @@ en CFBundleExecutable $(EXECUTABLE_NAME) - CFBundleIconFile - CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion @@ -15,20 +13,14 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu + $(CURRENT_PROJECT_VERSION) NSPrincipalClass - NSApplication + diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift new file mode 100644 index 000000000..48645f0fa --- /dev/null +++ b/Graph/Graph/Vertex.swift @@ -0,0 +1,44 @@ +// +// Vertex.swift +// Graph +// +// Created by Andrew McKnight on 5/8/16. +// + +import Foundation + +public struct Vertex: Equatable where T: Hashable { + + public var data: T + public let index: Int + +} + +extension Vertex: CustomStringConvertible { + + public var description: String { + return "\(index): \(data)" + } + +} + +extension Vertex: Hashable { + + public func hasher(into hasher: inout Hasher) { + hasher.combine(data) + hasher.combine(index) + } + +} + +public func ==(lhs: Vertex, rhs: Vertex) -> Bool { + guard lhs.index == rhs.index else { + return false + } + + guard lhs.data == rhs.data else { + return false + } + + return true +} diff --git a/Graph/GraphTests/GraphTests.swift b/Graph/GraphTests/GraphTests.swift new file mode 100644 index 000000000..289d9aa64 --- /dev/null +++ b/Graph/GraphTests/GraphTests.swift @@ -0,0 +1,158 @@ +// +// GraphTests.swift +// GraphTests +// +// Created by Andrew McKnight on 5/8/16. +// + +import XCTest +@testable import Graph + +class GraphTests: XCTestCase { + + func testAdjacencyMatrixGraphDescription() { + + let graph = AdjacencyMatrixGraph() + + let a = graph.createVertex("a") + let b = graph.createVertex("b") + let c = graph.createVertex("c") + + graph.addDirectedEdge(a, to: b, withWeight: 1.0) + graph.addDirectedEdge(b, to: c, withWeight: 2.0) + + let expectedValue = " ø 1.0 ø \n ø ø 2.0 \n ø ø ø " + XCTAssertEqual(graph.description, expectedValue) + } + + func testAdjacencyListGraphDescription() { + + let graph = AdjacencyListGraph() + + let a = graph.createVertex("a") + let b = graph.createVertex("b") + let c = graph.createVertex("c") + + graph.addDirectedEdge(a, to: b, withWeight: 1.0) + graph.addDirectedEdge(b, to: c, withWeight: 2.0) + graph.addDirectedEdge(a, to: c, withWeight: -5.5) + + let expectedValue = "a -> [(b: 1.0), (c: -5.5)]\nb -> [(c: 2.0)]" + XCTAssertEqual(graph.description, expectedValue) + } + + func testAddingPreexistingVertex() { + let adjacencyList = AdjacencyListGraph() + let adjacencyMatrix = AdjacencyMatrixGraph() + + for graph in [adjacencyList, adjacencyMatrix] { + let a = graph.createVertex("a") + let b = graph.createVertex("a") + + XCTAssertEqual(a, b, "Should have returned the same vertex when creating a new one with identical data") + XCTAssertEqual(graph.vertices.count, 1, "Graph should only contain one vertex after trying to create two vertices with identical data") + } + } + + func testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(_ graphType: AbstractGraph.Type) { + let graph = graphType.init() + + let a = graph.createVertex(1) + let b = graph.createVertex(2) + + graph.addDirectedEdge(a, to: b, withWeight: 1.0) + + let edgesFromA = graph.edgesFrom(a) + let edgesFromB = graph.edgesFrom(b) + + XCTAssertEqual(edgesFromA.count, 1) + XCTAssertEqual(edgesFromB.count, 0) + + XCTAssertEqual(edgesFromA.first?.to, b) + } + + func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(_ graphType: AbstractGraph.Type) { + let graph = graphType.init() + + let a = graph.createVertex(1) + let b = graph.createVertex(2) + + graph.addUndirectedEdge((a, b), withWeight: 1.0) + + let edgesFromA = graph.edgesFrom(a) + let edgesFromB = graph.edgesFrom(b) + + XCTAssertEqual(edgesFromA.count, 1) + XCTAssertEqual(edgesFromB.count, 1) + + XCTAssertEqual(edgesFromA.first?.to, b) + XCTAssertEqual(edgesFromB.first?.to, a) + } + + func testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(_ graphType: AbstractGraph.Type) { + let graph = graphType.init() + + let a = graph.createVertex(1) + let b = graph.createVertex(2) + + XCTAssertEqual(graph.edgesFrom(a).count, 0) + XCTAssertEqual(graph.edgesFrom(b).count, 0) + } + + func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(_ graphType: AbstractGraph.Type) { + let graph = graphType.init() + let verticesCount = 100 + var vertices: [Vertex] = [] + + for i in 0...self) + } + + func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedMatrixGraph() { + testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyMatrixGraph.self) + } + + func testEdgesFromReturnsNoInNoEdgeMatrixGraph() { + testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyMatrixGraph.self) + } + + func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedMatrixGraph() { + testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyMatrixGraph.self) + } + + func testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedListGraph() { + testEdgesFromReturnsCorrectEdgeInSingleEdgeDirecedGraphWithType(AdjacencyListGraph.self) + } + + func testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedListGraph() { + testEdgesFromReturnsCorrectEdgeInSingleEdgeUndirectedGraphWithType(AdjacencyListGraph.self) + } + + func testEdgesFromReturnsNoInNoEdgeListGraph() { + testEdgesFromReturnsNoEdgesInNoEdgeGraphWithType(AdjacencyListGraph.self) + } + + func testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedListGraph() { + testEdgesFromReturnsCorrectEdgesInBiggerGraphInDirectedGraphWithType(AdjacencyListGraph.self) + } +} diff --git a/Graph/GraphTests/Info.plist b/Graph/GraphTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Graph/GraphTests/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/Graph/Images/AdjacencyList.graffle b/Graph/Images/AdjacencyList.graffle new file mode 100644 index 000000000..62132edca Binary files /dev/null and b/Graph/Images/AdjacencyList.graffle differ diff --git a/Graph/Images/AdjacencyList.png b/Graph/Images/AdjacencyList.png new file mode 100644 index 000000000..faf9d9170 Binary files /dev/null and b/Graph/Images/AdjacencyList.png differ diff --git a/Graph/Images/AdjacencyMatrix.graffle b/Graph/Images/AdjacencyMatrix.graffle new file mode 100644 index 000000000..644bbfea4 Binary files /dev/null and b/Graph/Images/AdjacencyMatrix.graffle differ diff --git a/Graph/Images/AdjacencyMatrix.png b/Graph/Images/AdjacencyMatrix.png new file mode 100644 index 000000000..1cac1caf5 Binary files /dev/null and b/Graph/Images/AdjacencyMatrix.png differ diff --git a/Graph/Images/ChordMap.graffle b/Graph/Images/ChordMap.graffle new file mode 100644 index 000000000..5f83ffd76 Binary files /dev/null and b/Graph/Images/ChordMap.graffle differ diff --git a/Graph/Images/ChordMap.png b/Graph/Images/ChordMap.png new file mode 100644 index 000000000..d3f9932b6 Binary files /dev/null and b/Graph/Images/ChordMap.png differ diff --git a/Graph/Images/CoreData.graffle b/Graph/Images/CoreData.graffle new file mode 100644 index 000000000..caa78ecad Binary files /dev/null and b/Graph/Images/CoreData.graffle differ diff --git a/Graph/Images/CoreData.png b/Graph/Images/CoreData.png new file mode 100644 index 000000000..b8ffdd07b Binary files /dev/null and b/Graph/Images/CoreData.png differ diff --git a/Graph/Images/DAG.graffle b/Graph/Images/DAG.graffle new file mode 100644 index 000000000..68cb09554 Binary files /dev/null and b/Graph/Images/DAG.graffle differ diff --git a/Graph/Images/DAG.png b/Graph/Images/DAG.png new file mode 100644 index 000000000..c26924ca9 Binary files /dev/null and b/Graph/Images/DAG.png differ diff --git a/Graph/Images/Demo1.graffle b/Graph/Images/Demo1.graffle new file mode 100644 index 000000000..dba0fb600 Binary files /dev/null and b/Graph/Images/Demo1.graffle differ diff --git a/Graph/Images/Demo1.png b/Graph/Images/Demo1.png new file mode 100644 index 000000000..53fa32c46 Binary files /dev/null and b/Graph/Images/Demo1.png differ diff --git a/Graph/Images/Flights.graffle b/Graph/Images/Flights.graffle new file mode 100644 index 000000000..4b0da6927 Binary files /dev/null and b/Graph/Images/Flights.graffle differ diff --git a/Graph/Images/Flights.png b/Graph/Images/Flights.png new file mode 100644 index 000000000..879dc131f Binary files /dev/null and b/Graph/Images/Flights.png differ diff --git a/Graph/Images/FlightsDirected.graffle b/Graph/Images/FlightsDirected.graffle new file mode 100644 index 000000000..79e7632b9 Binary files /dev/null and b/Graph/Images/FlightsDirected.graffle differ diff --git a/Graph/Images/FlightsDirected.png b/Graph/Images/FlightsDirected.png new file mode 100644 index 000000000..5a677e7c0 Binary files /dev/null and b/Graph/Images/FlightsDirected.png differ diff --git a/Graph/Images/Graph.graffle b/Graph/Images/Graph.graffle new file mode 100644 index 000000000..d329bb433 Binary files /dev/null and b/Graph/Images/Graph.graffle differ diff --git a/Graph/Images/Graph.png b/Graph/Images/Graph.png new file mode 100644 index 000000000..dd461a817 Binary files /dev/null and b/Graph/Images/Graph.png differ diff --git a/Graph/Images/SocialNetwork.graffle b/Graph/Images/SocialNetwork.graffle new file mode 100644 index 000000000..83baf8fd3 Binary files /dev/null and b/Graph/Images/SocialNetwork.graffle differ diff --git a/Graph/Images/SocialNetwork.png b/Graph/Images/SocialNetwork.png new file mode 100644 index 000000000..ca5f662ae Binary files /dev/null and b/Graph/Images/SocialNetwork.png differ diff --git a/Graph/Images/StateMachine.graffle b/Graph/Images/StateMachine.graffle new file mode 100644 index 000000000..a0cfc4bfc Binary files /dev/null and b/Graph/Images/StateMachine.graffle differ diff --git a/Graph/Images/StateMachine.png b/Graph/Images/StateMachine.png new file mode 100644 index 000000000..82ef5c8e4 Binary files /dev/null and b/Graph/Images/StateMachine.png differ diff --git a/Graph/Images/Tasks.graffle b/Graph/Images/Tasks.graffle new file mode 100644 index 000000000..e64c331c6 Binary files /dev/null and b/Graph/Images/Tasks.graffle differ diff --git a/Graph/Images/Tasks.png b/Graph/Images/Tasks.png new file mode 100644 index 000000000..a3f62ba9e Binary files /dev/null and b/Graph/Images/Tasks.png differ diff --git a/Graph/Images/TreeAndList.graffle b/Graph/Images/TreeAndList.graffle new file mode 100644 index 000000000..dc2a180ad Binary files /dev/null and b/Graph/Images/TreeAndList.graffle differ diff --git a/Graph/Images/TreeAndList.png b/Graph/Images/TreeAndList.png new file mode 100644 index 000000000..14004c9c6 Binary files /dev/null and b/Graph/Images/TreeAndList.png differ diff --git a/Graph/README.markdown b/Graph/README.markdown new file mode 100644 index 000000000..1331a07d3 --- /dev/null +++ b/Graph/README.markdown @@ -0,0 +1,285 @@ +# Graph + +> This topic has been tutorialized [here](https://www.raywenderlich.com/152046/swift-algorithm-club-graphs-adjacency-list) + + +A graph looks like the following picture: + +![A graph](Images/Graph.png) + +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 called "nodes", and edges are called "links". + +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 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*. 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 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) + +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/). They can be considered graphs but in a simpler form. They both have vertices (nodes) and edges (links). + +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 common type of graph is the *directed acyclic graph* or DAG: + +![DAG](Images/DAG.png) + +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 a graph is a useful data structure. + +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, 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. 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 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 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 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 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 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 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 and edge objects, but how do you describe this in code? + +There are two main strategies: adjacency list and adjacency matrix. + +**Adjacency List.** In an adjacency list implementation, each vertex stores a list of edges that originate from that vertex. For example, if vertex A has an edge to vertices B, C, and D, then vertex A would have a list containing 3 edges. + +![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. + +**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) + +Adding another vertex to the graph is expensive, because a new matrix structure must be created with enough space to hold the new row/column, and the existing structure must be copied into the new one. + +So which one should you use? Most of the time, the adjacency list is the right approach. What follows is a more detailed comparison between the two. + +Let *V* be the number of vertices in the graph, and *E* the number of edges. Then we have: + +| Operation | Adjacency List | Adjacency Matrix | +|-----------------|----------------|------------------| +| Storage Space | O(V + E) | O(V^2) | +| Add Vertex | O(1) | O(V^2) | +| Add Edge | O(1) | O(1) | +| Check Adjacency | O(V) | O(1) | + +"Checking adjacency" means that we try to determine that a given vertex is an immediate neighbor of another vertex. The time to check adjacency for an adjacency list is **O(V)**, because in the worst case a vertex is connected to *every* other vertex. + +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. + +Here are sample implementations of both adjacency list and adjacency matrix: + +## The code: edges and vertices + +The adjacency list for each vertex consists of `Edge` objects: + +```swift +public struct Edge: Equatable where T: Equatable, T: Hashable { + + public let from: Vertex + public let to: Vertex + + public let weight: Double? + +} +``` + +This struct describes the "from" and "to" vertices and a weight value. Note that an `Edge` object is always directed, a one-way connection (shown as arrows in the illustrations above). If you want an undirected connection, you also need to add an `Edge` object in the opposite direction. Each `Edge` optionally stores a weight, so they can be used to describe both weighted and unweighted graphs. + +The `Vertex` looks like this: + +```swift +public struct Vertex: Equatable where T: Equatable, T: Hashable { + + public var data: T + public let index: Int + +} +``` + +It stores arbitrary data with a generic type `T`, which is `Hashable` to enforce uniqueness, and also `Equatable`. Vertices themselves are also `Equatable`. + +## The code: graphs + +> **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 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 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: + +```swift +for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { + + let v1 = graph.createVertex(1) + let v2 = graph.createVertex(2) + let v3 = graph.createVertex(3) + let v4 = graph.createVertex(4) + let v5 = graph.createVertex(5) + + graph.addDirectedEdge(v1, to: v2, withWeight: 1.0) + graph.addDirectedEdge(v2, to: v3, withWeight: 1.0) + 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. For undirected graphs, we call the following method instead: + +```swift + graph.addUndirectedEdge(v1, to: v2, withWeight: 1.0) + graph.addUndirectedEdge(v2, to: v3, withWeight: 1.0) + graph.addUndirectedEdge(v3, to: v4, withWeight: 4.5) + graph.addUndirectedEdge(v4, to: v1, withWeight: 2.8) + graph.addUndirectedEdge(v2, to: v5, withWeight: 3.2) +``` + +We could provide `nil` as the values for the `withWeight` parameter in either case to make unweighted graphs. + +## The code: adjacency list + +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 where T: Equatable, T: Hashable { + + var vertex: Vertex + var edges: [Edge]? = nil + + init(vertex: Vertex) { + self.vertex = vertex + } + + 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 +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: + +``` +v1 -> [(v2: 1.0)] +v2 -> [(v3: 1.0), (v5: 3.2)] +v3 -> [(v4: 4.5)] +v4 -> [(v1: 2.8)] +``` + +where the general form `a -> [(b: w), ...]` means an edge exists from `a` to `b` with weight `w` (with possibly more edges connecting `a` to other vertices as well). + +## The code: adjacency matrix + +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: + +```swift +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: adjacencyMatrix.count) + + // 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?](repeating: nil, count: adjacencyMatrix.count + 1) + adjacencyMatrix.append(newRow) + + _vertices.append(vertex) + + return vertex +} +``` + +Then the adjacency matrix looks like this: + + [[nil, 1.0, nil, nil, nil] v1 + [nil, nil, 1.0, nil, 3.2] v2 + [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 + + +## See also + +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* diff --git a/Hash Set/HashSet.playground/Contents.swift b/Hash Set/HashSet.playground/Contents.swift index d49864fa3..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..3ccaa94ea --- /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/HashSet.playground/playground.xcworkspace/contents.xcworkspacedata b/Hash Set/HashSet.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Hash Set/HashSet.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Hash Set/HashSet.playground/timeline.xctimeline b/Hash Set/HashSet.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Hash Set/HashSet.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Hash Set/HashSet.swift b/Hash Set/HashSet.swift index 57f8f2219..303353574 100644 --- a/Hash Set/HashSet.swift +++ b/Hash Set/HashSet.swift @@ -1,26 +1,26 @@ 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 } diff --git a/Hash Set/README.markdown b/Hash Set/README.markdown index 8dcc891d3..fb829c313 100644 --- a/Hash Set/README.markdown +++ b/Hash Set/README.markdown @@ -11,7 +11,7 @@ If the following were arrays, they'd all be different. However, they all represe [1, 2, 2, 3, 1] ``` -(Because each element can appear only once, it doesn't matter how often you write it down -- only one of them counts.) +Because each element can appear only once, it doesn't matter how often you write the element down -- only one of them counts. > **Note:** I often prefer to use sets over arrays when I have a collection of objects but don't care what order they are in. Using a set communicates to the programmer that the order of the elements is unimportant. If you're using an array, then you can't assume the same thing. @@ -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 - } } ``` @@ -135,21 +139,21 @@ let union = setA.union(setB) union.allElements() // [5, 6, 2, 3, 1, 4] ``` -As you can see, the union of the two sets contains all of the elements now. The values `3` and `4` appear only once, even though they were in both sets. +As you can see, the union of the two sets contains all of the elements now. The values `3` and `4` still appear only once, even though they were in both sets. The *intersection* of two sets contains only the elements that they have in common. Here is the code: ```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 - } } ``` @@ -192,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. +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/Hash Table/HashTable.playground/Contents.swift b/Hash Table/HashTable.playground/Contents.swift index d5788176a..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..f2a1be040 --- /dev/null +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -0,0 +1,155 @@ +/* + 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 { + 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 } + + /** + 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) + } +} + +extension HashTable: CustomStringConvertible { + /// A string that represents the contents of the hash table. + public var description: String { + let pairs = buckets.flatMap { b in b.map { e in "\(e.key) = \(e.value)" } } + return pairs.joined(separator: ", ") + } + + /// A string that represents the contents of + /// the hash table, suitable for debugging. + public var debugDescription: String { + var str = "" + for (i, bucket) in buckets.enumerated() { + let pairs = bucket.map { e in "\(e.key) = \(e.value)" } + str += "bucket \(i): " + pairs.joined(separator: ", ") + "\n" + } + return str + } +} diff --git a/Hash Table/HashTable.playground/playground.xcworkspace/contents.xcworkspacedata b/Hash Table/HashTable.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Hash Table/HashTable.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + 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 da9ca9064..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 5afecabba..fb0bda788 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. +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 a hash table works +## 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, it uses the 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 than two or more keys get assigned the same array index. This is called a collision. +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. +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,47 +91,45 @@ There are a few ways to handle collisions. A common one is to use chaining. The +-----+ ``` -Keys are not stored directly in the array. Instead, each element in the array is really a list of 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 item 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.) +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. But you can improve the odds by giving the hash table enough buckets and by using high-quality hash functions. +Chains should not become long because looking up items in the hash table would become a slow process. 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 an 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 { 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)) } ``` -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 `Element`s. +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 bythe `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: @@ -139,17 +137,17 @@ 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 indexForKey(key: Key) -> Int { - return abs(key.hashValue) % buckets.count + private func index(forKey key: Key) -> Int { + return abs(key.hashValue % buckets.count) } ``` -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 @@ -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:)`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 @@ -196,17 +193,16 @@ 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 `indexForKey()` to convert the key into an array index. That gives us the bucket, 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`. - -The code to insert 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? { - 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() { + for (i, element) in buckets[index].enumerated() { if element.key == key { let oldValue = element.value buckets[index][i].value = value @@ -221,20 +217,20 @@ The code to insert or update an existing element lives in `updateValue(forKey)`. } ``` -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: ```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 } @@ -243,22 +239,22 @@ Removing is similar in that again it loops through the chain: } ``` -And these are the basic functions of the hash table. They all work the same way: convert the key into an array index using its hash value, then loop through the chain for that bucket and perform the desired operation. +These are the basic functions of the hash table. They all work the same way: convert the key into an array index using its hash value, find the bucket, then loop through that bucket's chain and perform the desired operation. Try this stuff out in a playground. It should work just like a standard Swift `Dictionary`. ## 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! +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* diff --git a/Hashed Heap/HashedHeap.swift b/Hashed Heap/HashedHeap.swift new file mode 100644 index 000000000..106cdacb0 --- /dev/null +++ b/Hashed Heap/HashedHeap.swift @@ -0,0 +1,250 @@ +// Written by Alejandro Isaza. Adapted from heap implementation written by Kevin Randrup and Matthijs Hollemans. + +/// Heap with an index hash map (dictionary) to speed up lookups by value. +/// +/// A heap keeps elements ordered in a binary tree without the use of pointers. A hashed heap does that as well as +/// having amortized constant lookups by value. This is used in the A* and other heuristic search algorithms to achieve +/// optimal performance. +public struct HashedHeap { + /// The array that stores the heap's nodes. + private(set) var elements = [T]() + + /// Hash mapping from elements to indices in the `elements` array. + private(set) var indices = [T: Int]() + + /// Determines whether this is a max-heap (>) or min-heap (<). + fileprivate var isOrderedBefore: (T, T) -> Bool + + /// Creates an empty hashed 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) { + isOrderedBefore = sort + } + + /// Creates a hashed 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. + /// + /// - Complexity: O(n) + public init(array: [T], sort: @escaping (T, T) -> Bool) { + isOrderedBefore = sort + build(from: array) + } + + /// Converts an array to a max-heap or min-heap in a bottom-up manner. + /// + /// - Complexity: O(n) + private mutating func build(from array: [T]) { + elements = array + for index in elements.indices { + indices[elements[index]] = index + } + + for i in stride(from: (elements.count/2 - 1), through: 0, by: -1) { + shiftDown(i, heapSize: elements.count) + } + } + + /// Whether the heap is empty. + public var isEmpty: Bool { + return elements.isEmpty + } + + /// The number of elements in the heap. + public var count: Int { + return elements.count + } + + /// Accesses an element by its index. + public subscript(index: Int) -> T { + return elements[index] + } + + /// Returns the index of the given element. + /// + /// This is the operation that a hashed heap optimizes in compassion with a normal heap. In a normal heap this + /// would take O(n), but for the hashed heap this takes amortized constatn time. + /// + /// - Complexity: Amortized constant + public func index(of element: T) -> Int? { + return indices[element] + } + + /// Returns the maximum value in the heap (for a max-heap) or the minimum value (for a min-heap). + /// + /// - Complexity: O(1) + 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. + /// + /// - Complexity: O(log n) + public mutating func insert(_ value: T) { + elements.append(value) + indices[value] = elements.count - 1 + shiftUp(elements.count - 1) + } + + /// Adds new values to the heap. + public mutating func insert(_ sequence: S) where S.Iterator.Element == T { + for value in sequence { + insert(value) + } + } + + /// Replaces an element in the hash. + /// + /// 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(_ value: T, at index: Int) { + guard index < elements.count else { return } + + assert(isOrderedBefore(value, elements[index])) + set(value, at: index) + shiftUp(index) + } + + /// 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. + /// + /// - Complexity: O(log n) + @discardableResult + public mutating func remove() -> T? { + if elements.isEmpty { + return nil + } else if elements.count == 1 { + return 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] + set(removeLast(), at: 0) + shiftDown() + return value + } + } + + /// Removes an arbitrary node from the heap. + /// + /// You need to know the node's index, which may actually take O(n) steps to find. + /// + /// - Complexity: O(log n). + public mutating func remove(at index: Int) -> T? { + guard index < elements.count else { return nil } + + let size = elements.count - 1 + if index != size { + swapAt(index, size) + shiftDown(index, heapSize: size) + shiftUp(index) + } + return removeLast() + } + + /// Removes all elements from the heap. + public mutating func removeAll() { + elements.removeAll() + indices.removeAll() + } + + /// Removes the last element from the heap. + /// + /// - Complexity: O(1) + public mutating func removeLast() -> T { + guard let value = elements.last else { + preconditionFailure("Trying to remove element from empty heap") + } + indices[value] = nil + 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(of: childIndex) + + while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { + set(elements[parentIndex], at: childIndex) + childIndex = parentIndex + parentIndex = self.parentIndex(of: childIndex) + } + + set(child, at: childIndex) + } + + 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(of: 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 } + + swapAt(parentIndex, first) + parentIndex = first + } + } + + /// Replaces an element in the heap and updates the indices hash. + private mutating func set(_ newValue: T, at index: Int) { + indices[elements[index]] = nil + elements[index] = newValue + indices[newValue] = index + } + + /// Swap two elements in the heap and update the indices hash. + private mutating func swapAt(_ i: Int, _ j: Int) { + elements.swapAt(i, j) + indices[elements[i]] = i + indices[elements[j]] = j + } + + /// Returns the index of the parent of the element at index i. + /// + /// - Note: The element at index 0 is the root of the tree and has no parent. + @inline(__always) + func parentIndex(of index: Int) -> Int { + return (index - 1) / 2 + } + + /// Returns the index of the left child of the element at index i. + /// + /// - Note: this index can be greater than the heap size, in which case there is no left child. + @inline(__always) + func leftChildIndex(of index: Int) -> Int { + return 2*index + 1 + } + + /// Returns the index of the right child of the element at index i. + /// + /// - Note: this index can be greater than the heap size, in which case there is no right child. + @inline(__always) + func rightChildIndex(of index: Int) -> Int { + return 2*index + 2 + } +} diff --git a/Hashed Heap/README.markdown b/Hashed Heap/README.markdown new file mode 100644 index 000000000..8a4fece02 --- /dev/null +++ b/Hashed Heap/README.markdown @@ -0,0 +1,13 @@ +# Hashed Heap + +A hashed heap is a [heap](../Heap/) with a hash map (also known as a dictionary) to speed up lookup of elements by value. This combination doesn't compromize on time performance but requires extra storage for the hash map. This is mainly used for heuristic search algorihms, in particular A*. + +## The code + +See [HashedHeap.swift](HashedHeap.swift) for the implementation. See [Heap](../Heap/) for a detailed explanation of the basic heap implementation. + +## See also + +[Heap on Wikipedia](https://en.wikipedia.org/wiki/Heap_%28data_structure%29) + +*Written for the Swift Algorithm Club by [Alejandro Isaza](https://github.com/aleph7)* diff --git a/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.pbxproj b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..01f5fae50 --- /dev/null +++ b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.pbxproj @@ -0,0 +1,284 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3FC1C77A658003CECC7 /* HashedHeap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3FB1C77A658003CECC7 /* HashedHeap.swift */; }; + 7B80C3FE1C77A65E003CECC7 /* HashedHeapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3FD1C77A65E003CECC7 /* HashedHeapTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 7B2BBC801C779D720067B71D /* Hashed Heap Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Hashed Heap Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 7B80C3FB1C77A658003CECC7 /* HashedHeap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HashedHeap.swift; path = ../HashedHeap.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3FD1C77A65E003CECC7 /* HashedHeapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HashedHeapTests.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 /* Hashed Heap Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 7B80C3FB1C77A658003CECC7 /* HashedHeap.swift */, + 7B80C3FD1C77A65E003CECC7 /* HashedHeapTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* Hashed Heap Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Hashed Heap Tests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Hashed Heap Tests"; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* Hashed Heap 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 = 0900; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Hashed Heap Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* Hashed Heap 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 = ( + 7B80C3FE1C77A65E003CECC7 /* HashedHeapTests.swift in Sources */, + 7B80C3FC1C77A658003CECC7 /* HashedHeap.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Hashed Heap Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Hashed Heap Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/xcshareddata/xcschemes/Hashed Heap Tests.xcscheme b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/xcshareddata/xcschemes/Hashed Heap Tests.xcscheme new file mode 100644 index 000000000..3f298101d --- /dev/null +++ b/Hashed Heap/Tests/Hashed Heap Tests.xcodeproj/xcshareddata/xcschemes/Hashed Heap Tests.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Hashed Heap/Tests/HashedHeapTests.swift b/Hashed Heap/Tests/HashedHeapTests.swift new file mode 100755 index 000000000..895a21c63 --- /dev/null +++ b/Hashed Heap/Tests/HashedHeapTests.swift @@ -0,0 +1,96 @@ +import Foundation +import XCTest + +private struct Message: Hashable { + let text: String + let priority: Int + + var hashValue: Int { + return text.hashValue + } + + static func == (lhs: Message, rhs: Message) -> Bool { + return lhs.text == rhs.text + } + + static func < (m1: Message, m2: Message) -> Bool { + return m1.priority < m2.priority + } +} + +class HashedHeapTest: XCTestCase { + override func setUp() { + super.setUp() + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + func testEmpty() { + var queue = HashedHeap(sort: <) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.peek()) + XCTAssertNil(queue.remove()) + } + + func testOneElement() { + var queue = HashedHeap(sort: <) + + queue.insert(Message(text: "hello", priority: 100)) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 1) + XCTAssertEqual(queue.peek()!.priority, 100) + + let result = queue.remove() + XCTAssertEqual(result!.priority, 100) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.peek()) + } + + func testTwoElementsInOrder() { + var queue = HashedHeap(sort: <) + + queue.insert(Message(text: "hello", priority: 100)) + queue.insert(Message(text: "world", priority: 200)) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 2) + XCTAssertEqual(queue.peek()!.priority, 100) + + let result1 = queue.remove() + XCTAssertEqual(result1!.priority, 100) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 1) + XCTAssertEqual(queue.peek()!.priority, 200) + + let result2 = queue.remove() + XCTAssertEqual(result2!.priority, 200) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.peek()) + } + + func testTwoElementsOutOfOrder() { + var queue = HashedHeap(sort: <) + + queue.insert(Message(text: "world", priority: 200)) + queue.insert(Message(text: "hello", priority: 100)) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 2) + XCTAssertEqual(queue.peek()!.priority, 100) + + let result1 = queue.remove() + XCTAssertEqual(result1!.priority, 100) + XCTAssertFalse(queue.isEmpty) + XCTAssertEqual(queue.count, 1) + XCTAssertEqual(queue.peek()!.priority, 200) + + let result2 = queue.remove() + XCTAssertEqual(result2!.priority, 200) + XCTAssertTrue(queue.isEmpty) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.peek()) + } +} diff --git a/Hashed Heap/Tests/Info.plist b/Hashed Heap/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Hashed Heap/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/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift new file mode 100644 index 000000000..ed89b4462 --- /dev/null +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -0,0 +1,30 @@ +import UIKit + +func haversineDistance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { + + let haversin = { (angle: Double) -> Double in + return (1 - cos(angle))/2 + } + + 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 * .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. +haversineDistance(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..4d5f20e6a --- /dev/null +++ b/HaversineDistance/README.md @@ -0,0 +1,25 @@ +# 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. + +*Written for Swift Algorithm Club by Jaap Wijnen.* diff --git a/Heap Sort/HeapSort Tests/HeapSort.xcodeproj/project.pbxproj b/Heap Sort/HeapSort Tests/HeapSort.xcodeproj/project.pbxproj deleted file mode 100644 index f6da3b7db..000000000 --- a/Heap Sort/HeapSort Tests/HeapSort.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B1BFA451C69158D0051C9A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA441C69158D0051C9A4 /* AppDelegate.swift */; }; - 7B1BFA471C69158D0051C9A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA461C69158D0051C9A4 /* Assets.xcassets */; }; - 7B1BFA4A1C69158D0051C9A4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA481C69158D0051C9A4 /* MainMenu.xib */; }; - 7B1BFA551C69158D0051C9A4 /* HeapSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA541C69158D0051C9A4 /* HeapSortTests.swift */; }; - 7B1BFA601C69159D0051C9A4 /* HeapSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA5F1C69159D0051C9A4 /* HeapSort.swift */; }; - 7B1BFA621C6915A70051C9A4 /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA611C6915A70051C9A4 /* Heap.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B1BFA511C69158D0051C9A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B1BFA391C69158D0051C9A4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B1BFA401C69158D0051C9A4; - remoteInfo = HeapSort; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B1BFA411C69158D0051C9A4 /* HeapSort.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HeapSort.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA441C69158D0051C9A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B1BFA461C69158D0051C9A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B1BFA491C69158D0051C9A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B1BFA4B1C69158D0051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA501C69158D0051C9A4 /* HeapSortTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HeapSortTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA541C69158D0051C9A4 /* HeapSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeapSortTests.swift; sourceTree = ""; }; - 7B1BFA561C69158D0051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA5F1C69159D0051C9A4 /* HeapSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HeapSort.swift; path = ../../HeapSort.swift; sourceTree = ""; }; - 7B1BFA611C6915A70051C9A4 /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../../../Heap/Heap.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B1BFA3E1C69158D0051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA4D1C69158D0051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B1BFA381C69158D0051C9A4 = { - isa = PBXGroup; - children = ( - 7B1BFA431C69158D0051C9A4 /* HeapSort */, - 7B1BFA531C69158D0051C9A4 /* HeapSortTests */, - 7B1BFA421C69158D0051C9A4 /* Products */, - ); - sourceTree = ""; - }; - 7B1BFA421C69158D0051C9A4 /* Products */ = { - isa = PBXGroup; - children = ( - 7B1BFA411C69158D0051C9A4 /* HeapSort.app */, - 7B1BFA501C69158D0051C9A4 /* HeapSortTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B1BFA431C69158D0051C9A4 /* HeapSort */ = { - isa = PBXGroup; - children = ( - 7B1BFA441C69158D0051C9A4 /* AppDelegate.swift */, - 7B1BFA461C69158D0051C9A4 /* Assets.xcassets */, - 7B1BFA611C6915A70051C9A4 /* Heap.swift */, - 7B1BFA5F1C69159D0051C9A4 /* HeapSort.swift */, - 7B1BFA4B1C69158D0051C9A4 /* Info.plist */, - 7B1BFA481C69158D0051C9A4 /* MainMenu.xib */, - ); - path = HeapSort; - sourceTree = ""; - }; - 7B1BFA531C69158D0051C9A4 /* HeapSortTests */ = { - isa = PBXGroup; - children = ( - 7B1BFA541C69158D0051C9A4 /* HeapSortTests.swift */, - 7B1BFA561C69158D0051C9A4 /* Info.plist */, - ); - path = HeapSortTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B1BFA401C69158D0051C9A4 /* HeapSort */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA591C69158D0051C9A4 /* Build configuration list for PBXNativeTarget "HeapSort" */; - buildPhases = ( - 7B1BFA3D1C69158D0051C9A4 /* Sources */, - 7B1BFA3E1C69158D0051C9A4 /* Frameworks */, - 7B1BFA3F1C69158D0051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = HeapSort; - productName = HeapSort; - productReference = 7B1BFA411C69158D0051C9A4 /* HeapSort.app */; - productType = "com.apple.product-type.application"; - }; - 7B1BFA4F1C69158D0051C9A4 /* HeapSortTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA5C1C69158D0051C9A4 /* Build configuration list for PBXNativeTarget "HeapSortTests" */; - buildPhases = ( - 7B1BFA4C1C69158D0051C9A4 /* Sources */, - 7B1BFA4D1C69158D0051C9A4 /* Frameworks */, - 7B1BFA4E1C69158D0051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B1BFA521C69158D0051C9A4 /* PBXTargetDependency */, - ); - name = HeapSortTests; - productName = HeapSortTests; - productReference = 7B1BFA501C69158D0051C9A4 /* HeapSortTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B1BFA391C69158D0051C9A4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B1BFA401C69158D0051C9A4 = { - CreatedOnToolsVersion = 7.2; - }; - 7B1BFA4F1C69158D0051C9A4 = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B1BFA401C69158D0051C9A4; - }; - }; - }; - buildConfigurationList = 7B1BFA3C1C69158D0051C9A4 /* Build configuration list for PBXProject "HeapSort" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B1BFA381C69158D0051C9A4; - productRefGroup = 7B1BFA421C69158D0051C9A4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B1BFA401C69158D0051C9A4 /* HeapSort */, - 7B1BFA4F1C69158D0051C9A4 /* HeapSortTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B1BFA3F1C69158D0051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA471C69158D0051C9A4 /* Assets.xcassets in Resources */, - 7B1BFA4A1C69158D0051C9A4 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA4E1C69158D0051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B1BFA3D1C69158D0051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA621C6915A70051C9A4 /* Heap.swift in Sources */, - 7B1BFA451C69158D0051C9A4 /* AppDelegate.swift in Sources */, - 7B1BFA601C69159D0051C9A4 /* HeapSort.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA4C1C69158D0051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA551C69158D0051C9A4 /* HeapSortTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B1BFA521C69158D0051C9A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B1BFA401C69158D0051C9A4 /* HeapSort */; - targetProxy = 7B1BFA511C69158D0051C9A4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B1BFA481C69158D0051C9A4 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B1BFA491C69158D0051C9A4 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B1BFA571C69158D0051C9A4 /* 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; - }; - 7B1BFA581C69158D0051C9A4 /* 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; - }; - 7B1BFA5A1C69158D0051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B1BFA5B1C69158D0051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B1BFA5D1C69158D0051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HeapSort.app/Contents/MacOS/HeapSort"; - }; - name = Debug; - }; - 7B1BFA5E1C69158D0051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HeapSort.app/Contents/MacOS/HeapSort"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B1BFA3C1C69158D0051C9A4 /* Build configuration list for PBXProject "HeapSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA571C69158D0051C9A4 /* Debug */, - 7B1BFA581C69158D0051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA591C69158D0051C9A4 /* Build configuration list for PBXNativeTarget "HeapSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA5A1C69158D0051C9A4 /* Debug */, - 7B1BFA5B1C69158D0051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA5C1C69158D0051C9A4 /* Build configuration list for PBXNativeTarget "HeapSortTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA5D1C69158D0051C9A4 /* Debug */, - 7B1BFA5E1C69158D0051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B1BFA391C69158D0051C9A4 /* Project object */; -} diff --git a/Heap Sort/HeapSort Tests/HeapSort/AppDelegate.swift b/Heap Sort/HeapSort Tests/HeapSort/AppDelegate.swift deleted file mode 100644 index 08b4b6f47..000000000 --- a/Heap Sort/HeapSort Tests/HeapSort/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// HeapSort -// -// Created by Matthijs Hollemans on 08-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Heap Sort/HeapSort Tests/HeapSort/Assets.xcassets/AppIcon.appiconset/Contents.json b/Heap Sort/HeapSort Tests/HeapSort/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Heap Sort/HeapSort Tests/HeapSort/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/Heap Sort/HeapSort Tests/HeapSort/Base.lproj/MainMenu.xib b/Heap Sort/HeapSort Tests/HeapSort/Base.lproj/MainMenu.xib deleted file mode 100644 index cb25f88b2..000000000 --- a/Heap Sort/HeapSort Tests/HeapSort/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Heap Sort/HeapSort.swift b/Heap Sort/HeapSort.swift index ec5b4a478..0354817a6 100644 --- a/Heap Sort/HeapSort.swift +++ b/Heap Sort/HeapSort.swift @@ -1,18 +1,18 @@ 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) + for i in stride(from: (nodes.count - 1), through: 1, by: -1) { + nodes.swapAt(0, i) + shiftDown(from: 0, until: i) } - return elements + return nodes } } /* - 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] { + 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: @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/README.markdown b/Heap Sort/README.markdown index 84f978931..5bec58626 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -18,16 +18,16 @@ The heap's internal array is then: [ 25, 13, 20, 8, 7, 17, 2, 5, 4 ] -That's hardly what you'd call sorted! But now the sorting process starts: we swap the first element (index *0*) with the last one (index *n-1*) to get: +That's hardly what you'd call sorted! But now the sorting process starts: we swap the first element (index *0*) with the last one at index *n-1*, to get: [ 4, 13, 20, 8, 7, 17, 2, 5, 25 ] * * -Now the new root node, `4`, will be smaller than its children, so we fix up the max-heap up to element to *n-2* using the *shift down* or "heapify" procedure. After repairing the heap, the new root is now the second-largest item in the array: +Now the new root node, `4`, will be smaller than its children, so we fix up the max-heap up to element *n-2* using the *shift down* or "heapify" procedure. After repairing the heap, the new root is now the second-largest item in the array: [20, 13, 17, 8, 7, 4, 2, 5 | 25] -Important: When we fix the heap, we ignore the last item. That now contains the array's maximum value, so it is in its final sorted place already. The `|` bar indicates where the sorted portion of the array begins. We'll leave that part of the array alone from now on. +Important: When we fix the heap, we ignore the last item at index *n-1*. That now contains the array's maximum value, so it is in its final sorted place already. The `|` bar indicates where the sorted portion of the array begins. We'll leave that part of the array alone from now on. Again, we swap the first element with the last one (this time at index *n-2*): @@ -40,18 +40,18 @@ 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. +Performance of heap sort is **O(n log n)** in best, worst, and average case. Because we modify the array directly, heap sort can be performed in-place. But it is not a stable sort: the relative order of identical elements is not preserved. Here's how you can implement heap sort in Swift: ```swift 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 } @@ -67,10 +67,10 @@ let a1 = h1.sort() Because we need a max-heap to sort from low-to-high, you need to give `Heap` the reverse of the sort function. To sort `<`, the `Heap` object must be created with `>` as the sort function. In other words, sorting from low-to-high creates a max-heap and turns it into a min-heap. -We can write a helper function for that: +We can write a handy helper function for that: ```swift -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/HeapSort Tests/HeapSortTests/HeapSortTests.swift b/Heap Sort/Tests/HeapSortTests.swift similarity index 80% rename from Heap Sort/HeapSort Tests/HeapSortTests/HeapSortTests.swift rename to Heap Sort/Tests/HeapSortTests.swift index 70304fea7..dae1f8a68 100644 --- a/Heap Sort/HeapSort Tests/HeapSortTests/HeapSortTests.swift +++ b/Heap Sort/Tests/HeapSortTests.swift @@ -1,34 +1,26 @@ -// -// HeapSortTests.swift -// HeapSortTests -// -// Created by Matthijs Hollemans on 08-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - import XCTest -@testable import HeapSort class HeapSortTests: XCTestCase { + func testSort() { var h1 = Heap(array: [5, 13, 2, 25, 7, 17, 20, 8, 4], sort: >) let a1 = h1.sort() XCTAssertEqual(a1, [2, 4, 5, 7, 8, 13, 17, 20, 25]) - + let a1_ = heapsort([5, 13, 2, 25, 7, 17, 20, 8, 4], <) XCTAssertEqual(a1_, [2, 4, 5, 7, 8, 13, 17, 20, 25]) - + var h2 = Heap(array: [16, 14, 10, 8, 7, 8, 3, 2, 4, 1], sort: >) let a2 = h2.sort() XCTAssertEqual(a2, [1, 2, 3, 4, 7, 8, 8, 10, 14, 16]) - + let a2_ = heapsort([16, 14, 10, 8, 7, 8, 3, 2, 4, 1], <) XCTAssertEqual(a2_, [1, 2, 3, 4, 7, 8, 8, 10, 14, 16]) - + var h3 = Heap(array: [1, 2, 3, 4, 5, 6], sort: <) let a3 = h3.sort() XCTAssertEqual(a3, [6, 5, 4, 3, 2, 1]) - + let a3_ = heapsort([1, 2, 3, 4, 5, 6], >) XCTAssertEqual(a3_, [6, 5, 4, 3, 2, 1]) } diff --git a/Heap Sort/Tests/Info.plist b/Heap Sort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Heap Sort/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/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..62e6d4e3f --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,298 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3E01C77A3DB003CECC7 /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3DF1C77A3DB003CECC7 /* Heap.swift */; }; + 7B80C3E21C77A3E5003CECC7 /* HeapSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E11C77A3E5003CECC7 /* HeapSort.swift */; }; + 7B80C3E41C77A3EB003CECC7 /* HeapSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E31C77A3EB003CECC7 /* HeapSortTests.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; }; + 7B80C3DF1C77A3DB003CECC7 /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../../Heap/Heap.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3E11C77A3E5003CECC7 /* HeapSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HeapSort.swift; path = ../HeapSort.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3E31C77A3EB003CECC7 /* HeapSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeapSortTests.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 = ( + 7B80C3DF1C77A3DB003CECC7 /* Heap.swift */, + 7B80C3E11C77A3E5003CECC7 /* HeapSort.swift */, + 7B80C3E31C77A3EB003CECC7 /* HeapSortTests.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 = 1010; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1010; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 10.0"; + 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 = ( + 7B80C3E01C77A3DB003CECC7 /* Heap.swift in Sources */, + 7B80C3E41C77A3EB003CECC7 /* HeapSortTests.swift in Sources */, + 7B80C3E21C77A3E5003CECC7 /* HeapSort.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + 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 = 4.2; + }; + 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 = 4.2; + }; + 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/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..1608804f9 --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Heap/Heap Tests/Heap.xcodeproj/project.pbxproj b/Heap/Heap Tests/Heap.xcodeproj/project.pbxproj deleted file mode 100644 index c0fd77f65..000000000 --- a/Heap/Heap Tests/Heap.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18DF9F1C5BF41B005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18DF9E1C5BF41B005A2B8E /* AppDelegate.swift */; }; - 7B18DFA11C5BF41B005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18DFA01C5BF41B005A2B8E /* Assets.xcassets */; }; - 7B18DFA41C5BF41B005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18DFA21C5BF41B005A2B8E /* MainMenu.xib */; }; - 7B18DFAF1C5BF41B005A2B8E /* HeapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18DFAE1C5BF41B005A2B8E /* HeapTests.swift */; }; - 7B18DFBA1C5BF465005A2B8E /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18DFB91C5BF465005A2B8E /* Heap.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18DFAB1C5BF41B005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18DF931C5BF41B005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18DF9A1C5BF41B005A2B8E; - remoteInfo = Heap; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18DF9B1C5BF41B005A2B8E /* Heap.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Heap.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18DF9E1C5BF41B005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18DFA01C5BF41B005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18DFA31C5BF41B005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18DFA51C5BF41B005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18DFAA1C5BF41B005A2B8E /* HeapTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HeapTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18DFAE1C5BF41B005A2B8E /* HeapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeapTests.swift; sourceTree = ""; }; - 7B18DFB01C5BF41B005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18DFB91C5BF465005A2B8E /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../../Heap.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18DF981C5BF41B005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFA71C5BF41B005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18DF921C5BF41B005A2B8E = { - isa = PBXGroup; - children = ( - 7B18DF9D1C5BF41B005A2B8E /* Heap */, - 7B18DFAD1C5BF41B005A2B8E /* HeapTests */, - 7B18DF9C1C5BF41B005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18DF9C1C5BF41B005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18DF9B1C5BF41B005A2B8E /* Heap.app */, - 7B18DFAA1C5BF41B005A2B8E /* HeapTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18DF9D1C5BF41B005A2B8E /* Heap */ = { - isa = PBXGroup; - children = ( - 7B18DF9E1C5BF41B005A2B8E /* AppDelegate.swift */, - 7B18DFA01C5BF41B005A2B8E /* Assets.xcassets */, - 7B18DFB91C5BF465005A2B8E /* Heap.swift */, - 7B18DFA51C5BF41B005A2B8E /* Info.plist */, - 7B18DFA21C5BF41B005A2B8E /* MainMenu.xib */, - ); - path = Heap; - sourceTree = ""; - }; - 7B18DFAD1C5BF41B005A2B8E /* HeapTests */ = { - isa = PBXGroup; - children = ( - 7B18DFAE1C5BF41B005A2B8E /* HeapTests.swift */, - 7B18DFB01C5BF41B005A2B8E /* Info.plist */, - ); - path = HeapTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18DF9A1C5BF41B005A2B8E /* Heap */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18DFB31C5BF41B005A2B8E /* Build configuration list for PBXNativeTarget "Heap" */; - buildPhases = ( - 7B18DF971C5BF41B005A2B8E /* Sources */, - 7B18DF981C5BF41B005A2B8E /* Frameworks */, - 7B18DF991C5BF41B005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Heap; - productName = Heap; - productReference = 7B18DF9B1C5BF41B005A2B8E /* Heap.app */; - productType = "com.apple.product-type.application"; - }; - 7B18DFA91C5BF41B005A2B8E /* HeapTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18DFB61C5BF41B005A2B8E /* Build configuration list for PBXNativeTarget "HeapTests" */; - buildPhases = ( - 7B18DFA61C5BF41B005A2B8E /* Sources */, - 7B18DFA71C5BF41B005A2B8E /* Frameworks */, - 7B18DFA81C5BF41B005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18DFAC1C5BF41B005A2B8E /* PBXTargetDependency */, - ); - name = HeapTests; - productName = HeapTests; - productReference = 7B18DFAA1C5BF41B005A2B8E /* HeapTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18DF931C5BF41B005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18DF9A1C5BF41B005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18DFA91C5BF41B005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18DF9A1C5BF41B005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18DF961C5BF41B005A2B8E /* Build configuration list for PBXProject "Heap" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18DF921C5BF41B005A2B8E; - productRefGroup = 7B18DF9C1C5BF41B005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18DF9A1C5BF41B005A2B8E /* Heap */, - 7B18DFA91C5BF41B005A2B8E /* HeapTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18DF991C5BF41B005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18DFA11C5BF41B005A2B8E /* Assets.xcassets in Resources */, - 7B18DFA41C5BF41B005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFA81C5BF41B005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18DF971C5BF41B005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18DF9F1C5BF41B005A2B8E /* AppDelegate.swift in Sources */, - 7B18DFBA1C5BF465005A2B8E /* Heap.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18DFA61C5BF41B005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18DFAF1C5BF41B005A2B8E /* HeapTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18DFAC1C5BF41B005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18DF9A1C5BF41B005A2B8E /* Heap */; - targetProxy = 7B18DFAB1C5BF41B005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18DFA21C5BF41B005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18DFA31C5BF41B005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18DFB11C5BF41B005A2B8E /* 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; - }; - 7B18DFB21C5BF41B005A2B8E /* 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; - }; - 7B18DFB41C5BF41B005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Heap/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Heap; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18DFB51C5BF41B005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Heap/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Heap; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18DFB71C5BF41B005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Heap.app/Contents/MacOS/Heap"; - }; - name = Debug; - }; - 7B18DFB81C5BF41B005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = HeapTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.HeapTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Heap.app/Contents/MacOS/Heap"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18DF961C5BF41B005A2B8E /* Build configuration list for PBXProject "Heap" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18DFB11C5BF41B005A2B8E /* Debug */, - 7B18DFB21C5BF41B005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18DFB31C5BF41B005A2B8E /* Build configuration list for PBXNativeTarget "Heap" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18DFB41C5BF41B005A2B8E /* Debug */, - 7B18DFB51C5BF41B005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18DFB61C5BF41B005A2B8E /* Build configuration list for PBXNativeTarget "HeapTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18DFB71C5BF41B005A2B8E /* Debug */, - 7B18DFB81C5BF41B005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18DF931C5BF41B005A2B8E /* Project object */; -} diff --git a/Heap/Heap Tests/Heap/AppDelegate.swift b/Heap/Heap Tests/Heap/AppDelegate.swift deleted file mode 100644 index 954fc0c35..000000000 --- a/Heap/Heap Tests/Heap/AppDelegate.swift +++ /dev/null @@ -1,15 +0,0 @@ -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/Heap/Heap Tests/Heap/Assets.xcassets/AppIcon.appiconset/Contents.json b/Heap/Heap Tests/Heap/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Heap/Heap Tests/Heap/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/Heap/Heap Tests/Heap/Base.lproj/MainMenu.xib b/Heap/Heap Tests/Heap/Base.lproj/MainMenu.xib deleted file mode 100644 index e6d67c02a..000000000 --- a/Heap/Heap Tests/Heap/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Heap/Heap.swift b/Heap/Heap.swift old mode 100644 new mode 100755 index 3293f75bb..7560bc7b9 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -4,83 +4,80 @@ // public struct Heap { + /** The array that stores the heap's nodes. */ - var elements = [T]() + var nodes = [T]() + + /** + * Determines how to compare two nodes in the heap. + * Use '>' for a max-heap or '<' for a min-heap, + * or provide a comparing method if the heap is made + * of custom elements, for example tuples. + */ + private var orderCriteria: (T, T) -> Bool - /** Determines whether this is a max-heap (>) or min-heap (<). */ - private 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. + * For comparable data types, > makes a max-heap, < makes a min-heap. */ - public init(sort: (T, T) -> Bool) { - self.isOrderedBefore = sort + public init(sort: @escaping (T, T) -> Bool) { + self.orderCriteria = sort } - + /** * Creates a heap from an array. The order of the array does not matter; * the elements are inserted into the heap in the order determined by the - * sort function. + * sort function. For comparable data types, '>' makes a max-heap, + * '<' makes a min-heap. */ - public init(array: [T], sort: (T, T) -> Bool) { - self.isOrderedBefore = sort - buildHeap(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) - } + public init(array: [T], sort: @escaping (T, T) -> Bool) { + self.orderCriteria = sort + configureHeap(from: array) } - */ /** - * Converts an array to a max-heap or min-heap in a bottom-up manner. + * Configures the max-heap or min-heap from an array, in a bottom-up manner. * Performance: This runs pretty much in O(n). */ - private mutating func buildHeap(array: [T]) { - elements = array - for i in (elements.count/2 - 1).stride(through: 0, by: -1) { - shiftDown(index: i, heapSize: elements.count) + private mutating func configureHeap(from array: [T]) { + nodes = array + for i in stride(from: (nodes.count/2-1), through: 0, by: -1) { + shiftDown(i) } } - + public var isEmpty: Bool { - return elements.isEmpty + return nodes.isEmpty } public var count: Int { - return elements.count + return nodes.count } /** * 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) internal 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 indexOfLeftChild(i: Int) -> Int { + @inline(__always) internal 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 indexOfRightChild(i: Int) -> Int { + @inline(__always) internal func rightChildIndex(ofIndex i: Int) -> Int { return 2*i + 2 } @@ -89,135 +86,138 @@ public struct Heap { * value (for a min-heap). */ public func peek() -> T? { - return elements.first + return nodes.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(index: elements.count - 1) + public mutating func insert(_ value: T) { + nodes.append(value) + shiftUp(nodes.count - 1) } - public mutating func insert(sequence: S) { + /** + * Adds a sequence of values to the heap. This reorders the heap so that + * the max-heap or min-heap property still holds. Performance: O(log n). + */ + public mutating func insert(_ sequence: S) where S.Iterator.Element == T { for value in sequence { insert(value) } } /** - * Allows you to change an element. In a max-heap, the new element should be - * larger than the old one; in a min-heap it should be smaller. + * Allows you to change an element. This reorders the heap so that + * the max-heap or min-heap property still holds. */ public mutating func replace(index i: Int, value: T) { - assert(isOrderedBefore(value, elements[i])) - elements[i] = value - shiftUp(index: i) + guard i < nodes.count else { return } + + remove(at: i) + insert(value) } - + /** * 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? { - if elements.isEmpty { - return nil - } else if elements.count == 1 { - return elements.removeLast() + @discardableResult public mutating func remove() -> T? { + guard !nodes.isEmpty else { return nil } + + if nodes.count == 1 { + return nodes.removeLast() } else { // Use the last node to replace the first one, then fix the heap by // shifting this new first node into its proper position. - let value = elements[0] - elements[0] = elements.removeLast() - shiftDown() + let value = nodes[0] + nodes[0] = nodes.removeLast() + shiftDown(0) 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. + * Removes an arbitrary node from the heap. Performance: O(log n). + * Note that you need to know the node's index. */ - public mutating func removeAtIndex(i: Int) -> T? { - let size = elements.count - 1 - if i != size { - swap(&elements[i], &elements[size]) - shiftDown(index: i, heapSize: size) - shiftUp(index: i) + @discardableResult public mutating func remove(at index: Int) -> T? { + guard index < nodes.count else { return nil } + + let size = nodes.count - 1 + if index != size { + nodes.swapAt(index, size) + shiftDown(from: index, until: size) + shiftUp(index) } - return elements.removeLast() + return nodes.removeLast() } /** - * Takes a child node and looks at its parents; if a parent is not larger + * 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) { + internal mutating func shiftUp(_ index: Int) { var childIndex = index - let child = elements[childIndex] - var parentIndex = indexOfParent(childIndex) - - while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { - elements[childIndex] = elements[parentIndex] + let child = nodes[childIndex] + var parentIndex = self.parentIndex(ofIndex: childIndex) + + while childIndex > 0 && orderCriteria(child, nodes[parentIndex]) { + nodes[childIndex] = nodes[parentIndex] childIndex = parentIndex - parentIndex = indexOfParent(childIndex) + parentIndex = self.parentIndex(ofIndex: childIndex) } - - elements[childIndex] = child + + nodes[childIndex] = child } - mutating func shiftDown() { - shiftDown(index: 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 index: Int, heapSize: Int) { - var parentIndex = index - - while true { - let leftChildIndex = indexOfLeftChild(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 + internal mutating func shiftDown(from index: Int, until endIndex: Int) { + let leftChildIndex = self.leftChildIndex(ofIndex: index) + 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 = index + if leftChildIndex < endIndex && orderCriteria(nodes[leftChildIndex], nodes[first]) { + first = leftChildIndex + } + if rightChildIndex < endIndex && orderCriteria(nodes[rightChildIndex], nodes[first]) { + first = rightChildIndex } + if first == index { return } + + nodes.swapAt(index, first) + shiftDown(from: first, until: endIndex) } + + internal mutating func shiftDown(_ index: Int) { + shiftDown(from: index, until: nodes.count) + } + } // MARK: - Searching extension Heap where T: Equatable { - /** - * Searches the heap for the given element. Performance: O(n). - */ - public func indexOf(element: T) -> Int? { - return indexOf(element, 0) + + /** Get the index of a node in the heap. Performance: O(n). */ + public func index(of node: T) -> Int? { + return nodes.index(where: { $0 == node }) } - - private func indexOf(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 } + + /** Removes the first occurrence of a node from the heap. Performance: O(n). */ + @discardableResult public mutating func remove(node: T) -> T? { + if let index = index(of: node) { + return remove(at: index) + } return nil } + } diff --git a/Heap/README.markdown b/Heap/README.markdown old mode 100644 new mode 100755 index a51f97636..fee881129 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -1,19 +1,21 @@ # 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. +> This topic has been tutorialized [here](https://www.raywenderlich.com/160631/swift-algorithm-club-heap-and-priority-queue-data-structure) + +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: -- 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%20Queue/). +- To support [heap sorts](../Heap%20Sort/). +- 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 one 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,40 +23,41 @@ 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%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. -Note that 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. +## How does a heap compare to regular trees? -## How does heap compare to regular trees? +A heap is not a replacement for a binary search tree, and there are similarities and differences between them. Here are some main differences: -A heap isn't really 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 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.** 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: 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,75 +66,73 @@ 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 | 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`: ```swift array[parent(i)] >= array[i] ``` - -Verify that this heap property holds for the array for 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. +Verify that this heap property holds for the array from the example heap. -It's important to understand this relationship between array index and position in the tree. Here's a slightly larger heap: +As you can see, these equations allow us to find the parent or child index for any node without the need for pointers. It is more complicated than just dereferencing a pointer, but that is the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. -![Large heap](Images/LargeHeap.png) +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: -This tree has 15 nodes divided over four levels. Note that the numbers in this picture aren't the values of the nodes but the array indices that store the nodes! +![Large heap](Images/LargeHeap.png) -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: [ 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! -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 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) -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`. 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. ;-) @@ -143,35 +144,35 @@ 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 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 is a recursive procedure that takes **O(log n)** time. +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, this 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%20Sort/). Since the heap is an array, we can use its unique properties to sort the array from low to high. Time: **O(n log n).** The heap also has a `peek()` function that returns the maximum (max-heap) or minimum (min-heap) element, without removing it from the heap. Time: **O(1)**. -> **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) @@ -187,13 +188,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 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: @@ -201,11 +202,11 @@ 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 -Let's remove 10 from this tree: +Let's remove `(10)` from this tree: ![The heap before removal](Images/Heap1.png) @@ -213,27 +214,27 @@ 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 do the opposite: we take the last object we have, stick it up on top of the tree, and restore the heap property. ![The last node goes to the root](Images/Remove2.png) -Let's look at how to **shift-down** `(1)`. To maintain the heap property for this max-heap, we want to the highest number of top. We have 2 candidates for swapping places with: `(7)` and `(2)`. We choose the highest number between these three nodes to be on top. This is `(7)`, so swapping `(1)` and `(7)` gives us the following tree. +Let's look at how to **shift-down** `(1)`. To maintain the heap property for this max-heap, we want to the highest number of top. We have two candidates for swapping places with: `(7)` and `(2)`. We choose the highest number between these three nodes to be on top. That is `(7)`, so swapping `(1)` and `(7)` gives us the following tree. ![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 which takes **O(log n)** time. > **Note:** `shiftUp()` and `shiftDown()` can only fix one out-of-place element at a time. If there are multiple elements in the wrong place, you need to call these functions once for each of those elements. ## 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)`: @@ -243,13 +244,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, 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) @@ -262,23 +263,23 @@ 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) } } ``` -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 skip 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: ```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) { + for i in stride(from: (nodes.count/2-1), through: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) } } @@ -288,9 +289,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 item using `removeAtIndex()` or change the value of an item with `replace()`, then you need to obtain the index of that item 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%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: @@ -298,23 +299,21 @@ 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. Because we know that in a max-heap a parent node is always larger than its children. - -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. +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. -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. -> **Note:** There is away to turn this into **O(1)** 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 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 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: diff --git a/Heap/Heap Tests/HeapTests/HeapTests.swift b/Heap/Tests/HeapTests.swift old mode 100644 new mode 100755 similarity index 66% rename from Heap/Heap Tests/HeapTests/HeapTests.swift rename to Heap/Tests/HeapTests.swift index 653cf6af9..ecf143778 --- a/Heap/Heap Tests/HeapTests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -4,49 +4,48 @@ // import XCTest -@testable import Heap 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 } + let left = h.leftChildIndex(ofIndex: i) + let right = h.rightChildIndex(ofIndex: i) + let parent = h.parentIndex(ofIndex: i) + if left < h.count && h.nodes[i] < h.nodes[left] { return false } + if right < h.count && h.nodes[i] < h.nodes[right] { return false } + if i > 0 && h.nodes[parent] < h.nodes[i] { return false } } return true } - - 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 } + let left = h.leftChildIndex(ofIndex: i) + let right = h.rightChildIndex(ofIndex: i) + let parent = h.parentIndex(ofIndex: i) + if left < h.count && h.nodes[i] > h.nodes[left] { return false } + if right < h.count && h.nodes[i] > h.nodes[right] { return false } + if i > 0 && h.nodes[parent] > h.nodes[i] { return false } } return true } - - 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 } } return a2.count == 0 } - + func testEmptyHeap() { var heap = Heap(sort: <) XCTAssertTrue(heap.isEmpty) @@ -54,7 +53,7 @@ class HeapTests: XCTestCase { XCTAssertNil(heap.peek()) XCTAssertNil(heap.remove()) } - + func testIsEmpty() { var heap = Heap(sort: >) XCTAssertTrue(heap.isEmpty) @@ -70,7 +69,7 @@ class HeapTests: XCTestCase { heap.insert(1) XCTAssertEqual(1, heap.count) } - + func testMaxHeapOneElement() { let heap = Heap(array: [10], sort: >) XCTAssertTrue(verifyMaxHeap(heap)) @@ -79,97 +78,97 @@ class HeapTests: XCTestCase { XCTAssertEqual(heap.count, 1) XCTAssertEqual(heap.peek()!, 10) } - + func testCreateMaxHeap() { let h1 = Heap(array: [1, 2, 3, 4, 5, 6, 7], sort: >) XCTAssertTrue(verifyMaxHeap(h1)) XCTAssertFalse(verifyMinHeap(h1)) - XCTAssertEqual(h1.elements, [7, 5, 6, 4, 2, 1, 3]) + XCTAssertEqual(h1.nodes, [7, 5, 6, 4, 2, 1, 3]) XCTAssertFalse(h1.isEmpty) XCTAssertEqual(h1.count, 7) XCTAssertEqual(h1.peek()!, 7) - + let h2 = Heap(array: [7, 6, 5, 4, 3, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h2)) XCTAssertFalse(verifyMinHeap(h2)) - XCTAssertEqual(h2.elements, [7, 6, 5, 4, 3, 2, 1]) + XCTAssertEqual(h2.nodes, [7, 6, 5, 4, 3, 2, 1]) XCTAssertFalse(h2.isEmpty) XCTAssertEqual(h2.count, 7) XCTAssertEqual(h2.peek()!, 7) - + let h3 = Heap(array: [4, 1, 3, 2, 16, 9, 10, 14, 8, 7], sort: >) XCTAssertTrue(verifyMaxHeap(h3)) XCTAssertFalse(verifyMinHeap(h3)) - XCTAssertEqual(h3.elements, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) + XCTAssertEqual(h3.nodes, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) XCTAssertFalse(h3.isEmpty) XCTAssertEqual(h3.count, 10) XCTAssertEqual(h3.peek()!, 16) - + let h4 = Heap(array: [27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0], sort: >) XCTAssertTrue(verifyMaxHeap(h4)) XCTAssertFalse(verifyMinHeap(h4)) - XCTAssertEqual(h4.elements, [27, 17, 10, 16, 13, 9, 1, 5, 7, 12, 4, 8, 3, 0]) + XCTAssertEqual(h4.nodes, [27, 17, 10, 16, 13, 9, 1, 5, 7, 12, 4, 8, 3, 0]) XCTAssertFalse(h4.isEmpty) XCTAssertEqual(h4.count, 14) XCTAssertEqual(h4.peek()!, 27) } - + func testCreateMinHeap() { let h1 = Heap(array: [1, 2, 3, 4, 5, 6, 7], sort: <) XCTAssertTrue(verifyMinHeap(h1)) XCTAssertFalse(verifyMaxHeap(h1)) - XCTAssertEqual(h1.elements, [1, 2, 3, 4, 5, 6, 7]) + XCTAssertEqual(h1.nodes, [1, 2, 3, 4, 5, 6, 7]) XCTAssertFalse(h1.isEmpty) XCTAssertEqual(h1.count, 7) XCTAssertEqual(h1.peek()!, 1) - + let h2 = Heap(array: [7, 6, 5, 4, 3, 2, 1], sort: <) XCTAssertTrue(verifyMinHeap(h2)) XCTAssertFalse(verifyMaxHeap(h2)) - XCTAssertEqual(h2.elements, [1, 3, 2, 4, 6, 7, 5]) + XCTAssertEqual(h2.nodes, [1, 3, 2, 4, 6, 7, 5]) XCTAssertFalse(h2.isEmpty) XCTAssertEqual(h2.count, 7) XCTAssertEqual(h2.peek()!, 1) - + let h3 = Heap(array: [4, 1, 3, 2, 16, 9, 10, 14, 8, 7], sort: <) XCTAssertTrue(verifyMinHeap(h3)) XCTAssertFalse(verifyMaxHeap(h3)) - XCTAssertEqual(h3.elements, [1, 2, 3, 4, 7, 9, 10, 14, 8, 16]) + XCTAssertEqual(h3.nodes, [1, 2, 3, 4, 7, 9, 10, 14, 8, 16]) XCTAssertFalse(h3.isEmpty) XCTAssertEqual(h3.count, 10) XCTAssertEqual(h3.peek()!, 1) - + let h4 = Heap(array: [27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0], sort: <) XCTAssertTrue(verifyMinHeap(h4)) XCTAssertFalse(verifyMaxHeap(h4)) - XCTAssertEqual(h4.elements, [0, 4, 1, 5, 12, 8, 3, 16, 7, 17, 13, 10, 9, 27]) + XCTAssertEqual(h4.nodes, [0, 4, 1, 5, 12, 8, 3, 16, 7, 17, 13, 10, 9, 27]) XCTAssertFalse(h4.isEmpty) XCTAssertEqual(h4.count, 14) XCTAssertEqual(h4.peek()!, 0) } - - func testCreateMaxHeapEqualElements() { + + func testCreateMaxHeapEqualnodes() { let heap = Heap(array: [1, 1, 1, 1, 1], sort: >) XCTAssertTrue(verifyMaxHeap(heap)) XCTAssertTrue(verifyMinHeap(heap)) - XCTAssertEqual(heap.elements, [1, 1, 1, 1, 1]) + XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1]) } - - func testCreateMinHeapEqualElements() { + + func testCreateMinHeapEqualnodes() { let heap = Heap(array: [1, 1, 1, 1, 1], sort: <) XCTAssertTrue(verifyMinHeap(heap)) XCTAssertTrue(verifyMaxHeap(heap)) - XCTAssertEqual(heap.elements, [1, 1, 1, 1, 1]) + XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1]) } - - private func randomArray(n: Int) -> [Int] { + + fileprivate func randomArray(_ n: Int) -> [Int] { var a = [Int]() for _ in 0..) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) - - let v1 = h.removeAtIndex(5) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) + + //test index out of bounds + let v = h.remove(at: 10) + XCTAssertEqual(v, nil) + XCTAssertTrue(verifyMaxHeap(h)) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) + + let v1 = h.remove(at: 5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 65]) - - let v2 = h.removeAtIndex(4) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 65]) + + let v2 = h.remove(at: 4) XCTAssertEqual(v2, 20) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 65, 70, 10, 50]) - - let v3 = h.removeAtIndex(4) + XCTAssertEqual(h.nodes, [100, 65, 70, 10, 50]) + + let v3 = h.remove(at: 4) XCTAssertEqual(v3, 50) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 65, 70, 10]) - - let v4 = h.removeAtIndex(0) + XCTAssertEqual(h.nodes, [100, 65, 70, 10]) + + let v4 = h.remove(at: 0) XCTAssertEqual(v4, 100) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [70, 65, 10]) - + XCTAssertEqual(h.nodes, [70, 65, 10]) + XCTAssertEqual(h.peek()!, 70) let v5 = h.remove() XCTAssertEqual(v5, 70) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [65, 10]) - + XCTAssertEqual(h.nodes, [65, 10]) + XCTAssertEqual(h.peek()!, 65) let v6 = h.remove() XCTAssertEqual(v6, 65) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [10]) - + XCTAssertEqual(h.nodes, [10]) + XCTAssertEqual(h.peek()!, 10) let v7 = h.remove() XCTAssertEqual(v7, 10) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, []) - + XCTAssertEqual(h.nodes, []) + XCTAssertNil(h.peek()) } - + func testRemoveEmpty() { var heap = Heap(sort: >) let removed = heap.remove() XCTAssertNil(removed) } - + func testRemoveRoot() { var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) + XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) XCTAssertEqual(h.peek()!, 15) let v = h.remove() XCTAssertEqual(v, 15) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2]) + XCTAssertEqual(h.nodes, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2]) } - + func testRemoveRandomItems() { for n in 1...40 { var a = randomArray(n) var h = Heap(array: a, sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertTrue(isPermutation(a, h.elements)) - + XCTAssertTrue(isPermutation(a, h.nodes)) + let m = (n + 1)/2 for k in 1...m { let i = Int(arc4random_uniform(UInt32(n - k + 1))) - let v = h.removeAtIndex(i)! - let j = a.indexOf(v)! - a.removeAtIndex(j) - + let v = h.remove(at: i)! + let j = a.index(of: v)! + a.remove(at: j) + XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.count, a.count) XCTAssertEqual(h.count, n - k) - XCTAssertTrue(isPermutation(a, h.elements)) + XCTAssertTrue(isPermutation(a, h.nodes)) } } } - + func testInsert() { var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) - + XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) + h.insert(10) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 10, 5, 12, 9, 7, 4, 0, 6, 2, 1, 8]) + XCTAssertEqual(h.nodes, [15, 13, 10, 5, 12, 9, 7, 4, 0, 6, 2, 1, 8]) } - + func testInsertArrayAndRemove() { var heap = Heap(sort: >) heap.insert([1, 3, 2, 7, 5, 9]) - XCTAssertEqual(heap.elements, [9, 5, 7, 1, 3, 2]) - + XCTAssertEqual(heap.nodes, [9, 5, 7, 1, 3, 2]) + XCTAssertEqual(9, heap.remove()) XCTAssertEqual(7, heap.remove()) XCTAssertEqual(5, heap.remove()) @@ -300,14 +305,17 @@ class HeapTests: XCTestCase { XCTAssertEqual(1, heap.remove()) XCTAssertNil(heap.remove()) } - + func testReplace() { var h = Heap(array: [16, 14, 10, 8, 7, 9, 3, 2, 4, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) - + h.replace(index: 5, value: 13) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [16, 14, 13, 8, 7, 10, 3, 2, 4, 1]) + + //test index out of bounds + h.replace(index: 20, value: 2) + XCTAssertTrue(verifyMaxHeap(h)) } + } diff --git a/Heap/Tests/Info.plist b/Heap/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Heap/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/Heap/Tests/Tests.xcodeproj/project.pbxproj b/Heap/Tests/Tests.xcodeproj/project.pbxproj new file mode 100755 index 000000000..0ab48ba3b --- /dev/null +++ b/Heap/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,294 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3DC1C77A38C003CECC7 /* HeapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3DB1C77A38C003CECC7 /* HeapTests.swift */; }; + 7B80C3DE1C77A393003CECC7 /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3DD1C77A393003CECC7 /* Heap.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; }; + 7B80C3DB1C77A38C003CECC7 /* HeapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeapTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3DD1C77A393003CECC7 /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../Heap.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 = ( + 7B80C3DD1C77A393003CECC7 /* Heap.swift */, + 7B80C3DB1C77A38C003CECC7 /* HeapTests.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 = 1010; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1010; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 10.0"; + 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 = ( + 7B80C3DC1C77A38C003CECC7 /* HeapTests.swift in Sources */, + 7B80C3DE1C77A393003CECC7 /* Heap.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + 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 = 4.2; + }; + 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 = 4.2; + }; + 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/Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000..6c0ea8493 --- /dev/null +++ b/Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Heap/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Heap/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Heap/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100755 index 000000000..1608804f9 --- /dev/null +++ b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/How to Contribute.markdown b/How to Contribute.markdown deleted file mode 100644 index 0069c57ba..000000000 --- a/How to Contribute.markdown +++ /dev/null @@ -1,29 +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. - -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. If you wrote it, you deserve the credit and fame. -5. Add a playground and/or unit tests. - -Just so you know, I will probably edit your text and code for grammar etc, just to ensure a certain level of polish. - -## 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/hollance/swift-algorithm-club/issues) and we'll talk! diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift new file mode 100644 index 000000000..2d59908e9 --- /dev/null +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -0,0 +1,23 @@ +//: Playground - noun: a place where people can play + +import Foundation + +let s1 = "so much words wow many compression" +if let originalData = s1.data(using: .utf8) { + print(originalData.count) + + let huffman1 = Huffman() + let compressedData = huffman1.compressData(data: originalData as NSData) + print(compressedData.length) + + let frequencyTable = huffman1.frequencyTable() + //print(frequencyTable) + + let huffman2 = Huffman() + let decompressedData = huffman2.decompressData(data: compressedData, frequencyTable: frequencyTable) + print(decompressedData.length) + + let s2 = String(data: decompressedData as Data, 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 new file mode 100644 index 000000000..b578ef6e4 --- /dev/null +++ b/Huffman Coding/Huffman.playground/Sources/Heap.swift @@ -0,0 +1,223 @@ +// +// 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(array: 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). + */ + private mutating func buildHeap(array: [T]) { + elements = array + for i in stride(from: elements.count/2 - 1, to: 0, by: -1) { + shiftDown(index: 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 indexOfParent(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 indexOfLeftChild(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 indexOfRightChild(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(index: 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) { + assert(isOrderedBefore(value, elements[i])) + elements[i] = value + shiftUp(index: 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). + */ + 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 removeAtIndex(i: Int) -> T? { + let size = elements.count - 1 + if i != size { + elements.swapAt(i, size) + shiftDown(index: i, heapSize: size) + shiftUp(index: i) + } + 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 = indexOfParent(i: childIndex) + + while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { + elements[childIndex] = elements[parentIndex] + childIndex = parentIndex + parentIndex = indexOfParent(i: childIndex) + } + + elements[childIndex] = child + } + + mutating func shiftDown() { + shiftDown(index: 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 = indexOfLeftChild(i: parentIndex) + let rightChildIndex = leftChildIndex + 1 + + // Figure out which comes first if we order them by the sort function: + // the parent, the left child, or the right child. If the parent comes + // first, we're done. If not, that element is out-of-place and we make + // it "float down" the tree until the heap property is restored. + var first = parentIndex + if leftChildIndex < heapSize && isOrderedBefore(elements[leftChildIndex], elements[first]) { + first = leftChildIndex + } + if rightChildIndex < heapSize && isOrderedBefore(elements[rightChildIndex], elements[first]) { + first = rightChildIndex + } + if first == parentIndex { return } + + elements.swapAt(parentIndex, first) + parentIndex = first + } + } +} + +// 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) + } + + 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 = 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 new file mode 100644 index 000000000..79b24b09a --- /dev/null +++ b/Huffman Coding/Huffman.playground/Sources/Huffman.swift @@ -0,0 +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. +*/ +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 + 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 + 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. */ + 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 + 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. */ + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + 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)) + } + return a + } +} + +extension Huffman { + /* 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 + } +} + +extension Huffman { + /* Compresses the contents of an NSData object. */ + 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) + outData.append(&b, length: 1) + i += 1 + } + 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 + the original byte value. */ + 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) + } +} diff --git a/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift new file mode 100644 index 000000000..3e5163521 --- /dev/null +++ b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift @@ -0,0 +1,50 @@ +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.append(&outByte, length: 1) + outCount = 0 + } + 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.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 = 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 + } +} diff --git a/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift b/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift new file mode 100644 index 000000000..4cc9d15ed --- /dev/null +++ b/Huffman Coding/Huffman.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 indexOf(element: T) -> Int? { + return heap.index(of: element) + } +} diff --git a/Huffman Coding/Huffman.playground/contents.xcplayground b/Huffman Coding/Huffman.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Huffman Coding/Huffman.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Huffman Coding/Huffman.playground/playground.xcworkspace/contents.xcworkspacedata b/Huffman Coding/Huffman.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Huffman Coding/Huffman.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Huffman Coding/Huffman.playground/timeline.xctimeline b/Huffman Coding/Huffman.playground/timeline.xctimeline new file mode 100644 index 000000000..5588b0fdd --- /dev/null +++ b/Huffman Coding/Huffman.playground/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Huffman Coding/Huffman.swift b/Huffman Coding/Huffman.swift new file mode 100644 index 000000000..cad80327d --- /dev/null +++ b/Huffman Coding/Huffman.swift @@ -0,0 +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. + */ +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 + 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 + 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. */ + 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 + 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. */ + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + 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)) + } + return a + } +} + +extension Huffman { + /* 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 + } +} + +extension Huffman { + /* Compresses the contents of an NSData object. */ + 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) + outData.append(&b, length: 1) + i += 1 + } + 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 + the original byte value. */ + 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) + } +} diff --git a/Huffman Coding/Images/BuildTree.gif b/Huffman Coding/Images/BuildTree.gif new file mode 100644 index 000000000..6f5e51523 Binary files /dev/null and b/Huffman Coding/Images/BuildTree.gif differ diff --git a/Huffman Coding/Images/BuildTree.graffle b/Huffman Coding/Images/BuildTree.graffle new file mode 100644 index 000000000..778fac420 Binary files /dev/null and b/Huffman Coding/Images/BuildTree.graffle differ diff --git a/Huffman Coding/Images/BuildTree.psd b/Huffman Coding/Images/BuildTree.psd new file mode 100644 index 000000000..e13923fb3 Binary files /dev/null and b/Huffman Coding/Images/BuildTree.psd differ diff --git a/Huffman Coding/Images/Compression.graffle b/Huffman Coding/Images/Compression.graffle new file mode 100644 index 000000000..e69912012 Binary files /dev/null and b/Huffman Coding/Images/Compression.graffle differ diff --git a/Huffman Coding/Images/Compression.png b/Huffman Coding/Images/Compression.png new file mode 100644 index 000000000..e241d15c9 Binary files /dev/null and b/Huffman Coding/Images/Compression.png differ diff --git a/Huffman Coding/Images/Decompression.graffle b/Huffman Coding/Images/Decompression.graffle new file mode 100644 index 000000000..dd33b5faf Binary files /dev/null and b/Huffman Coding/Images/Decompression.graffle differ diff --git a/Huffman Coding/Images/Decompression.png b/Huffman Coding/Images/Decompression.png new file mode 100644 index 000000000..a2946a621 Binary files /dev/null and b/Huffman Coding/Images/Decompression.png differ diff --git a/Huffman Coding/Images/Tree.graffle b/Huffman Coding/Images/Tree.graffle new file mode 100644 index 000000000..171290233 Binary files /dev/null and b/Huffman Coding/Images/Tree.graffle differ diff --git a/Huffman Coding/Images/Tree.png b/Huffman Coding/Images/Tree.png new file mode 100644 index 000000000..a90b11986 Binary files /dev/null and b/Huffman Coding/Images/Tree.png differ diff --git a/Huffman Coding/NSData+Bits.swift b/Huffman Coding/NSData+Bits.swift new file mode 100644 index 000000000..1f5333296 --- /dev/null +++ b/Huffman Coding/NSData+Bits.swift @@ -0,0 +1,50 @@ +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.append(&outByte, length: 1) + outCount = 0 + } + 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.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 = 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 + } +} diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown new file mode 100644 index 000000000..d1181d215 --- /dev/null +++ b/Huffman Coding/README.markdown @@ -0,0 +1,415 @@ +# Huffman Coding + +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: + + so much words wow many compression + +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 + +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 + 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 + +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 + 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 + +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%! + +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, 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: + +![The compression tree](Images/Tree.png) + +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 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 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`). 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 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 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 { + 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 + } + + public func flush() { + if outCount > 0 { + if outCount < 8 { + let diff = UInt8(8 - outCount) + outByte <<= diff + } + data.append(&outByte, length: 1) + } + } +} +``` + +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. + +Here is a similar helper object for reading individual bits from `NSData`: + +```swift +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 + inCount = 0 + ptr = ptr.successor() + } + let bit = inByte & 0x80 // read the next bit + inByte <<= 1 + inCount += 1 + return bit == 0 ? false : true + } +} +``` + +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:** 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 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 need to build a tree, we might store the frequency table as the leaves of the tree. + +Here are the definitions we need: + +```swift +class Huffman { + typealias NodeIndex = Int + + struct Node { + var count = 0 + var index: NodeIndex = -1 + var parent: NodeIndex = -1 + var left: NodeIndex = -1 + var right: NodeIndex = -1 + } + + var tree = [Node](repeating: Node(), count: 256) + + var root: NodeIndex = -1 +} +``` + +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 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: + +```swift + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + 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)) + } + return a + } +``` + +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 + +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 the highest up in the tree. + +To build the tree, we do the following: + +1. Find the two nodes with the smallest counts that do not have a parent node yet. +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 fast. Here, we repeatedly need to find the node with the smallest count. + +The function `buildTree()` then becomes: + +```swift + fileprivate func buildTree() { + var queue = PriorityQueue(sort: { $0.count < $1.count }) + for node in tree where node.count > 0 { + queue.enqueue(node) // 1 + } + + while queue.count > 1 { + let node1 = queue.dequeue()! // 2 + let node2 = queue.dequeue()! + + var parentNode = Node() // 3 + parentNode.count = node1.count + node2.count + parentNode.left = node1.index + parentNode.right = node2.index + parentNode.index = tree.count + tree.append(parentNode) + + tree[node1.index].parent = parentNode.index // 4 + tree[node2.index].parent = parentNode.index + + queue.enqueue(parentNode) // 5 + } + + let rootNode = queue.dequeue()! // 6 + root = rootNode.index + } +``` + +Here is how it works step-by-step: + +1. Create a priority queue and enqueue all the leaf nodes that have at least a count of 1. (If the count is 0, then this byte value did not appear in the input data.) The `PriorityQueue` object sorts the nodes by their count, so that the node with the lowest count is always the first one that gets dequeued. + +2. While there are at least two nodes left in the queue, remove the two nodes that are at the front of the queue. Since this is a min-priority queue, this gives us the two nodes with the smallest counts that do not have a parent node yet. + +3. Create a new intermediate node that connects `node1` and `node2`. The count of this new node is the sum of the counts of `node1` and `node2`. Because the nodes are connected using array indices instead of real pointers, we use `node1.index` and `node2.index` to find these nodes in the `tree` array. (This is why a `Node` needs to know its own index.) + +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 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 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 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. + +## Compression + +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 + public func compressData(data: NSData) -> NSData { + countByteFrequency(inData: data) + buildTree() + + let writer = BitWriter() + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + for _ in 0.. **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: + +```swift + private func traverseTree(writer: BitWriter, nodeIndex h: Int, childIndex child: Int) { + if tree[h].parent != -1 { + traverseTree(writer: writer, nodeIndex: tree[h].parent, childIndex: h) + } + if child != -1 { + if child == tree[h].left { + writer.writeBit(bit: true) + } else if child == tree[h].right { + writer.writeBit(bit: false) + } + } + } +``` + +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 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 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: + +```swift +let s1 = "so much words wow many compression" +if let originalData = s1.dataUsingEncoding(NSUTF8StringEncoding) { + let huffman1 = Huffman() + let compressedData = huffman1.compressData(originalData) + print(compressedData.length) +} +``` + +## Decompression + +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: + +```swift + fileprivate func restoreTree(fromTable frequencyTable: [Freq]) { + for freq in frequencyTable { + let i = Int(freq.byte) + tree[i].count = freq.count + tree[i].index = i + } + buildTree() + } +``` + +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 it returns the original data: + +```swift + 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 + } +``` + +This also uses a helper method to traverse the tree: + +```swift + 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 + } + } + return UInt8(h) + } +``` + +`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 is how we 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)! +``` + +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. + +we can see how this works in more detail in the Playground. + +## See also + +[Huffman coding at Wikipedia](https://en.wikipedia.org/wiki/Huffman_coding) + +The code is loosely based on Al Stevens' C Programming column from Dr.Dobb's Magazine, February 1991 and October 1992. + +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Images/DataStructuresAndAlgorithmsInSwiftBook.png b/Images/DataStructuresAndAlgorithmsInSwiftBook.png new file mode 100644 index 000000000..f8de0ba72 Binary files /dev/null and b/Images/DataStructuresAndAlgorithmsInSwiftBook.png differ diff --git a/Images/SwiftAlgorithm-410-transp.png b/Images/SwiftAlgorithm-410-transp.png new file mode 100644 index 000000000..567c1d8eb Binary files /dev/null and b/Images/SwiftAlgorithm-410-transp.png differ diff --git a/Images/scheme-settings-for-travis.png b/Images/scheme-settings-for-travis.png new file mode 100644 index 000000000..2ada94839 Binary files /dev/null and b/Images/scheme-settings-for-travis.png differ diff --git a/Insertion Sort/InsertionSort Tests/InsertionSort.xcodeproj/project.pbxproj b/Insertion Sort/InsertionSort Tests/InsertionSort.xcodeproj/project.pbxproj deleted file mode 100644 index 1eed2d04e..000000000 --- a/Insertion Sort/InsertionSort Tests/InsertionSort.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E0971C5BFA2E005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */; }; - 7B18E0991C5BFA2E005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E0981C5BFA2E005A2B8E /* Assets.xcassets */; }; - 7B18E09C1C5BFA2E005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E09A1C5BFA2E005A2B8E /* MainMenu.xib */; }; - 7B18E0A71C5BFA2E005A2B8E /* InsertionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0A61C5BFA2E005A2B8E /* InsertionSortTests.swift */; }; - 7B18E0B21C5BFA4B005A2B8E /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0B11C5BFA4B005A2B8E /* SortingTestHelpers.swift */; }; - 7B18E0B41C5BFA5F005A2B8E /* InsertionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0B31C5BFA5F005A2B8E /* InsertionSort.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E0A31C5BFA2E005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E08B1C5BFA2E005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E0921C5BFA2E005A2B8E; - remoteInfo = InsertionSort; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E0931C5BFA2E005A2B8E /* InsertionSort.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InsertionSort.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E0981C5BFA2E005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18E09B1C5BFA2E005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18E09D1C5BFA2E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0A21C5BFA2E005A2B8E /* InsertionSortTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InsertionSortTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0A61C5BFA2E005A2B8E /* InsertionSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertionSortTests.swift; sourceTree = ""; }; - 7B18E0A81C5BFA2E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0B11C5BFA4B005A2B8E /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = "../../../Quicksort/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift"; sourceTree = ""; }; - 7B18E0B31C5BFA5F005A2B8E /* InsertionSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InsertionSort.swift; path = ../../InsertionSort.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E0901C5BFA2E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E09F1C5BFA2E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E08A1C5BFA2E005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E0951C5BFA2E005A2B8E /* InsertionSort */, - 7B18E0A51C5BFA2E005A2B8E /* InsertionSortTests */, - 7B18E0941C5BFA2E005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0941C5BFA2E005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E0931C5BFA2E005A2B8E /* InsertionSort.app */, - 7B18E0A21C5BFA2E005A2B8E /* InsertionSortTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E0951C5BFA2E005A2B8E /* InsertionSort */ = { - isa = PBXGroup; - children = ( - 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */, - 7B18E0981C5BFA2E005A2B8E /* Assets.xcassets */, - 7B18E09D1C5BFA2E005A2B8E /* Info.plist */, - 7B18E0B31C5BFA5F005A2B8E /* InsertionSort.swift */, - 7B18E09A1C5BFA2E005A2B8E /* MainMenu.xib */, - ); - path = InsertionSort; - sourceTree = ""; - }; - 7B18E0A51C5BFA2E005A2B8E /* InsertionSortTests */ = { - isa = PBXGroup; - children = ( - 7B18E0A81C5BFA2E005A2B8E /* Info.plist */, - 7B18E0A61C5BFA2E005A2B8E /* InsertionSortTests.swift */, - 7B18E0B11C5BFA4B005A2B8E /* SortingTestHelpers.swift */, - ); - path = InsertionSortTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E0921C5BFA2E005A2B8E /* InsertionSort */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0AB1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "InsertionSort" */; - buildPhases = ( - 7B18E08F1C5BFA2E005A2B8E /* Sources */, - 7B18E0901C5BFA2E005A2B8E /* Frameworks */, - 7B18E0911C5BFA2E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = InsertionSort; - productName = InsertionSort; - productReference = 7B18E0931C5BFA2E005A2B8E /* InsertionSort.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E0A11C5BFA2E005A2B8E /* InsertionSortTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0AE1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "InsertionSortTests" */; - buildPhases = ( - 7B18E09E1C5BFA2E005A2B8E /* Sources */, - 7B18E09F1C5BFA2E005A2B8E /* Frameworks */, - 7B18E0A01C5BFA2E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0A41C5BFA2E005A2B8E /* PBXTargetDependency */, - ); - name = InsertionSortTests; - productName = InsertionSortTests; - productReference = 7B18E0A21C5BFA2E005A2B8E /* InsertionSortTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E08B1C5BFA2E005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E0921C5BFA2E005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E0A11C5BFA2E005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E0921C5BFA2E005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E08E1C5BFA2E005A2B8E /* Build configuration list for PBXProject "InsertionSort" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E08A1C5BFA2E005A2B8E; - productRefGroup = 7B18E0941C5BFA2E005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E0921C5BFA2E005A2B8E /* InsertionSort */, - 7B18E0A11C5BFA2E005A2B8E /* InsertionSortTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E0911C5BFA2E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0991C5BFA2E005A2B8E /* Assets.xcassets in Resources */, - 7B18E09C1C5BFA2E005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0A01C5BFA2E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E08F1C5BFA2E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0971C5BFA2E005A2B8E /* AppDelegate.swift in Sources */, - 7B18E0B41C5BFA5F005A2B8E /* InsertionSort.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E09E1C5BFA2E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0B21C5BFA4B005A2B8E /* SortingTestHelpers.swift in Sources */, - 7B18E0A71C5BFA2E005A2B8E /* InsertionSortTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0A41C5BFA2E005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E0921C5BFA2E005A2B8E /* InsertionSort */; - targetProxy = 7B18E0A31C5BFA2E005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18E09A1C5BFA2E005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18E09B1C5BFA2E005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E0A91C5BFA2E005A2B8E /* 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; - }; - 7B18E0AA1C5BFA2E005A2B8E /* 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; - }; - 7B18E0AC1C5BFA2E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = InsertionSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.InsertionSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0AD1C5BFA2E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = InsertionSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.InsertionSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0AF1C5BFA2E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = InsertionSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.InsertionSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/InsertionSort.app/Contents/MacOS/InsertionSort"; - }; - name = Debug; - }; - 7B18E0B01C5BFA2E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = InsertionSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.InsertionSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/InsertionSort.app/Contents/MacOS/InsertionSort"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E08E1C5BFA2E005A2B8E /* Build configuration list for PBXProject "InsertionSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0A91C5BFA2E005A2B8E /* Debug */, - 7B18E0AA1C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0AB1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "InsertionSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0AC1C5BFA2E005A2B8E /* Debug */, - 7B18E0AD1C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0AE1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "InsertionSortTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0AF1C5BFA2E005A2B8E /* Debug */, - 7B18E0B01C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E08B1C5BFA2E005A2B8E /* Project object */; -} diff --git a/Insertion Sort/InsertionSort Tests/InsertionSort/AppDelegate.swift b/Insertion Sort/InsertionSort Tests/InsertionSort/AppDelegate.swift deleted file mode 100644 index 7e8ee6125..000000000 --- a/Insertion Sort/InsertionSort Tests/InsertionSort/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// InsertionSort -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Insertion Sort/InsertionSort Tests/InsertionSort/Assets.xcassets/AppIcon.appiconset/Contents.json b/Insertion Sort/InsertionSort Tests/InsertionSort/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Insertion Sort/InsertionSort Tests/InsertionSort/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/Insertion Sort/InsertionSort Tests/InsertionSort/Base.lproj/MainMenu.xib b/Insertion Sort/InsertionSort Tests/InsertionSort/Base.lproj/MainMenu.xib deleted file mode 100644 index c08abf93b..000000000 --- a/Insertion Sort/InsertionSort Tests/InsertionSort/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Insertion Sort/InsertionSort Tests/InsertionSort/Info.plist b/Insertion Sort/InsertionSort Tests/InsertionSort/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Insertion Sort/InsertionSort Tests/InsertionSort/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 867feb190..e1d3a312e 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -1,19 +1,46 @@ //: Playground - noun: a place where people can play -func insertionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { - var a = array - for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { - a[y] = a[y - 1] - y -= 1 +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameters: +/// - array: the array of elements to be sorted +/// - isOrderedBefore: returns true if the elements provided are in the corect order +/// - Returns: a sorted array containing the same elements +func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + + var sortedArray = array + for index in 1.. 0 && isOrderedBefore(temp, sortedArray[currentIndex - 1]) { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 + } + sortedArray[currentIndex] = temp } - a[y] = temp - } - return a + return sortedArray +} + +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol +/// - Returns: a sorted array containing the same elements +func insertionSort(_ array: [T]) -> [T] { + var sortedArray = array + for index in 1.. 0 && temp < sortedArray[currentIndex - 1] { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 + } + sortedArray[currentIndex] = temp + } + return sortedArray } let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] -insertionSort(list, <) -insertionSort(list, >) +print(insertionSort(list)) +print(insertionSort(list, <)) +print(insertionSort(list, >)) diff --git a/Insertion Sort/InsertionSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Insertion Sort/InsertionSort.playground/timeline.xctimeline b/Insertion Sort/InsertionSort.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Insertion Sort/InsertionSort.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 886054e53..5f0b6c2b4 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -1,15 +1,40 @@ -func insertionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { - guard array.count > 1 else { return array } +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameters: +/// - array: the array of elements to be sorted +/// - isOrderedBefore: returns true if the elements provided are in the corect order +/// - Returns: a sorted array containing the same elements +func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + /// - sortedArray: copy the array to save stability + var sortedArray = array + for index in 1.. 0, isOrderedBefore(temp, sortedArray[currentIndex - 1]) { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 + } + sortedArray[currentIndex] = temp + } + return sortedArray +} + +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameter array: the array to be sorted, containing elements that conform to the Comparable protocol +/// - Returns: a sorted array containing the same elements +func insertionSort(_ array: [T]) -> [T] { + guard array.count > 1 else { return array } - var a = array - for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { - a[y] = a[y - 1] - y -= 1 + var sortedArray = array + for var index in 1.. 0, temp < sortedArray[index - 1] { + sortedArray[index] = sortedArray[index - 1] + index -= 1 + } + sortedArray[index] = temp } - a[y] = temp - } - return a + return sortedArray } diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index ea39f5dad..f7b933b92 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -13,7 +13,7 @@ You are given an array of numbers and need to put them in the right order. The i That's why this is called an "insertion" sort, because you take a number from the pile and insert it in the array in its proper sorted position. -### An example +## An example Let's say the numbers to sort are `[ 8, 3, 5, 4, 6 ]`. This is our unsorted pile. @@ -25,7 +25,7 @@ Pick the next number from the pile, `5`, and insert it into the sorted array. It Repeat this process until the pile is empty. -### In-place sort +## In-place sort The above explanation makes it seem like you need two arrays: one for the unsorted pile and one that contains the numbers in sorted order. @@ -54,7 +54,7 @@ This is how the content of the array changes during the sort: In each step, the `|` bar moves up one position. As you can see, the beginning of the array up to the `|` is always sorted. The pile shrinks by one and the sorted portion grows by one, until the pile is empty and there are no more unsorted numbers left. -### How to insert +## How to insert At each step you pick the top-most number from the unsorted pile and insert it into the sorted portion of the array. You must put that number in the proper place so that the beginning of the array remains sorted. How does that work? @@ -85,22 +85,24 @@ Again, look at the previous element. Is `3` greater than `4`? No, it is not. Tha This was a description of the inner loop of the insertion sort algorithm, which you'll see in the next section. It inserts the number from the top of the pile into the sorted portion by swapping numbers. -### The code +## The code -Here is a simple implementation of insertion sort in Swift: +Here is an implementation of insertion sort in Swift: ```swift -func insertionSort(array: [Int]) -> [Int] { - var a = array // 1 - for x in 1.. 0 && a[y] < a[y - 1] { // 3 - swap(&a[y - 1], &a[y]) - y -= 1 +func insertionSort(_ array: [Int]) -> [Int] { + var sortedArray = array // 1 + for index in 1.. 0 && sortedArray[currentIndex] < sortedArray[currentIndex - 1] { // 3 + sortedArray.swapAt(currentIndex - 1, currentIndex) + currentIndex -= 1 + } } - } - return a + return sortedArray } + + ``` Put this code in a playground and test it like so: @@ -112,15 +114,15 @@ insertionSort(list) Here is how the code works. -1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sort()`, the `insertionSort()` function will return a sorted *copy* of the original array. +1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sorted()`, the `insertionSort()` function will return a sorted *copy* of the original array. -2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `x` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `x` -- is always sorted. The rest, from index `x` until the last element, is the unsorted pile. +2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `currentIndex` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `currentIndex` -- is always sorted. The rest, from index `currentIndex` until the last element, is the unsorted pile. -3. The inner loop looks at the element at position `x`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. +3. The inner loop looks at the element at position `currentIndex`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. -Note: The outer loop starts at index 1, not 0. Moving the very first element from the pile to the sorted portion doesn't actually change anything, so we might as well skip it. +> **Note:** The outer loop starts at index 1, not 0. Moving the very first element from the pile to the sorted portion doesn't actually change anything, so we might as well skip it. -### No more swaps +## No more swaps The above version of insertion sort works fine, but it can be made a tiny bit faster by removing the call to `swap()`. @@ -151,31 +153,31 @@ Instead of swapping with each of the previous elements, we can just shift all th In code that looks like this: ```swift -func insertionSort(array: [Int]) -> [Int] { - var a = array - for x in 1.. 0 && temp < a[y - 1] { - a[y] = a[y - 1] // 1 - y -= 1 +func insertionSort(_ array: [Int]) -> [Int] { + var sortedArray = array + for index in 1.. 0 && temp < sortedArray[currentIndex - 1] { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] // 1 + currentIndex -= 1 } - a[y] = temp // 2 + sortedArray[currentIndex] = temp // 2 } - return a + return sortedArray } ``` The line at `//1` is what shifts up the previous elements by one position. At the end of the inner loop, `y` is the destination index for the new number in the sorted portion, and the line at `//2` copies this number into place. -### Making it generic +## Making it generic It would be nice to sort other things than just numbers. We can make the datatype of the array generic and use a user-supplied function (or closure) to perform the less-than comparison. This only requires two changes to the code. The function signature becomes: ```swift -func insertionSort(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. @@ -188,7 +190,7 @@ The only other change is in the inner loop, which now becomes: while y > 0 && isOrderedBefore(temp, a[y - 1]) { ``` -Instead of writing `temp < a[y - 1]`, we now call the `isOrderedBefore()` function. It does the exact same thing, except we can now compare any kind of object, not just numbers. +Instead of writing `temp < a[y - 1]`, we call the `isOrderedBefore()` function. It does the exact same thing, except we can now compare any kind of object, not just numbers. To test this in a playground, do: @@ -218,7 +220,7 @@ The closure tells `insertionSort()` to sort on the `priority` property of the ob Insertion sort is a *stable* sort. A sort is stable when elements that have identical sort keys remain in the same relative order after sorting. This is not important for simple values such as numbers or strings, but it is important when sorting more complex objects. In the example above, if two objects have the same `priority`, regardless of the values of their other properties, those two objects don't get swapped around. -### Performance +## Performance Insertion sort is really fast if the array is already sorted. That sounds obvious, but this is not true for all search algorithms. In practice, a lot of data will already be largely -- if not entirely -- sorted and insertion sort works quite well in that case. @@ -228,8 +230,8 @@ Insertion sort is actually very fast for sorting small arrays. Some standard lib I did a quick test comparing our `insertionSort()` with Swift's built-in `sort()`. On arrays of about 100 items or so, the difference in speed is tiny. However, as your input becomes larger, **O(n^2)** quickly starts to perform a lot worse than **O(n log n)** and insertion sort just can't keep up. -### See also +## See also -See also [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort). +[Insertion sort on Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort) -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Insertion Sort/Tests/Info.plist b/Insertion Sort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Insertion Sort/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/Insertion Sort/InsertionSort Tests/InsertionSortTests/InsertionSortTests.swift b/Insertion Sort/Tests/InsertionSortTests.swift similarity index 80% rename from Insertion Sort/InsertionSort Tests/InsertionSortTests/InsertionSortTests.swift rename to Insertion Sort/Tests/InsertionSortTests.swift index 351ee6157..49f5eda9a 100644 --- a/Insertion Sort/InsertionSort Tests/InsertionSortTests/InsertionSortTests.swift +++ b/Insertion Sort/Tests/InsertionSortTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import InsertionSort class InsertionSortTests: XCTestCase { func testInsertionSort() { diff --git a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e9ea3bc53 --- /dev/null +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,291 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */; }; + 7B80C3EC1C77A536003CECC7 /* InsertionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3EB1C77A536003CECC7 /* InsertionSortTests.swift */; }; + 7B80C3EE1C77A53E003CECC7 /* InsertionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3ED1C77A53E003CECC7 /* InsertionSort.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; }; + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = ../../Quicksort/Tests/SortingTestHelpers.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3EB1C77A536003CECC7 /* InsertionSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsertionSortTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3ED1C77A53E003CECC7 /* InsertionSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InsertionSort.swift; path = ../InsertionSort.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 = ( + 7B80C3ED1C77A53E003CECC7 /* InsertionSort.swift */, + 7B80C3EB1C77A536003CECC7 /* InsertionSortTests.swift */, + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */, + 7B80C3EE1C77A53E003CECC7 /* InsertionSort.swift in Sources */, + 7B80C3EC1C77A536003CECC7 /* InsertionSortTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; + }; + 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_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; + }; + 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/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Introsort/HeapSort.swift b/Introsort/HeapSort.swift new file mode 100644 index 000000000..f5bc466da --- /dev/null +++ b/Introsort/HeapSort.swift @@ -0,0 +1,50 @@ +import Foundation + +private func shiftDown(_ elements: inout [T], _ index: Int, _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let countToIndex = elements.distance(from: range.lowerBound, to: index) + let countFromIndex = elements.distance(from: index, to: range.upperBound) + + guard countToIndex + 1 < countFromIndex else { return } + + let left = elements.index(index, offsetBy: countToIndex + 1) + var largest = index + if areInIncreasingOrder(elements[largest], elements[left]) { + largest = left + } + + if countToIndex + 2 < countFromIndex { + let right = elements.index(after: left) + if areInIncreasingOrder(elements[largest], elements[right]) { + largest = right + } + } + + if largest != index { + elements.swapAt(index, largest) + shiftDown(&elements, largest, range, by: areInIncreasingOrder) + } + +} + +private func heapify(_ list: inout [T], _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let root = range.lowerBound + var node = list.index(root, offsetBy: list.distance(from: range.lowerBound, to: range.upperBound)/2) + + while node != root { + list.formIndex(before: &node) + shiftDown(&list, node, range, by: areInIncreasingOrder) + } +} + +public func heapsort(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + var hi = range.upperBound + let lo = range.lowerBound + heapify(&array, range, by: areInIncreasingOrder) + array.formIndex(before: &hi) + + while hi != lo { + array.swapAt(lo, hi) + shiftDown(&array, lo, lo..(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + guard !range.isEmpty else { return } + + let start = range.lowerBound + var sortedEnd = start + + array.formIndex(after: &sortedEnd) + while sortedEnd != range.upperBound { + let x = array[sortedEnd] + + var i = sortedEnd + repeat { + let predecessor = array[array.index(before: i)] + + guard areInIncreasingOrder(x, predecessor) else { break } + array[i] = predecessor + array.formIndex(before: &i) + } while i != start + + if i != sortedEnd { + array[i] = x + } + array.formIndex(after: &sortedEnd) + } + +} diff --git a/Introsort/IntroSort.swift b/Introsort/IntroSort.swift new file mode 100644 index 000000000..866b2603f --- /dev/null +++ b/Introsort/IntroSort.swift @@ -0,0 +1,32 @@ +import Foundation + +public func introsort(_ array: inout [T], by areInIncreasingOrder: (T, T) -> Bool) { + //The depth limit is as best practice 2 * log( n ) + let depthLimit = 2 * floor(log2(Double(array.count))) + + introSortImplementation(for: &array, range: 0..(for array: inout [T], range: Range, depthLimit: Int, by areInIncreasingOrder: (T, T) -> Bool) { + if array.distance(from: range.lowerBound, to: range.upperBound) < 20 { + //if the partition count is less than 20 we can sort it using insertion sort. This algorithm in fact performs well on collections + //of this size, plus, at this point is quite probable that the quisksort part of the algorithm produced a partition which is + //nearly sorted. As we knoe insertion sort tends to O( n ) if this is the case. + insertionSort(for: &array, range: range, by: areInIncreasingOrder) + } else if depthLimit == 0 { + //If we reached the depth limit for this recursion branch, it's possible that we are hitting quick sort's worst case. + //Since quicksort degrades to O( n^2 ) in its worst case we stop using quicksort for this recursion branch and we switch to heapsort. + //Our preference remains quicksort, and we hope to be rare to see this condition to be true + heapsort(for: &array, range: range, by: areInIncreasingOrder) + } else { + //By default we use quicksort to sort our collection. The partition index method chose a pivot, and puts all the + //elements less than pivot on the left, and the ones bigger than pivot on the right. At the end of the operation the + //position of the pivot in the array is returned so that we can form the two partitions. + let partIdx = partitionIndex(for: &array, subRange: range, by: areInIncreasingOrder) + + //We can recursively call introsort implementation, decreasing the depthLimit for the left partition and the right partition. + introSortImplementation(for: &array, range: range.lowerBound..(_ array: inout [T], by areInIncreasingOrder: (T, T) -> Bool) { + //The depth limit is as best practice 2 * log( n ) + let depthLimit = 2 * floor(log2(Double(array.count))) + + introSortImplementation(for: &array, range: 0..(for array: inout [T], range: Range, depthLimit: Int, by areInIncreasingOrder: (T, T) -> Bool) { + if array.distance(from: range.lowerBound, to: range.upperBound) < 20 { + //if the partition count is less than 20 we can sort it using insertion sort. This algorithm in fact performs well on collections + //of this size, plus, at this point is quite probable that the quisksort part of the algorithm produced a partition which is + //nearly sorted. As we knoe insertion sort tends to O( n ) if this is the case. + insertionSort(for: &array, range: range, by: areInIncreasingOrder) + } else if depthLimit == 0 { + //If we reached the depth limit for this recursion branch, it's possible that we are hitting quick sort's worst case. + //Since quicksort degrades to O( n^2 ) in its worst case we stop using quicksort for this recursion branch and we switch to heapsort. + //Our preference remains quicksort, and we hope to be rare to see this condition to be true + heapsort(for: &array, range: range, by: areInIncreasingOrder) + } else { + //By default we use quicksort to sort our collection. The partition index method chose a pivot, and puts all the + //elements less than pivot on the left, and the ones bigger than pivot on the right. At the end of the operation the + //position of the pivot in the array is returned so that we can form the two partitions. + let partIdx = partitionIndex(for: &array, subRange: range, by: areInIncreasingOrder) + + //We can recursively call introsort implementation, decreasing the depthLimit for the left partition and the right partition. + introSortImplementation(for: &array, range: range.lowerBound..(_ elements: inout [T], _ index: Int, _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let countToIndex = elements.distance(from: range.lowerBound, to: index) + let countFromIndex = elements.distance(from: index, to: range.upperBound) + + guard countToIndex + 1 < countFromIndex else { return } + + let left = elements.index(index, offsetBy: countToIndex + 1) + var largest = index + if areInIncreasingOrder(elements[largest], elements[left]) { + largest = left + } + + if countToIndex + 2 < countFromIndex { + let right = elements.index(after: left) + if areInIncreasingOrder(elements[largest], elements[right]) { + largest = right + } + } + + if largest != index { + elements.swapAt(index, largest) + shiftDown(&elements, largest, range, by: areInIncreasingOrder) + } + +} + +private func heapify(_ list: inout [T], _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let root = range.lowerBound + var node = list.index(root, offsetBy: list.distance(from: range.lowerBound, to: range.upperBound)/2) + + while node != root { + list.formIndex(before: &node) + shiftDown(&list, node, range, by: areInIncreasingOrder) + } +} + +public func heapsort(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + var hi = range.upperBound + let lo = range.lowerBound + heapify(&array, range, by: areInIncreasingOrder) + array.formIndex(before: &hi) + + while hi != lo { + array.swapAt(lo, hi) + shiftDown(&array, lo, lo..(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + guard !range.isEmpty else { return } + + let start = range.lowerBound + var sortedEnd = start + + array.formIndex(after: &sortedEnd) + while sortedEnd != range.upperBound { + let x = array[sortedEnd] + + var i = sortedEnd + repeat { + let predecessor = array[array.index(before: i)] + + guard areInIncreasingOrder(x, predecessor) else { break } + array[i] = predecessor + array.formIndex(before: &i) + } while i != start + + if i != sortedEnd { + array[i] = x + } + array.formIndex(after: &sortedEnd) + } + +} diff --git a/Introsort/Introsort.playground/Sources/Partition.swift b/Introsort/Introsort.playground/Sources/Partition.swift new file mode 100644 index 000000000..e24636da7 --- /dev/null +++ b/Introsort/Introsort.playground/Sources/Partition.swift @@ -0,0 +1,43 @@ +import Foundation + +public func partitionIndex(for elements: inout [T], subRange range: Range, by areInIncreasingOrder: (T, T) -> Bool) -> Int { + var lo = range.lowerBound + var hi = elements.index(before: range.upperBound) + + // Sort the first, middle, and last elements, then use the middle value + // as the pivot for the partition. + let half = elements.distance(from: lo, to: hi) / 2 + let mid = elements.index(lo, offsetBy: half) + + sort3(in: &elements, a: lo, b: mid, c: hi, by: areInIncreasingOrder) + let pivot = elements[mid] + + while true { + elements.formIndex(after: &lo) + guard findLo(in: elements, pivot: pivot, from: &lo, to: hi, by: areInIncreasingOrder) else { break } + elements.formIndex(before: &hi) + guard findHi(in: elements, pivot: pivot, from: lo, to: &hi, by: areInIncreasingOrder) else { break } + elements.swapAt(lo, hi) + } + + + return lo +} + +private func findLo(in array: [T], pivot: T, from lo: inout Int, to hi: Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while lo != hi { + if !areInIncreasingOrder(array[lo], pivot) { + return true + } + array.formIndex(after: &lo) + } + return false +} + +private func findHi(in array: [T], pivot: T, from lo: Int, to hi: inout Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while hi != lo { + if areInIncreasingOrder(array[hi], pivot) { return true } + array.formIndex(before: &hi) + } + return false +} diff --git a/Introsort/Introsort.playground/Sources/Randomize.swift b/Introsort/Introsort.playground/Sources/Randomize.swift new file mode 100644 index 000000000..6d1d57132 --- /dev/null +++ b/Introsort/Introsort.playground/Sources/Randomize.swift @@ -0,0 +1,9 @@ +import Foundation + +public func randomize(n: Int) -> [Int] { + var unsorted = [Int]() + for _ in 0..(in array: inout [T], a: Int, b: Int, c: Int, by areInIncreasingOrder: (T, T) -> Bool) { + switch (areInIncreasingOrder(array[b], array[a]), + areInIncreasingOrder(array[c], array[b])) { + case (false, false): break + case (true, true): array.swapAt(a, c) + case (true, false): + array.swapAt(a, b) + + if areInIncreasingOrder(array[c], array[b]) { + array.swapAt(b, c) + } + case (false, true): + array.swapAt(b, c) + + if areInIncreasingOrder(array[b], array[a]) { + array.swapAt(a, b) + } + } +} diff --git a/Introsort/Introsort.playground/contents.xcplayground b/Introsort/Introsort.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Introsort/Introsort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Introsort/Partition.swift b/Introsort/Partition.swift new file mode 100644 index 000000000..e24636da7 --- /dev/null +++ b/Introsort/Partition.swift @@ -0,0 +1,43 @@ +import Foundation + +public func partitionIndex(for elements: inout [T], subRange range: Range, by areInIncreasingOrder: (T, T) -> Bool) -> Int { + var lo = range.lowerBound + var hi = elements.index(before: range.upperBound) + + // Sort the first, middle, and last elements, then use the middle value + // as the pivot for the partition. + let half = elements.distance(from: lo, to: hi) / 2 + let mid = elements.index(lo, offsetBy: half) + + sort3(in: &elements, a: lo, b: mid, c: hi, by: areInIncreasingOrder) + let pivot = elements[mid] + + while true { + elements.formIndex(after: &lo) + guard findLo(in: elements, pivot: pivot, from: &lo, to: hi, by: areInIncreasingOrder) else { break } + elements.formIndex(before: &hi) + guard findHi(in: elements, pivot: pivot, from: lo, to: &hi, by: areInIncreasingOrder) else { break } + elements.swapAt(lo, hi) + } + + + return lo +} + +private func findLo(in array: [T], pivot: T, from lo: inout Int, to hi: Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while lo != hi { + if !areInIncreasingOrder(array[lo], pivot) { + return true + } + array.formIndex(after: &lo) + } + return false +} + +private func findHi(in array: [T], pivot: T, from lo: Int, to hi: inout Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while hi != lo { + if areInIncreasingOrder(array[hi], pivot) { return true } + array.formIndex(before: &hi) + } + return false +} diff --git a/Introsort/README.markdown b/Introsort/README.markdown new file mode 100644 index 000000000..280950928 --- /dev/null +++ b/Introsort/README.markdown @@ -0,0 +1,113 @@ +# IntroSort + +Goal: Sort an array from low to high (or high to low). + +IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. + +The classic implementation of introsort uses a recursive Quicksort with a fallback to Heapsort in the case where the recursion depth level reached a certain maximum value. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. + +The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. + +Here's an implementation in pseudocode: + +``` +procedure sort(A : array): + let maxdepth = ⌊log(length(A))⌋ × 2 + introSort(A, maxdepth) + +procedure introsort(A, maxdepth): + n ← length(A) + if n < 20: + insertionsort(A) + else if maxdepth = 0: + heapsort(A) + else: + p ← partition(A) // the pivot is selected using median of 3 + introsort(A[0:p], maxdepth - 1) + introsort(A[p+1:n], maxdepth - 1) +``` + +## An example + +Let's walk through the example. The array is initially: + + [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] + + +For this example let's assume that `maxDepth` is **2** and that the size of the partition for the insertionSort to kick in is **5** + +The first iteration of introsort begins by attempting to use insertionSort. The collection has 13 elements, so it tries to do heapsort instead. The condition for heapsort to occur is if `maxdepth == 0` evaluates true. Since `maxdepth` is currently **2** for the first iteration, introsort will default to quicksort. + +The `partition` method picks the first element, the median and the last, it sorts them and uses the new median as pivot. + + [ 10, 8, 26 ] -> [ 8, 10, 26 ] + +Our array is now + + [ 8, 0, 3, 9, 2, 14, 10, 27, 1, 5, 8, -1, 26 ] + +**10** is the pivot. After the choice of the pivot, the `partition` method swaps elements to get all the elements less than pivot on the left, and all the elements more or equal than pivot on the right. + + [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10, 27, 14, 26 ] + +Because of the swaps, the index of of pivot is now changed and returned. The next step of introsort is to call recursively itself for the two sub arrays: + + less: [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + greater: [ 27, 14, 26 ] + +## maxDepth: 1, branch: less + + [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + +The count of the array is still more than 5 so we don't meet yet the conditions for insertion sort to kick in. At this iteration maxDepth is decreased by one but it is still more than zero, so heapsort will not act. + +Just like in the previous iteration quicksort wins and the `partition` method choses a pivot and sorts the elemets less than pivot on the left and the elements more or equeal than pivot on the right. + + array: [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + pivot candidates: [ 8, 1, 10] -> [ 1, 8, 10] + pivot: 8 + before partition: [ 1, 0, 3, 9, 2, 8, 5, 8, -1, 10 ] + after partition: [ 1, 0, 3, -1, 2, 5, 8, 8, 9, 10 ] + + less: [ 1, 0, 3, -1, 2, 5, 8 ] + greater: [ 8, 9, 10 ] + +## maxDepth: 0, branch: less + + [ 1, 0, 3, -1, 2, 5, 8 ] + +Just like before, introsort is recursively executed for `less` and greater. This time `less`has a count more than **5** so it will not be sorted with insertion sort, but the maxDepth decreased again by 1 is now 0 and heapsort takes over sorting the array. + + heapsort -> [ -1, 0, 1, 2, 3, 5, 8 ] + +## maxDepth: 0, branch: greater + + [ 8, 9, 10 ] + +following greater in this recursion, the count of elements is 3, which is less than 5, so this partition is sorted using insertionSort. + + insertionSort -> [ 8, 9 , 10] + + +## back to maxDepth = 1, branch: greater + + [ 27, 14, 26 ] + +At this point the original array has mutated to be + + [ -1, 0, 1, 2, 3, 5, 8, 8, 9, 10, 27, 14, 26 ] + +now the `less` partition is sorted and since the count of the `greater` partition is 3 it will be sorted with insertion sort `[ 14, 26, 27 ]` + +The array is now successfully sorted + + [ -1, 0, 1, 2, 3, 5, 8, 8, 9, 10, 14, 26, 27 ] + + +## See also + +[Introsort on Wikipedia](https://en.wikipedia.org/wiki/Introsort) +[Introsort comparison with other sorting algorithms](http://agostini.tech/2017/12/18/swift-sorting-algorithm/) +[Introsort implementation from the Swift standard library](https://github.com/apple/swift/blob/09f77ff58d250f5d62855ea359fc304f40b531df/stdlib/public/core/Sort.swift.gyb) + +*Written for Swift Algorithm Club by Giuseppe Lanza* diff --git a/Introsort/Randomize.swift b/Introsort/Randomize.swift new file mode 100644 index 000000000..6d1d57132 --- /dev/null +++ b/Introsort/Randomize.swift @@ -0,0 +1,9 @@ +import Foundation + +public func randomize(n: Int) -> [Int] { + var unsorted = [Int]() + for _ in 0..(in array: inout [T], a: Int, b: Int, c: Int, by areInIncreasingOrder: (T, T) -> Bool) { + switch (areInIncreasingOrder(array[b], array[a]), + areInIncreasingOrder(array[c], array[b])) { + case (false, false): break + case (true, true): array.swapAt(a, c) + case (true, false): + array.swapAt(a, b) + + if areInIncreasingOrder(array[c], array[b]) { + array.swapAt(b, c) + } + case (false, true): + array.swapAt(b, c) + + if areInIncreasingOrder(array[b], array[a]) { + array.swapAt(a, b) + } + } +} diff --git a/K-Means/Images/k_means_bad1.png b/K-Means/Images/k_means_bad1.png new file mode 100644 index 000000000..07cb656b6 Binary files /dev/null and b/K-Means/Images/k_means_bad1.png differ diff --git a/K-Means/Images/k_means_bad2.png b/K-Means/Images/k_means_bad2.png new file mode 100644 index 000000000..74b99d4db Binary files /dev/null and b/K-Means/Images/k_means_bad2.png differ diff --git a/K-Means/Images/k_means_good.png b/K-Means/Images/k_means_good.png new file mode 100644 index 000000000..bb6a996a8 Binary files /dev/null and b/K-Means/Images/k_means_good.png differ diff --git a/K-Means/KMeans.swift b/K-Means/KMeans.swift new file mode 100644 index 000000000..bccc6efd3 --- /dev/null +++ b/K-Means/KMeans.swift @@ -0,0 +1,95 @@ +import Foundation + +class KMeans { + let numCenters: Int + let labels: [Label] + private(set) var centroids = [Vector]() + + init(labels: [Label]) { + assert(labels.count > 1, "Exception: KMeans with less than 2 centers.") + self.labels = labels + self.numCenters = labels.count + } + + private func indexOfNearestCenter(_ x: Vector, centers: [Vector]) -> Int { + var nearestDist = Double.greatestFiniteMagnitude + var minIndex = 0 + + for (idx, center) in centers.enumerated() { + let dist = x.distanceTo(center) + if dist < nearestDist { + minIndex = idx + nearestDist = dist + } + } + return minIndex + } + + 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) + + var centerMoveDist = 0.0 + repeat { + // This array keeps track of which data points belong to which centroids. + var classification: [[Vector]] = .init(repeating: [], count: numCenters) + + // For each data point, find the centroid that it is closest to. + for p in points { + let classIndex = indexOfNearestCenter(p, centers: centers) + classification[classIndex].append(p) + } + + // 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, +) / Double(assignedPoints.count) + } + + // Find out how far each centroid moved since the last iteration. If it's + // only a small distance, then we're done. + centerMoveDist = 0.0 + for idx in 0.. convergeDistance + + centroids = centers + } + + 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] { + assert(!centroids.isEmpty, "Exception: KMeans tried to fit on a non trained model.") + + return points.map(fit) + } +} + +// Pick k random elements from samples +func reservoirSample(_ samples: [T], k: Int) -> [T] { + var result = [T]() + + // Fill the result array with first k elements + for i in 0.. **Note:** These examples are contrived to show the exact nature of k-Means and finding clusters. The clusters in these examples are very easily identified by human eyes: we see there is one in the lower left corner, one in the upper right corner, and maybe one in the middle. In practice, however, data may have many dimensions and may be impossible to visualize. In such cases, k-Means is much better at this job than human eyes! + +#### Bad 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 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) + +In this example, the blue cluster never really could separate from the red cluster and as such sort of got stuck down there. + +#### Improving bad clustering + +In these examples of "bad" clustering, the algorithm got stuck in a local optimum. It does find clusters but they're not the best way to divide up the data. To increase your chances of success, you can run the algorithm several times, each time with different points as the initial centroids. You choose the clustering that gives the best results. + +To calculate how "good" the clustering is, you find the distance of each data point to its cluster, and add up all these distances. The lower this number, the better! That means each cluster is really in the center of a group of data points, and all clusters are roughly the same size and are spaced evenly apart. + +## The code + +This is what the algorithm could look like in Swift. The `points` array contains the input data as `Vector` objects. The output is an array of `Vector` objects representing the clusters that were found. + +```swift +func kMeans(numCenters: Int, convergeDistance: Double, points: [Vector]) -> [Vector] { + + // Randomly take k objects from the input data to make the initial centroids. + var centers = reservoirSample(points, k: numCenters) + + // This loop repeats until we've reached convergence, i.e. when the centroids + // have moved less than convergeDistance since the last iteration. + var centerMoveDist = 0.0 + repeat { + // In each iteration of the loop, we move the centroids to a new position. + // The newCenters array contains those new positions. + let zeros = [Double](count: points[0].length, repeatedValue: 0) + var newCenters = [Vector](count: numCenters, repeatedValue: Vector(zeros)) + + // We keep track of how many data points belong to each centroid, so we + // can calculate the average later. + var counts = [Double](count: numCenters, repeatedValue: 0) + + // For each data point, find the centroid that it is closest to. We also + // add up the data points that belong to that centroid, in order to compute + // that average. + for p in points { + let c = indexOfNearestCenter(p, centers: centers) + newCenters[c] += p + counts[c] += 1 + } + + // Take the average of all the data points that belong to each centroid. + // This moves the centroid to a new position. + for idx in 0.. convergeDistance + + return centers +} +``` + +> **Note:** The code in [KMeans.swift](KMeans.swift) is slightly more advanced than the above listing. It also assigns labels to the clusters and has a few other tricks up its sleeve. Check it out! + +## Performance + +k-Means is classified as an NP-Hard type of problem. That means it's almost impossible to find the optimal solution. The selection of the initial centroids has a big effect on how the resulting clusters may end up. Finding an exact solution is not likely -- even in 2 dimensional space. + +As seen from the steps above the complexity really isn't that bad -- it is often considered to be on the order of **O(kndi)**, where **k** is the number of centroids, **n** is the number of **d**-dimensional vectors, and **i** is the number of iterations for convergence. + +The amount of data has a linear effect on the running time of k-Means, but tuning how far you want the centroids to converge can have a big impact how many iterations will be done. As a general rule, **k** should be relatively small compared to the number of vectors. + +Often times as more data is added certain points may lie in the boundary between two centroids and as such those centroids would continue to bounce back and forth and the convergence distance would need to be tuned to prevent that. + +## See Also + +[K-Means Clustering on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering) + +*Written by John Gill and Matthijs Hollemans* diff --git a/K-Means/Tests/Info.plist b/K-Means/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/K-Means/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/K-Means/Tests/KMeansTests.swift b/K-Means/Tests/KMeansTests.swift new file mode 100644 index 000000000..7e0c93004 --- /dev/null +++ b/K-Means/Tests/KMeansTests.swift @@ -0,0 +1,74 @@ +// +// Tests.swift +// Tests +// +// Created by John Gill on 2/29/16. +// +// + +import Foundation +import XCTest + +class KMeansTests: XCTestCase { + func genPoints(_ numPoints: Int, numDimensions: Int) -> [Vector] { + var points = [Vector]() + for _ in 0..(labels: ["A", "B", "C"]) + kmm.trainCenters(points, convergeDistance: 0.01) + + for (label, centroid) in zip(kmm.labels, kmm.centroids) { + print("\(label): \(centroid)") + } + + print("\nClassifications") + for (label, point) in zip(kmm.fit(points), points) { + print("\(label): \(point)") + } + } + + func testSmall_10D() { + let points = genPoints(10, numDimensions: 10) + + print("\nCenters") + let kmm = KMeans(labels: [1, 2, 3]) + kmm.trainCenters(points, convergeDistance: 0.01) + for c in kmm.centroids { + print(c) + } + } + + func testLarge_2D() { + let points = genPoints(10000, numDimensions: 2) + + print("\nCenters") + let kmm = KMeans(labels: ["A", "B", "C", "D", "E"]) + kmm.trainCenters(points, convergeDistance: 0.01) + for c in kmm.centroids { + print(c) + } + } + + func testLarge_10D() { + let points = genPoints(10000, numDimensions: 10) + + print("\nCenters") + let kmm = KMeans(labels: [1, 2, 3, 4, 5]) + kmm.trainCenters(points, convergeDistance: 0.01) + for c in kmm.centroids { + print(c) + } + } +} diff --git a/K-Means/Tests/Tests.xcodeproj/project.pbxproj b/K-Means/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..1cbd139e5 --- /dev/null +++ b/K-Means/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,318 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B80894E41C852D100018730E /* KMeansTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80894E31C852D100018730E /* KMeansTests.swift */; }; + B80894EA1C852DA00018730E /* Vector.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80894E91C852DA00018730E /* Vector.swift */; }; + B80894EB1C8530830018730E /* KMeans.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80894DB1C852CFA0018730E /* KMeans.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B80894DB1C852CFA0018730E /* KMeans.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; name = KMeans.swift; path = ../KMeans.swift; sourceTree = SOURCE_ROOT; tabWidth = 2; }; + B80894E01C852D100018730E /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B80894E31C852D100018730E /* KMeansTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMeansTests.swift; sourceTree = SOURCE_ROOT; }; + B80894E51C852D100018730E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + B80894E91C852DA00018730E /* Vector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vector.swift; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B80894DD1C852D100018730E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B80894D41C852CDC0018730E = { + isa = PBXGroup; + children = ( + B80894E21C852D100018730E /* Tests */, + B80894E11C852D100018730E /* Products */, + ); + sourceTree = ""; + }; + B80894E11C852D100018730E /* Products */ = { + isa = PBXGroup; + children = ( + B80894E01C852D100018730E /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + B80894E21C852D100018730E /* Tests */ = { + isa = PBXGroup; + children = ( + B80894DB1C852CFA0018730E /* KMeans.swift */, + B80894E31C852D100018730E /* KMeansTests.swift */, + B80894E91C852DA00018730E /* Vector.swift */, + B80894E51C852D100018730E /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B80894DF1C852D100018730E /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B80894E61C852D100018730E /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + B80894DC1C852D100018730E /* Sources */, + B80894DD1C852D100018730E /* Frameworks */, + B80894DE1C852D100018730E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = B80894E01C852D100018730E /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B80894D51C852CDC0018730E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1000; + TargetAttributes = { + B80894DF1C852D100018730E = { + CreatedOnToolsVersion = 7.2.1; + LastSwiftMigration = 1000; + }; + }; + }; + buildConfigurationList = B80894D81C852CDC0018730E /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = B80894D41C852CDC0018730E; + productRefGroup = B80894E11C852D100018730E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B80894DF1C852D100018730E /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B80894DE1C852D100018730E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B80894DC1C852D100018730E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B80894EA1C852DA00018730E /* Vector.swift in Sources */, + B80894E41C852D100018730E /* KMeansTests.swift in Sources */, + B80894EB1C8530830018730E /* KMeans.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B80894D91C852CDC0018730E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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; + }; + B80894DA1C852CDC0018730E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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; + }; + B80894E71C852D100018730E /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + 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; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.alvahouse322.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + B80894E81C852D100018730E /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = 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 = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.alvahouse322.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B80894D81C852CDC0018730E /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B80894D91C852CDC0018730E /* Debug */, + B80894DA1C852CDC0018730E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B80894E61C852D100018730E /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B80894E71C852D100018730E /* Debug */, + B80894E81C852D100018730E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B80894D51C852CDC0018730E /* Project object */; +} diff --git a/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/K-Means/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..73ba8f37d --- /dev/null +++ b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/K-Means/Tests/Vector.swift b/K-Means/Tests/Vector.swift new file mode 100644 index 000000000..591d2d498 --- /dev/null +++ b/K-Means/Tests/Vector.swift @@ -0,0 +1,68 @@ +import Foundation + +struct Vector: CustomStringConvertible, Equatable { + private(set) var length = 0 + private(set) var data: [Double] + + init(_ data: [Double]) { + self.data = data + self.length = data.count + } + + var description: String { + return "Vector (\(data)" + } + + func distanceTo(_ other: Vector) -> Double { + var result = 0.0 + for idx in 0.. Bool { + for idx in 0.. Vector { + var results = [Double]() + for idx in 0.. Vector { + var results = [Double]() + for idx in 0.. Vector { + var results = [Double](repeating: 0, count: left.length) + for (idx, value) in left.data.enumerated() { + results[idx] = value / right + } + return Vector(results) +} + +func /= (left: inout Vector, right: Double) { + left = left / right +} diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift new file mode 100644 index 000000000..e0ce23b19 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -0,0 +1,60 @@ +//: Playground - noun: a place where people can play + +import Foundation + +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, by num2: Int, base: Int = 10) -> Int { + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } + + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) + + for i in num1Array.indices { + var carry = 0 + for j in num2Array.indices { + product[i + j] += carry + num1Array[i] * num2Array[j] + carry = product[i + j] / base + product[i + j] %= base + } + product[i + num2Array.count] += carry + } + + return Int(product.reversed().map { String($0) }.reduce("", +))! +} + +// Karatsuba Multiplication - O(n^log2(3)) +func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1String = String(num1) + let num2String = String(num2) + + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) + } + + let n = max(num1String.count, num2String.count) + let nBy2 = n / 2 + + let a = num1 / 10^^nBy2 + let b = num1 % 10^^nBy2 + let c = num2 / 10^^nBy2 + let d = num2 % 10^^nBy2 + + let ac = karatsuba(a, by: c) + let bd = karatsuba(b, by: d) + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd + + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd + + return product +} diff --git a/Karatsuba Multiplication/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.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift new file mode 100644 index 000000000..3d14a243a --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -0,0 +1,66 @@ +// +// KaratsubaMultiplication.swift +// +// +// Created by Richard Ash on 9/12/16. +// +// + +import Foundation + +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, by num2: Int, base: Int = 10) -> Int { + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } + + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) + + for i in num1Array.indices { + var carry = 0 + for j in num2Array.indices { + product[i + j] += carry + num1Array[i] * num2Array[j] + carry = product[i + j] / base + product[i + j] %= base + } + product[i + num2Array.count] += carry + } + + return Int(product.reversed().map { String($0) }.reduce("", +))! +} + +// Karatsuba Multiplication - O(n^log2(3)) +func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1String = String(num1) + let num2String = String(num2) + + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) + } + + let n = max(num1String.count, num2String.count) + let nBy2 = n / 2 + + let a = num1 / 10^^nBy2 + let b = num1 % 10^^nBy2 + let c = num2 / 10^^nBy2 + let d = num2 % 10^^nBy2 + + let ac = karatsuba(a, by: c) + let bd = karatsuba(b, by: d) + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd + + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd + + return product +} diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown new file mode 100644 index 000000000..02e54a1bf --- /dev/null +++ b/Karatsuba Multiplication/README.markdown @@ -0,0 +1,124 @@ +# Karatsuba Multiplication + +Goal: To quickly multiply two numbers together + +## Long Multiplication + +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 + + 5678 + *1234 + ------ + 22712 + 17034- + 11356-- + 5678--- + -------- + 7006652 + +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 of 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! 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 + +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*10^m + b) * (c*10^m + d) + = a*c*10^(2m) + (a*d + b*c)*10^(m) + b*d + +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*d = (a*c + a*d + b*c + b*d) - a*c - b*d + = (a*d + b*c) + +Pretty cool, huh? + +Here's the full implementation. Note that the recursive algorithm is most efficient at m = n/2. + +```swift +// Karatsuba Multiplication +func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1String = String(num1) + let num2String = String(num2) + + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) + } + + let n = max(num1String.count, num2String.count) + let nBy2 = n / 2 + + let a = num1 / 10^^nBy2 + let b = num1 % 10^^nBy2 + let c = num2 / 10^^nBy2 + let d = num2 % 10^^nBy2 + + let ac = karatsuba(a, by: c) + let bd = karatsuba(b, by: d) + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd + + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd + + return product +} +``` + +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 + + 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) + +[Master Theorem](https://en.wikipedia.org/wiki/Master_theorem) + +*Written for Swift Algorithm Club by Richard Ash* diff --git a/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift new file mode 100644 index 000000000..379c9e812 --- /dev/null +++ b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift @@ -0,0 +1,17 @@ +// +// KaratsubaMultiplicationTests.swift +// Tests +// +// Created by Afonso Graça on 8/10/18. +// + +import XCTest + +final class KaratsubaMultiplicationTests: XCTestCase { + + func testReadmeExample() { + let subject = karatsuba(1234, by: 5678) + + XCTAssertEqual(subject, 7006652) + } +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ef23067ee --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,305 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */; }; + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6AF099A2216B54D500F69B16 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6AF099A7216B54D500F69B16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = KaratsubaMultiplication.swift; path = ../KaratsubaMultiplication.swift; sourceTree = ""; }; + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaratsubaMultiplicationTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6AF0999F216B54D500F69B16 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6AF09997216B545D00F69B16 = { + isa = PBXGroup; + children = ( + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */, + 6AF099A4216B54D500F69B16 /* Tests */, + 6AF099A3216B54D500F69B16 /* Products */, + ); + sourceTree = ""; + }; + 6AF099A3216B54D500F69B16 /* Products */ = { + isa = PBXGroup; + children = ( + 6AF099A2216B54D500F69B16 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 6AF099A4216B54D500F69B16 /* Tests */ = { + isa = PBXGroup; + children = ( + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */, + 6AF099A7216B54D500F69B16 /* Info.plist */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6AF099A1216B54D500F69B16 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 6AF0999E216B54D500F69B16 /* Sources */, + 6AF0999F216B54D500F69B16 /* Frameworks */, + 6AF099A0216B54D500F69B16 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 6AF099A2216B54D500F69B16 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6AF09998216B545D00F69B16 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + TargetAttributes = { + 6AF099A1216B54D500F69B16 = { + CreatedOnToolsVersion = 10.0; + }; + }; + }; + buildConfigurationList = 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 6AF09997216B545D00F69B16; + productRefGroup = 6AF099A3216B54D500F69B16 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6AF099A1216B54D500F69B16 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6AF099A0216B54D500F69B16 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6AF0999E216B54D500F69B16 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */, + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 6AF0999C216B545D00F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 6AF0999D216B545D00F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 6AF099A9216B54D500F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 6AF099AA216B54D500F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF0999C216B545D00F69B16 /* Debug */, + 6AF0999D216B545D00F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF099A9216B54D500F69B16 /* Debug */, + 6AF099AA216B54D500F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6AF09998216B545D00F69B16 /* Project object */; +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..1288fd9a8 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Karatsuba Multiplication/Tests/Tests/Info.plist b/Karatsuba Multiplication/Tests/Tests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift new file mode 100644 index 000000000..9b4a50fa0 --- /dev/null +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -0,0 +1,121 @@ +//: Playground - noun: a place where people can play + +func ZetaAlgorithm(ptnr: String) -> [Int]? { + + let pattern = Array(ptnr) + 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 + } + } + } + return zeta +} + +extension String { + + func indexesOf(ptnr: String) -> [Int]? { + + let text = Array(self) + 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 + } +} + +/* Examples */ + +let dna = "ACCCGGTTTTAAAGAACCACCATAAGATATAGACAGATATAGGACAGATATAGAGACAAAACCCCATACCCCAATATTTTTTTGGGGAGAAAAACACCACAGATAGATACACAGACTACACGAGATACGACATACAGCAGCATAACGACAACAGCAGATAGACGATCATAACAGCAATCAGACCGAGCGCAGCAGCTTTTAAGCACCAGCCCCACAAAAAACGACAATFATCATCATATACAGACGACGACACGACATATCACACGACAGCATA" +dna.indexesOf(ptnr: "CATA") // [20, 64, 130, 140, 166, 234, 255, 270] + +let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" +concert.indexesOf(ptnr: "🎻🎷") // [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.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift new file mode 100644 index 000000000..be0cd961d --- /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) + let pattern = Array(ptnr) + + 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 + } +} diff --git a/Knuth-Morris-Pratt/README.markdown b/Knuth-Morris-Pratt/README.markdown new file mode 100644 index 000000000..2e4d5360b --- /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-Horspool/) is usually preferred, the algorithm that we will introduce is simpler, and has the same (linear) running time. + +The idea behind the algorithm is not too different from the [naive string search](../Brute-Force%20String%20Search/) procedure. As it, Knuth-Morris-Pratt aligns the text with the pattern and goes with character comparisons from left to right. But, instead of making a shift of one character when a mismatch occurs, it uses a more intelligent way to move the pattern along the text. In fact, the algorithm features a pattern pre-processing stage where it acquires all the informations that will make the algorithm skip redundant comparisons, resulting in larger shifts. + +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* diff --git a/Kth Largest Element/README.markdown b/Kth Largest Element/README.markdown index 04d10ad99..b23d22b74 100644 --- a/Kth Largest Element/README.markdown +++ b/Kth Largest Element/README.markdown @@ -6,21 +6,21 @@ For example, the 1-st largest element is the maximum value that occurs in the ar ## The naive solution -The following solution is semi-naive. Its time complexity is **O(n log n)** since it first sorts the array, and uses an additional **O(n)** space. Better solutions using heaps exist that run in **O(n)** time. +The following solution is semi-naive. Its time complexity is **O(n log n)** since it first sorts the array, and therefore also uses additional **O(n)** space. ```swift func kthLargest(a: [Int], k: Int) -> Int? { let len = a.count - - if k <= 0 || k > len || len < 1 { return nil } - - let sorted = a.sort() - - return sorted[len - k] + if k > 0 && k <= len { + let sorted = a.sorted() + return sorted[len - k] + } else { + return nil + } } ``` -The `kthLargest()` function takes two parameters: the array `a` consisting of integers, and `k`. It returns the k-th largest element. +The `kthLargest()` function takes two parameters: the array `a` consisting of integers, and `k`. It returns the *k*-th largest element. Let's take a look at an example and run through the algorithm to see how it works. Given `k = 4` and the array: @@ -40,17 +40,17 @@ Now, all we must do is take the value at index `a.count - k`: a[a.count - k] = a[8 - 4] = a[4] = 9 ``` -Of course, if you were looking for the k-th *smallest* element, you'd use `a[k]`. +Of course, if you were looking for the k-th *smallest* element, you'd use `a[k-1]`. ## A faster solution -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. -Quicksort also splits up arrays. It uses partitioning to move all smaller values to the left of the pivot and all greater values to the right. After partitioning around a certain pivot, that pivot will already be in its final, sorted position. We can use that to our advantage here. +Quicksort also splits up arrays. It uses partitioning to move all smaller values to the left of the pivot and all greater values to the right. After partitioning around a certain pivot, that pivot value will already be in its final, sorted position. We can use that to our advantage here. -We choose a random pivot, partition the array around that pivot, and then act like a binary search and only continue in the left or right partition. This repeats until we've found a pivot that happens to end up in the *k*-th position. +Here's how it works: We choose a random pivot, partition the array around that pivot, then act like a binary search and only continue in the left or right partition. This repeats until we've found a pivot that happens to end up in the *k*-th position. Let's look at the original example again. We're looking for the 4-th largest element in this array: @@ -58,12 +58,12 @@ Let's look at the original example again. We're looking for the 4-th largest ele The algorithm is a bit easier to follow if we look for the k-th *smallest* item instead, so let's take `k = 4` and look for the 4-th smallest element. -Note that we don't have to sort the array first. We pick a random pivot, let's say `11` and partition the array around that. We might end up with something like this: +Note that we don't have to sort the array first. We pick one of the elements at random to be the pivot, let's say `11`, and partition the array around that. We might end up with something like this: [ 7, 9, -1, 0, 6, 11, 92, 23 ] <------ smaller larger --> -As you can see, all values smaller than `11` are on the left; all values larger are on the right. The pivot value is now in its final place. The index of the pivot is 5, so the 4-th smallest element must be in the left partition somewhere. We can ignore the rest of the array from now on: +As you can see, all values smaller than `11` are on the left; all values larger are on the right. The pivot value `11` is now in its final place. The index of the pivot is 5, so the 4-th smallest element must be in the left partition somewhere. We can ignore the rest of the array from now on: [ 7, 9, -1, 0, 6, x, x, x ] @@ -84,29 +84,29 @@ The index of pivot `9` is 4, and that's exactly the *k* we're looking for. We're The following function implements these ideas: ```swift -public func randomizedSelect(array: [T], order k: Int) -> T { +public func randomizedSelect(_ array: [T], order k: Int) -> T { var a = array - - func randomPivot(inout a: [T], _ low: Int, _ high: Int) -> T { + + func randomPivot(_ a: inout [T], _ low: Int, _ high: Int) -> T { let pivotIndex = random(min: low, max: high) - swap(&a, pivotIndex, high) + a.swapAt(pivotIndex, high) return a[high] } - func randomizedPartition(inout a: [T], _ low: Int, _ high: Int) -> Int { + func randomizedPartition(_ a: inout [T], _ low: Int, _ high: Int) -> Int { let pivot = randomPivot(&a, low, high) var i = low for j in low..(inout a: [T], _ low: Int, _ high: Int, _ k: Int) -> T { + func randomizedSelect(_ a: inout [T], _ low: Int, _ high: Int, _ k: Int) -> T { if low < high { let p = randomizedPartition(&a, low, high) if k == p { @@ -120,21 +120,21 @@ public func randomizedSelect(array: [T], order k: Int) -> T { return a[low] } } - + precondition(a.count > 0) return randomizedSelect(&a, 0, a.count - 1, k) } ``` -To keep things readable, it splits up the functionality into three inner functions: +To keep things readable, the functionality is split into three inner functions: - `randomPivot()` picks a random number and puts it at the end of the current partition (this is a requirement of the Lomuto partitioning scheme, see the discussion on [quicksort](../Quicksort/) for more details). - `randomizedPartition()` is Lomuto's partitioning scheme from quicksort. When this completes, the randomly chosen pivot is in its final sorted position in the array. It returns the array index of the pivot. -- `randomizedSelect()` does all the hard work. It first calls the partitioning function and then decides what to do next. If the index of the pivot is equal to the k-th number we're looking for, we're done. If `k` is less than the pivot index, it must be in the left partition and we'll recursively try again there. Likewise for when the k-th number must be in the right partition. +- `randomizedSelect()` does all the hard work. It first calls the partitioning function and then decides what to do next. If the index of the pivot is equal to the *k*-th number we're looking for, we're done. If `k` is less than the pivot index, it must be in the left partition and we'll recursively try again there. Likewise for when the *k*-th number must be in the right partition. -Pretty cool, huh? +Pretty cool, huh? Normally quicksort is an **O(n log n)** algorithm, but because we only partition smaller and smaller slices of the array, the running time of `randomizedSelect()` works out to **O(n)**. > **Note:** This function calculates the *k*-th smallest item in the array, where *k* starts at 0. If you want the *k*-th largest item, call it with `a.count - k`. diff --git a/Kth Largest Element/kthLargest.playground/Contents.swift b/Kth Largest Element/kthLargest.playground/Contents.swift index 9cac62f4e..a27dfce7d 100644 --- a/Kth Largest Element/kthLargest.playground/Contents.swift +++ b/Kth Largest Element/kthLargest.playground/Contents.swift @@ -1,88 +1,17 @@ //: Playground - noun: a place where people can play -func kthLargest(a: [Int], k: Int) -> Int? { - let len = a.count - if k <= 0 || k > len || len < 1 { return nil } - - let sorted = a.sort() - return sorted[len - k] -} - 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) - - - - -import Foundation - -/* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { - assert(min < max) - return min + Int(arc4random_uniform(UInt32(max - min + 1))) -} - -/* - 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) { - if i != j { - swap(&a[i], &a[j]) - } -} - -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) - return a[high] - } - - func randomizedPartition(inout a: [T], _ low: Int, _ high: Int) -> Int { - let pivot = randomPivot(&a, low, high) - var i = low - for j in low..(inout a: [T], _ low: Int, _ high: Int, _ k: Int) -> T { - if low < high { - let p = randomizedPartition(&a, low, high) - if k == p { - return a[p] - } else if k < p { - return randomizedSelect(&a, low, p - 1, k) - } else { - return randomizedSelect(&a, p + 1, high, k) - } - } else { - return a[low] - } - } - - precondition(a.count > 0) - return randomizedSelect(&a, 0, a.count - 1, k) -} - +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) randomizedSelect(a, order: 0) randomizedSelect(a, order: 1) diff --git a/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift new file mode 100644 index 000000000..aad15eac6 --- /dev/null +++ b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift @@ -0,0 +1,71 @@ +import Foundation + +/* + Returns the k-th largest value inside of an array a. + This is an O(n log n) solution since we sort the array. +*/ +public func kthLargest(_ a: [Int], _ k: Int) -> Int? { + let len = a.count + if k > 0 && k <= len { + let sorted = a.sorted() + return sorted[len - k] + } else { + return nil + } +} + +// MARK: - Randomized selection + +/* + Returns the i-th smallest element from the array. + + This works a bit like quicksort and a bit like binary search. + + The partitioning step picks a random pivot and uses Lomuto's scheme to + rearrange the array; afterwards, this pivot is in its final sorted position. + + If this pivot index equals i, we're done. If i is smaller, then we continue + with the left side, otherwise we continue with the right side. + + Expected running time: O(n) if the elements are distinct. +*/ +public func randomizedSelect(_ array: [T], order k: Int) -> T { + var a = array + + func randomPivot(_ a: inout [T], _ low: Int, _ high: Int) -> T { + let pivotIndex = Int.random(in: low...high) + a.swapAt(pivotIndex, high) + return a[high] + } + + func randomizedPartition(_ a: inout [T], _ low: Int, _ high: Int) -> Int { + let pivot = randomPivot(&a, low, high) + var i = low + for j in low..(_ a: inout [T], _ low: Int, _ high: Int, _ k: Int) -> T { + if low < high { + let p = randomizedPartition(&a, low, high) + if k == p { + return a[p] + } else if k < p { + return randomizedSelect(&a, low, p - 1, k) + } else { + return randomizedSelect(&a, p + 1, high, k) + } + } else { + return a[low] + } + } + + precondition(a.count > 0) + return randomizedSelect(&a, 0, a.count - 1, k) +} diff --git a/Kth Largest Element/kthLargest.playground/playground.xcworkspace/contents.xcworkspacedata b/Kth Largest Element/kthLargest.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Kth Largest Element/kthLargest.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 @@ - - - - - diff --git a/Kth Largest Element/kthLargest.swift b/Kth Largest Element/kthLargest.swift deleted file mode 100644 index 69c03b76f..000000000 --- a/Kth Largest Element/kthLargest.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation - -/* - * Returns the k-th largest value inside of an array a. - * This is an O(n log n) solution since we sort the array. - */ -func kthLargest(a: [Int], k: Int) -> Int? { - let len = a.count - if k <= 0 || k > len || len < 1 { return nil } - - let sorted = a.sort() - return sorted[len - k] -} - -// MARK: - Randomized selection - -/* Returns a random integer in the range min...max, inclusive. */ -public func random(min min: Int, max: Int) -> Int { - assert(min < max) - return min + Int(arc4random_uniform(UInt32(max - min + 1))) -} - -/* - 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) { - if i != j { - swap(&a[i], &a[j]) - } -} - -/* - Returns the i-th smallest element from the array. - - This works a bit like quicksort and a bit like binary search. - - The partitioning step picks a random pivot and uses Lomuto's scheme to - rearrange the array; afterwards, this pivot is in its final sorted position. - - If this pivot index equals i, we're done. If i is smaller, then we continue - with the left side, otherwise we continue with the right side. - - Expected running time: O(n) if the elements are distinct. -*/ -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) - return a[high] - } - - func randomizedPartition(inout a: [T], _ low: Int, _ high: Int) -> Int { - let pivot = randomPivot(&a, low, high) - var i = low - for j in low..(inout a: [T], _ low: Int, _ high: Int, _ k: Int) -> T { - if low < high { - let p = randomizedPartition(&a, low, high) - if k == p { - return a[p] - } else if k < p { - return randomizedSelect(&a, low, p - 1, k) - } else { - return randomizedSelect(&a, p + 1, high, k) - } - } else { - return a[low] - } - } - - precondition(a.count > 0) - return randomizedSelect(&a, 0, a.count - 1, k) -} diff --git a/LRU Cache/LRUCache.playground/Contents.swift b/LRU Cache/LRUCache.playground/Contents.swift new file mode 100644 index 000000000..35dcc5d59 --- /dev/null +++ b/LRU Cache/LRUCache.playground/Contents.swift @@ -0,0 +1,10 @@ +let cache = LRUCache(2) +cache.set("a", val: 1) +cache.set("b", val: 2) +cache.get("a") // returns 1 +cache.set("c", val: 3) // evicts key "b" +cache.get("b") // returns nil (not found) +cache.set("d", val: 4) // evicts key "a" +cache.get("a") // returns nil (not found) +cache.get("c") // returns 3 +cache.get("d") // returns 4 diff --git a/LRU Cache/LRUCache.playground/Sources/LRUCache.swift b/LRU Cache/LRUCache.playground/Sources/LRUCache.swift new file mode 100644 index 000000000..3b9ca1139 --- /dev/null +++ b/LRU Cache/LRUCache.playground/Sources/LRUCache.swift @@ -0,0 +1,59 @@ +// +// LRUCache.swift +// +// +// Created by Kai Chen on 16/07/2017. +// +// + +import Foundation + +public class LRUCache { + private let maxSize: Int + private var cache: [KeyType: Any] = [:] + private var priority: LinkedList = LinkedList() + private var key2node: [KeyType: LinkedList.LinkedListNode] = [:] + + public init(_ maxSize: Int) { + self.maxSize = maxSize + } + + public func get(_ key: KeyType) -> Any? { + guard let val = cache[key] else { + return nil + } + + remove(key) + insert(key, val: val) + + return val + } + + public func set(_ key: KeyType, val: Any) { + if cache[key] != nil { + remove(key) + } else if priority.count >= maxSize, let keyToRemove = priority.last?.value { + remove(keyToRemove) + } + + insert(key, val: val) + } + + private func remove(_ key: KeyType) { + cache.removeValue(forKey: key) + guard let node = key2node[key] else { + return + } + priority.remove(node: node) + key2node.removeValue(forKey: key) + } + + private func insert(_ key: KeyType, val: Any) { + cache[key] = val + priority.insert(key, atIndex: 0) + guard let first = priority.first else { + return + } + key2node[key] = first + } +} diff --git a/LRU Cache/LRUCache.playground/Sources/LinkedList.swift b/LRU Cache/LRUCache.playground/Sources/LinkedList.swift new file mode 100755 index 000000000..a5594eb31 --- /dev/null +++ b/LRU Cache/LRUCache.playground/Sources/LinkedList.swift @@ -0,0 +1,246 @@ +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 let next = node.next { + node = next + } + return node + } else { + return nil + } + } + + public var count: Int { + if var node = head { + var c = 1 + while 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(_ node: Node) { + let newNode = LinkedListNode(value: node.value) + if let lastNode = last { + newNode.previous = lastNode + lastNode.next = newNode + } else { + head = newNode + } + } + + 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) + + var i = index + var next = head + var prev: Node? + + while next != nil && i > 0 { + i -= 1 + prev = next + next = next!.next + } + assert(i == 0) // if > 0, then specified index was too large + + return (prev, next) + } + + public func insert(_ value: T, atIndex index: Int) { + let newNode = Node(value: value) + self.insert(newNode, atIndex: index) + } + + public func insert(_ node: Node, atIndex index: Int) { + let (prev, next) = nodesBeforeAndAfter(index: index) + let newNode = LinkedListNode(value: node.value) + newNode.previous = prev + newNode.next = next + prev?.next = newNode + next?.previous = newNode + + if prev == nil { + head = newNode + } + } + + public func insert(_ list: LinkedList, atIndex index: Int) { + if list.isEmpty { return } + var (prev, next) = nodesBeforeAndAfter(index: index) + var nodeToCopy = list.head + var newNode: Node? + while let node = nodeToCopy { + newNode = Node(value: node.value) + newNode?.previous = prev + if let previous = prev { + previous.next = newNode + } else { + self.head = newNode + } + nodeToCopy = nodeToCopy?.next + prev = newNode + } + 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) + 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 + "]" + } +} + +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 + } +} + +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() + + for element in elements { + self.append(element) + } + } +} diff --git a/LRU Cache/LRUCache.playground/contents.xcplayground b/LRU Cache/LRUCache.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/LRU Cache/LRUCache.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/LRU Cache/LRUCache.swift b/LRU Cache/LRUCache.swift new file mode 100644 index 000000000..4d15599de --- /dev/null +++ b/LRU Cache/LRUCache.swift @@ -0,0 +1,59 @@ +// +// LRUCache.swift +// +// +// Created by Kai Chen on 16/07/2017. +// +// + +import Foundation + +public class LRUCache { + private let maxSize: Int + private var cache: [KeyType: Any] = [:] + private var priority: LinkedList = LinkedList() + private var key2node: [KeyType: LinkedList.LinkedListNode] = [:] + + public init(_ maxSize: Int) { + self.maxSize = maxSize + } + + public func get(_ key: KeyType) -> Any? { + guard let val = cache[key] else { + return nil + } + + remove(key) + insert(key, val: val) + + return val + } + + public func set(_ key: KeyType, val: Any) { + if cache[key] != nil { + remove(key) + } else if priority.count >= maxSize, let keyToRemove = priority.last?.value { + remove(keyToRemove) + } + + insert(key, val: val) + } + + private func remove(_ key: KeyType) { + cache.removeValue(forKey: key) + guard let node = key2node[key] else { + return + } + priority.remove(node: node) + key2node.removeValue(forKey: key) + } + + private func insert(_ key: KeyType, val: Any) { + cache[key] = val + priority.insert(key, atIndex: 0) + guard let first = priority.first else { + return + } + key2node[key] = first + } +} diff --git a/LRU Cache/Readme.md b/LRU Cache/Readme.md new file mode 100644 index 000000000..8e2941991 --- /dev/null +++ b/LRU Cache/Readme.md @@ -0,0 +1,57 @@ +# LRU Cache + +Caches are used to hold objects in memory. A caches size is finite; If the system doesn't have enough memory, the cache must be purged or the program will crash. [Least Recently Used][1] (LRU) is a popular algorithm in cache design. + +In this implementation of the LRU Cache, a size is declared during instantiation, and any insertions that go beyond the size will purge the least recently used element of the cache. A *priority queue* is used to enforce this behavior. + +## The priority queue + +The key to the LRU cache is the priority queue. For simplicity, you'll model the queue using a linked list. All interactions with the LRU cache should respect this queue; Calling `get` and `set` should update the priority queue to reflect the most recently accessed element. + +### Interesting tidbits + + +#### Adding values + +Each time we access an element, either `set` or `get` we need to insert the element in the head of priority list. We use a helper method to handle this procedure: + +```swift +private func insert(_ key: KeyType, val: Any) { + cache[key] = val + priority.insert(key, atIndex: 0) + guard let first = priority.first else { + return + } + key2node[key] = first +} +``` + +#### Purging the cache + +When the cache is full, a purge must take place starting with the least recently used element. In this case, we need to `remove` the lowest priority node. The operation is like this: + +```swift +private func remove(_ key: KeyType) { + cache.removeValue(key) + guard let node = key2node[key] else { + return + } + priority.remove(node) + key2node.removeValue(key) +} +``` + +### Optimizing Performance + +Removing elements from the priority queue is a frequent operation for the LRU cache. Since priority queue is modelled using a linked list, this is an expensive operation that costs `O(n)` time. This is the bottleneck for both the `set` and `get` methods. + +To help alleviate this problem, a hash table is used to store the references of each node: + +``` +private var key2node: [KeyType: LinkedList.LinkedListNode] = [:] +``` + +*Written for the Swift Algorithm Club by Kai Chen, with additions by Kelvin Lau* + + +[1]: https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU diff --git a/Linear Regression/Images/graph1.png b/Linear Regression/Images/graph1.png new file mode 100644 index 000000000..bffe838ef Binary files /dev/null and b/Linear Regression/Images/graph1.png differ diff --git a/Linear Regression/Images/graph2.png b/Linear Regression/Images/graph2.png new file mode 100644 index 000000000..cdb45b1a8 Binary files /dev/null and b/Linear Regression/Images/graph2.png differ diff --git a/Linear Regression/Images/graph3.png b/Linear Regression/Images/graph3.png new file mode 100644 index 000000000..a0ec76e5b Binary files /dev/null and b/Linear Regression/Images/graph3.png differ diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift new file mode 100644 index 000000000..a093ef566 --- /dev/null +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -0,0 +1,50 @@ +// Linear Regression + +import Foundation + +let carAge: [Double] = [10, 8, 3, 3, 2, 1] +let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] +var intercept = 0.0 +var slope = 0.0 + +func predictedCarPrice(_ carAge: Double) -> Double { + return intercept + slope * carAge +} + +// An iterative approach + +let numberOfCarAdvertsWeSaw = carPrice.count +let numberOfIterations = 100 +let alpha = 0.0001 + +for _ in 1...numberOfIterations { + for i in 0.. Double { + return input.reduce(0, +) / Double(input.count) +} + +func multiply(_ a: [Double], _ b: [Double]) -> [Double] { + return zip(a, b).map(*) +} + +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(ys) - slope * average(xs) + return { x in intercept + slope * x } +} + +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/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..d07bf1497 --- /dev/null +++ b/Linear Regression/README.markdown @@ -0,0 +1,149 @@ +# Linear Regression + +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? + +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 minimizing 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 * 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 +let numberOfIterations = 100 +let alpha = 0.0001 + +for _ in 1...numberOfIterations { + for i in 0.. 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. + +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(_ a: [Double], _ b: [Double]) -> [Double] { + return zip(a,b).map(*) +} +``` + +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(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 { 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: + +![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* diff --git a/Linear Search/LinearSearch.playground/Contents.swift b/Linear Search/LinearSearch.playground/Contents.swift index 02fb6e940..8c616ded4 100644 --- a/Linear Search/LinearSearch.playground/Contents.swift +++ b/Linear Search/LinearSearch.playground/Contents.swift @@ -1,10 +1,10 @@ //: Playground - noun: a place where people can play -func linearSearch(array: [T], _ object: T) -> Int? { - for (index, obj) in array.enumerate() where obj == object { - return index - } - return nil +func linearSearch(_ array: [T], _ object: T) -> Int? { + for (index, obj) in array.enumerated() where obj == object { + return index + } + return nil } let array = [5, 2, 4, 7] diff --git a/Linear Search/LinearSearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Linear Search/LinearSearch.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Linear Search/LinearSearch.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Linear Search/LinearSearch.playground/timeline.xctimeline b/Linear Search/LinearSearch.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Linear Search/LinearSearch.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Linear Search/LinearSearch.swift b/Linear Search/LinearSearch.swift index fe64ef24e..c5374d0a4 100644 --- a/Linear Search/LinearSearch.swift +++ b/Linear Search/LinearSearch.swift @@ -1,6 +1,10 @@ -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 } + +func linearSearch1(_ array: [T], _ object: T) -> Array.Index? { + return array.index { $0 == object } +} diff --git a/Linear Search/README.markdown b/Linear Search/README.markdown index 178a1dd09..4649f4fc4 100644 --- a/Linear Search/README.markdown +++ b/Linear Search/README.markdown @@ -2,21 +2,23 @@ Goal: Find a particular value in an array. -We have an array of generic objects and we iterate over all the objects by comparing each one to the object we're looking for. If the two objects are equal, we stop and we return the index of the object in the array. If not, we continue to look for the next object as long as we have objects in the array. +We have an array of generic objects. With linear search, we iterate over all the objects in the array and compare each one to the object we're looking for. If the two objects are equal, we stop and return the current array index. If not, we continue to look for the next object as long as we have objects in the array. -### An example +## An example Let's say we have an array of numbers `[5, 2, 4, 7]` and we want to check if the array contains the number `2`. -We start by comparing the first number in the array, `5` with the number we're looking for, `2`. They are obviously not the same number and so we continue by taking the second element in the array. We compare the number `2` to our number `2` and we notice that they are the same. We stop our iteration and we return `1`, which is the index of the number `2` in the array. +We start by comparing the first number in the array, `5`, to the number we're looking for, `2`. They are obviously not the same, and so we continue to the next array element. -### The code +We compare the number `2` from the array to our number `2` and notice they are equal. Now we can stop our iteration and return 1, which is the index of the number `2` in the array. + +## The code 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 @@ -30,14 +32,14 @@ let array = [5, 2, 4, 7] linearSearch(array, 2) // This will return 1 ``` -### Performance +## Performance -Linear search runs at **O(n)**. It compares the object we are looking for with each object in the array and so the time it takes is proportional to the array length. +Linear search runs at **O(n)**. It compares the object we are looking for with each object in the array and so the time it takes is proportional to the array length. In the worst case, we need to look at all the elements in the array. -The best-case performance is **O(1)** but this case is rare because the object we're looking for has to be positioned at the start of the array to be immediately found. +The best-case performance is **O(1)** but this case is rare because the object we're looking for has to be positioned at the start of the array to be immediately found. You might get lucky, but most of the time you won't. On average, linear search needs to look at half the objects in the array. -### See also +## See also -See also [Wikipedia](https://en.wikipedia.org/wiki/Linear_search). +[Linear search on Wikipedia](https://en.wikipedia.org/wiki/Linear_search) *Written by [Patrick Balestra](http://www.github.com/BalestraPatrick)* diff --git a/Linked List/LinkedList Tests/LinkedList.xcodeproj/project.pbxproj b/Linked List/LinkedList Tests/LinkedList.xcodeproj/project.pbxproj deleted file mode 100644 index 20817809d..000000000 --- a/Linked List/LinkedList Tests/LinkedList.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B1BF9C81C6288D40051C9A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BF9C71C6288D40051C9A4 /* AppDelegate.swift */; }; - 7B1BF9CA1C6288D40051C9A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BF9C91C6288D40051C9A4 /* Assets.xcassets */; }; - 7B1BF9CD1C6288D40051C9A4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BF9CB1C6288D40051C9A4 /* MainMenu.xib */; }; - 7B1BF9D81C6288D40051C9A4 /* LinkedListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BF9D71C6288D40051C9A4 /* LinkedListTests.swift */; }; - 7B1BF9E31C62897B0051C9A4 /* LinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BF9E21C62897B0051C9A4 /* LinkedList.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B1BF9D41C6288D40051C9A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B1BF9BC1C6288D40051C9A4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B1BF9C31C6288D40051C9A4; - remoteInfo = LinkedList; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B1BF9C41C6288D40051C9A4 /* LinkedList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LinkedList.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BF9C71C6288D40051C9A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B1BF9C91C6288D40051C9A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B1BF9CC1C6288D40051C9A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B1BF9CE1C6288D40051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BF9D31C6288D40051C9A4 /* LinkedListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinkedListTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BF9D71C6288D40051C9A4 /* LinkedListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedListTests.swift; sourceTree = ""; }; - 7B1BF9D91C6288D40051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BF9E21C62897B0051C9A4 /* LinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinkedList.swift; path = ../../LinkedList.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B1BF9C11C6288D40051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9D01C6288D40051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B1BF9BB1C6288D40051C9A4 = { - isa = PBXGroup; - children = ( - 7B1BF9C61C6288D40051C9A4 /* LinkedList */, - 7B1BF9D61C6288D40051C9A4 /* LinkedListTests */, - 7B1BF9C51C6288D40051C9A4 /* Products */, - ); - sourceTree = ""; - }; - 7B1BF9C51C6288D40051C9A4 /* Products */ = { - isa = PBXGroup; - children = ( - 7B1BF9C41C6288D40051C9A4 /* LinkedList.app */, - 7B1BF9D31C6288D40051C9A4 /* LinkedListTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B1BF9C61C6288D40051C9A4 /* LinkedList */ = { - isa = PBXGroup; - children = ( - 7B1BF9C71C6288D40051C9A4 /* AppDelegate.swift */, - 7B1BF9C91C6288D40051C9A4 /* Assets.xcassets */, - 7B1BF9CE1C6288D40051C9A4 /* Info.plist */, - 7B1BF9E21C62897B0051C9A4 /* LinkedList.swift */, - 7B1BF9CB1C6288D40051C9A4 /* MainMenu.xib */, - ); - path = LinkedList; - sourceTree = ""; - }; - 7B1BF9D61C6288D40051C9A4 /* LinkedListTests */ = { - isa = PBXGroup; - children = ( - 7B1BF9D71C6288D40051C9A4 /* LinkedListTests.swift */, - 7B1BF9D91C6288D40051C9A4 /* Info.plist */, - ); - path = LinkedListTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B1BF9C31C6288D40051C9A4 /* LinkedList */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BF9DC1C6288D40051C9A4 /* Build configuration list for PBXNativeTarget "LinkedList" */; - buildPhases = ( - 7B1BF9C01C6288D40051C9A4 /* Sources */, - 7B1BF9C11C6288D40051C9A4 /* Frameworks */, - 7B1BF9C21C6288D40051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = LinkedList; - productName = LinkedList; - productReference = 7B1BF9C41C6288D40051C9A4 /* LinkedList.app */; - productType = "com.apple.product-type.application"; - }; - 7B1BF9D21C6288D40051C9A4 /* LinkedListTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BF9DF1C6288D40051C9A4 /* Build configuration list for PBXNativeTarget "LinkedListTests" */; - buildPhases = ( - 7B1BF9CF1C6288D40051C9A4 /* Sources */, - 7B1BF9D01C6288D40051C9A4 /* Frameworks */, - 7B1BF9D11C6288D40051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B1BF9D51C6288D40051C9A4 /* PBXTargetDependency */, - ); - name = LinkedListTests; - productName = LinkedListTests; - productReference = 7B1BF9D31C6288D40051C9A4 /* LinkedListTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B1BF9BC1C6288D40051C9A4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B1BF9C31C6288D40051C9A4 = { - CreatedOnToolsVersion = 7.2; - }; - 7B1BF9D21C6288D40051C9A4 = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B1BF9C31C6288D40051C9A4; - }; - }; - }; - buildConfigurationList = 7B1BF9BF1C6288D40051C9A4 /* Build configuration list for PBXProject "LinkedList" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B1BF9BB1C6288D40051C9A4; - productRefGroup = 7B1BF9C51C6288D40051C9A4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B1BF9C31C6288D40051C9A4 /* LinkedList */, - 7B1BF9D21C6288D40051C9A4 /* LinkedListTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B1BF9C21C6288D40051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BF9CA1C6288D40051C9A4 /* Assets.xcassets in Resources */, - 7B1BF9CD1C6288D40051C9A4 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9D11C6288D40051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B1BF9C01C6288D40051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BF9E31C62897B0051C9A4 /* LinkedList.swift in Sources */, - 7B1BF9C81C6288D40051C9A4 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BF9CF1C6288D40051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BF9D81C6288D40051C9A4 /* LinkedListTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B1BF9D51C6288D40051C9A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B1BF9C31C6288D40051C9A4 /* LinkedList */; - targetProxy = 7B1BF9D41C6288D40051C9A4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B1BF9CB1C6288D40051C9A4 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B1BF9CC1C6288D40051C9A4 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B1BF9DA1C6288D40051C9A4 /* 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; - }; - 7B1BF9DB1C6288D40051C9A4 /* 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; - }; - 7B1BF9DD1C6288D40051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = LinkedList/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.LinkedList; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B1BF9DE1C6288D40051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = LinkedList/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.LinkedList; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B1BF9E01C6288D40051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = LinkedListTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.LinkedListTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LinkedList.app/Contents/MacOS/LinkedList"; - }; - name = Debug; - }; - 7B1BF9E11C6288D40051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = LinkedListTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.LinkedListTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LinkedList.app/Contents/MacOS/LinkedList"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B1BF9BF1C6288D40051C9A4 /* Build configuration list for PBXProject "LinkedList" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BF9DA1C6288D40051C9A4 /* Debug */, - 7B1BF9DB1C6288D40051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BF9DC1C6288D40051C9A4 /* Build configuration list for PBXNativeTarget "LinkedList" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BF9DD1C6288D40051C9A4 /* Debug */, - 7B1BF9DE1C6288D40051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BF9DF1C6288D40051C9A4 /* Build configuration list for PBXNativeTarget "LinkedListTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BF9E01C6288D40051C9A4 /* Debug */, - 7B1BF9E11C6288D40051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B1BF9BC1C6288D40051C9A4 /* Project object */; -} diff --git a/Linked List/LinkedList Tests/LinkedList/AppDelegate.swift b/Linked List/LinkedList Tests/LinkedList/AppDelegate.swift deleted file mode 100644 index f83b01f35..000000000 --- a/Linked List/LinkedList Tests/LinkedList/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// LinkedList -// -// Created by Matthijs Hollemans on 03-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Linked List/LinkedList Tests/LinkedList/Assets.xcassets/AppIcon.appiconset/Contents.json b/Linked List/LinkedList Tests/LinkedList/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Linked List/LinkedList Tests/LinkedList/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/Linked List/LinkedList Tests/LinkedList/Base.lproj/MainMenu.xib b/Linked List/LinkedList Tests/LinkedList/Base.lproj/MainMenu.xib deleted file mode 100644 index 32e8f7bae..000000000 --- a/Linked List/LinkedList Tests/LinkedList/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Linked List/LinkedList Tests/LinkedList/Info.plist b/Linked List/LinkedList Tests/LinkedList/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Linked List/LinkedList Tests/LinkedList/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Linked List/LinkedList Tests/LinkedListTests/LinkedListTests.swift b/Linked List/LinkedList Tests/LinkedListTests/LinkedListTests.swift deleted file mode 100755 index 80241114c..000000000 --- a/Linked List/LinkedList Tests/LinkedListTests/LinkedListTests.swift +++ /dev/null @@ -1,252 +0,0 @@ -import XCTest -@testable import LinkedList - -class LinkedListTest: XCTestCase { - let numbers = [8, 2, 10, 9, 7, 5] - - private func buildList() -> 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.nodeAtIndex(0) - XCTAssertNil(node) - } - - func testNodeAtIndexInListWithOneElement() { - let list = LinkedList() - list.append(123) - - let node = list.nodeAtIndex(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.nodeAtIndex(-1)) - XCTAssertNil(list.nodeAtIndex(nodeCount)) - - let first = list.nodeAtIndex(0) - XCTAssertNotNil(first) - XCTAssertTrue(first === list.first) - XCTAssertEqual(first!.value, numbers[0]) - - let last = list.nodeAtIndex(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.nodeAtIndex(0) - XCTAssertNotNil(node) - XCTAssertEqual(node!.value, 123) - } - - func testInsertAtIndex() { - let list = buildList() - let prev = list.nodeAtIndex(2) - let next = list.nodeAtIndex(3) - let nodeCount = list.count - - list.insert(444, atIndex: 3) - - let node = list.nodeAtIndex(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.removeAtIndex(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.nodeAtIndex(2) - let next = list.nodeAtIndex(3) - let nodeCount = list.count - - list.insert(444, atIndex: 3) - - let value = list.removeAtIndex(3) - XCTAssertEqual(value, 444) - - let node = list.nodeAtIndex(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/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 1f3d98bc4..76b911310 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -1,250 +1,465 @@ -//: Playground - noun: a place where people can play +//: # Linked Lists -public class LinkedListNode { - var value: T - var next: LinkedListNode? - var previous: LinkedListNode? +// For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu - public init(value: T) { - self.value = value - } -} +//: Linked List Class Declaration: -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!) - } +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 + private(set) var head: Node? + + /// Computed property to iterate through the linked list and return the last node in the list (if any) + public var last: Node? { + guard var node = head else { + return nil + } + + while let next = node.next { + node = next + } + return node + } + + /// Computed property to check if the linked list is empty + public var isEmpty: Bool { + return head == nil + } + + /// Computed property to iterate through the linked list and return the total number of nodes + public var count: Int { + guard var node = head else { + return 0 + } + + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count + } + + /// Default initializer + public init() {} + + + /// Subscript function to return the node at a specific index + /// + /// - Parameter index: Integer value of the requested value's index + public subscript(index: Int) -> T { + let node = self.node(at: index) + return node.value + } + + /// Function to return the node at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the node's index to be returned + /// - Returns: LinkedListNode + public func node(at index: Int) -> Node { + assert(head != nil, "List is empty") + assert(index >= 0, "index must be greater than 0") + + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { + let prev = node.previous + let next = node.next + + if let prev = prev { + prev.next = next + } else { + head = next + } + next?.previous = prev + + node.previous = nil + node.next = nil + return node.value + } + + /// Function to remove the last node/value in the list. Crashes if the list is empty + /// + /// - Returns: The data value contained in the deleted node. + @discardableResult public func removeLast() -> T { + assert(!isEmpty) + return remove(node: last!) + } + + /// Function to remove a node/value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the index of the node to be removed + /// - Returns: The data value contained in the deleted node + @discardableResult public func remove(at index: Int) -> T { + let node = self.node(at: index) + return remove(node: node) + } } +//: End of the base class declarations & beginning of extensions' declarations: + +// MARK: - Extension to enable the standard conversion of a list to String extension LinkedList: CustomStringConvertible { - public var description: String { - var s = "[" - var node = head - while node != nil { - s += "\(node!.value)" - node = node!.next - if node != nil { s += ", " } - } - return s + "]" - } + public var description: String { + var s = "[" + var node = head + while let nd = node { + s += "\(nd.value)" + node = nd.next + if node != nil { s += ", " } + } + return s + "]" + } } +// MARK: - Extension to add a 'reverse' function to the list extension LinkedList { - public func reverse() { - var node = head - while node != nil { - swap(&node!.next, &node!.previous) - head = node - node = node!.previous - } - } + public func reverse() { + var node = head + while let currentNode = node { + node = currentNode.next + swap(¤tNode.next, ¤tNode.previous) + head = currentNode + } + } } +// MARK: - An extension with an implementation of 'map' & 'filter' functions extension LinkedList { - public func map(transform: T -> U) -> LinkedList { - let result = LinkedList() - var node = head - while node != nil { - result.append(transform(node!.value)) - node = node!.next - } - 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 let nd = node { + result.append(transform(nd.value)) + node = nd.next + } + return result + } + + public func filter(predicate: (T) -> Bool) -> LinkedList { + let result = LinkedList() + var node = head + while let nd = node { + if predicate(nd.value) { + result.append(nd.value) + } + node = nd.next + } + return result + } } +// MARK: - Extension to enable initialization from an Array +extension LinkedList { + convenience init(array: Array) { + self.init() + + array.forEach { append($0) } + } +} +// MARK: - Extension to enable initialization from an Array Literal +extension LinkedList: ExpressibleByArrayLiteral { + public convenience init(arrayLiteral elements: T...) { + self.init() + + elements.forEach { append($0) } + } +} +// MARK: - Collection +extension LinkedList: Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag + 1) + } +} +// MARK: - Collection Index +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex: Comparable { + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} +//: Ok, now that the declarations are done, let's see our Linked List in action: let list = LinkedList() list.isEmpty // true -list.first // nil +list.head // nil list.last // nil list.append("Hello") -list.isEmpty -list.first!.value // "Hello" +list.isEmpty // false +list.head!.value // "Hello" list.last!.value // "Hello" list.count // 1 list.append("World") -list.first!.value // "Hello" +list.head!.value // "Hello" list.last!.value // "World" list.count // 2 -list.first!.previous // nil -list.first!.next!.value // "World" +list.head!.previous // nil +list.head!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.nodeAtIndex(0)!.value // "Hello" -list.nodeAtIndex(1)!.value // "World" -list.nodeAtIndex(2) // nil +list.node(at: 0).value // "Hello" +list.node(at: 1).value // "World" +//list.node(at: 2) // crash! list[0] // "Hello" list[1] // "World" //list[2] // crash! -list.insert("Swift", atIndex: 1) -list[0] -list[1] -list[2] +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(at: 2) // "Goodbye" + +list.insert("Swift", at: 1) +list[0] // "Hello" +list[1] // "Swift" +list[2] // "World" print(list) list.reverse() // [World, Swift, Hello] -list.nodeAtIndex(0)!.value = "Universe" -list.nodeAtIndex(1)!.value = "Swifty" -let m = list.map { s in s.characters.count } +list.node(at: 0).value = "Universe" +list.node(at: 1).value = "Swifty" +let m = list.map { s in s.count } m // [8, 6, 5] -let f = list.filter { s in s.characters.count > 5 } +let f = list.filter { s in s.count > 5 } f // [Universe, Swifty] -//list.removeAll() -//list.isEmpty - -list.removeNode(list.first!) // "Hello" +list.remove(node: list.head!) // "Universe" list.count // 2 -list[0] // "Swift" -list[1] // "World" +list[0] // "Swifty" +list[1] // "Hello" -list.removeLast() // "World" +list.count // 2 +list.removeLast() // "Hello" +list.head?.value list.count // 1 -list[0] // "Swift" +list[0] // "Swifty" -list.removeAtIndex(0) // "Swift" +list.remove(at: 0) // "Swifty" list.count // 0 + +let list3 = LinkedList() +list3.insert("2", at: 0) // [2] +list3.count // 1 +list3.insert("4", at: 1) // [2,4] +list3.count // 2 +list3.insert("5", at: 2) // [2,4,5] +list3.count // 3 +list3.insert("3", at: 1) // [2,3,4,5] +list3.insert("1", at: 0) // [1,2,3,4,5] + +let list4 = LinkedList() +list4.insert(list3, at: 0) // [1,2,3,4,5] +list4.count // 5 + +let list5 = LinkedList() +list5.append("0") // [0] +list5.insert("End", at:1) // [0,End] +list5.count // 2 +list5.insert(list4, at: 1) // [0,1,2,3,4,5,End] +list5.count // 7 + + +let linkedList: LinkedList = [1, 2, 3, 4] // [1, 2, 3, 4] +linkedList.count // 4 +linkedList[0] // 1 + +// Infer the type from the array +let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] +listArrayLiteral2.count // 3 +listArrayLiteral2[0] // "Swift" +listArrayLiteral2.removeLast() // "Club" + + +// Conformance to the Collection protocol +let collection: LinkedList = [1, 2, 3, 4, 5] +let index2 = collection.index(collection.startIndex, offsetBy: 2) +let value = collection[index2] // 3 + +// Iterating in a for loop, since the Sequence protocol allows this. +var sum = 0 +for element in collection { + sum += element +} +sum //15 + +// Another way of achieving the same result though 'reduce', another method defined in an extension of Sequence. Collections are Sequences. +let result = collection.reduce(0) {$0 + $1} // 15 + + + + diff --git a/Linked List/LinkedList.playground/contents.xcplayground b/Linked List/LinkedList.playground/contents.xcplayground index 06828af92..5e28f2dd0 100644 --- a/Linked List/LinkedList.playground/contents.xcplayground +++ b/Linked List/LinkedList.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Linked List/LinkedList.playground/playground.xcworkspace/contents.xcworkspacedata b/Linked List/LinkedList.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Linked List/LinkedList.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Linked List/LinkedList.playground/timeline.xctimeline b/Linked List/LinkedList.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Linked List/LinkedList.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 9c6382c94..de8a42c93 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,191 +1,341 @@ -/* - Doubly-linked list - - Most operations on the linked list have complexity O(n). -*/ -public class LinkedListNode { - var value: T - var next: LinkedListNode? - var previous: LinkedListNode? - - public init(value: T) { - self.value = value - } +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 + private(set) var head: Node? + + /// Computed property to iterate through the linked list and return the last node in the list (if any) + public var last: Node? { + guard var node = head else { + return nil + } + + while let next = node.next { + node = next + } + return node + } + + /// Computed property to check if the linked list is empty + public var isEmpty: Bool { + return head == nil + } + + /// Computed property to iterate through the linked list and return the total number of nodes + public var count: Int { + guard var node = head else { + return 0 + } + + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count + } + + /// Default initializer + public init() {} + + + /// Subscript function to return the node at a specific index + /// + /// - Parameter index: Integer value of the requested value's index + public subscript(index: Int) -> T { + let node = self.node(at: index) + return node.value + } + + /// Function to return the node at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the node's index to be returned + /// - Returns: LinkedListNode + public func node(at index: Int) -> Node { + assert(head != nil, "List is empty") + assert(index >= 0, "index must be greater or equal to 0") + + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { + let prev = node.previous + let next = node.next + + if let prev = prev { + prev.next = next + } else { + head = next + } + next?.previous = prev + + node.previous = nil + node.next = nil + return node.value + } + + /// Function to remove the last node/value in the list. Crashes if the list is empty + /// + /// - Returns: The data value contained in the deleted node. + @discardableResult public func removeLast() -> T { + assert(!isEmpty) + return remove(node: last!) + } + + /// Function to remove a node/value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the index of the node to be removed + /// - Returns: The data value contained in the deleted node + @discardableResult public func remove(at index: Int) -> T { + let node = self.node(at: index) + return remove(node: node) + } } -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!) - } -} +//: End of the base class declarations & beginning of extensions' declarations: +// MARK: - Extension to enable the standard conversion of a list to String extension LinkedList: CustomStringConvertible { - public var description: String { - var s = "[" - var node = head - while node != nil { - s += "\(node!.value)" - node = node!.next - if node != nil { s += ", " } - } - return s + "]" - } + public var description: String { + var s = "[" + var node = head + while let nd = node { + s += "\(nd.value)" + node = nd.next + if node != nil { s += ", " } + } + return s + "]" + } } +// MARK: - Extension to add a 'reverse' function to the list extension LinkedList { - public func reverse() { - var node = head - while node != nil { - swap(&node!.next, &node!.previous) - head = node - node = node!.previous - } - } + public func reverse() { + var node = head + while let currentNode = node { + node = currentNode.next + swap(¤tNode.next, ¤tNode.previous) + head = currentNode + } + } } +// MARK: - An extension with an implementation of 'map' & 'filter' functions extension LinkedList { - public func map(transform: T -> U) -> LinkedList { - let result = LinkedList() - var node = head - while node != nil { - result.append(transform(node!.value)) - node = node!.next - } - 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 let nd = node { + result.append(transform(nd.value)) + node = nd.next + } + return result + } + + public func filter(predicate: (T) -> Bool) -> LinkedList { + let result = LinkedList() + var node = head + while let nd = node { + if predicate(nd.value) { + result.append(nd.value) + } + node = nd.next + } + return result + } +} + +// MARK: - Extension to enable initialization from an Array +extension LinkedList { + convenience init(array: Array) { + self.init() + + array.forEach { append($0) } + } +} + +// MARK: - Extension to enable initialization from an Array Literal +extension LinkedList: ExpressibleByArrayLiteral { + public convenience init(arrayLiteral elements: T...) { + self.init() + + elements.forEach { append($0) } + } +} + +// MARK: - Collection +extension LinkedList: Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag + 1) + } +} + +// MARK: - Collection Index +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex: Comparable { + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } } + diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 0ce6c57fa..ea399ee12 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -1,6 +1,8 @@ # Linked List -A linked list is a sequence of data items, just like an array. But where an array allocates a big block of memory and then divides this into different parts to store the objects, the elements in a linked list are totally separate objects in memory and are connected through links: +> This topic has been tutorialized [here](https://www.raywenderlich.com/144083/swift-algorithm-club-swift-linked-list-data-structure) + +A linked list is a sequence of data items, just like an array. But where an array allocates a big block of memory to store the objects, the elements in a linked list are totally separate objects in memory and are connected through links: +--------+ +--------+ +--------+ +--------+ | | | | | | | | @@ -38,15 +40,17 @@ This means that when you're dealing with a linked list, you should insert new it ## Singly vs doubly linked lists -A singly linked list uses less memory than a doubly linked list because it doesn't need to store all those `previous` pointers. +A singly linked list uses a little less memory than a doubly linked list because it doesn't need to store all those `previous` pointers. -But if you have a node and you need to find its previous node, you're screwed. You have to start back at the head of the list and iterate through the entire list until you get to the right node. +But if you have a node and you need to find its previous node, you're screwed. You have to start at the head of the list and iterate through the entire list until you get to the right node. For many tasks, a doubly linked list makes things easier. ## Why use a linked list? -An example of where to use a linked list is when you need a [queue](../Queue/). With an array, removing elements from the front of the queue is slow because it needs to shift down all the other elements in memory. But with a linked list it's just a matter of changing `head` to point to the second element. Much faster. +A typical example of where to use a linked list is when you need a [queue](../Queue/). With an array, removing elements from the front of the queue is slow because it needs to shift down all the other elements in memory. But with a linked list it's just a matter of changing `head` to point to the second element. Much faster. + +But to be honest, you hardly ever need to write your own linked list these days. Still, it's useful to understand how they work; the principle of linking objects together is also used with [trees](../Tree/) and [graphs](../Graph/). ## The code @@ -56,7 +60,7 @@ We'll start by defining a type to describe the nodes: public class LinkedListNode { var value: T var next: LinkedListNode? - var previous: LinkedListNode? + weak var previous: LinkedListNode? public init(value: T) { self.value = value @@ -68,6 +72,8 @@ This is a generic type, so `T` can be any kind of data that you'd like to store Ours is a doubly-linked list and each node has a `next` and `previous` pointer. These can be `nil` if there are no next or previous nodes, so these variables must be optionals. (In what follows, I'll point out which functions would need to change if this was just a singly- instead of a doubly-linked list.) +> **Note:** To avoid ownership cycles, we declare the `previous` pointer to be weak. If you have a node `A` that is followed by node `B` in the list, then `A` points to `B` but also `B` points to `A`. In certain circumstances, this ownership cycle can cause nodes to be kept alive even after you deleted them. We don't want that, so we make one of the pointers `weak` to break the cycle. + Let's start building `LinkedList`. Here's the first bit: ```swift @@ -75,18 +81,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 2 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.) @@ -104,20 +110,20 @@ Let's also add a property that gives you the last node in the list. This is wher ```swift public var last: Node? { - if var node = head { - while case let next? = node.next { - node = next - } - return node - } else { + guard var node = head else { return nil } + + while let next = node.next { + node = next + } + return node } ``` If you're new to Swift, you've probably seen `if let` but maybe not `if var`. It does the same thing -- it unwraps the `head` optional and puts the result in a new local variable named `node`. The difference is that `node` is not a constant but an actual variable, so we can change it inside the loop. -The loop also does some Swift magic. The `while case let next? = node.next` bit keeps looping until `node.next` is nil. You could have written this as follows: +The loop also does some Swift magic. The `while let next = node.next` bit keeps looping until `node.next` is nil. You could have written this as follows: ```swift var node: Node? = head @@ -192,16 +198,16 @@ Let's add a method to count how many nodes are in the list. This will look very ```swift public var count: Int { - if var node = head { - var c = 1 - while case let next? = node.next { - node = next - c += 1 - } - return c - } else { + guard var node = head else { return 0 } + + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count } ``` @@ -212,37 +218,43 @@ It loops through the list in the same manner but this time increments a counter What if we wanted to find the node at a specific index in the list? With an array we can just write `array[index]` and it's an **O(1)** operation. It's a bit more involved with linked lists, but again the code follows a similar pattern: ```swift - public func 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 + public func node(atIndex index: Int) -> Node { + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { - let node = nodeAtIndex(index) - assert(node != nil) - return node!.value + let node = node(atIndex: index) + return node.value } ``` @@ -258,84 +270,100 @@ It crashes on `list[2]` because there is no node at that index. So far we've written code to add new nodes to the end of the list, but that's slow because you need to find the end of the list first. (It would be fast if we used a tail pointer.) For this reason, if the order of the items in the list doesn't matter, you should insert at the front of the list instead. That's always an **O(1)** operation. -Let's write a method that lets you insert a new node at any index in the list. First, we'll define a helper function: -```swift - private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { - assert(index >= 0) - - var i = index - var next = head - var prev: Node? - - while next != nil && i > 0 { - i -= 1 - prev = next - next = next!.next - } - assert(i == 0) +Let's write a method that lets you insert a new node at any index in the list. - return (prev, next) - } +```swift + public func insert(_ node: Node, atIndex index: Int) { + let newNode = node + if index == 0 { + newNode.next = head + head?.previous = newNode + head = newNode + } else { + let prev = self.node(atIndex: index-1) + let next = prev.next + + newNode.previous = prev + newNode.next = prev.next + prev.next = newNode + next?.previous = newNode + } +} ``` -This returns a tuple containing the node currently at the specified index and the node that immediately precedes it, if any. The loop is very similar to `nodeAtIndex()`, except that here we also keep track of what the previous node is as we iterate through the list. - -Let's look at an example. Suppose we have the following list: - - head --> A --> B --> C --> D --> E --> nil - -We want to find the nodes before and after index 3. As we start the loop, `i = 3`, `next` points at `"A"`, and `prev` is nil. - - head --> A --> B --> C --> D --> E --> nil - next - -We decrement `i`, make `prev` point to `"A"`, and move `next` to the next node, `"B"`: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -Again, we decrement `i` and update the pointers. Now `prev` points to `"B"`, and `next` points to `"C"`: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -As you can see, `prev` always follows one behind `next`. We do this one more time and then `i` equals 0 and we exit the loop: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -The `assert()` after the loop checks whether there really were enough nodes in the list. If `i > 0` at this point, then the specified index was too large. +As with node(atIndex :) method, insert(_: at:) method also branches depending on whether the given index is 0 or not. +First let's look at the former case. Suppose we have the following list and the new node(C). + + +---------+ +---------+ + head --->| |---->| |-----//-----> + | A | | B | + nil <---| |<----| |<----//------ + +---------+ +---------+ + [0] [1] + + + +---------+ + new --->| |----> nil + | C | + | | + +---------+ + +Now put the new node before the first node. In this way: -> **Note:** If any of the loops in this article don't make much sense to you, then draw a linked list on a piece of paper and step through the loop by hand, just like what we did here. + new.next = head + head.previous = new + + +---------+ +---------+ +---------+ + new --->| |--> head -->| |---->| |-----//-----> + | C | | A | | B | + | |<-----------| |<----| |<----//------ + +---------+ +---------+ +---------+ -For this example, the function returns `("C", "D")` because `"D"` is the node at index 3 and `"C"` is the one right before that. -Now that we have this helper function, we can write the method for inserting nodes: +Finally, replace the head with the new node. -```swift - public func insert(value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index) // 1 + head = new - let newNode = Node(value: value) // 2 - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { // 3 - head = newNode - } - } -``` + +---------+ +---------+ +---------+ + head --->| |--->| |---->| |-----//-----> + | C | | A | | B | + nil <---| |<---| |<----| |<----//------ + +---------+ +---------+ +---------+ + [0] [1] [2] + + +However, when the given index is greater than 0, it is necessary to get the node previous and next index and insert between them. +You can also obtain the previous and next node using node(atIndex:) as follows: + + +---------+ +---------+ +---------+ + head --->| |---//--->| |---->| |---- + | | | A | | B | + nil <---| |---//<---| |<----| |<--- + +---------+ +---------+ +---------+ + [0] [index-1] [index] + ^ ^ + | | + prev next + + prev = node(at: index-1) + next = prev.next -Some notes about this method: +Now insert new node between the prev and the next. -1. First, we need to find where to insert this node. After calling the helper method, `prev` points to the previous node and `next` is the node currently at the given index. We'll insert the new node in between these two. Note that `prev` can be nil (index is 0), `next` can be nil (index equals size of the list), or both can be nil if the list is empty. + new.prev = prev; prev.next = new // connect prev and new. + new.next = next; next.prev = new // connect new and next. -2. Create the new node and connect the `previous` and `next` pointers. Because the local `prev` and `next` variables are optionals and may be nil, so we use optional chaining here. + +---------+ +---------+ +---------+ +---------+ + head --->| |---//--->| |---->| |---->| | + | | | A | | C | | B | + nil <---| |---//<---| |<----| |<----| | + +---------+ +---------+ +---------+ +---------+ + [0] [index-1] [index] [index+1] + ^ ^ ^ + | | | + prev new next -3. If the new node is being inserted at the front of the list, we need to update the `head` pointer. Note: If the list had a tail pointer, you'd also need to update that pointer here if `next == nil`, because that means the last element has changed. Try it out: @@ -347,8 +375,7 @@ list[2] // "World" ``` Also try adding new nodes to the front and back of the list, to verify that this works properly. - -> **Note:** The `nodesBeforeAndAfter()` and `insert(atIndex)` functions can also be used with a singly linked list because we don't depend on the node's `previous` pointer to find the previous element. +> **Note:** The `node(atIndex:)` and `insert(_: atIndex:)` functions can also be used with a singly linked list because we don't depend on the node's `previous` pointer to find the previous element. What else do we need? Removing nodes, of course! First we'll do `removeAll()`, which is really simple: @@ -360,20 +387,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 `remove()` 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 - + if let prev = prev { prev.next = next } else { head = next } next?.previous = prev - + node.previous = nil node.next = nil return node.value @@ -387,39 +414,39 @@ 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!) } ``` -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" list.count // 1 list[0] // "Swift" -list.removeAtIndex(0) // "Swift" +list.removeAt(0) // "Swift" list.count // 0 ``` -> **Note:** For a singly linked list, it's slightly more complicated. You can't just use `last` to find the end of the list because you also need a reference to the second-to-last node. You'd need to use the `nodesBeforeAndAfter()` helper method instead. If you're using a tail pointer, then `removeLast()` is really quick, but you do need to remember to make `tail` point to the previous node. +> **Note:** For a singly linked list, removing the last node is slightly more complicated. You can't just use `last` to find the end of the list because you also need a reference to the second-to-last node. Instead, use the `nodesBeforeAndAfter()` helper method. If the list has a tail pointer, then `removeLast()` is really quick, but you do need to remember to make `tail` point to the previous node. There's a few other fun things we can do with our `LinkedList` class. It's handy to have some sort of readable debug output: @@ -444,14 +471,28 @@ This will print the list like so: How about reversing a list, so that the head becomes the tail and vice versa? There is a very fast algorithm for that: +Iterative Approach: ```swift public func reverse() { var node = head - while node != nil { - swap(&node!.next, &node!.previous) - head = node - node = node!.previous + tail = node // If you had a tail pointer + while let currentNode = node { + node = currentNode.next + swap(¤tNode.next, ¤tNode.previous) + head = currentNode + } + } +``` +Recursive Approach: +```swift + public func reverse(node: head) { + if !head || !head.next { + return head } + let temp = reverse(head.next) + head.next.next = head + head.next = nil + return temp } ``` @@ -463,10 +504,6 @@ This loops through the entire list and simply swaps the `next` and `previous` po nil <---| |--->| |--->| |--->| |<--- head +--------+ +--------+ +--------+ +--------+ -You may be wondering why the last statement says `node = node!.previous` to go to the next node instead of `node!.next` like you'd expect, but remember that we just swapped those pointers! - -> **Note:** I couldn't find a way to make this code more Swift-like, without the forced unwrapping. Suggestions for improvements are welcome! - Arrays have `map()` and `filter()` functions, and there's no reason why linked lists shouldn't either. ```swift @@ -512,7 +549,7 @@ And here's filter: And a silly example: ```swift -let f = list.filter { s in s.characters.count > 5 } +let f = list.filter { s in s.count > 5 } f // [Universe, Swifty] ``` @@ -520,27 +557,93 @@ Exercise for the reader: These implementations of `map()` and `filter()` aren't ## An alternative approach -The version of `LinkedList` you've seen so far uses nodes that are classes and therefore use reference semantics. Nothing wrong with that, but that does make them a bit more heavyweight than Swift's other collections such as `Array` and `Dictionary`. +The version of `LinkedList` you've seen so far uses nodes that are classes and therefore have reference semantics. Nothing wrong with that, but that does make them a bit more heavyweight than Swift's other collections such as `Array` and `Dictionary`. It is possible to implement a linked list with value semantics using an enum. That would look somewhat like this: ```swift enum ListNode { - indirect case Node(T, next: ListNode) - case End + indirect case node(T, next: ListNode) + case end } ``` -The big difference with the class-based version is that any modification you make to this list will result in a *new copy* being created. Whether that's what you want or not depends on the application. +The big difference with the enum-based version is that any modification you make to this list will result in a *new copy* being created because of [Swift's value semantics](https://developer.apple.com/swift/blog/?id=10). Whether that's what you want or not depends on the application. [I might fill out this section in more detail if there's a demand for it.] +## Conforming to the Collection protocol +Types that conform to the Sequence protocol, whose elements can be traversed multiple times, nondestructively, and accessed by indexed subscript should conform to the Collection protocol defined in Swift's Standard Library. + +Doing so grants access to a very large number of properties and operations that are common when dealing collections of data. In addition to this, it lets custom types follow the patterns that are common to Swift developers. + +In order to conform to this protocol, classes need to provide: + 1 `startIndex` and `endIndex` properties. + 2 Subscript access to elements as O(1). Diversions of this time complexity need to be documented. + +```swift +/// The position of the first element in a nonempty collection. +public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } +} + +/// The collection's "past the end" position---that is, the position one +/// greater than the last valid subscript argument. +/// - Complexity: O(n), where n is the number of elements in the list. +/// This diverts from the protocol's expectation. +public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } +} +``` + +```swift +public subscript(position: Index) -> T { + get { + return position.node!.value + } +} +``` + +Becuase collections are responsible for managing their own indexes, the implementation below keeps a reference to a node in the list. A tag property in the index represents the position of the node in the list. + +```swift +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex : Comparable +{ + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} +``` + +Finally, the linked is is able to calculate the index after a given one with the following implementation. +```swift +public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) +} +``` + ## Some things to keep in mind Linked lists are flexible but many operations are **O(n)**. When performing operations on a linked list, you always need to be careful to update the relevant `next` and `previous` pointers, and possibly also the `head` and `tail` pointers. If you mess this up, your list will no longer be correct and your program will likely crash at some point. Be careful! -When processing lists, you can often use recursion: process the first element and then recursively call the operation 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. +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* diff --git a/Linked List/Tests/Info.plist b/Linked List/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Linked List/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/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift new file mode 100755 index 000000000..b16af05ba --- /dev/null +++ b/Linked List/Tests/LinkedListTests.swift @@ -0,0 +1,339 @@ +import XCTest + +class LinkedListTest: XCTestCase { + let numbers = [8, 2, 10, 9, 7, 5] + + fileprivate func buildList() -> LinkedList { + let list = LinkedList() + for number in numbers { + list.append(number) + } + return list + } + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + func testEmptyList() { + let list = LinkedList() + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testListWithOneElement() { + let list = LinkedList() + list.append(123) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + + XCTAssertNotNil(list.first) + XCTAssertNil(list.head!.previous) + XCTAssertNil(list.head!.next) + XCTAssertEqual(list.head!.value, 123) + + XCTAssertNotNil(list.last) + XCTAssertNil(list.last!.previous) + XCTAssertNil(list.last!.next) + XCTAssertEqual(list.last!.value, 123) + + XCTAssertTrue(list.head === list.last) + } + + func testListWithTwoElements() { + let list = LinkedList() + list.append(123) + list.append(456) + + XCTAssertEqual(list.count, 2) + + XCTAssertNotNil(list.first) + XCTAssertEqual(list.head!.value, 123) + + XCTAssertNotNil(list.last) + XCTAssertEqual(list.last!.value, 456) + + XCTAssertTrue(list.head !== list.last) + + XCTAssertNil(list.head!.previous) + XCTAssertTrue(list.head!.next === list.last) + XCTAssertTrue(list.last!.previous === list.head) + XCTAssertNil(list.last!.next) + } + + func testListWithThreeElements() { + let list = LinkedList() + list.append(123) + list.append(456) + list.append(789) + + XCTAssertEqual(list.count, 3) + + XCTAssertNotNil(list.first) + XCTAssertEqual(list.head!.value, 123) + + let second = list.head!.next + XCTAssertNotNil(second) + XCTAssertEqual(second!.value, 456) + + XCTAssertNotNil(list.last) + XCTAssertEqual(list.last!.value, 789) + + XCTAssertNil(list.head!.previous) + XCTAssertTrue(list.head!.next === second) + XCTAssertTrue(second!.previous === list.head) + XCTAssertTrue(second!.next === list.last) + XCTAssertTrue(list.last!.previous === second) + XCTAssertNil(list.last!.next) + } + + func testNodeAtIndexInListWithOneElement() { + let list = LinkedList() + list.append(123) + + let node = list.node(at: 0) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 123) + XCTAssertTrue(node === list.head) + } + + func testNodeAtIndex() { + let list = buildList() + + let nodeCount = list.count + XCTAssertEqual(nodeCount, numbers.count) + + let first = list.node(at: 0) + XCTAssertNotNil(first) + XCTAssertTrue(first === list.head) + XCTAssertEqual(first.value, numbers[0]) + + let last = list.node(at: nodeCount - 1) + XCTAssertNotNil(last) + XCTAssertTrue(last === list.last) + XCTAssertEqual(last.value, numbers[nodeCount - 1]) + + for i in 0..() + list.insert(123, at: 0) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + + let node = list.node(at: 0) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 123) + } + + func testInsertAtIndex() { + let list = buildList() + let prev = list.node(at: 2) + let next = list.node(at: 3) + let nodeCount = list.count + + list.insert(444, at: 3) + + let node = list.node(at: 3) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 444) + XCTAssertEqual(nodeCount + 1, list.count) + + XCTAssertFalse(prev === node) + XCTAssertFalse(next === node) + XCTAssertTrue(prev.next === node) + XCTAssertTrue(next.previous === node) + } + + func testInsertListAtIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: 2) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 1).value, 2) + XCTAssertEqual(list.node(at: 2).value, 99) + XCTAssertEqual(list.node(at: 3).value, 102) + XCTAssertEqual(list.node(at: 4).value, 10) + } + + func testInsertListAtFirstIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: 0) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 0).value, 99) + XCTAssertEqual(list.node(at: 1).value, 102) + XCTAssertEqual(list.node(at: 2).value, 8) + } + + func testInsertListAtLastIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: list.count) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) + } + + func testAppendList() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.append(list2) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) + } + + func testAppendListToEmptyList() { + let list = LinkedList() + let list2 = LinkedList() + list2.append(5) + list2.append(10) + list.append(list2) + XCTAssertTrue(list.count == 2) + XCTAssertEqual(list.node(at: 0).value, 5) + XCTAssertEqual(list.node(at: 1).value, 10) + } + + func testRemoveAtIndexOnListWithOneElement() { + let list = LinkedList() + list.append(123) + + let value = list.remove(at: 0) + XCTAssertEqual(value, 123) + + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testRemoveAtIndex() { + let list = buildList() + let prev = list.node(at: 2) + let next = list.node(at: 3) + let nodeCount = list.count + + list.insert(444, at: 3) + + let value = list.remove(at: 3) + XCTAssertEqual(value, 444) + + let node = list.node(at: 3) + XCTAssertTrue(next === node) + XCTAssertTrue(prev.next === node) + XCTAssertTrue(node.previous === prev) + XCTAssertEqual(nodeCount, list.count) + } + + func testRemoveLastOnListWithOneElement() { + let list = LinkedList() + list.append(123) + + let value = list.removeLast() + XCTAssertEqual(value, 123) + + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testRemoveLast() { + let list = buildList() + let last = list.last + let prev = last!.previous + let nodeCount = list.count + + let value = list.removeLast() + XCTAssertEqual(value, 5) + + XCTAssertNil(last!.previous) + XCTAssertNil(last!.next) + + XCTAssertNil(prev!.next) + XCTAssertTrue(list.last === prev) + XCTAssertEqual(nodeCount - 1, list.count) + } + + func testRemoveAll() { + let list = buildList() + list.removeAll() + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testReverseLinkedList() { + let list = buildList() + let first = list.head + let last = list.last + let nodeCount = list.count + + list.reverse() + + XCTAssertTrue(first === list.last) + XCTAssertTrue(last === list.head) + XCTAssertEqual(nodeCount, list.count) + } + + func testArrayLiteralInitTypeInfer() { + let arrayLiteralInitInfer: LinkedList = [1.0, 2.0, 3.0] + + XCTAssertEqual(arrayLiteralInitInfer.count, 3) + XCTAssertEqual(arrayLiteralInitInfer.head?.value, 1.0) + XCTAssertEqual(arrayLiteralInitInfer.last?.value, 3.0) + XCTAssertEqual(arrayLiteralInitInfer[1], 2.0) + XCTAssertEqual(arrayLiteralInitInfer.removeLast(), 3.0) + XCTAssertEqual(arrayLiteralInitInfer.count, 2) + } + + func testArrayLiteralInitExplicit() { + let arrayLiteralInitExplicit: LinkedList = [1, 2, 3] + + XCTAssertEqual(arrayLiteralInitExplicit.count, 3) + XCTAssertEqual(arrayLiteralInitExplicit.head?.value, 1) + XCTAssertEqual(arrayLiteralInitExplicit.last?.value, 3) + XCTAssertEqual(arrayLiteralInitExplicit[1], 2) + XCTAssertEqual(arrayLiteralInitExplicit.removeLast(), 3) + XCTAssertEqual(arrayLiteralInitExplicit.count, 2) + } + + func testConformanceToCollectionProtocol() { + let collection: LinkedList = [1, 2, 3, 4, 5] + let index2 = collection.index(collection.startIndex, offsetBy: 2) + let value = collection[index2] + + XCTAssertTrue(value == 3) + } +} diff --git a/Linked List/Tests/Tests.xcodeproj/project.pbxproj b/Linked List/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..388dcd96c --- /dev/null +++ b/Linked List/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,264 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3F81C77A618003CECC7 /* LinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F71C77A618003CECC7 /* LinkedList.swift */; }; + 7B80C3FA1C77A61E003CECC7 /* LinkedListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F91C77A61E003CECC7 /* LinkedListTests.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; }; + 7B80C3F71C77A618003CECC7 /* LinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinkedList.swift; path = ../LinkedList.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3F91C77A61E003CECC7 /* LinkedListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkedListTests.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 = ( + 7B80C3F71C77A618003CECC7 /* LinkedList.swift */, + 7B80C3F91C77A61E003CECC7 /* LinkedListTests.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 = ( + 7B80C3F81C77A618003CECC7 /* LinkedList.swift in Sources */, + 7B80C3FA1C77A61E003CECC7 /* LinkedListTests.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 = 4.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 = 4.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/Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8ef8d8581 --- /dev/null +++ b/Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift new file mode 100644 index 000000000..0e78b7043 --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift @@ -0,0 +1,63 @@ +// last checked with Xcode 11.4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +extension String { + public func longestCommonSubsequence(_ other: String) -> String { + + func lcsLength(_ other: String) -> [[Int]] { + var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.count+1), count: self.count+1) + + for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { + if otherChar == selfChar { + matrix[i+1][j+1] = matrix[i][j] + 1 + } else { + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + return matrix + } + + func backtrack(_ matrix: [[Int]]) -> String { + var i = self.count + var j = other.count + var charInSequence = self.endIndex + + var lcs = String() + + while i >= 1 && j >= 1 { + if matrix[i][j] == matrix[i][j - 1] { + j -= 1 + } else if matrix[i][j] == matrix[i - 1][j] { + i -= 1 + charInSequence = self.index(before: charInSequence) + } else { + i -= 1 + j -= 1 + charInSequence = self.index(before: charInSequence) + lcs.append(self[charInSequence]) + } + } + return String(lcs.reversed()) + } + + return backtrack(lcsLength(other)) + } +} + +// Examples + +let a = "ABCBX" +let b = "ABDCAB" +let c = "KLMK" + +a.longestCommonSubsequence(c) // "" +a.longestCommonSubsequence("") // "" +a.longestCommonSubsequence(b) // "ABCB" +b.longestCommonSubsequence(a) // "ABCB" +a.longestCommonSubsequence(a) // "ABCBX" + +"Hello World".longestCommonSubsequence("Bonjour le monde") diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/playground.xcworkspace/contents.xcworkspacedata b/Longest Common Subsequence/LongestCommonSubsequence.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Longest Common Subsequence/LongestCommonSubsequence.swift b/Longest Common Subsequence/LongestCommonSubsequence.swift new file mode 100644 index 000000000..b6834279d --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.swift @@ -0,0 +1,70 @@ +extension 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]] { + + // 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]](repeating: [Int](repeating: 0, count: other.characters.count+1), count: self.characters.count+1) + + 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 + } else { + // Not a match, propagates highest lcs length found so far. + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + // Due to propagation, lcs length is at matrix[n][m]. + return matrix + } + + // Backtracks from matrix[n][m] to matrix[1][1] looking for chars that are + // common to both strings. + func backtrack(_ matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + + // charInSequence is in sync with i so we can get self[i] + var charInSequence = self.endIndex + + var lcs = String() + + while i >= 1 && j >= 1 { + // Indicates propagation without change: no new char was added to lcs. + if matrix[i][j] == matrix[i][j - 1] { + j -= 1 + } + // Indicates propagation without change: no new char was added to lcs. + else if matrix[i][j] == matrix[i - 1][j] { + i -= 1 + // As i was decremented, move back charInSequence. + 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 = 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.reversed()) + } + + // Combine dynamic programming approach with backtrack to find the lcs. + return backtrack(lcsLength(other)) + } +} diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown new file mode 100644 index 000000000..8a4a763c6 --- /dev/null +++ b/Longest Common Subsequence/README.markdown @@ -0,0 +1,201 @@ +# Longest Common Subsequence + +The Longest Common Subsequence (LCS) of two strings is the longest sequence of characters that appear in the same order in both strings. + +For example the LCS of `"Hello World"` and `"Bonjour le monde"` is `"oorld"`. If you go through both strings from left-to-right, you'll find that the characters `o`, `o`, `r`, `l`, `d` appear in both strings in that order. + +Other possible subsequences are `"ed"` and `"old"`, but these are all shorter than `"oorld"`. + +> **Note:** This should not be confused with the Longest Common Substring problem, where the characters must form a substring of both strings, i.e they have to be immediate neighbors. With a subsequence, it's OK if the characters are not right next to each other, but they must be in the same order. + +One way to find the LCS of two strings `a` and `b` is using dynamic programming and a backtracking strategy. + +## Finding the length of the LCS with dynamic programming + +First, we want to find the length of the longest common subsequence between strings `a` and `b`. We're not looking for the actual subsequence yet, only how long it is. + +To determine the length of the LCS between all combinations of substrings of `a` and `b`, we can use a *dynamic programming* technique. Dynamic programming basically means that you compute all possibilities and store them inside a look-up table. + +> **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]`. + +Given strings `"ABCBX"` and `"ABDCAB"`, the output matrix of `lcsLength(_:)` is the following: + +``` +| | Ø | A | B | D | C | A | B | +| Ø | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| A | 0 | 1 | 1 | 1 | 1 | 1 | 1 | +| B | 0 | 1 | 2 | 2 | 2 | 2 | 2 | +| C | 0 | 1 | 2 | 2 | 3 | 3 | 3 | +| B | 0 | 1 | 2 | 2 | 3 | 3 | 4 | +| X | 0 | 1 | 2 | 2 | 3 | 3 | 4 | +``` + +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`: + +```swift +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.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 + } else { + // Not a match, propagates highest lcs length found so far. + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + return matrix +} +``` + +First, this creates a new matrix -- really a 2-dimensional array -- and fills it with zeros. Then it loops through both strings, `self` and `other`, and compares their characters in order to fill in the matrix. If two characters match, we increment the length of the subsequence. However, if two characters are different, then we "propagate" the highest LCS length found so far. + +Let's say the following is the current situation: + +``` +| | Ø | A | B | D | C | A | B | +| Ø | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| A | 0 | 1 | 1 | 1 | 1 | 1 | 1 | +| B | 0 | 1 | 2 | 2 | 2 | 2 | 2 | +| C | 0 | 1 | 2 | * | | | | +| B | 0 | | | | | | | +| X | 0 | | | | | | | +``` + +The `*` marks the two characters we're currently comparing, `C` versus `D`. These characters are not the same, so we propagate the highest length we've seen so far, which is `2`: + +``` +| | Ø | A | B | D | C | A | B | +| Ø | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| A | 0 | 1 | 1 | 1 | 1 | 1 | 1 | +| B | 0 | 1 | 2 | 2 | 2 | 2 | 2 | +| C | 0 | 1 | 2 | 2 | * | | | +| B | 0 | | | | | | | +| X | 0 | | | | | | | +``` + +Now we compare `C` with `C`. These are equal, and we increment the length to `3`: + +``` +| | Ø | A | B | D | C | A | B | +| Ø | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| A | 0 | 1 | 1 | 1 | 1 | 1 | 1 | +| B | 0 | 1 | 2 | 2 | 2 | 2 | 2 | +| C | 0 | 1 | 2 | 2 | 3 | * | | +| B | 0 | | | | | | | +| X | 0 | | | | | | | +``` + +And so on... this is how `lcsLength(_:)` fills in the entire matrix. + +## Backtracking to find the actual subsequence + +So far we've calculated the length of every possible subsequence. The length of the longest subsequence is found in the bottom-right corner of matrix, at `matrix[n+1][m+1]`. In the above example it is 4, so the LCS consists of 4 characters. + +Having the length of every combination of substrings makes it possible to determine *which* characters are part of the LCS itself by using a backtracking strategy. + +Backtracking starts at `matrix[n+1][m+1]` and walks up and left (in this priority) looking for changes that do not indicate a simple propagation. + +``` +| | Ø| A| B| D| C| A| B| +| Ø | 0| 0| 0| 0| 0| 0| 0| +| A | 0|↖ 1| 1| 1| 1| 1| 1| +| B | 0| 1|↖ 2|← 2| 2| 2| 2| +| C | 0| 1| 2| 2|↖ 3|← 3| 3| +| B | 0| 1| 2| 2| 3| 3|↖ 4| +| X | 0| 1| 2| 2| 3| 3|↑ 4| +``` + +Each `↖` move indicates a character (in row/column header) that is part of the LCS. + +If the number on the left and above are different than the number in the current cell, no propagation happened. In that case `matrix[i][j]` indicates a common char between the strings `a` and `b`, so the characters at `a[i - 1]` and `b[j - 1]` are part of the LCS that we're looking for. + +One thing to notice is, as it's running backwards, the LCS is built in reverse order. Before returning, the result is reversed to reflect the actual LCS. + +Here is the backtracking code: + +```swift +func backtrack(_ matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + + var charInSequence = self.endIndex + + var lcs = String() + + while i >= 1 && j >= 1 { + // Indicates propagation without change: no new char was added to lcs. + if matrix[i][j] == matrix[i][j - 1] { + j -= 1 + } + // Indicates propagation without change: no new char was added to lcs. + else if matrix[i][j] == matrix[i - 1][j] { + i -= 1 + 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 = self.index(before: charInSequence) + lcs.append(self[charInSequence]) + } + } + + return String(lcs.characters.reversed()) +} +``` + +This backtracks from `matrix[n+1][m+1]` (bottom-right corner) to `matrix[1][1]` (top-left corner), looking for characters that are common to both strings. It adds those characters to a new string, `lcs`. + +The `charInSequence` variable is an index into the string given by `self`. Initially this points to the last character of the string. Each time we decrement `i`, we also move back `charInSequence`. When the two characters are found to be equal, we add the character at `self[charInSequence]` to the new `lcs` string. (We can't just write `self[i]` because `i` may not map to the current position inside the Swift string.) + +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 + +To find the LCS between two strings, we first call `lcsLength(_:)` and then `backtrack(_:)`: + +```swift +extension String { + public func longestCommonSubsequence(_ other: String) -> String { + + func lcsLength(_ other: String) -> [[Int]] { + ... + } + + func backtrack(_ matrix: [[Int]]) -> String { + ... + } + + return backtrack(lcsLength(other)) + } +} +``` + +To keep everything tidy, the two helper functions are nested inside the main `longestCommonSubsequence()` function. + +Here's how you could try it out in a Playground: + +```swift +let a = "ABCBX" +let b = "ABDCAB" +a.longestCommonSubsequence(b) // "ABCB" + +let c = "KLMK" +a.longestCommonSubsequence(c) // "" (no common subsequence) + +"Hello World".longestCommonSubsequence("Bonjour le monde") // "oorld" +``` + +*Written for Swift Algorithm Club by Pedro Vereza* diff --git a/Longest Common Subsequence/Tests/LongestCommonSubsequenceTests.swift b/Longest Common Subsequence/Tests/LongestCommonSubsequenceTests.swift new file mode 100644 index 000000000..2498b6dd7 --- /dev/null +++ b/Longest Common Subsequence/Tests/LongestCommonSubsequenceTests.swift @@ -0,0 +1,32 @@ +import Foundation +import XCTest + +class LongestCommonSubsequenceTests: XCTestCase { + + func testLCSwithSelfIsSelf() { + let a = "ABCDE" + + XCTAssertEqual(a, a.longestCommonSubsequence(a)) + } + + func testLCSWithEmptyStringIsEmptyString() { + let a = "ABCDE" + + XCTAssertEqual("", a.longestCommonSubsequence("")) + } + + func testLCSIsEmptyWhenNoCharMatches() { + let a = "ABCDE" + let b = "WXYZ" + + XCTAssertEqual("", a.longestCommonSubsequence(b)) + } + + func testLCSIsNotCommutative() { + let a = "ABCDEF" + let b = "XAWDMVBEKD" + + XCTAssertEqual("ADE", a.longestCommonSubsequence(b)) + XCTAssertEqual("ABD", b.longestCommonSubsequence(a)) + } +} diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..bf9c18fd3 --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,297 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4716C7AF1C93751E00F6C1C0 /* LongestCommonSubsequenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsequenceTests.swift */; }; + 4716C7B01C93751E00F6C1C0 /* LongestCommonSubsequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LongestCommonSubsequence.swift; path = ../../LongestCommonSubsequence.swift; sourceTree = ""; }; + 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsequenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LongestCommonSubsequenceTests.swift; path = ../LongestCommonSubsequenceTests.swift; sourceTree = ""; }; + 4716C7A71C93750500F6C1C0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4716C7AB1C93750500F6C1C0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4716C7A41C93750500F6C1C0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4716C7811C936DCB00F6C1C0 = { + isa = PBXGroup; + children = ( + 4716C7A81C93750500F6C1C0 /* Tests */, + 4716C78F1C93746D00F6C1C0 /* Products */, + ); + sourceTree = ""; + }; + 4716C78F1C93746D00F6C1C0 /* Products */ = { + isa = PBXGroup; + children = ( + 4716C7A71C93750500F6C1C0 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 4716C7A81C93750500F6C1C0 /* Tests */ = { + isa = PBXGroup; + children = ( + 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */, + 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsequenceTests.swift */, + 4716C7AB1C93750500F6C1C0 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4716C7A61C93750500F6C1C0 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4716C7AC1C93750500F6C1C0 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 4716C7A31C93750500F6C1C0 /* Sources */, + 4716C7A41C93750500F6C1C0 /* Frameworks */, + 4716C7A51C93750500F6C1C0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 4716C7A71C93750500F6C1C0 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4716C7821C936DCB00F6C1C0 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0800; + TargetAttributes = { + 4716C7A61C93750500F6C1C0 = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = 4716C7851C936DCB00F6C1C0 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4716C7811C936DCB00F6C1C0; + productRefGroup = 4716C78F1C93746D00F6C1C0 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4716C7A61C93750500F6C1C0 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4716C7A51C93750500F6C1C0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4716C7A31C93750500F6C1C0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4716C7AF1C93751E00F6C1C0 /* LongestCommonSubsequenceTests.swift in Sources */, + 4716C7B01C93751E00F6C1C0 /* LongestCommonSubsequence.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 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; + }; + 4716C7AD1C93750500F6C1C0 /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + 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; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = me.pedrovereza.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 4716C7AE1C93750500F6C1C0 /* 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 = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = 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.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = me.pedrovereza.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4716C7851C936DCB00F6C1C0 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4716C7861C936DCB00F6C1C0 /* Debug */, + 4716C7871C936DCB00F6C1C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4716C7AC1C93750500F6C1C0 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4716C7AD1C93750500F6C1C0 /* Debug */, + 4716C7AE1C93750500F6C1C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4716C7821C936DCB00F6C1C0 /* Project object */; +} diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..0b0682c43 --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Longest Common Subsequence/Tests/Tests/Info.plist b/Longest Common Subsequence/Tests/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Longest Common Subsequence/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 + + diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index 27e52ab09..ca1347890 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 leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [T], rightPile: [T]) -> [T] { var leftIndex = 0 var rightIndex = 0 - var orderedPile = [Int]() + var orderedPile = [T]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } - while leftIndex < leftPile.count && rightIndex < rightPile.count { + while true { + guard leftIndex < leftPile.endIndex else { + orderedPile.append(contentsOf: rightPile[rightIndex.. 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 } let array = [2, 1, 5, 4, 9] let sortedArray = mergeSort(array) - - +let array2 = ["Tom", "Harry", "Ron", "Chandler", "Monica"] +let sortedArray2 = mergeSort(array2) /* 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 - + var width = 1 while width < n { - + var i = 0 while i < n { var j = i var l = i var r = i + width - + let lmax = min(l + width, n) let rmax = min(r + width, n) - + while l < lmax && r < rmax { if isOrderedBefore(z[d][l], z[d][r]) { z[1 - d][j] = z[d][l] @@ -89,7 +85,7 @@ func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { i += width*2 } - + width *= 2 // in each step, the subarray to merge becomes larger d = 1 - d // swap active array } diff --git a/Merge Sort/MergeSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Merge Sort/MergeSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Merge Sort/MergeSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Merge Sort/MergeSort.playground/timeline.xctimeline b/Merge Sort/MergeSort.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Merge Sort/MergeSort.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Merge Sort/MergeSort.swift b/Merge Sort/MergeSort.swift index 35bf7b5f8..00e35f498 100644 --- a/Merge Sort/MergeSort.swift +++ b/Merge Sort/MergeSort.swift @@ -1,12 +1,12 @@ // // Mergesort.swift -// +// // // Created by Kelvin Lau on 2016-02-03. // // -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 leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [T], rightPile: [T]) -> [T] { 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 - } + var orderedPile: [T] = [] + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) } - while leftIndex < leftPile.count { - orderedPile.append(leftPile[leftIndex]) - leftIndex += 1 + while true { + guard leftIndex < leftPile.endIndex else { + orderedPile.append(contentsOf: rightPile[rightIndex.. [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 - + var width = 1 while width < n { - + var i = 0 while i < n { - + var j = i var l = i var r = i + width - + let lmax = min(l + width, n) let rmax = min(r + width, n) - + while l < lmax && r < rmax { if isOrderedBefore(z[d][l], z[d][r]) { z[1 - d][j] = z[d][l] @@ -97,10 +95,10 @@ func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { j += 1 r += 1 } - + i += width*2 } - + width *= 2 // in each step, the subarray to merge becomes larger d = 1 - d // swap active array } diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index 190f76a34..d86f062f4 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -1,48 +1,50 @@ # Merge Sort +> This topic has been tutorialized [here](https://www.raywenderlich.com/154256/swift-algorithm-club-swift-merge-sort) + 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 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 want to sort the contents in order. +- 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. Our goal is to keep splitting the pile until you can't 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. -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 split into 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]` +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. -Since you're left with only two piles, `[9]` finally gets its chance to merge, resulting in the sorted array `[1, 2, 4, 5, 9]`. +You are left with only two piles `[1, 2, 4, 5]` and `[9]`, finally gets its chance to merge, resulting in the sorted array as `[1, 2, 4, 5, 9]`. ## Top-down implementation 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 @@ -57,26 +59,27 @@ 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. +2. Find the middle index. -3. Using the middle index from the previous step, recursively split the left side of the resulting arrays. +3. Using the middle index from the previous step, recursively split the left side of the array. -4. Using the middle index, recursively split the right side of the resulting arrays. +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: ```swift -func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] { +func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { // 1 var leftIndex = 0 var rightIndex = 0 - // 2 + // 2 var orderedPile = [Int]() + orderedPile.reserveCapacity(leftPile.count + rightPile.count) // 3 while leftIndex < leftPile.count && rightIndex < rightPile.count { @@ -109,17 +112,17 @@ func merge(leftPile 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. Since you already know number of elements that will end up in this array, you reserve capacity to avoid reallocation overhead later. -3. This while loop will compare the elements from the left and right sides, and append them 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. These are merged into one larger sorted pile in the following steps: +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: leftPile rightPile orderedPile [ 1, 7, 8 ] [ 3, 6, 9 ] [ ] @@ -131,56 +134,56 @@ 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 ] l -->r - + leftPile rightPile orderedPile [ 1, 7, 8 ] [ 3, 6, 9 ] [ 1, 3, 6, 7 ] -->l r - + leftPile rightPile orderedPile [ 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: ```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 var d = 0 - + var width = 1 while width < n { // 2 - + var i = 0 while i < n { // 3 var j = i var l = i var r = i + width - + let lmax = min(l + width, n) let rmax = min(r + width, n) - + while l < lmax && r < rmax { // 4 if isOrderedBefore(z[d][l], z[d][r]) { z[1 - d][j] = z[d][l] @@ -204,7 +207,7 @@ func mergeSortBottomUp(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { i += width*2 } - + width *= 2 d = 1 - d // 5 } @@ -212,19 +215,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, this 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,18 +240,18 @@ 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 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 does not 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)**. +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 -See also [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort) +[Merge sort on Wikipedia](https://en.wikipedia.org/wiki/Merge_sort) *Written by Kelvin Lau. Additions by Matthijs Hollemans.* 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 000000000..1a06d151a Binary files /dev/null and b/Miller-Rabin Primality Test/Images/img_pseudo.png differ 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..35b457d1c --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -0,0 +1,26 @@ +//: Playground - noun: a place where people can play + +do { + // Real primes + try checkWithMillerRabin(5) + try checkWithMillerRabin(439) + try checkWithMillerRabin(1201) + try checkWithMillerRabin(143477) + try checkWithMillerRabin(1299869) + try checkWithMillerRabin(15487361) + try checkWithMillerRabin(179426363) + + // Fake primes + try checkWithMillerRabin(15) + try checkWithMillerRabin(435) + try checkWithMillerRabin(1207) + try checkWithMillerRabin(143473) + try checkWithMillerRabin(1291869) + try checkWithMillerRabin(15487161) + try checkWithMillerRabin(178426363) + + // Specifying accuracy + try checkWithMillerRabin(179426363, accuracy: 10) +} catch { + dump(error) +} \ No newline at end of file diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift new file mode 100644 index 000000000..03daac1fa --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift @@ -0,0 +1,100 @@ +// +// MRPrimality.swift +// +// +// Created by Sahn Cha on 2016. 10. 18.. +// +// + +import Foundation + +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow +} + +/* + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime + */ +public func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } + + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw MillerRabinError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } + + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } + + return result +} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/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.playground/playground.xcworkspace/contents.xcworkspacedata b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.swift new file mode 100644 index 000000000..24b9c674c --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -0,0 +1,100 @@ +// +// MRPrimality.swift +// +// +// Created by Sahn Cha on 2016. 10. 18.. +// +// + +import Foundation + +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow +} + +/* + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime +*/ +func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } + + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw EncryptionError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } + + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } + + return result +} diff --git a/Miller-Rabin Primality Test/README.markdown b/Miller-Rabin Primality Test/README.markdown new file mode 100644 index 000000000..9cc677a2e --- /dev/null +++ b/Miller-Rabin Primality Test/README.markdown @@ -0,0 +1,44 @@ +# Miller-Rabin Primality Test + +In 1976, Gray Miller introduced an algorithm, through his ph.d thesis[1], which determines a primality of the given number. The original algorithm was deterministic under the Extended Reimann Hypothesis, which is yet to be proven. After four years, Michael O. Rabin improved the algorithm[2] by using probabilistic approach and it no longer assumes the unproven hypothesis. + +## 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_. + +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`. + +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`. + +### Pseudo Code + +The following pseudo code is excerpted from Wikipedia[3]: + +![Image of Pseudocode](./Images/img_pseudo.png) + +## Usage + +```swift +checkWithMillerRabin(7) // test if 7 is prime. (default iteration = 1) +checkWithMillerRabin(7, accuracy: 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_ +_Code updated by **Simon C. Krüger**._ + +[1]: https://cs.uwaterloo.ca/research/tr/1975/CS-75-27.pdf +[2]: http://www.sciencedirect.com/science/article/pii/0022314X80900840 +[3]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test diff --git a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift new file mode 100644 index 000000000..5db0aeb0d --- /dev/null +++ b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift @@ -0,0 +1,39 @@ + +// Minimum Edit Distance + +extension String { + + public func minimumEditDistance(other: String) -> Int { + let m = self.count + let n = other.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.enumerated() { + for (j, otherChar) in other.enumerated() { + if otherChar == selfChar { + // substitution of equal symbols with cost 0 + matrix[i + 1][j + 1] = matrix[i][j] + } 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] = Swift.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 100644 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 new file mode 100755 index 000000000..c8e5e2f6d --- /dev/null +++ b/Minimum Edit Distance/README.markdown @@ -0,0 +1,64 @@ +# Minimum Edit Distance + +The minimum edit distance is a possibility to measure the similarity of two strings *w* and *u* by counting costs of operations which are necessary to transform *w* into *u* (or vice versa). + +### Algorithm using Levenshtein distance + +A common distance measure is given by the *Levenshtein distance*, which allows the following three transformation operations: + +* **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. + +When transforming a string by a sequence of operations, the costs of the single operations are added to obtain the (minimal) edit distance. For example, the string *Door* can be transformed by the operations *o→l*, *r→l*, *ε→s* to the string *Dolls*, which results in a minimum edit distance of 3. + +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]](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: + +```swift +// 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 +} +``` + +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.enumerated() { + for (j, otherChar) in other.enumerated() { + if otherChar == selfChar { + // substitution of equal symbols with cost 0 + matrix[i + 1][j + 1] = matrix[i][j] + } 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] = Swift.min(matrix[i][j] + 1, matrix[i + 1][j] + 1, matrix[i][j + 1] + 1) + } + } +} +``` + +After applying this algorithm, the minimal edit distance can be read from the rightmost bottom cell and is returned. + +```swift +return matrix[m][n] +``` + +This algorithm has a time complexity of Θ(*mn*). + +**TODO**: Other distance measures. + +*Written for Swift Algorithm Club by Luisa Herrmann* diff --git a/Minimum Spanning Tree (Unweighted)/Images/Graph.png b/Minimum Spanning Tree (Unweighted)/Images/Graph.png new file mode 100644 index 000000000..e85072898 Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/Graph.png differ diff --git a/Minimum Spanning Tree (Unweighted)/Images/Graph.sketch b/Minimum Spanning Tree (Unweighted)/Images/Graph.sketch new file mode 100644 index 000000000..e73e42379 Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/Graph.sketch differ diff --git a/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.png b/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.png new file mode 100644 index 000000000..bce73cc8e Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.png differ diff --git a/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.sketch b/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.sketch new file mode 100644 index 000000000..93a5b808c Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/MinimumSpanningTree.sketch differ diff --git a/Minimum Spanning Tree (Unweighted)/Images/Tree.graffle b/Minimum Spanning Tree (Unweighted)/Images/Tree.graffle new file mode 100644 index 000000000..686769bda Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/Tree.graffle differ diff --git a/Minimum Spanning Tree (Unweighted)/Images/Tree.png b/Minimum Spanning Tree (Unweighted)/Images/Tree.png new file mode 100644 index 000000000..1101f66ac Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/Images/Tree.png differ 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 new file mode 100644 index 000000000..8ad04379c --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift @@ -0,0 +1,70 @@ +func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { + let minimumSpanningTree = graph.duplicate() + + var queue = Queue() + let sourceInMinimumSpanningTree = minimumSpanningTree.findNodeWithLabel(source.label) + queue.enqueue(sourceInMinimumSpanningTree) + sourceInMinimumSpanningTree.visited = true + + while let current = queue.dequeue() { + for edge in current.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + neighborNode.visited = true + queue.enqueue(neighborNode) + } else { + current.remove(edge) + } + } + } + + return minimumSpanningTree +} + +/*: +![Graph](Minimum_Spanning_Tree.png) +*/ + +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeH) +graph.addEdge(nodeB, neighbor: nodeA) +graph.addEdge(nodeB, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeH) +graph.addEdge(nodeC, neighbor: nodeB) +graph.addEdge(nodeC, neighbor: nodeD) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeI) +graph.addEdge(nodeD, neighbor: nodeC) +graph.addEdge(nodeD, neighbor: nodeE) +graph.addEdge(nodeD, neighbor: nodeF) +graph.addEdge(nodeE, neighbor: nodeD) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeC) +graph.addEdge(nodeF, neighbor: nodeD) +graph.addEdge(nodeF, neighbor: nodeE) +graph.addEdge(nodeF, neighbor: nodeG) +graph.addEdge(nodeG, neighbor: nodeF) +graph.addEdge(nodeG, neighbor: nodeH) +graph.addEdge(nodeG, neighbor: nodeI) +graph.addEdge(nodeH, neighbor: nodeA) +graph.addEdge(nodeH, neighbor: nodeB) +graph.addEdge(nodeH, neighbor: nodeG) +graph.addEdge(nodeH, neighbor: nodeI) +graph.addEdge(nodeI, neighbor: nodeC) +graph.addEdge(nodeI, neighbor: nodeG) +graph.addEdge(nodeI, neighbor: nodeH) + +let minimumSpanningTree = breadthFirstSearchMinimumSpanningTree(graph, source: nodeA) +print(minimumSpanningTree) diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Resources/Minimum_Spanning_Tree.png b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Resources/Minimum_Spanning_Tree.png new file mode 100644 index 000000000..bce73cc8e Binary files /dev/null and b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Resources/Minimum_Spanning_Tree.png differ diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Edge.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Edge.swift new file mode 100644 index 000000000..9a58a1f96 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Edge.swift @@ -0,0 +1,11 @@ +public class Edge: Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift new file mode 100644 index 000000000..e2bb82677 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Graph.swift @@ -0,0 +1,55 @@ +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})]" + } + } + 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) + } + + 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) + } + } + + return duplicated + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift new file mode 100644 index 000000000..0aedb6ef9 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Node.swift @@ -0,0 +1,32 @@ +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))" + } + 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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift new file mode 100644 index 000000000..3d98f801c --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Sources/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + private var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/contents.xcplayground b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/contents.xcplayground new file mode 100644 index 000000000..5ed29117b --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift new file mode 100644 index 000000000..645a41999 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.swift @@ -0,0 +1,22 @@ +func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { + let minimumSpanningTree = graph.duplicate() + + var queue = Queue() + let sourceInMinimumSpanningTree = minimumSpanningTree.findNodeWithLabel(source.label) + queue.enqueue(sourceInMinimumSpanningTree) + sourceInMinimumSpanningTree.visited = true + + while let current = queue.dequeue() { + for edge in current.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + neighborNode.visited = true + queue.enqueue(neighborNode) + } else { + current.remove(edge) + } + } + } + + return minimumSpanningTree +} diff --git a/Minimum Spanning Tree (Unweighted)/README.markdown b/Minimum Spanning Tree (Unweighted)/README.markdown new file mode 100644 index 000000000..23f18c335 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/README.markdown @@ -0,0 +1,190 @@ +# Minimum Spanning Tree (Unweighted Graph) + +A minimum spanning tree describes a path that contains the smallest number of edges that are needed to visit every node in the graph. + +Take a look at the following graph: + +![Graph](Images/Graph.png) + +If we start from node `a` and want to visit every other node, then what is the most efficient path to do that? We can calculate this with the minimum spanning tree algorithm. + +Here is the minimum spanning tree for the graph. It is represented by the bold edges: + +![Minimum spanning tree](Images/MinimumSpanningTree.png) + +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%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. + +```swift +queue.enqueue(a) +a.visited = true +``` + +The queue is now `[ a ]`. As is usual with breadth-first search, we dequeue the node at the front of the queue, `a`, and enqueue its immediate neighbor nodes `b` and `h`. We mark them as visited too. + +```swift +queue.dequeue() // a +queue.enqueue(b) +b.visited = true +queue.enqueue(h) +h.visited = true +``` + +The queue is now `[ b, h ]`. Dequeue `b` and enqueue the neighbor node `c`. Mark it as visited. Remove the edge from `b` to `h` because `h` has already been visited. + +```swift +queue.dequeue() // b +queue.enqueue(c) +c.visited = true +b.removeEdgeTo(h) +``` + +The queue is now `[ h, c ]`. Dequeue `h` and enqueue the neighbor nodes `g` and `i`, and mark them as visited. + +```swift +queue.dequeue() // h +queue.enqueue(g) +g.visited = true +queue.enqueue(i) +i.visited = true +``` + +The queue is now `[ c, g, i ]`. Dequeue `c` and enqueue the neighbor nodes `d` and `f`, and mark them as visited. Remove the edge between `c` and `i` because `i` has already been visited. + +```swift +queue.dequeue() // c +queue.enqueue(d) +d.visited = true +queue.enqueue(f) +f.visited = true +c.removeEdgeTo(i) +``` + +The queue is now `[ g, i, d, f ]`. Dequeue `g`. All of its neighbors have been discovered already, so there is nothing to enqueue. Remove the edges from `g` to `f`, as well as `g` to `i`, because `f` and `i` have already been discovered. + +```swift +queue.dequeue() // g +g.removeEdgeTo(f) +g.removeEdgeTo(i) +``` + +The queue is now `[ i, d, f ]`. Dequeue `i`. Nothing else to do for this node. + +```swift +queue.dequeue() // i +``` + +The queue is now `[ d, f ]`. Dequeue `d` and enqueue the neighbor node `e`. Mark it as visited. Remove the edge from `d` to `f` because `f` has already been visited. + +```swift +queue.dequeue() // d +queue.enqueue(e) +e.visited = true +d.removeEdgeTo(f) +``` + +The queue is now `[ f, e ]`. Dequeue `f`. Remove the edge between `f` and `e` because `e` has already been visited. + +```swift +queue.dequeue() // f +f.removeEdgeTo(e) +``` + +The queue is now `[ e ]`. Dequeue `e`. + +```swift +queue.dequeue() // e +``` + +The queue is empty, which means the minimum spanning tree has been computed. + +Here's the code: + +```swift +func breadthFirstSearchMinimumSpanningTree(graph: Graph, source: Node) -> Graph { + let minimumSpanningTree = graph.duplicate() + + var queue = Queue() + let sourceInMinimumSpanningTree = minimumSpanningTree.findNodeWithLabel(source.label) + queue.enqueue(sourceInMinimumSpanningTree) + sourceInMinimumSpanningTree.visited = true + + while let current = queue.dequeue() { + for edge in current.neighbors { + let neighborNode = edge.neighbor + if !neighborNode.visited { + neighborNode.visited = true + queue.enqueue(neighborNode) + } else { + current.remove(edge) + } + } + } + + return minimumSpanningTree +} +``` + +This function returns a new `Graph` object that describes just the minimum spanning tree. In the figure, that would be the graph containing just the bold edges. + +Put this code in a playground and test it like so: + +```swift +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") + +graph.addEdge(nodeA, neighbor: nodeB) +graph.addEdge(nodeA, neighbor: nodeH) +graph.addEdge(nodeB, neighbor: nodeA) +graph.addEdge(nodeB, neighbor: nodeC) +graph.addEdge(nodeB, neighbor: nodeH) +graph.addEdge(nodeC, neighbor: nodeB) +graph.addEdge(nodeC, neighbor: nodeD) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeI) +graph.addEdge(nodeD, neighbor: nodeC) +graph.addEdge(nodeD, neighbor: nodeE) +graph.addEdge(nodeD, neighbor: nodeF) +graph.addEdge(nodeE, neighbor: nodeD) +graph.addEdge(nodeE, neighbor: nodeF) +graph.addEdge(nodeF, neighbor: nodeC) +graph.addEdge(nodeF, neighbor: nodeD) +graph.addEdge(nodeF, neighbor: nodeE) +graph.addEdge(nodeF, neighbor: nodeG) +graph.addEdge(nodeG, neighbor: nodeF) +graph.addEdge(nodeG, neighbor: nodeH) +graph.addEdge(nodeG, neighbor: nodeI) +graph.addEdge(nodeH, neighbor: nodeA) +graph.addEdge(nodeH, neighbor: nodeB) +graph.addEdge(nodeH, neighbor: nodeG) +graph.addEdge(nodeH, neighbor: nodeI) +graph.addEdge(nodeI, neighbor: nodeC) +graph.addEdge(nodeI, neighbor: nodeG) +graph.addEdge(nodeI, neighbor: nodeH) + +let minimumSpanningTree = breadthFirstSearchMinimumSpanningTree(graph, source: nodeA) + +print(minimumSpanningTree) // [node: a edges: ["b", "h"]] + // [node: b edges: ["c"]] + // [node: c edges: ["d", "f"]] + // [node: d edges: ["e"]] + // [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%20Search) to find the minimum spanning tree. + +*Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift new file mode 100644 index 000000000..c8cb77ac8 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Graph.swift @@ -0,0 +1,106 @@ +// MARK: - Edge + +public class Edge: Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + 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))" + } + 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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + 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})]" + } + } + 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) + } + + 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) + } + } + + return duplicated + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Info.plist b/Minimum Spanning Tree (Unweighted)/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/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/Minimum Spanning Tree (Unweighted)/Tests/MinimumSpanningTreeTests.swift b/Minimum Spanning Tree (Unweighted)/Tests/MinimumSpanningTreeTests.swift new file mode 100644 index 000000000..af8da4e5a --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/MinimumSpanningTreeTests.swift @@ -0,0 +1,107 @@ +import XCTest + +class MinimumSpanningTreeTests: XCTestCase { + + func testMinimumSpanningTreeReturnsSameTreeWhenGivenTree() { + 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") + tree.addEdge(nodeA, neighbor: nodeB) + tree.addEdge(nodeA, neighbor: nodeC) + tree.addEdge(nodeB, neighbor: nodeD) + tree.addEdge(nodeB, neighbor: nodeE) + tree.addEdge(nodeC, neighbor: nodeF) + tree.addEdge(nodeC, neighbor: nodeG) + tree.addEdge(nodeE, neighbor: nodeH) + + let minimumSpanningTree = breadthFirstSearchMinimumSpanningTree(tree, source: nodeA) + + XCTAssertEqual(minimumSpanningTree, tree) + } + + func testMinimumSpanningTreeReturnsMinimumSpanningTreeWhenGivenGraph() { + let graphAndSourceNode = createGraph() + let expectedMinimumSpanningTree = createMinimumSpanningTree() + + let actualMinimumSpanningTree = breadthFirstSearchMinimumSpanningTree(graphAndSourceNode.graph, + source: graphAndSourceNode.source) + + XCTAssertEqual(actualMinimumSpanningTree, expectedMinimumSpanningTree) + } + + func createGraph() -> (graph: Graph, source: Node) { + 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") + + graph.addEdge(nodeA, neighbor: nodeB) + graph.addEdge(nodeA, neighbor: nodeH) + graph.addEdge(nodeB, neighbor: nodeA) + graph.addEdge(nodeB, neighbor: nodeC) + graph.addEdge(nodeB, neighbor: nodeH) + graph.addEdge(nodeC, neighbor: nodeB) + graph.addEdge(nodeC, neighbor: nodeD) + graph.addEdge(nodeC, neighbor: nodeF) + graph.addEdge(nodeC, neighbor: nodeI) + graph.addEdge(nodeD, neighbor: nodeC) + graph.addEdge(nodeD, neighbor: nodeE) + graph.addEdge(nodeD, neighbor: nodeF) + graph.addEdge(nodeE, neighbor: nodeD) + graph.addEdge(nodeE, neighbor: nodeF) + graph.addEdge(nodeF, neighbor: nodeC) + graph.addEdge(nodeF, neighbor: nodeD) + graph.addEdge(nodeF, neighbor: nodeE) + graph.addEdge(nodeF, neighbor: nodeG) + graph.addEdge(nodeG, neighbor: nodeF) + graph.addEdge(nodeG, neighbor: nodeH) + graph.addEdge(nodeG, neighbor: nodeI) + graph.addEdge(nodeH, neighbor: nodeA) + graph.addEdge(nodeH, neighbor: nodeB) + graph.addEdge(nodeH, neighbor: nodeG) + graph.addEdge(nodeH, neighbor: nodeI) + graph.addEdge(nodeI, neighbor: nodeC) + graph.addEdge(nodeI, neighbor: nodeG) + graph.addEdge(nodeI, neighbor: nodeH) + + return (graph, nodeA) + } + + func createMinimumSpanningTree() -> Graph { + let minimumSpanningTree = Graph() + + let nodeA = minimumSpanningTree.addNode("a") + let nodeB = minimumSpanningTree.addNode("b") + let nodeC = minimumSpanningTree.addNode("c") + let nodeD = minimumSpanningTree.addNode("d") + let nodeE = minimumSpanningTree.addNode("e") + let nodeF = minimumSpanningTree.addNode("f") + let nodeG = minimumSpanningTree.addNode("g") + let nodeH = minimumSpanningTree.addNode("h") + let nodeI = minimumSpanningTree.addNode("i") + + minimumSpanningTree.addEdge(nodeA, neighbor: nodeB) + minimumSpanningTree.addEdge(nodeA, neighbor: nodeH) + minimumSpanningTree.addEdge(nodeB, neighbor: nodeC) + minimumSpanningTree.addEdge(nodeH, neighbor: nodeG) + minimumSpanningTree.addEdge(nodeH, neighbor: nodeI) + minimumSpanningTree.addEdge(nodeC, neighbor: nodeD) + minimumSpanningTree.addEdge(nodeC, neighbor: nodeF) + minimumSpanningTree.addEdge(nodeD, neighbor: nodeE) + + return minimumSpanningTree + } +} diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift b/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift new file mode 100644 index 000000000..3d98f801c --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + private var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..afb3b8acb --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,298 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 83AACB421C844CED00DDAFC7 /* MinimumSpanningTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AACB411C844CED00DDAFC7 /* MinimumSpanningTreeTests.swift */; }; + 83F9C9691C84437C00B3A87F /* MinimumSpanningTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9661C84437C00B3A87F /* MinimumSpanningTree.swift */; }; + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9701C84449D00B3A87F /* Queue.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; }; + 83AACB411C844CED00DDAFC7 /* MinimumSpanningTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimumSpanningTreeTests.swift; sourceTree = SOURCE_ROOT; }; + 83F9C9661C84437C00B3A87F /* MinimumSpanningTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MinimumSpanningTree.swift; path = ../MinimumSpanningTree.swift; sourceTree = SOURCE_ROOT; }; + 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = SOURCE_ROOT; }; + 83F9C9701C84449D00B3A87F /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.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 = ( + 83F9C9661C84437C00B3A87F /* MinimumSpanningTree.swift */, + 83AACB411C844CED00DDAFC7 /* MinimumSpanningTreeTests.swift */, + 83F9C96E1C84449D00B3A87F /* Graph.swift */, + 83F9C9701C84449D00B3A87F /* Queue.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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 83AACB421C844CED00DDAFC7 /* MinimumSpanningTreeTests.swift in Sources */, + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */, + 83F9C9691C84437C00B3A87F /* MinimumSpanningTree.swift in Sources */, + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Minimum Spanning Tree/Images/kruskal.png b/Minimum Spanning Tree/Images/kruskal.png new file mode 100644 index 000000000..5172f180f Binary files /dev/null and b/Minimum Spanning Tree/Images/kruskal.png differ diff --git a/Minimum Spanning Tree/Images/prim.png b/Minimum Spanning Tree/Images/prim.png new file mode 100644 index 000000000..b8db7c0b9 Binary files /dev/null and b/Minimum Spanning Tree/Images/prim.png differ diff --git a/Minimum Spanning Tree/Kruskal.swift b/Minimum Spanning Tree/Kruskal.swift new file mode 100644 index 000000000..7db4aeb2d --- /dev/null +++ b/Minimum Spanning Tree/Kruskal.swift @@ -0,0 +1,30 @@ +// +// 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..7e3532429 --- /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() + + guard let start = graph.vertices.first else { + 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: start, 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 000000000..2138fd535 Binary files /dev/null and b/Minimum Spanning Tree/MinimumSpanningTree.playground/Resources/mst.png differ 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..f6e4d4fc1 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Sources/Graph.swift @@ -0,0 +1,48 @@ +// 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) + + adjList[v1] = adjList[v1] ?? [] + adjList[v1]?.append((vertex: v2, weight: w)) + + adjList[v2] = adjList[v2] ?? [] + 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..8a2c2aa07 --- /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 { + elements.swapAt(index,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 } + + elements.swapAt(parentIndex,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/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/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Minimum Spanning Tree/Prim.swift b/Minimum Spanning Tree/Prim.swift new file mode 100644 index 000000000..b05fc1b1f --- /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() + + guard let start = graph.vertices.first else { + 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: start, 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..6ae7a89d9 --- /dev/null +++ b/Minimum Spanning Tree/README.markdown @@ -0,0 +1,104 @@ +# Minimum Spanning Tree (Weighted Graph) + +> This topic has been tutorialized [here](https://www.raywenderlich.com/169392/swift-algorithm-club-minimum-spanning-tree-with-prims-algorithm) + +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/MinimumCoinChange/LICENSE b/MinimumCoinChange/LICENSE new file mode 100755 index 000000000..fda6e6146 --- /dev/null +++ b/MinimumCoinChange/LICENSE @@ -0,0 +1,21 @@ +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. 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..c83708dee --- /dev/null +++ b/MinimumCoinChange/Sources/MinimumCoinChange.swift @@ -0,0 +1,89 @@ +// +// Minimum Coin Change Problem Playground +// Compare Greedy Algorithm and Dynamic Programming Algorithm in Swift +// +// Created by Jacopo Mangiavacchi on 04/03/17. +// + +import Foundation + +public enum MinimumCoinChangeError: Error { + case noRestPossibleForTheGivenValue +} + +public struct MinimumCoinChange { + internal let sortedCoinSet: [Int] + + public init(coinSet: [Int]) { + self.sortedCoinSet = coinSet.sorted(by: { $0 > $1}) + } + + //Greedy Algorithm + 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 { + break + } + } + + if newValue > 0 { + throw MinimumCoinChangeError.noRestPossibleForTheGivenValue + } + + return change + } + + //Dynamic Programming Algorithm + public func changeDynamic(_ value: Int) throws -> [Int] { + guard value > 0 else { return [] } + + var cache: [Int : [Int]] = [:] + + func _changeDynamic(_ value: Int) -> [Int] { + guard value > 0 else { return [] } + + if let cached = cache[value] { + return cached + } + + var potentialChangeArray: [[Int]] = [] + + for coin in sortedCoinSet { + if value - coin >= 0 { + var potentialChange: [Int] = [coin] + potentialChange.append(contentsOf: _changeDynamic(value - coin)) + + if potentialChange.reduce(0, +) == value { + potentialChangeArray.append(potentialChange) + } + } + } + + if potentialChangeArray.count > 0 { + let sortedPotentialChangeArray = potentialChangeArray.sorted(by: { $0.count < $1.count }) + cache[value] = sortedPotentialChangeArray[0] + return sortedPotentialChangeArray[0] + } + + return [] + } + + let change: [Int] = _changeDynamic(value) + + if change.reduce(0, +) != value { + throw MinimumCoinChangeError.noRestPossibleForTheGivenValue + } + + 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..45beff775 --- /dev/null +++ b/MinimumCoinChange/Tests/MinimumCoinChangeTests/MinimumCoinChangeTests.swift @@ -0,0 +1,35 @@ +import XCTest +@testable import MinimumCoinChange + +class MinimumCoinChangeTests: XCTestCase { + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + func testExample() { + let mcc = MinimumCoinChange(coinSet: [1, 2, 5, 10, 20, 25]) + print("Coin set: \(mcc.sortedCoinSet)") + + do { + for i in 0..<100 { + let greedy = try mcc.changeGreedy(i) + let dynamic = try mcc.changeDynamic(i) + + 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 = [ + ("testExample", testExample), + ] +} diff --git a/MinimumCoinChange/eurocoins.gif b/MinimumCoinChange/eurocoins.gif new file mode 100644 index 000000000..2d9e81e55 Binary files /dev/null and b/MinimumCoinChange/eurocoins.gif differ diff --git a/Monty Hall Problem/MontyHall.playground/Contents.swift b/Monty Hall Problem/MontyHall.playground/Contents.swift new file mode 100644 index 000000000..a809410c7 --- /dev/null +++ b/Monty Hall Problem/MontyHall.playground/Contents.swift @@ -0,0 +1,53 @@ +//: Playground - noun: a place where people can play + +import Foundation + +func random(_ n: Int) -> Int { + return Int(arc4random_uniform(UInt32(n))) +} + +let numberOfDoors = 3 + +var rounds = 0 +var winOriginalChoice = 0 +var winChangedMind = 0 + +func playRound() { + // The door with the prize. + let prizeDoor = random(numberOfDoors) + + // The door the player chooses. + let chooseDoor = random(numberOfDoors) + + // The door that Monty opens. This must be empty and not the one the player chose. + var openDoor = -1 + repeat { + openDoor = random(numberOfDoors) + } while openDoor == prizeDoor || openDoor == chooseDoor + + // What happens when the player changes his mind and picks the other door. + var changeMind = -1 + repeat { + changeMind = random(numberOfDoors) + } while changeMind == openDoor || changeMind == chooseDoor + + // Figure out which choice was the winner. + if chooseDoor == prizeDoor { + winOriginalChoice += 1 + } + if changeMind == prizeDoor { + winChangedMind += 1 + } + + rounds += 1 +} + +// Run the simulation a large number of times. +for _ in 1...5000 { + playRound() +} + +let stubbornPct = Double(winOriginalChoice)/Double(rounds) +let changedMindPct = Double(winChangedMind)/Double(rounds) + +print(String(format: "Played %d rounds, stubborn: %g%% vs changed mind: %g%%", rounds, stubbornPct, changedMindPct)) diff --git a/Monty Hall Problem/MontyHall.playground/contents.xcplayground b/Monty Hall Problem/MontyHall.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Monty Hall Problem/MontyHall.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Monty Hall Problem/MontyHall.playground/playground.xcworkspace/contents.xcworkspacedata b/Monty Hall Problem/MontyHall.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Monty Hall Problem/MontyHall.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Monty Hall Problem/README.markdown b/Monty Hall Problem/README.markdown new file mode 100644 index 000000000..f096a3a7a --- /dev/null +++ b/Monty Hall Problem/README.markdown @@ -0,0 +1,88 @@ +# The Monty Hall Problem + +Congrats! You've reached the final round of the popular [Monty Hall game show](https://en.wikipedia.org/wiki/Let%27s_Make_a_Deal). Monty, the show host, gives you the choice between 3 doors. Behind one of the doors is a prize (a new car? a trip to Hawaii? a microwave oven?), the other two are empty. + +After you make your choice, Monty decides to make things a bit more interesting and opens one of the two doors that you didn't pick. Of course, the one he opens is empty. There are now two doors left, behind one of which is the coveted prize. + +Now Monty gives you the opportunity to change your mind. Should you stick with your original choice, should you pick the other door, or doesn't it matter? + +You'd think that changing your answer wouldn't improve your chances... but it does! + +This is a very nonintuitive result. Maybe you have trouble believing this is true. Don't worry, when this problem was first proposed many professional mathematicians didn't believe it either, so you're in good company. + +There's a simple way to verify this claim: we can write a program to test it out! We should be able to show who wins more often by playing the game a large number of times. + +Here's the code (see the [playground](MontyHall.playground/Contents.swift) for the full thing). First, we randomly choose the door that has the prize: + +```swift + let prizeDoor = random(3) +``` + +We also randomly pick the choice of the player: + +```swift + let chooseDoor = random(3) +``` + +Next, Monty opens one of the empty doors. Obviously, he won't choose the door that the player chose or the one with the prize. + +```swift + var openDoor = -1 + repeat { + openDoor = random(3) + } while openDoor == prizeDoor || openDoor == chooseDoor +``` + +There are only two closed doors left, one of which has the prize. What happens when the player changes his mind and picks the other door? + +```swift + var changeMind = -1 + repeat { + changeMind = random(3) + } while changeMind == openDoor || changeMind == chooseDoor +``` + +Now we see which choice was the right one: + +```swift + if chooseDoor == prizeDoor { + winOriginalChoice += 1 + } + if changeMind == prizeDoor { + winChangedMind += 1 + } +``` + +If the prize is behind the player's original door choice, we increment `winOriginalChoice`. If the prize is behind the other door, then the player would have won if he changed his mind, and so we increment `winChangedMind`. + +And that's all there is to it. + +If you run the above code 1000 times or so, you'll find that the probability of choosing the prize without changing your mind is about 33%. But if you *do* change your mind, the probability of winning is 67% -- that is twice as large! + +Try it out in the playground if you still don't believe it. ;-) + +Here's why: When you first make a choice, your chances of picking the prize are 1 out of 3, or 33% + +After Monty opens one of the doors, this gives you new information. However, it doesn't change the probability of your original choice being the winner. That chance remains 33% because you made that choice when you didn't know yet what was behind this open door. + +Since probabilities always need to add up to 100%, the chance that the prize is behind the other door is now 100 - 33 = 67%. So, as strange as it may sound, you're better off switching doors! + +This is hard to wrap your head around, but easily shown using a simulation that runs a significant number of times. Probability is weird. + +By the way, you can simplify the code to this: + +```swift + let prizeDoor = random(3) + let chooseDoor = random(3) + if chooseDoor == prizeDoor { + winOriginalChoice += 1 + } else { + winChangedMind += 1 + } +``` + +Now it's no longer a simulation but the logic is equivalent. You can clearly see that the `chooseDoor` only wins 1/3rd of the time -- because it's a random number between 1 and 3 -- so changing your mind must win the other 2/3rds of the time. + +[Monty Hall Problem on Wikipedia](https://en.wikipedia.org/wiki/Monty_Hall_problem) + +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Multiset/Multiset.playground/Contents.swift b/Multiset/Multiset.playground/Contents.swift new file mode 100644 index 000000000..64b729df1 --- /dev/null +++ b/Multiset/Multiset.playground/Contents.swift @@ -0,0 +1,38 @@ +//: Playground - noun: a place where people can play + +import Cocoa + +var set = Multiset() + +set.add("Foo") +set.add("Foo") +set.add("Bar") +set.add("Baz") + +set.count +set.count(for: "Foo") + +set.allItems + +var set2 = Multiset() +set2.add("Foo") +set2.add("Foo") + +set2.isSubSet(of: set) // true +set.isSubSet(of: set2) // false + +// Convenience constructor: pass a Collection of Hashables to the constructor +var cacti = Multiset("cacti") +cacti.allItems +var tactical = Multiset("tactical") +cacti.isSubSet(of: tactical) // true +tactical.isSubSet(of: cacti) // false + +// Test ExpressibleByArrayLiteral protocol +let set3: Multiset = ["foo", "bar"] +set3.count(for: "foo") + +// Test Equatable protocol +let set4 = Multiset(set3.allItems) +set4 == set3 // true +set4 == set // false diff --git a/Multiset/Multiset.playground/Sources/Multiset.swift b/Multiset/Multiset.playground/Sources/Multiset.swift new file mode 100644 index 000000000..5dba5d32c --- /dev/null +++ b/Multiset/Multiset.playground/Sources/Multiset.swift @@ -0,0 +1,84 @@ +// +// Multiset.swift +// Multiset +// +// Created by Simon Whitaker on 28/08/2017. +// + +import Foundation + +public struct Multiset { + private var storage: [T: UInt] = [:] + public private(set) var count: UInt = 0 + + public init() {} + + public init(_ collection: C) where C.Element == T { + for element in collection { + self.add(element) + } + } + + public mutating func add (_ elem: T) { + storage[elem, default: 0] += 1 + count += 1 + } + + public mutating func remove (_ elem: T) { + if let currentCount = storage[elem] { + if currentCount > 1 { + storage[elem] = currentCount - 1 + } else { + storage.removeValue(forKey: elem) + } + count -= 1 + } + } + + public func isSubSet (of superset: Multiset) -> Bool { + for (key, count) in storage { + let supersetcount = superset.storage[key] ?? 0 + if count > supersetcount { + return false + } + } + return true + } + + public func count(for key: T) -> UInt { + return storage[key] ?? 0 + } + + public var allItems: [T] { + var result = [T]() + for (key, count) in storage { + for _ in 0 ..< count { + result.append(key) + } + } + return result + } +} + +// MARK: - Equatable +extension Multiset: Equatable { + public static func == (lhs: Multiset, rhs: Multiset) -> Bool { + if lhs.storage.count != rhs.storage.count { + return false + } + for (lkey, lcount) in lhs.storage { + let rcount = rhs.storage[lkey] ?? 0 + if lcount != rcount { + return false + } + } + return true + } +} + +// MARK: - ExpressibleByArrayLiteral +extension Multiset: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: T...) { + self.init(elements) + } +} diff --git a/Multiset/Multiset.playground/contents.xcplayground b/Multiset/Multiset.playground/contents.xcplayground new file mode 100644 index 000000000..63b6dd8df --- /dev/null +++ b/Multiset/Multiset.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Multiset/README.markdown b/Multiset/README.markdown new file mode 100644 index 000000000..cdd0af885 --- /dev/null +++ b/Multiset/README.markdown @@ -0,0 +1,104 @@ +# Multiset + +A multiset (also known as a bag) is a data structure similar to a regular set, but it can store multiple instances of the same element. + +For example, if I added the elements 1, 2, 2 to a regular set, the set would only contain two items, since adding 2 a second time has no effect. + +``` +var set = Set() +set.add(1) // set is now [1] +set.add(2) // set is now [1, 2] +set.add(2) // set is still [1, 2] +``` + +By comparison, after adding the elements 1, 2, 2 to a multiset, it would contain three items. + +``` +var set = Multiset() +set.add(1) // set is now [1] +set.add(2) // set is now [1, 2] +set.add(2) // set is now [1, 2, 2] +``` + +You might be thinking that this looks an awful lot like an array. So why would you use a multiset? Let's consider the differences between the two… + +- Ordering: arrays maintain the order of items added to them, multisets do not +- Testing for membership: testing whether an element is a member of the collection is O(N) for arrays, O(1) for multisets. +- Testing for subset: testing whether collection X is a subset of collection Y is a simple operation for a multiset, but complex for arrays + +Typical operations on a multiset are: + +- Add an element +- Remove an element +- Get the count for an element (the number of times it's been added) +- Get the count for the whole set (the number of items that have been added) +- Check whether it is a subset of another multiset + +One real-world use of multisets is to determine whether one string is a partial anagram of another. For example, the word "cacti" is a partial anagrams of "tactical". (In other words, I can rearrange the letters of "tactical" to make "cacti", with some letters left over.) + +``` swift +var cacti = Multiset("cacti") +var tactical = Multiset("tactical") +cacti.isSubSet(of: tactical) // true! +``` + +## Implementation + +Under the hood, this implementation of Multiset uses a dictionary to store a mapping of elements to the number of times they've been added. + +Here's the essence of it: + +``` swift +public struct Multiset { + private var storage: [Element: UInt] = [:] + + public init() {} +``` + +And here's how you'd use this class to create a multiset of strings: + +``` swift +var set = Multiset() +``` + +Adding an element is a case of incrementing the counter for that element, or setting it to 1 if it doesn't already exist: + +``` swift +public mutating func add (_ elem: Element) { + storage[elem, default: 0] += 1 +} +``` + +Here's how you'd use this method to add to the set we created earlier: + +```swift +set.add("foo") +set.add("foo") +set.allItems // returns ["foo", "foo"] +``` + +Our set now contains two elements, both the string "foo". + +Removing an element works much the same way as adding; decrement the counter for the element, or remove it from the underlying dictionary if its value is 1 before removal. + +``` swift +public mutating func remove (_ elem: Element) { + if let currentCount = storage[elem] { + if currentCount > 1 { + storage[elem] = currentCount - 1 + } else { + storage.removeValue(forKey: elem) + } + } +} +``` + +Getting the count for an item is simple: we just return the value for the given item in the internal dictionary. + +``` swift +public func count(for key: Element) -> UInt { + return storage[key] ?? 0 +} +``` + +*Written for the Swift Algorithm Club by Simon Whitaker* diff --git a/Myers Difference Algorithm/Images/EditGraph.png b/Myers Difference Algorithm/Images/EditGraph.png new file mode 100644 index 000000000..f31bb50a3 Binary files /dev/null and b/Myers Difference Algorithm/Images/EditGraph.png differ diff --git a/Myers Difference Algorithm/Images/EditGraph_k_move.png b/Myers Difference Algorithm/Images/EditGraph_k_move.png new file mode 100644 index 000000000..a8ea45c29 Binary files /dev/null and b/Myers Difference Algorithm/Images/EditGraph_k_move.png differ diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..113487acc --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift @@ -0,0 +1,22 @@ +//: Playground - noun: a place where people can play +import Foundation + +let shortestEditDistance: ([String], [String]) -> Int = MyersDifferenceAlgorithm.calculateShortestEditDistance(from:to:) + +/*** + All elements are same, so any scripts do not need. + So, the edit distance is 0 + ***/ +shortestEditDistance(["1", "2", "3"], ["1", "2", "3"]) + +/*** + Last element "3" should be inserted. + So, the edit distance is 1 + ***/ +shortestEditDistance(["1", "2"], ["1", "2", "3"]) + +/*** + First, remove "1", then insert "1" after "2". + So, the edit distance is 2 +***/ +shortestEditDistance(["1", "2", "3"], ["2", "1", "3"]) diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md new file mode 100644 index 000000000..6be30ecda --- /dev/null +++ b/Myers Difference Algorithm/README.md @@ -0,0 +1,162 @@ +# Myers Difference Algorithm + +Myers Difference Algorithm(MDA) is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. For example, let's assume you have two arrays: + +``` +let firstArray = [1, 2, 3] +let secondArray = [2, 3, 4] +``` + +The common subsequences of these two arrays are `[2]`, and `[2, 3]`. The longest common sequence in this case is `[2, 3]`. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. + +## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph + +### Edit Graph + +MDA uses an **Edit Graph** to solve the LCS/SES problem. Below is a illustration depicting an edit graph: + + + +The x-axis at the top of the graph represents one of the sequences, `X`. The y-axis at the left side of the graph represents the other sequence, `Y`. Hence, the two sequences in question is the following: + +``` +X = [A, B, C, A, B, B, A] +Y = [C, B, A, B, A, C] +``` + +MDA generates the edit graph through the following steps: + +1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. +2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` +3. Line for `x - y = k`, this line called k-line. Black dot line is this and pink number is the value of k. +3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point, light green one. +4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, where `(i, j)` is match point, then diagonal edge appears. + +Each elements on the figure shows that, +- `Red number and dotted lines`: The red number is the value of k and dotted lines are k-line. +- `Green dots: The match points`, which is the point `(i, j)` where `X[i] == Y[j]` +- `Blue line`: The shortest path from source to sink, which is the path we are going to find finally. + +> **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` + +We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. + +The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction, SES is Shortest Edit Scripts. + +Let's get back on track. On this edit graph, the horizontal movement to vertex `(i, j)` is compatible with the script `delete at index i from X`, the vertical movement to vertex `(i, j)` is compatible with the script `insert the element of Y at index j to immediately after the element of X at index i`. How about for the diagonal movement?. This movement to vertex `(i, j)` means `X[i] = Y[j]`, so no script needs. + +- horizontal movement -> delete +- vertical movement -> insert +- diagonal movement -> no script because both are same. + +Next, add cost 1 for non-diagonal movement, because they can be compatible with script. And 0 for diagonal movement, same means no script. + +The total cost for the minimum path, exploring from `source` to `sink`, is the same as the length of the Longest Common Subsequence or Shortest Edit Script. + +So, LCS/SES problem can be solved by finding the shortest path from `source` to `sink`. + +### Myers Algorithm + +As mentioned above, the problem of finding a shortest edit script can be reduced to finding a path from `source (0, 0)` to `sink (N, M)` with the fewest number of horizontal and vertical edges. Let `D-path` be a path starting at `source` that has exactly `D` non-diagonal edges, or must move non-diagonally D-times. + +For example, A 0-path consists solely of diagonal edges. This means both sequences are completely same. + +By a simple induction, D-path must consist of a (D-1)-path followed by a non-diagonal edge and then diagonal edges, which called `snake`. The minimum value of D is 0, both sequences being same. To the contrary, the maximum value of D is N + M because delete all elements from X and insert all elements from Y to X is the worst case edit scripts. For getting D, or the length of SES, running loop from 0 to N + M is enough. + +```swift +for D in 0...N + M +``` + +Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. Red chalky line shows that. + + + +So, threre are several end points of D-path, or D-path can end on several k-line. We need the information to get the next path ((D+1)-path) as mentioned above. In fact, D-path must end on +k-line, where k in { -D, -D + 2, ....., D - 2, D }. This is so simple, starting point, `source` is `(0, 0)` on (k=0)-line. D is the number of non-diagonal edges and non-diagonal movement changes current k-line to (kpm1)-line. Because 0 is even number, if D is even number D-path will end on (even_k)-line, if D is odd number D-path will end on (odd_k)-line. + +Searching loop outline will be below. + +```swift +for D in 0...N + M { + for k in stride(from: -D, through: D, by: 2) { + //Find the end point of the furthest reaching D-path in k-line. + if furthestReachingX == N && furthestReachingY == M { + // The D-path is the shortest path + // D is the length of Shortest Edit Script + return + } + } +} +``` + +The D-path on k-line can be decomposed into +- a furthest reaching (D-1)-path on (k-1)-line, followed by a horizontal edge, followed by `snake`. +- a furthest reaching (D-1)-path on (k+1)-line, followed by a vertical edge, followed by `snake`. +as discussed above. + +The Myers Algorithm key point are these. +- D-path must end on k-line, where k in { -D, -D + 2, ....., D - 2, D } +- The D-path on k-line can be decomposed into two patterns + +thanks for these, the number of calculation become less. + +```swift +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} +``` diff --git a/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift new file mode 100644 index 000000000..6a2e01aab --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/Contents.swift @@ -0,0 +1,110 @@ +import Foundation + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +/*: + ## 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]) +/*: + 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/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..6e6d7b4c0 --- /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..89da2d470 --- /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.playground/timeline.xctimeline b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline new file mode 100644 index 000000000..7bc414f58 --- /dev/null +++ b/Naive Bayes Classifier/NaiveBayes.playground/timeline.xctimeline @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/Naive Bayes Classifier/NaiveBayes.swift b/Naive Bayes Classifier/NaiveBayes.swift new file mode 100644 index 000000000..46a0bb4f5 --- /dev/null +++ b/Naive Bayes Classifier/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) + } + +} + +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 new file mode 100644 index 000000000..9c0f0082a --- /dev/null +++ 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 000000000..363ff3425 Binary files /dev/null and b/Naive Bayes Classifier/images/bayes.gif differ diff --git a/Naive Bayes Classifier/images/code_example.png b/Naive Bayes Classifier/images/code_example.png new file mode 100644 index 000000000..a147ecdd6 Binary files /dev/null and b/Naive Bayes Classifier/images/code_example.png differ diff --git a/Naive Bayes Classifier/images/mean.gif b/Naive Bayes Classifier/images/mean.gif new file mode 100644 index 000000000..7518c9995 Binary files /dev/null and b/Naive Bayes Classifier/images/mean.gif differ diff --git a/Naive Bayes Classifier/images/multinomial.gif b/Naive Bayes Classifier/images/multinomial.gif new file mode 100644 index 000000000..dbad012fd Binary files /dev/null and b/Naive Bayes Classifier/images/multinomial.gif differ diff --git a/Naive Bayes Classifier/images/normal_distribution.gif b/Naive Bayes Classifier/images/normal_distribution.gif new file mode 100644 index 000000000..b2f35e8eb Binary files /dev/null and b/Naive Bayes Classifier/images/normal_distribution.gif differ diff --git a/Naive Bayes Classifier/images/standard_deviation.gif b/Naive Bayes Classifier/images/standard_deviation.gif new file mode 100644 index 000000000..b917d9922 Binary files /dev/null and b/Naive Bayes Classifier/images/standard_deviation.gif differ diff --git a/Naive Bayes Classifier/images/tennis_dataset.png b/Naive Bayes Classifier/images/tennis_dataset.png new file mode 100644 index 000000000..ce9a1a699 Binary files /dev/null and b/Naive Bayes Classifier/images/tennis_dataset.png differ diff --git a/Octree/Octree.playground/Contents.swift b/Octree/Octree.playground/Contents.swift new file mode 100644 index 000000000..cdcd2df0f --- /dev/null +++ b/Octree/Octree.playground/Contents.swift @@ -0,0 +1,33 @@ +//: Playground - noun: a place where people can play + +import UIKit +import simd + +let boxMin = vector_double3(0, 2, 6) +let boxMax = vector_double3(5, 10, 9) +let box = Box(boxMin: boxMin, boxMax: boxMax) +var octree = Octree(boundingBox: box, minimumCellSize: 5.0) +var five = octree.add(5, at: vector_double3(3,4,8)) +octree.add(8, at: vector_double3(3,4,8.2)) +octree.add(10, at: vector_double3(3,4,8.2)) +octree.add(7, at: vector_double3(2,5,8)) +octree.add(2, at: vector_double3(1,6,7)) + +var cont = octree.elements(at: vector_double3(3,4,8.2)) +octree.remove(8) +octree.elements(at: vector_double3(3,4,8)) + +let boxMin2 = vector_double3(1,3,7) +let boxMax2 = vector_double3(4,9,8) +let box2 = Box(boxMin: boxMin2, boxMax: boxMax2) +box.isContained(in: box2) +box.intersects(box2) + +let boxMin3 = vector_double3(3,8,8) +let boxMax3 = vector_double3(10,12,20) +let box3 = Box(boxMin: boxMin3, boxMax: boxMax3) +box3.intersects(box3) + +octree.elements(in: box) +octree.elements(in: box2) +print(octree) diff --git a/Octree/Octree.playground/Sources/Octree.swift b/Octree/Octree.playground/Sources/Octree.swift new file mode 100644 index 000000000..72863fb7c --- /dev/null +++ b/Octree/Octree.playground/Sources/Octree.swift @@ -0,0 +1,372 @@ +import Foundation +import simd + +public struct Box: CustomStringConvertible { + public var boxMin: vector_double3 + public var boxMax: vector_double3 + + public init(boxMin: vector_double3, boxMax: vector_double3) { + self.boxMin = boxMin + self.boxMax = boxMax + } + + public var boxSize: vector_double3 { + return boxMax - boxMin + } + + var halfBoxSize: vector_double3 { + return boxSize/2 + } + + var frontLeftTop: Box { + let boxMin = self.boxMin + vector_double3(0, halfBoxSize.y, halfBoxSize.z) + let boxMax = self.boxMax - vector_double3(halfBoxSize.x, 0, 0) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var frontLeftBottom: Box { + let boxMin = self.boxMin + vector_double3(0, 0, halfBoxSize.z) + let boxMax = self.boxMax - vector_double3(halfBoxSize.x, halfBoxSize.y, 0) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var frontRightTop: Box { + let boxMin = self.boxMin + vector_double3(halfBoxSize.x, halfBoxSize.y, halfBoxSize.z) + let boxMax = self.boxMax - vector_double3(0, 0, 0) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var frontRightBottom: Box { + let boxMin = self.boxMin + vector_double3(halfBoxSize.x, 0, halfBoxSize.z) + let boxMax = self.boxMax - vector_double3(0, halfBoxSize.y, 0) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var backLeftTop: Box { + let boxMin = self.boxMin + vector_double3(0, halfBoxSize.y, 0) + let boxMax = self.boxMax - vector_double3(halfBoxSize.x, 0, halfBoxSize.z) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var backLeftBottom: Box { + let boxMin = self.boxMin + vector_double3(0, 0, 0) + let boxMax = self.boxMax - vector_double3(halfBoxSize.x, halfBoxSize.y, halfBoxSize.z) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var backRightTop: Box { + let boxMin = self.boxMin + vector_double3(halfBoxSize.x, halfBoxSize.y, 0) + let boxMax = self.boxMax - vector_double3(0, 0, halfBoxSize.z) + return Box(boxMin: boxMin, boxMax: boxMax) + } + var backRightBottom: Box { + let boxMin = self.boxMin + vector_double3(halfBoxSize.x, 0, 0) + let boxMax = self.boxMax - vector_double3(0, halfBoxSize.y, halfBoxSize.z) + return Box(boxMin: boxMin, boxMax: boxMax) + } + + public func contains(_ point: vector_double3) -> Bool { + return (boxMin.x <= point.x && point.x <= boxMax.x) && (boxMin.y <= point.y && point.y <= boxMax.y) && (boxMin.z <= point.z && point.z <= boxMax.z) + } + + public func contains(_ box: Box) -> Bool { + return + self.boxMin.x <= box.boxMin.x && + self.boxMin.y <= box.boxMin.y && + self.boxMin.z <= box.boxMin.z && + self.boxMax.x >= box.boxMax.x && + self.boxMax.y >= box.boxMax.y && + self.boxMax.z >= box.boxMax.z + } + + public func isContained(in box: Box) -> Bool { + return + self.boxMin.x >= box.boxMin.x && + self.boxMin.y >= box.boxMin.y && + self.boxMin.z >= box.boxMin.z && + self.boxMax.x <= box.boxMax.x && + self.boxMax.y <= box.boxMax.y && + self.boxMax.z <= box.boxMax.z + } + + /* This intersect function does not handle all possibilities such as two beams + of different diameter crossing each other half way. But it does cover all cases + needed for an octree as the bounding box has to contain the given intersect box */ + public func intersects(_ box: Box) -> Bool { + let corners = [ + vector_double3(boxMin.x, boxMax.y, boxMax.z), //frontLeftTop + vector_double3(boxMin.x, boxMin.y, boxMax.z), //frontLeftBottom + vector_double3(boxMax.x, boxMax.y, boxMax.z), //frontRightTop + vector_double3(boxMax.x, boxMin.y, boxMax.z), //frontRightBottom + vector_double3(boxMin.x, boxMax.y, boxMin.z), //backLeftTop + vector_double3(boxMin.x, boxMin.y, boxMin.z), //backLeftBottom + vector_double3(boxMax.x, boxMax.y, boxMin.z), //backRightTop + vector_double3(boxMax.x, boxMin.y, boxMin.z) //backRightBottom + ] + for corner in corners { + if box.contains(corner) { + return true + } + } + return false + } + + public var description: String { + return "Box from:\(boxMin) to:\(boxMax)" + } +} + +public class OctreeNode: CustomStringConvertible { + let box: Box + var point: vector_double3! + var elements: [T]! + var type: NodeType = .leaf + + enum NodeType { + case leaf + case `internal`(children: Children) + } + + public var description: String { + switch type { + case .leaf: + return "leaf node with \(box) elements: \(elements)" + case .internal: + return "internal node with \(box)" + } + } + + 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 + } + + struct Children: Sequence { + let frontLeftTop: OctreeNode + let frontLeftBottom: OctreeNode + let frontRightTop: OctreeNode + let frontRightBottom: OctreeNode + let backLeftTop: OctreeNode + let backLeftBottom: OctreeNode + let backRightTop: OctreeNode + let backRightBottom: OctreeNode + + init(parentNode: OctreeNode) { + frontLeftTop = OctreeNode(box: parentNode.box.frontLeftTop) + frontLeftBottom = OctreeNode(box: parentNode.box.frontLeftBottom) + frontRightTop = OctreeNode(box: parentNode.box.frontRightTop) + frontRightBottom = OctreeNode(box: parentNode.box.frontRightBottom) + backLeftTop = OctreeNode(box: parentNode.box.backLeftTop) + backLeftBottom = OctreeNode(box: parentNode.box.backLeftBottom) + backRightTop = OctreeNode(box: parentNode.box.backRightTop) + backRightBottom = OctreeNode(box: parentNode.box.backRightBottom) + } + + struct ChildrenIterator: IteratorProtocol { + var index = 0 + let children: Children + + init(children: Children) { + self.children = children + } + + mutating func next() -> OctreeNode? { + defer { index += 1 } + switch index { + case 0: return children.frontLeftTop + case 1: return children.frontLeftBottom + case 2: return children.frontRightTop + case 3: return children.frontRightBottom + case 4: return children.backLeftTop + case 5: return children.backLeftBottom + case 6: return children.backRightTop + case 7: return children.backRightBottom + default: return nil + } + } + } + + func makeIterator() -> ChildrenIterator { + return ChildrenIterator(children: self) + } + } + + init(box: Box) { + self.box = box + } + + @discardableResult + func add(_ element: T, at point: vector_double3) -> OctreeNode { + return tryAdd(element, at: point)! + } + + private func tryAdd(_ element: T, at point: vector_double3) -> OctreeNode? { + if !box.contains(point) { + return nil + } + + switch type { + case .internal(let children): + // pass the point to one of the children + for child in children { + if let child = child.tryAdd(element, at: point) { + return child + } + } + + fatalError("box.contains evaluted to true, but none of the children added the point") + case .leaf: + if self.point != nil { + // leaf already has an asigned point + if self.point == point { + self.elements.append(element) + return self + } else { + return subdivide(adding: element, at: point) + } + } else { + self.elements = [element] + self.point = point + return self + } + } + } + + func add(_ elements: [T], at point: vector_double3) { + for element in elements { + self.add(element, at: point) + } + } + + @discardableResult + func remove(_ element: T) -> Bool { + switch type { + case .leaf: + if let elements = self.elements { + // leaf contains one ore more elements + if let index = elements.index(of: element) { + // leaf contains the element we want to remove + self.elements.remove(at: index) + // if elements is now empty remove it + if self.elements.isEmpty { + self.elements = nil + } + return true + } + } + return false + case .internal(let children): + for child in children { + if child.remove(element) { + return true + } + } + return false + } + } + + func elements(at point: vector_double3) -> [T]? { + switch type { + case .leaf: + if self.point == point { + return self.elements + } + case .internal(let children): + for child in children { + if child.box.contains(point) { + return child.elements(at: point) + } + } + } + // tree does not contain given point + return nil + } + + func elements(in box: Box) -> [T]? { + var values: [T] = [] + switch type { + case .leaf: + // check if leaf has an assigned point + if let point = self.point { + // check if point is inside given box + if box.contains(point) { + values += elements ?? [] + } + } + case .internal(let children): + for child in children { + if child.box.isContained(in: box) { + // child is contained in box + // add all children of child + values += child.elements(in: child.box) ?? [] + } else if child.box.contains(box) || child.box.intersects(box) { + // child contains at least part of box + values += child.elements(in: box) ?? [] + } + // child does not contain any part of given box + } + } + if values.isEmpty { return nil } + return values + } + + private func subdivide(adding element: T, at point: vector_double3) -> OctreeNode? { + precondition(self.elements != nil, "Subdividing while leaf does not contain a element") + precondition(self.point != nil, "Subdividing while leaf does not contain a point") + switch type { + case .leaf: + type = .internal(children: Children(parentNode: self)) + // add element previously contained in leaf to children + self.add(self.elements, at: self.point) + self.elements = nil + self.point = nil + // add new element to children + return self.add(element, at: point) + case .internal: + preconditionFailure("Calling subdivide on an internal node") + } + } +} + +public class Octree: CustomStringConvertible { + var root: OctreeNode + + public var description: String { + return "Octree\n" + root.recursiveDescription + } + + public init(boundingBox: Box, minimumCellSize: Double) { + root = OctreeNode(box: boundingBox) + } + + @discardableResult + public func add(_ element: T, at point: vector_double3) -> OctreeNode { + return root.add(element, at: point) + } + + @discardableResult + public func remove(_ element: T, using node: OctreeNode) -> Bool { + return node.remove(element) + } + + @discardableResult + public func remove(_ element: T) -> Bool { + return root.remove(element) + } + + public func elements(at point: vector_double3) -> [T]? { + return root.elements(at: point) + } + + public func elements(in box: Box) -> [T]? { + precondition(root.box.contains(box), "box is outside of octree bounds") + return root.elements(in: box) + } +} diff --git a/Octree/Octree.playground/contents.xcplayground b/Octree/Octree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Octree/Octree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Octree/Octree.playground/timeline.xctimeline b/Octree/Octree.playground/timeline.xctimeline new file mode 100644 index 000000000..783cc6694 --- /dev/null +++ b/Octree/Octree.playground/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Octree/README.md b/Octree/README.md new file mode 100644 index 000000000..12b8cff39 --- /dev/null +++ b/Octree/README.md @@ -0,0 +1,27 @@ +# OcTree + +An octree is a [tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Tree) in which each internal (not leaf) node has eight children. Often used for collision detection in games for example. + +### Problem + +Consider the following problem: your need to store a number of objects in 3D space (each at a certain location with `X`, `Y` and `Z` coordinates) and then you need to answer which objects lie in a certain 3D 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 + +Octrees are most commonly used to partition a three-dimensional space by recursively subdividing it into 8 regions. Let's see how we can use an Octree to store some values. + +Each node in the tree represents a box-like region. Leaf nodes store a single point in that region with an array of objects assigned to that point. + +Once an object within the same region (but at a different point) is added the leaf node turns into an internal node and 8 child nodes (leaves) are added to it. All points previously contained in the node are passed to its corresponding children and stored. Thus only leaves contain actual points and values. + +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. + +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 + +More info on [Wiki](https://en.wikipedia.org/wiki/Octree) +Apple's implementation of [GKOctree](https://developer.apple.com/documentation/gameplaykit/gkoctree) + +*Written for Swift Algorithm Club by Jaap Wijnen* +*Heavily inspired by Timur Galimov's Quadtree implementation and Apple's GKOctree implementation diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index b83e9c62a..e48af22e2 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -1,35 +1,37 @@ //: 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 { 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() } - - 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 } @@ -46,19 +48,21 @@ public struct OrderedArray { */ // Fast version that uses a binary search. - 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 } } @@ -68,8 +72,6 @@ extension OrderedArray: CustomStringConvertible { } } - - var a = OrderedArray(array: [5, 1, 3, 9, 7, -1]) a // [-1, 1, 3, 5, 7, 9] @@ -79,4 +81,3 @@ a // [-1, 1, 3, 4, 5, 7, 9] a.insert(-2) // inserted at index 0 a.insert(10) // inserted at index 8 a // [-2, -1, 1, 3, 4, 5, 7, 9, 10] - diff --git a/Ordered Array/OrderedArray.playground/playground.xcworkspace/contents.xcworkspacedata b/Ordered Array/OrderedArray.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Ordered Array/OrderedArray.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Ordered Array/OrderedArray.playground/timeline.xctimeline b/Ordered Array/OrderedArray.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Ordered Array/OrderedArray.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Ordered Array/OrderedArray.swift b/Ordered Array/OrderedArray.swift index e6e1ca79f..f92311445 100644 --- a/Ordered Array/OrderedArray.swift +++ b/Ordered Array/OrderedArray.swift @@ -4,37 +4,37 @@ */ public struct OrderedArray { private var array = [T]() - + public init(array: [T]) { self.array = array.sort() } - + 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) } - + public mutating func removeAll() { array.removeAll() } - + public mutating func insert(newElement: T) -> Int { let i = findInsertionPoint(newElement) array.insert(newElement, atIndex: i) return i } - + private func findInsertionPoint(newElement: T) -> Int { var range = 0.. { - 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,31 +81,35 @@ 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 in order to insert the new element. 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: ```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 } ``` The big difference with a regular binary search is that this doesn't return `nil` when the value can't be found, but the array index where the element would have been. That's where we insert the new object. -Note that using binary search doesn't change the worst-case running time complexity of `insert()`. The binary search itself takes only **O(log n)** time, but inserting a new object in the middle of an array still involves shifting all remaining elements to the right in memory. So overall, the time complexity is still **O(n)**. But in practice this new version definitely is a lot faster, especially on large arrays. +Note that using binary search doesn't change the worst-case running time complexity of `insert()`. The binary search itself takes only **O(log n)** time, but inserting a new object in the middle of an array still involves shifting all remaining elements in memory. So overall, the time complexity is still **O(n)**. But in practice this new version definitely is a lot faster, especially on large arrays. + +A more complete and production ready [SortedArray](https://github.com/ole/SortedArray) is avalible from [Ole Begemann](https://github.com/ole). The [accompanying article](https://oleb.net/blog/2017/02/sorted-array/) explains the advantages and tradeoffs. *Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Ordered Set/OrderedSet.playground/Contents.swift b/Ordered Set/OrderedSet.playground/Contents.swift new file mode 100644 index 000000000..6a2415231 --- /dev/null +++ b/Ordered Set/OrderedSet.playground/Contents.swift @@ -0,0 +1,22 @@ +let s = OrderedSet() + +s.add(1) +s.add(2) +s.add(-1) +s.add(0) +s.insert(4, at: 3) + +print(s.all()) // [1, 2, -1, 4, 0] + +s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here + +print(s.all()) // [1, 2, -1, 4, 0] + +s.remove(-1) + +print(s.all()) // [1, 2, 4, 0] + +print(s.object(at: 1)) // 2 + +print(s.object(at: 2)) // 4 + diff --git a/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift new file mode 100644 index 000000000..5508c3637 --- /dev/null +++ b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift @@ -0,0 +1,76 @@ +public class OrderedSet { + private var objects: [T] = [] + private var indexOfKey: [T: Int] = [:] + + public init() {} + + // O(1) + public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return + } + + objects.append(object) + indexOfKey[object] = objects.count - 1 + } + + // O(n) + public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1.. T { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + return objects[index] + } + + // O(1) + public func set(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object + } + + // O(1) + public func indexOf(_ object: T) -> Int { + return indexOfKey[object] ?? -1 + } + + // O(n) + public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. [T] { + return objects + } +} diff --git a/Ordered Set/OrderedSet.playground/contents.xcplayground b/Ordered Set/OrderedSet.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Ordered Set/OrderedSet.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Ordered Set/OrderedSet.swift b/Ordered Set/OrderedSet.swift new file mode 100644 index 000000000..8b6df7d3e --- /dev/null +++ b/Ordered Set/OrderedSet.swift @@ -0,0 +1,77 @@ +public class OrderedSet { + private var objects: [T] = [] + private var indexOfKey: [T: Int] = [:] + + public init() {} + + // O(1) + public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return + } + + objects.append(object) + indexOfKey[object] = objects.count - 1 + } + + // O(n) + public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1.. T { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + return objects[index] + } + + // O(1) + public func set(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object + } + + // O(1) + public func indexOf(_ object: T) -> Int { + return indexOfKey[object] ?? -1 + } + + // O(n) + public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. [T] { + return objects + } +} + diff --git a/Ordered Set/README.markdown b/Ordered Set/README.markdown new file mode 100644 index 000000000..82d736731 --- /dev/null +++ b/Ordered Set/README.markdown @@ -0,0 +1,121 @@ +# Ordered Set + +Let's look into how to implement [Ordered Set](https://developer.apple.com/documentation/foundation/nsorderedset). + +Here is the example about how it works + +```swift +let s = AppleOrderedSet() + +s.add(1) +s.add(2) +s.add(-1) +s.add(0) +s.insert(4, at: 3) + +print(s.all()) // [1, 2, -1, 4, 0] + +s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here + +print(s.all()) // [1, 2, -1, 4, 0] + +s.remove(-1) + +print(s.all()) // [1, 2, 4, 0] + +print(s.object(at: 1)) // 2 + +print(s.object(at: 2)) // 4 +``` + +The significant difference is the the array is not sorted. The elements in the array are the same when insert them. Image the array without duplicates and with `O(logn)` or `O(1)` search time. + +The idea here is using a data structure to provide `O(1)` or `O(logn)` time complexity, so it's easy to think about hash table. + +```swift +var indexOfKey: [T: Int] +var objects: [T] +``` + +`indexOfKey` is used to track the index of the element. `objects` is array holding elements. + +We will go through some key functions details here. + +### Add + +Update `indexOfKey` and insert element in the end of `objects` + +```swift +// O(1) +public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return + } + + objects.append(object) + indexOfKey[object] = objects.count - 1 +} +``` + +### Insert + +Insert in a random place of the array will cost `O(n)` time. + +```swift +// O(n) +public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1..= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object +} +``` + +### Remove + +Remove element in the array will cost `O(n)`. At the same time, we need to update all elements's index after the removed element. + +```swift +// O(n) +public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. Bool { + let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) + let length = strippedString.count + + if length > 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) + } + return false +} + +/** + Compares a strings left side character against right side character following + - parameter str: The string to compare characters of + - parameter left: Index of left side to compare, must be less than or equal to right + - parameter right: Index of right side to compare, must be greater than or equal to left + - returns: `true` if left side and right side have all been compared and they all match, `false` if a left and right aren't equal + */ +private func palindrome(_ str: String, left: Int, right: Int) -> Bool { + if left >= right { + return true + } + + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] + + if lhs != rhs { + return false + } + + return palindrome(str, left: left + 1, right: right - 1) +} diff --git a/Palindromes/Palindromes.playground/contents.xcplayground b/Palindromes/Palindromes.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Palindromes/Palindromes.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file 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.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown new file mode 100644 index 000000000..e4012d8da --- /dev/null +++ b/Palindromes/README.markdown @@ -0,0 +1,107 @@ +# Palindromes + +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 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, 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 + +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.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. + +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 +return palindrome(str, left: left + 1, right: right - 1) +``` + +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 [Joshua Alvarado](https://github.com/lostatseajoshua)* diff --git a/Palindromes/Test/Palindrome.swift b/Palindromes/Test/Palindrome.swift new file mode 100644 index 000000000..16af14fdb --- /dev/null +++ b/Palindromes/Test/Palindrome.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.count + + if length > 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) + } + return false +} + +private func palindrome(_ str: String, left: Int, right: Int) -> Bool { + if left >= right { + return true + } + + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] + + if lhs != rhs { + return false + } + + return palindrome(str, left: left + 1, right: right - 1) +} diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj new file mode 100644 index 000000000..f01f6f061 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -0,0 +1,293 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8831E0D960A00A38FB8 /* Test.swift */; }; + 9437D88B1E0D969500A38FB8 /* Palindrome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8791E0D948A00A38FB8 /* Palindrome.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 9437D8791E0D948A00A38FB8 /* Palindrome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindrome.swift; sourceTree = ""; }; + 9437D8811E0D960A00A38FB8 /* Test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 9437D8831E0D960A00A38FB8 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; + 9437D8851E0D960A00A38FB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* 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 /* Palindrome.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 = 1000; + ORGANIZATIONNAME = "Joshua Alvarado"; + TargetAttributes = { + 9437D8801E0D960A00A38FB8 = { + CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 1000; + 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 /* Palindrome.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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9437D8661E0D945200A38FB8 /* Project object */; +} diff --git a/Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..87cc241f8 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + 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..72ae3d696 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Palindromes/Test/Test/Info.plist b/Palindromes/Test/Test/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Palindromes/Test/Test/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/Test/Test/Test.swift b/Palindromes/Test/Test/Test.swift new file mode 100644 index 000000000..ddf970300 --- /dev/null +++ b/Palindromes/Test/Test/Test.swift @@ -0,0 +1,69 @@ +// +// PalindromeTests.swift +// Test +// +// Created by Joshua Alvarado on 12/23/16. +// Copyright © 2016 Joshua Alvarado. All rights reserved. +// + +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 { + // Put the code you want to measure the time of here. + _ = isPalindrome("abbcbba") + _ = isPalindrome("asdkfaksjdfasjkdfhaslkjdfakjsdfhakljsdhflkjasdfhkasdjhfklajsdfhkljasdf") + _ = 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")) + } +} diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj new file mode 100644 index 000000000..aeba4777b --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj @@ -0,0 +1,296 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */; }; + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */; }; + 8EF612481F9E00E000267358 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EF612471F9E00E000267358 /* main.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8EF612421F9E00E000267358 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Point2D.swift; sourceTree = ""; }; + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line2D.swift; sourceTree = ""; }; + 8EF612441F9E00E000267358 /* Points Lines Planes */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Points Lines Planes"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8EF612471F9E00E000267358 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8EF612411F9E00E000267358 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */ = { + isa = PBXGroup; + children = ( + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */, + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */, + ); + path = 2D; + sourceTree = ""; + }; + 8EF6123B1F9E00DF00267358 = { + isa = PBXGroup; + children = ( + 8EF612461F9E00E000267358 /* Points Lines Planes */, + 8EF612451F9E00E000267358 /* Products */, + ); + sourceTree = ""; + }; + 8EF612451F9E00E000267358 /* Products */ = { + isa = PBXGroup; + children = ( + 8EF612441F9E00E000267358 /* Points Lines Planes */, + ); + name = Products; + sourceTree = ""; + }; + 8EF612461F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXGroup; + children = ( + 8EF612471F9E00E000267358 /* main.swift */, + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */, + ); + path = "Points Lines Planes"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8EF612431F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */; + buildPhases = ( + 8EF612401F9E00E000267358 /* Sources */, + 8EF612411F9E00E000267358 /* Frameworks */, + 8EF612421F9E00E000267358 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Points Lines Planes"; + productName = "Points Lines Planes"; + productReference = 8EF612441F9E00E000267358 /* Points Lines Planes */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8EF6123C1F9E00DF00267358 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = Workmoose; + TargetAttributes = { + 8EF612431F9E00E000267358 = { + CreatedOnToolsVersion = 9.0.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 8EF6123B1F9E00DF00267358; + productRefGroup = 8EF612451F9E00E000267358 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8EF612431F9E00E000267358 /* Points Lines Planes */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8EF612401F9E00E000267358 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */, + 8EF612481F9E00E000267358 /* main.swift in Sources */, + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8EF612491F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8EF6124A1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 8EF6124C1F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 8EF6124D1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF612491F9E00E000267358 /* Debug */, + 8EF6124A1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF6124C1F9E00E000267358 /* Debug */, + 8EF6124D1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8EF6123C1F9E00DF00267358 /* Project object */; +} diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..82bfe2b7d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift new file mode 100644 index 000000000..c23040b14 --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift @@ -0,0 +1,141 @@ +// +// Line2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Line2D: Equatable { + + var slope: Slope + var offset: Double + var direction: Direction + + enum Slope: Equatable { + case finite(slope: Double) + case infinite(offset: Double) + } + + enum Direction: Equatable { + case increasing + case decreasing + } + + init(from p1: Point2D, to p2: Point2D) { + if p1 == p2 { fatalError("Points can not be equal when creating a line between them") } + if p1.x == p2.x { + self.slope = .infinite(offset: p1.x) + self.offset = 0 + self.direction = p1.y < p2.y ? .increasing : .decreasing + + return + } + + let slope = (p1.y - p2.y)/(p1.x - p2.x) + self.slope = .finite(slope: slope) + offset = (p1.y + p2.y - slope * (p1.x + p2.x))/2 + if slope >= 0 { + // so a horizontal line going left to right is called increasing + self.direction = p1.x < p2.x ? .increasing : .decreasing + } else { + self.direction = p1.x < p2.x ? .decreasing : .increasing + } + } + + fileprivate init(slope: Slope, offset: Double, direction: Direction) { + self.slope = slope + self.offset = offset + self.direction = direction + } + + // returns y coordinate on line for given x + func y(at x: Double) -> Double { + switch self.slope { + case .finite(let slope): + return slope * x + self.offset + case .infinite: + fatalError("y can be anywhere on vertical line") + } + } + + // returns x coordinate on line for given y + func x(at y: Double) -> Double { + switch self.slope { + case .finite(let slope): + if slope == 0 { + fatalError("x can be anywhere on horizontal line") + } + return (y - self.offset)/slope + case .infinite(let offset): + return offset + } + } + + // finds intersection point between two lines. returns nil when lines don't intersect or lie on top of each other. + func intersect(with line: Line2D) -> Point2D? { + if self == line { return nil } + switch (self.slope, line.slope) { + case (.infinite, .infinite): + // lines are either parallel or on top of each other. + return nil + case (.finite(let slope1), .finite(let slope2)): + if slope1 == slope2 { return nil } // lines are parallel + // lines are not parallel calculate intersection point + let x = (line.offset - self.offset)/(slope1 - slope2) + let y = (slope1 + slope2) * x + self.offset + line.offset + return Point2D(x: x, y: y) + case (.infinite(let offset), .finite): + // one line is vertical so we only check what y value the other line has at that point + let x = offset + let y = line.y(at: x) + return Point2D(x: x, y: y) + case (.finite, .infinite(let offset)): + // one line is vertical so we only check what y value the other line has at that point + // lines are switched with respect to case above this one + let x = offset + let y = self.y(at: x) + return Point2D(x: x, y: y) + } + } + + // returns a line perpendicular to self at the given y coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(y: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: self.x(at: y), y: y)) + } + + // returns a line perpendicular to self at the given x coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(x: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: x, y: self.y(at: x))) + } + + private func perpendicularLineAt(p: Point2D) -> Line2D { + switch self.slope { + case .finite(let slope): + if slope == 0 { + // line is horizontal so new line will be vertical + let dir: Direction = self.direction == .increasing ? .decreasing : .increasing + return Line2D(slope: .infinite(offset: p.x), offset: 0, direction: dir) + } + + // line is neither horizontal nor vertical + // we make a new line through the point p with new slope -1/slope + let offset = (slope + 1/slope)*p.x + self.offset + + // determine direction of new line based on direction of the old line and its slope + let dir: Direction + switch self.direction { + case .increasing: + dir = slope > 0 ? .decreasing : .increasing + case .decreasing: + dir = slope > 0 ? .increasing : .decreasing + } + return Line2D(slope: .finite(slope: -1/slope), offset: offset, direction: dir) + case .infinite: + // line is vertical so new line will be horizontal + let dir: Direction = self.direction == .increasing ? .increasing : .decreasing + return Line2D(slope: .finite(slope: 0), offset: p.y, direction: dir) + } + } +} diff --git a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift new file mode 100644 index 000000000..bbd8305f8 --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift @@ -0,0 +1,36 @@ +// +// Point2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Point2D: Equatable { + var x: Double + var y: Double + + // returns true if point is on or right of line + func isRight(of line: Line2D) -> Bool { + switch line.slope { + case .finite: + let y = line.y(at: self.x) + switch line.direction { + case .increasing: + return y >= self.y + case .decreasing: + return y <= self.y + } + case .infinite(let offset): + switch line.direction { + case .increasing: + return self.x >= offset + case .decreasing: + return self.x <= offset + } + } + } + + func isLeft(of line: Line2D) -> Bool { + return !self.isRight(of: line) + } +} diff --git a/Points Lines Planes/Points Lines Planes/main.swift b/Points Lines Planes/Points Lines Planes/main.swift new file mode 100644 index 000000000..02137fc9d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/main.swift @@ -0,0 +1,24 @@ +// +// main.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 23-10-17. +// + +let p0 = Point2D(x: 0, y: 2) +let p1 = Point2D(x: 1, y: 1) +let p2 = Point2D(x: 1, y: 3) +let p3 = Point2D(x: 3, y: 1) +let p4 = Point2D(x: 3, y: 3) + +let horLine = Line2D(from: p1, to: p3) +let verLine = Line2D(from: p1, to: p2) +let line45 = Line2D(from: p1, to: p4) + +print(horLine.intersect(with: verLine)) +print(p0.isRight(of: line45)) +print(p0.isRight(of: horLine)) +print(p0.isRight(of: verLine)) +let lineperp = horLine.perpendicularLineAt(x: 2) +print(lineperp) + diff --git a/Points Lines Planes/README.md b/Points Lines Planes/README.md new file mode 100644 index 000000000..2d36667ec --- /dev/null +++ b/Points Lines Planes/README.md @@ -0,0 +1,34 @@ +# Points Lines (Planes) +This implements data structures for points lines and planes(not yet) in (for now) 2D space and a few functions to play around with them. This was originally written to improve on the Convex Hull algorithm but I thought it might be a nice addition in itself. Im planning to add 3D implementations as well. + +# implementation +Two `struct`s are implemented the `Point2D` and `Line2D`. + +``` +struct Point2D: { + var x: Double + var y: double +} +``` + +``` +struct Line2D { + var slope: Slope + var offset: Double + var direction: Direction +} +``` +Here `Slope` is an enum to account for vertical lines. +slope is infinite for vertical lines, offset is the x coordinate where the line crosses the line `y=0`. +slope is finite for any other line and contains a double with the actual value of the slope. +``` +enum Slope { + case finite(slope: Double) + case infinite(offset: Double) +} +``` +`Line2D` also contains a `Direction` enum. This is introduced in order to make lines directional in order to be able to determine what is left and right of a certain line. It is `.increasing` if the line points in positive y direction and `.decreasing` if it points in the negative y direction. + +`Line2D`'s offset is the the y-coordinate where the line crosses the vertical `x=0` line. + +*Written for the Swift Algorithm Club by Jaap Wijnen.* diff --git a/Priority Queue/PriorityQueue Tests/PriorityQueue.xcodeproj/project.pbxproj b/Priority Queue/PriorityQueue Tests/PriorityQueue.xcodeproj/project.pbxproj deleted file mode 100644 index d855143a1..000000000 --- a/Priority Queue/PriorityQueue Tests/PriorityQueue.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B1BFA1A1C6914970051C9A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA191C6914970051C9A4 /* AppDelegate.swift */; }; - 7B1BFA1C1C6914970051C9A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA1B1C6914970051C9A4 /* Assets.xcassets */; }; - 7B1BFA1F1C6914970051C9A4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA1D1C6914970051C9A4 /* MainMenu.xib */; }; - 7B1BFA2A1C6914970051C9A4 /* PriorityQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA291C6914970051C9A4 /* PriorityQueueTests.swift */; }; - 7B1BFA351C6914B60051C9A4 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA341C6914B60051C9A4 /* PriorityQueue.swift */; }; - 7B1BFA371C6914C20051C9A4 /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA361C6914C20051C9A4 /* Heap.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B1BFA261C6914970051C9A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B1BFA0E1C6914970051C9A4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B1BFA151C6914970051C9A4; - remoteInfo = PriorityQueue; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B1BFA161C6914970051C9A4 /* PriorityQueue.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PriorityQueue.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA191C6914970051C9A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B1BFA1B1C6914970051C9A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B1BFA1E1C6914970051C9A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B1BFA201C6914970051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA251C6914970051C9A4 /* PriorityQueueTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PriorityQueueTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA291C6914970051C9A4 /* PriorityQueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriorityQueueTests.swift; sourceTree = ""; }; - 7B1BFA2B1C6914970051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA341C6914B60051C9A4 /* PriorityQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = ../../PriorityQueue.swift; sourceTree = ""; }; - 7B1BFA361C6914C20051C9A4 /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../../../Heap/Heap.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B1BFA131C6914970051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA221C6914970051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B1BFA0D1C6914970051C9A4 = { - isa = PBXGroup; - children = ( - 7B1BFA181C6914970051C9A4 /* PriorityQueue */, - 7B1BFA281C6914970051C9A4 /* PriorityQueueTests */, - 7B1BFA171C6914970051C9A4 /* Products */, - ); - sourceTree = ""; - }; - 7B1BFA171C6914970051C9A4 /* Products */ = { - isa = PBXGroup; - children = ( - 7B1BFA161C6914970051C9A4 /* PriorityQueue.app */, - 7B1BFA251C6914970051C9A4 /* PriorityQueueTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B1BFA181C6914970051C9A4 /* PriorityQueue */ = { - isa = PBXGroup; - children = ( - 7B1BFA191C6914970051C9A4 /* AppDelegate.swift */, - 7B1BFA1B1C6914970051C9A4 /* Assets.xcassets */, - 7B1BFA361C6914C20051C9A4 /* Heap.swift */, - 7B1BFA201C6914970051C9A4 /* Info.plist */, - 7B1BFA1D1C6914970051C9A4 /* MainMenu.xib */, - 7B1BFA341C6914B60051C9A4 /* PriorityQueue.swift */, - ); - path = PriorityQueue; - sourceTree = ""; - }; - 7B1BFA281C6914970051C9A4 /* PriorityQueueTests */ = { - isa = PBXGroup; - children = ( - 7B1BFA291C6914970051C9A4 /* PriorityQueueTests.swift */, - 7B1BFA2B1C6914970051C9A4 /* Info.plist */, - ); - path = PriorityQueueTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B1BFA151C6914970051C9A4 /* PriorityQueue */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA2E1C6914970051C9A4 /* Build configuration list for PBXNativeTarget "PriorityQueue" */; - buildPhases = ( - 7B1BFA121C6914970051C9A4 /* Sources */, - 7B1BFA131C6914970051C9A4 /* Frameworks */, - 7B1BFA141C6914970051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = PriorityQueue; - productName = PriorityQueue; - productReference = 7B1BFA161C6914970051C9A4 /* PriorityQueue.app */; - productType = "com.apple.product-type.application"; - }; - 7B1BFA241C6914970051C9A4 /* PriorityQueueTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA311C6914970051C9A4 /* Build configuration list for PBXNativeTarget "PriorityQueueTests" */; - buildPhases = ( - 7B1BFA211C6914970051C9A4 /* Sources */, - 7B1BFA221C6914970051C9A4 /* Frameworks */, - 7B1BFA231C6914970051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B1BFA271C6914970051C9A4 /* PBXTargetDependency */, - ); - name = PriorityQueueTests; - productName = PriorityQueueTests; - productReference = 7B1BFA251C6914970051C9A4 /* PriorityQueueTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B1BFA0E1C6914970051C9A4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B1BFA151C6914970051C9A4 = { - CreatedOnToolsVersion = 7.2; - }; - 7B1BFA241C6914970051C9A4 = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B1BFA151C6914970051C9A4; - }; - }; - }; - buildConfigurationList = 7B1BFA111C6914970051C9A4 /* Build configuration list for PBXProject "PriorityQueue" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B1BFA0D1C6914970051C9A4; - productRefGroup = 7B1BFA171C6914970051C9A4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B1BFA151C6914970051C9A4 /* PriorityQueue */, - 7B1BFA241C6914970051C9A4 /* PriorityQueueTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B1BFA141C6914970051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA1C1C6914970051C9A4 /* Assets.xcassets in Resources */, - 7B1BFA1F1C6914970051C9A4 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA231C6914970051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B1BFA121C6914970051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA371C6914C20051C9A4 /* Heap.swift in Sources */, - 7B1BFA1A1C6914970051C9A4 /* AppDelegate.swift in Sources */, - 7B1BFA351C6914B60051C9A4 /* PriorityQueue.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA211C6914970051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA2A1C6914970051C9A4 /* PriorityQueueTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B1BFA271C6914970051C9A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B1BFA151C6914970051C9A4 /* PriorityQueue */; - targetProxy = 7B1BFA261C6914970051C9A4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B1BFA1D1C6914970051C9A4 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B1BFA1E1C6914970051C9A4 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B1BFA2C1C6914970051C9A4 /* 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; - }; - 7B1BFA2D1C6914970051C9A4 /* 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; - }; - 7B1BFA2F1C6914970051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = PriorityQueue/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.PriorityQueue; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B1BFA301C6914970051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = PriorityQueue/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.PriorityQueue; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B1BFA321C6914970051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = PriorityQueueTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.PriorityQueueTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PriorityQueue.app/Contents/MacOS/PriorityQueue"; - }; - name = Debug; - }; - 7B1BFA331C6914970051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = PriorityQueueTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.PriorityQueueTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PriorityQueue.app/Contents/MacOS/PriorityQueue"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B1BFA111C6914970051C9A4 /* Build configuration list for PBXProject "PriorityQueue" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA2C1C6914970051C9A4 /* Debug */, - 7B1BFA2D1C6914970051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA2E1C6914970051C9A4 /* Build configuration list for PBXNativeTarget "PriorityQueue" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA2F1C6914970051C9A4 /* Debug */, - 7B1BFA301C6914970051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA311C6914970051C9A4 /* Build configuration list for PBXNativeTarget "PriorityQueueTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA321C6914970051C9A4 /* Debug */, - 7B1BFA331C6914970051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B1BFA0E1C6914970051C9A4 /* Project object */; -} diff --git a/Priority Queue/PriorityQueue Tests/PriorityQueue/AppDelegate.swift b/Priority Queue/PriorityQueue Tests/PriorityQueue/AppDelegate.swift deleted file mode 100644 index 0154bd5eb..000000000 --- a/Priority Queue/PriorityQueue Tests/PriorityQueue/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// PriorityQueue -// -// Created by Matthijs Hollemans on 08-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Priority Queue/PriorityQueue Tests/PriorityQueue/Assets.xcassets/AppIcon.appiconset/Contents.json b/Priority Queue/PriorityQueue Tests/PriorityQueue/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Priority Queue/PriorityQueue Tests/PriorityQueue/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/Priority Queue/PriorityQueue Tests/PriorityQueue/Base.lproj/MainMenu.xib b/Priority Queue/PriorityQueue Tests/PriorityQueue/Base.lproj/MainMenu.xib deleted file mode 100644 index b36de4331..000000000 --- a/Priority Queue/PriorityQueue Tests/PriorityQueue/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Priority Queue/PriorityQueue Tests/PriorityQueue/Info.plist b/Priority Queue/PriorityQueue Tests/PriorityQueue/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Priority Queue/PriorityQueue Tests/PriorityQueue/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Priority Queue/PriorityQueue.swift b/Priority Queue/PriorityQueue.swift index 7a7cee34b..92f7b6d3f 100644 --- a/Priority Queue/PriorityQueue.swift +++ b/Priority Queue/PriorityQueue.swift @@ -3,7 +3,7 @@ the queue. The heap is a natural data structure for a priority queue, so this object - simply wraps the Heap struct. + simply wraps the Heap struct. All operations are O(lg n). @@ -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 c5e088520..fbbcaa0f3 100644 --- a/Priority Queue/README.markdown +++ b/Priority Queue/README.markdown @@ -8,11 +8,11 @@ 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. -- [Huffman encoding](../Huffman Encoding/) 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,15 +31,15 @@ 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: ```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/Info.plist b/Priority Queue/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Priority Queue/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/Priority Queue/PriorityQueue Tests/PriorityQueueTests/PriorityQueueTests.swift b/Priority Queue/Tests/PriorityQueueTests.swift similarity index 94% rename from Priority Queue/PriorityQueue Tests/PriorityQueueTests/PriorityQueueTests.swift rename to Priority Queue/Tests/PriorityQueueTests.swift index e0fc1bd28..e31fa3d07 100755 --- a/Priority Queue/PriorityQueue Tests/PriorityQueueTests/PriorityQueueTests.swift +++ b/Priority Queue/Tests/PriorityQueueTests.swift @@ -1,6 +1,5 @@ import Foundation import XCTest -@testable import PriorityQueue private struct Message { let text: String @@ -12,6 +11,13 @@ private func < (m1: Message, m2: Message) -> Bool { } class PriorityQueueTest: XCTestCase { + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + func testEmpty() { var queue = PriorityQueue(sort: <) XCTAssertTrue(queue.isEmpty) diff --git a/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..5ddfd574d --- /dev/null +++ b/Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,275 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3FC1C77A658003CECC7 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3FB1C77A658003CECC7 /* PriorityQueue.swift */; }; + 7B80C3FE1C77A65E003CECC7 /* PriorityQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3FD1C77A65E003CECC7 /* PriorityQueueTests.swift */; }; + 7B80C4001C77A67B003CECC7 /* Heap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3FF1C77A67B003CECC7 /* Heap.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; }; + 7B80C3FB1C77A658003CECC7 /* PriorityQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = ../PriorityQueue.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3FD1C77A65E003CECC7 /* PriorityQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PriorityQueueTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3FF1C77A67B003CECC7 /* Heap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Heap.swift; path = ../../Heap/Heap.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 = ( + 7B80C3FF1C77A67B003CECC7 /* Heap.swift */, + 7B80C3FB1C77A658003CECC7 /* PriorityQueue.swift */, + 7B80C3FD1C77A65E003CECC7 /* PriorityQueueTests.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 = 0820; + }; + }; + }; + 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 = ( + 7B80C4001C77A67B003CECC7 /* Heap.swift in Sources */, + 7B80C3FE1C77A65E003CECC7 /* PriorityQueueTests.swift in Sources */, + 7B80C3FC1C77A658003CECC7 /* PriorityQueue.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"; + SWIFT_VERSION = 4.0; + }; + 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"; + SWIFT_VERSION = 4.0; + }; + 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 = 4.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 = 4.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/Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Priority Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/QuadTree/Images/quadtree.png b/QuadTree/Images/quadtree.png new file mode 100644 index 000000000..53af6fb08 Binary files /dev/null and b/QuadTree/Images/quadtree.png differ diff --git a/QuadTree/QuadTree.playground/Contents.swift b/QuadTree/QuadTree.playground/Contents.swift new file mode 100644 index 000000000..ad8ee31f8 --- /dev/null +++ b/QuadTree/QuadTree.playground/Contents.swift @@ -0,0 +1,13 @@ +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..7fd459e97 --- /dev/null +++ b/QuadTree/QuadTree.playground/Sources/QuadTree.swift @@ -0,0 +1,289 @@ +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 PointsContainer { + 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: 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 + 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: 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) + } +} + +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..ff660f852 --- /dev/null +++ b/QuadTree/README.md @@ -0,0 +1,159 @@ +# 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 + +Quadtrees are most commonly used to partition a two-dimensional space by recursively subdividing it into four regions(quadrants). Let's see how we can use a Quadtree to store the points. + +Each node in the tree represents a rectangular region and stores a limited number(`maxPointCapacity`) of points that all lie in its region. + +```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.contains(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.contains(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 Article](https://robots.thoughtbot.com/how-to-handle-large-amounts-of-data-on-maps)) + +More info on [Wikipedia](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..9bd8ad28f --- /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)]) + } +} diff --git a/Queue/Queue Tests/Queue.xcodeproj/project.pbxproj b/Queue/Queue Tests/Queue.xcodeproj/project.pbxproj deleted file mode 100644 index 5e2275234..000000000 --- a/Queue/Queue Tests/Queue.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E01A1C5BF7A1005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0191C5BF7A1005A2B8E /* AppDelegate.swift */; }; - 7B18E01C1C5BF7A1005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E01B1C5BF7A1005A2B8E /* Assets.xcassets */; }; - 7B18E01F1C5BF7A1005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E01D1C5BF7A1005A2B8E /* MainMenu.xib */; }; - 7B18E02A1C5BF7A1005A2B8E /* QueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0291C5BF7A1005A2B8E /* QueueTests.swift */; }; - 7B18E0351C5BF7C2005A2B8E /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0341C5BF7C2005A2B8E /* Queue.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E0261C5BF7A1005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E00E1C5BF7A1005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E0151C5BF7A1005A2B8E; - remoteInfo = Queue; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E0161C5BF7A1005A2B8E /* Queue.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Queue.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0191C5BF7A1005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E01B1C5BF7A1005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18E01E1C5BF7A1005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18E0201C5BF7A1005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0251C5BF7A1005A2B8E /* QueueTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QueueTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0291C5BF7A1005A2B8E /* QueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueTests.swift; sourceTree = ""; }; - 7B18E02B1C5BF7A1005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0341C5BF7C2005A2B8E /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = ../../Queue.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E0131C5BF7A1005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0221C5BF7A1005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E00D1C5BF7A1005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E0181C5BF7A1005A2B8E /* Queue */, - 7B18E0281C5BF7A1005A2B8E /* QueueTests */, - 7B18E0171C5BF7A1005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0171C5BF7A1005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E0161C5BF7A1005A2B8E /* Queue.app */, - 7B18E0251C5BF7A1005A2B8E /* QueueTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E0181C5BF7A1005A2B8E /* Queue */ = { - isa = PBXGroup; - children = ( - 7B18E0191C5BF7A1005A2B8E /* AppDelegate.swift */, - 7B18E01B1C5BF7A1005A2B8E /* Assets.xcassets */, - 7B18E0201C5BF7A1005A2B8E /* Info.plist */, - 7B18E01D1C5BF7A1005A2B8E /* MainMenu.xib */, - 7B18E0341C5BF7C2005A2B8E /* Queue.swift */, - ); - path = Queue; - sourceTree = ""; - }; - 7B18E0281C5BF7A1005A2B8E /* QueueTests */ = { - isa = PBXGroup; - children = ( - 7B18E0291C5BF7A1005A2B8E /* QueueTests.swift */, - 7B18E02B1C5BF7A1005A2B8E /* Info.plist */, - ); - path = QueueTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E0151C5BF7A1005A2B8E /* Queue */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E02E1C5BF7A1005A2B8E /* Build configuration list for PBXNativeTarget "Queue" */; - buildPhases = ( - 7B18E0121C5BF7A1005A2B8E /* Sources */, - 7B18E0131C5BF7A1005A2B8E /* Frameworks */, - 7B18E0141C5BF7A1005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Queue; - productName = Queue; - productReference = 7B18E0161C5BF7A1005A2B8E /* Queue.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E0241C5BF7A1005A2B8E /* QueueTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0311C5BF7A1005A2B8E /* Build configuration list for PBXNativeTarget "QueueTests" */; - buildPhases = ( - 7B18E0211C5BF7A1005A2B8E /* Sources */, - 7B18E0221C5BF7A1005A2B8E /* Frameworks */, - 7B18E0231C5BF7A1005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0271C5BF7A1005A2B8E /* PBXTargetDependency */, - ); - name = QueueTests; - productName = QueueTests; - productReference = 7B18E0251C5BF7A1005A2B8E /* QueueTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E00E1C5BF7A1005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E0151C5BF7A1005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E0241C5BF7A1005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E0151C5BF7A1005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E0111C5BF7A1005A2B8E /* Build configuration list for PBXProject "Queue" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E00D1C5BF7A1005A2B8E; - productRefGroup = 7B18E0171C5BF7A1005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E0151C5BF7A1005A2B8E /* Queue */, - 7B18E0241C5BF7A1005A2B8E /* QueueTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E0141C5BF7A1005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E01C1C5BF7A1005A2B8E /* Assets.xcassets in Resources */, - 7B18E01F1C5BF7A1005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0231C5BF7A1005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E0121C5BF7A1005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E01A1C5BF7A1005A2B8E /* AppDelegate.swift in Sources */, - 7B18E0351C5BF7C2005A2B8E /* Queue.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0211C5BF7A1005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E02A1C5BF7A1005A2B8E /* QueueTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0271C5BF7A1005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E0151C5BF7A1005A2B8E /* Queue */; - targetProxy = 7B18E0261C5BF7A1005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18E01D1C5BF7A1005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18E01E1C5BF7A1005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E02C1C5BF7A1005A2B8E /* 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; - }; - 7B18E02D1C5BF7A1005A2B8E /* 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; - }; - 7B18E02F1C5BF7A1005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Queue/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Queue; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0301C5BF7A1005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Queue/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Queue; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0321C5BF7A1005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QueueTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.QueueTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Queue.app/Contents/MacOS/Queue"; - }; - name = Debug; - }; - 7B18E0331C5BF7A1005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QueueTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.QueueTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Queue.app/Contents/MacOS/Queue"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E0111C5BF7A1005A2B8E /* Build configuration list for PBXProject "Queue" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E02C1C5BF7A1005A2B8E /* Debug */, - 7B18E02D1C5BF7A1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E02E1C5BF7A1005A2B8E /* Build configuration list for PBXNativeTarget "Queue" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E02F1C5BF7A1005A2B8E /* Debug */, - 7B18E0301C5BF7A1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0311C5BF7A1005A2B8E /* Build configuration list for PBXNativeTarget "QueueTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0321C5BF7A1005A2B8E /* Debug */, - 7B18E0331C5BF7A1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E00E1C5BF7A1005A2B8E /* Project object */; -} diff --git a/Queue/Queue Tests/Queue/AppDelegate.swift b/Queue/Queue Tests/Queue/AppDelegate.swift deleted file mode 100644 index 307e0984f..000000000 --- a/Queue/Queue Tests/Queue/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// Queue -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Queue/Queue Tests/Queue/Assets.xcassets/AppIcon.appiconset/Contents.json b/Queue/Queue Tests/Queue/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Queue/Queue Tests/Queue/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/Queue/Queue Tests/Queue/Base.lproj/MainMenu.xib b/Queue/Queue Tests/Queue/Base.lproj/MainMenu.xib deleted file mode 100644 index fbacc16b3..000000000 --- a/Queue/Queue Tests/Queue/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Queue/Queue Tests/Queue/Info.plist b/Queue/Queue Tests/Queue/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Queue/Queue Tests/Queue/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift new file mode 100644 index 000000000..3b17b98cb --- /dev/null +++ b/Queue/Queue-Optimized.swift @@ -0,0 +1,56 @@ +/* + First-in first-out queue (FIFO) + + New elements are added to the end of the queue. Dequeuing pulls elements from + the front of the queue. + + Enqueuing and dequeuing are O(1) operations. +*/ +public struct Queue { + fileprivate var array = [T?]() + fileprivate 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 let element = array[guarded: 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 + } + + public var front: T? { + if isEmpty { + return nil + } else { + return array[head] + } + } +} + +extension Array { + subscript(guarded idx: Int) -> Element? { + guard (startIndex.. { - var array = [T]() - - public var isEmpty: Bool { - return array.isEmpty - } + fileprivate var array = [T]() public var count: Int { return array.count } - public mutating func enqueue(element: T) { + public var isEmpty: Bool { + return array.isEmpty + } + + public mutating func enqueue(_ element: T) { array.append(element) } @@ -30,7 +30,7 @@ public struct Queue { } } - public func peek() -> T? { + public var front: T? { return array.first } } diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index 8289c46ac..08327783f 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -1,7 +1,7 @@ /* Queue - A queue is a list where you can only insert new items at the back and + 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! @@ -12,29 +12,29 @@ */ public struct Queue { - private var array = [T]() - - public var count: Int { - return array.count - } - + fileprivate var array = [T]() + public var isEmpty: Bool { return array.isEmpty } - - public mutating func enqueue(element: T) { + + public var count: Int { + return array.count + } + + public mutating func enqueue(_ element: T) { array.append(element) } - + public mutating func dequeue() -> T? { - if count == 0 { + if isEmpty { return nil } else { return array.removeFirst() } } - - public func peek() -> T? { + + public var front: T? { return array.first } } @@ -53,7 +53,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/playground.xcworkspace/contents.xcworkspacedata b/Queue/Queue.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Queue/Queue.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/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 7b90daa9a..ca55f0f28 100644 --- a/Queue/README.markdown +++ b/Queue/README.markdown @@ -1,12 +1,14 @@ # Queue +> This topic has been tutorialized [here](https://www.raywenderlich.com/148141/swift-algorithm-club-swift-queue-data-structure) + 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,14 +40,16 @@ 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 { - var array = [T]() - + fileprivate var array = [T]() + public var isEmpty: Bool { return array.isEmpty } @@ -53,8 +57,8 @@ public struct Queue { public var count: Int { return array.count } - - public mutating func enqueue(element: T) { + + public mutating func enqueue(_ element: T) { array.append(element) } @@ -66,20 +70,195 @@ public struct Queue { } } - public func peek() -> T? { + public var front: T? { return array.first } } ``` -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. + +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() +queue.enqueue("Ada") +queue.enqueue("Steve") +queue.enqueue("Tim") +``` + +then the array might actually look like this: + + [ "Ada", "Steve", "Tim", xxx, xxx, xxx ] + +where `xxx` is memory that is reserved but not filled in yet. Adding a new element to the array overwrites the next unused spot: + + [ "Ada", "Steve", "Tim", "Grace", xxx, xxx ] + +This results by copying memory from one place to another which is a constant-time operation. + +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 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 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"`: + + before [ "Ada", "Steve", "Tim", "Grace", xxx, xxx ] + / / / + / / / + / / / + / / / + 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... + +## A more efficient queue + +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 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 ] + +After dequeuing `"Steve"`, the array is: + + [ xxx, xxx, "Tim", "Grace", xxx, xxx ] + +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 which is an **O(n)** operation. Because this only happens once in a while, dequeuing is **O(1)** on average. + +Here is how you can implement this version of `Queue`: + +```swift +public struct Queue { + fileprivate var array = [T?]() + fileprivate 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 + } + + public var front: T? { + if isEmpty { + return nil + } else { + return array[head] + } + } +} +``` + +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 the next item has become the front one. + +We go from this: + + [ "Ada", "Steve", "Tim", "Grace", xxx, xxx ] + head + +to this: + + [ xxx, "Steve", "Tim", "Grace", xxx, xxx ] + head + +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. + +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) + if array.count > 50 && percentage > 0.25 { + array.removeFirst(head) + head = 0 + } +``` + +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 the following: + +```swift +var q = Queue() +q.array // [] empty array + +q.enqueue("Ada") +q.enqueue("Steve") +q.enqueue("Tim") +q.array // [{Some "Ada"}, {Some "Steve"}, {Some "Tim"}] +q.count // 3 + +q.dequeue() // "Ada" +q.array // [nil, {Some "Steve"}, {Some "Tim"}] +q.count // 2 + +q.dequeue() // "Steve" +q.array // [nil, nil, {Some "Tim"}] +q.count // 1 + +q.enqueue("Grace") +q.array // [nil, nil, {Some "Tim"}, {Some "Grace"}] +q.count // 2 +``` + +To test the trimming behavior, replace the line, + +```swift + if array.count > 50 && percentage > 0.25 { +``` + +with: + +```swift + if head > 2 { +``` + +Now if you dequeue another object, the array will look as follows: + +```swift +q.dequeue() // "Tim" +q.array // [{Some "Grace"}] +q.count // 1 +``` -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. +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. -However, to dequeue we remove the element from the beginning of the array. This is an **O(n)** operation because it requires all remaining array elements to be shifted in memory. +## See also -More efficient implementations would use a linked list, a [circular buffer](../Ring Buffer/), or a [heap](../Heap/). (I might add an example of this later.) +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 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 by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Queue/Tests/Info.plist b/Queue/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Queue/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/Queue/Queue Tests/QueueTests/QueueTests.swift b/Queue/Tests/QueueTests.swift similarity index 80% rename from Queue/Queue Tests/QueueTests/QueueTests.swift rename to Queue/Tests/QueueTests.swift index 1ffea7468..b820ac0d3 100755 --- a/Queue/Queue Tests/QueueTests/QueueTests.swift +++ b/Queue/Tests/QueueTests.swift @@ -1,13 +1,12 @@ import Foundation import XCTest -@testable import Queue class QueueTest: XCTestCase { func testEmpty() { var queue = Queue() XCTAssertTrue(queue.isEmpty) XCTAssertEqual(queue.count, 0) - XCTAssertEqual(queue.peek(), nil) + XCTAssertEqual(queue.front, nil) XCTAssertNil(queue.dequeue()) } @@ -17,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() { @@ -33,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() { @@ -59,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/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..f927aba0d --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,287 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C4021C77A6BF003CECC7 /* Queue-Optimized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4011C77A6BF003CECC7 /* Queue-Optimized.swift */; }; + 7B80C4041C77A6C5003CECC7 /* QueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4031C77A6C5003CECC7 /* QueueTests.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; }; + 7B80C4011C77A6BF003CECC7 /* Queue-Optimized.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Queue-Optimized.swift"; path = "../Queue-Optimized.swift"; sourceTree = SOURCE_ROOT; }; + 7B80C4031C77A6C5003CECC7 /* QueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueueTests.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 = ( + 7B80C4011C77A6BF003CECC7 /* Queue-Optimized.swift */, + 7B80C4031C77A6C5003CECC7 /* QueueTests.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 = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1000; + }; + }; + }; + 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 = ( + 7B80C4021C77A6BF003CECC7 /* Queue-Optimized.swift in Sources */, + 7B80C4041C77A6C5003CECC7 /* QueueTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + }; + 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/Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..afd69e6a7 --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Quicksort/Quicksort Tests/Quicksort.xcodeproj/project.pbxproj b/Quicksort/Quicksort Tests/Quicksort.xcodeproj/project.pbxproj deleted file mode 100644 index 9737ad3b4..000000000 --- a/Quicksort/Quicksort Tests/Quicksort.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E06C1C5BF86E005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E06B1C5BF86E005A2B8E /* AppDelegate.swift */; }; - 7B18E06E1C5BF86E005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E06D1C5BF86E005A2B8E /* Assets.xcassets */; }; - 7B18E0711C5BF86E005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E06F1C5BF86E005A2B8E /* MainMenu.xib */; }; - 7B18E07C1C5BF86E005A2B8E /* QuicksortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E07B1C5BF86E005A2B8E /* QuicksortTests.swift */; }; - 7B18E0871C5BF8F3005A2B8E /* Quicksort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0861C5BF8F3005A2B8E /* Quicksort.swift */; }; - 7B18E0891C5BF92B005A2B8E /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0881C5BF92B005A2B8E /* SortingTestHelpers.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E0781C5BF86E005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E0601C5BF86E005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E0671C5BF86E005A2B8E; - remoteInfo = Quicksort; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E0681C5BF86E005A2B8E /* Quicksort.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Quicksort.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E06B1C5BF86E005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E06D1C5BF86E005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18E0701C5BF86E005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18E0721C5BF86E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0771C5BF86E005A2B8E /* QuicksortTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuicksortTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E07B1C5BF86E005A2B8E /* QuicksortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuicksortTests.swift; sourceTree = ""; }; - 7B18E07D1C5BF86E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0861C5BF8F3005A2B8E /* Quicksort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Quicksort.swift; path = ../../Quicksort.swift; sourceTree = ""; }; - 7B18E0881C5BF92B005A2B8E /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortingTestHelpers.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E0651C5BF86E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0741C5BF86E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E05F1C5BF86E005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E06A1C5BF86E005A2B8E /* Quicksort */, - 7B18E07A1C5BF86E005A2B8E /* QuicksortTests */, - 7B18E0691C5BF86E005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0691C5BF86E005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E0681C5BF86E005A2B8E /* Quicksort.app */, - 7B18E0771C5BF86E005A2B8E /* QuicksortTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E06A1C5BF86E005A2B8E /* Quicksort */ = { - isa = PBXGroup; - children = ( - 7B18E06B1C5BF86E005A2B8E /* AppDelegate.swift */, - 7B18E06D1C5BF86E005A2B8E /* Assets.xcassets */, - 7B18E0721C5BF86E005A2B8E /* Info.plist */, - 7B18E06F1C5BF86E005A2B8E /* MainMenu.xib */, - 7B18E0861C5BF8F3005A2B8E /* Quicksort.swift */, - ); - path = Quicksort; - sourceTree = ""; - }; - 7B18E07A1C5BF86E005A2B8E /* QuicksortTests */ = { - isa = PBXGroup; - children = ( - 7B18E07D1C5BF86E005A2B8E /* Info.plist */, - 7B18E07B1C5BF86E005A2B8E /* QuicksortTests.swift */, - 7B18E0881C5BF92B005A2B8E /* SortingTestHelpers.swift */, - ); - path = QuicksortTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E0671C5BF86E005A2B8E /* Quicksort */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0801C5BF86E005A2B8E /* Build configuration list for PBXNativeTarget "Quicksort" */; - buildPhases = ( - 7B18E0641C5BF86E005A2B8E /* Sources */, - 7B18E0651C5BF86E005A2B8E /* Frameworks */, - 7B18E0661C5BF86E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Quicksort; - productName = Quicksort; - productReference = 7B18E0681C5BF86E005A2B8E /* Quicksort.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E0761C5BF86E005A2B8E /* QuicksortTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0831C5BF86E005A2B8E /* Build configuration list for PBXNativeTarget "QuicksortTests" */; - buildPhases = ( - 7B18E0731C5BF86E005A2B8E /* Sources */, - 7B18E0741C5BF86E005A2B8E /* Frameworks */, - 7B18E0751C5BF86E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0791C5BF86E005A2B8E /* PBXTargetDependency */, - ); - name = QuicksortTests; - productName = QuicksortTests; - productReference = 7B18E0771C5BF86E005A2B8E /* QuicksortTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E0601C5BF86E005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E0671C5BF86E005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E0761C5BF86E005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E0671C5BF86E005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E0631C5BF86E005A2B8E /* Build configuration list for PBXProject "Quicksort" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E05F1C5BF86E005A2B8E; - productRefGroup = 7B18E0691C5BF86E005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E0671C5BF86E005A2B8E /* Quicksort */, - 7B18E0761C5BF86E005A2B8E /* QuicksortTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E0661C5BF86E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E06E1C5BF86E005A2B8E /* Assets.xcassets in Resources */, - 7B18E0711C5BF86E005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0751C5BF86E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E0641C5BF86E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E06C1C5BF86E005A2B8E /* AppDelegate.swift in Sources */, - 7B18E0871C5BF8F3005A2B8E /* Quicksort.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0731C5BF86E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0891C5BF92B005A2B8E /* SortingTestHelpers.swift in Sources */, - 7B18E07C1C5BF86E005A2B8E /* QuicksortTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0791C5BF86E005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E0671C5BF86E005A2B8E /* Quicksort */; - targetProxy = 7B18E0781C5BF86E005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18E06F1C5BF86E005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18E0701C5BF86E005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E07E1C5BF86E005A2B8E /* 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; - }; - 7B18E07F1C5BF86E005A2B8E /* 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; - }; - 7B18E0811C5BF86E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Quicksort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Quicksort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0821C5BF86E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Quicksort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Quicksort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0841C5BF86E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QuicksortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.QuicksortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Quicksort.app/Contents/MacOS/Quicksort"; - }; - name = Debug; - }; - 7B18E0851C5BF86E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QuicksortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.QuicksortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Quicksort.app/Contents/MacOS/Quicksort"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E0631C5BF86E005A2B8E /* Build configuration list for PBXProject "Quicksort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E07E1C5BF86E005A2B8E /* Debug */, - 7B18E07F1C5BF86E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0801C5BF86E005A2B8E /* Build configuration list for PBXNativeTarget "Quicksort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0811C5BF86E005A2B8E /* Debug */, - 7B18E0821C5BF86E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0831C5BF86E005A2B8E /* Build configuration list for PBXNativeTarget "QuicksortTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0841C5BF86E005A2B8E /* Debug */, - 7B18E0851C5BF86E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E0601C5BF86E005A2B8E /* Project object */; -} diff --git a/Quicksort/Quicksort Tests/Quicksort/AppDelegate.swift b/Quicksort/Quicksort Tests/Quicksort/AppDelegate.swift deleted file mode 100644 index 633208e7b..000000000 --- a/Quicksort/Quicksort Tests/Quicksort/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// Quicksort -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Quicksort/Quicksort Tests/Quicksort/Assets.xcassets/AppIcon.appiconset/Contents.json b/Quicksort/Quicksort Tests/Quicksort/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Quicksort/Quicksort Tests/Quicksort/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/Quicksort/Quicksort Tests/Quicksort/Base.lproj/MainMenu.xib b/Quicksort/Quicksort Tests/Quicksort/Base.lproj/MainMenu.xib deleted file mode 100644 index 41a33b27a..000000000 --- a/Quicksort/Quicksort Tests/Quicksort/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Quicksort/Quicksort Tests/Quicksort/Info.plist b/Quicksort/Quicksort Tests/Quicksort/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Quicksort/Quicksort Tests/Quicksort/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Quicksort/Quicksort.playground/Contents.swift b/Quicksort/Quicksort.playground/Contents.swift index 2d9ef3590..1bbf7b967 100644 --- a/Quicksort/Quicksort.playground/Contents.swift +++ b/Quicksort/Quicksort.playground/Contents.swift @@ -2,31 +2,26 @@ import Foundation - // *** Simple but inefficient version of quicksort *** -func quicksort(a: [T]) -> [T] { - if a.count <= 1 { - return a - } else { - let pivot = a[a.count/2] - let less = a.filter { $0 < pivot } - let equal = a.filter { $0 == pivot } - let greater = a.filter { $0 > pivot } - - // Uncomment this following line to see in detail what the - // pivot is in each step and how the subarrays are partitioned. - //print(pivot, less, equal, greater) - - return quicksort(less) + equal + quicksort(greater) - } +func quicksort(_ a: [T]) -> [T] { + guard a.count > 1 else { return a } + + let pivot = a[a.count/2] + let less = a.filter { $0 < pivot } + let equal = a.filter { $0 == pivot } + let greater = a.filter { $0 > pivot } + + // Uncomment this following line to see in detail what the + // pivot is in each step and how the subarrays are partitioned. + //print(pivot, less, equal, greater) return quicksort(less) + equal + quicksort(greater) + + return quicksort(less) + equal + quicksort(greater) } let list1 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] quicksort(list1) - - // *** Using Lomuto partitioning *** /* @@ -36,18 +31,18 @@ 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 for j in low..(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) @@ -65,8 +60,6 @@ func quicksortLomuto(inout a: [T], low: Int, high: Int) { quicksortLomuto(&list2, low: 0, high: list2.count - 1) - - // *** Hoare partitioning *** /* @@ -77,17 +70,17 @@ 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 - + while true { repeat { j -= 1 } while a[j] > pivot repeat { i += 1 } while a[i] < pivot - + if i < j { - swap(&a[i], &a[j]) + a.swapAt(i, j) } else { return j } @@ -98,7 +91,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) @@ -108,21 +101,19 @@ func quicksortHoare(inout a: [T], low: Int, high: Int) { 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]) - + let p = partitionLomuto(&a, low: low, high: high) quicksortRandom(&a, low: low, high: p - 1) quicksortRandom(&a, low: p + 1, high: high) @@ -133,17 +124,15 @@ var list4 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] quicksortRandom(&list4, low: 0, high: list4.count - 1) list4 - - // *** Dutch national flag partioning *** /* 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]) + a.swapAt(i, j) } } @@ -151,13 +140,13 @@ 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 var equal = low var larger = high - + while equal <= larger { if a[equal] < pivot { swap(&a, smaller, equal) @@ -177,7 +166,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) diff --git a/Quicksort/Quicksort.playground/playground.xcworkspace/contents.xcworkspacedata b/Quicksort/Quicksort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Quicksort/Quicksort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Quicksort/Quicksort.playground/timeline.xctimeline b/Quicksort/Quicksort.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Quicksort/Quicksort.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Quicksort/Quicksort.swift b/Quicksort/Quicksort.swift index 1d3b0602d..a67122723 100644 --- a/Quicksort/Quicksort.swift +++ b/Quicksort/Quicksort.swift @@ -3,16 +3,15 @@ import Foundation /* Easy to understand but not very efficient. */ -func quicksort(a: [T]) -> [T] { - if a.count <= 1 { - return a - } else { - let pivot = a[a.count/2] - let less = a.filter { $0 < pivot } - let equal = a.filter { $0 == pivot } - let greater = a.filter { $0 > pivot } - return quicksort(less) + equal + quicksort(greater) - } +func quicksort(_ a: [T]) -> [T] { + guard a.count > 1 else { return a } + + let pivot = a[a.count/2] + let less = a.filter { $0 < pivot } + let equal = a.filter { $0 == pivot } + let greater = a.filter { $0 > pivot } + + return quicksort(less) + equal + quicksort(greater) } // MARK: - Lomuto @@ -30,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] @@ -46,7 +45,7 @@ func partitionLomuto(inout a: [T], low: Int, high: Int) -> Int { i += 1 } } - + // Swap the pivot element with the first element that is greater than // the pivot. Now the pivot sits between the <= and > regions and the // array is properly partitioned. @@ -57,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) @@ -81,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 @@ -89,9 +88,9 @@ func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { while true { repeat { j -= 1 } while a[j] > pivot repeat { i += 1 } while a[i] < pivot - + if i < j { - swap(&a[i], &a[j]) + a.swapAt(i, j) } else { return j } @@ -102,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) @@ -113,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))) } @@ -122,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) @@ -143,9 +142,9 @@ 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]) + a.swapAt(i, j) } } @@ -166,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 @@ -196,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/README.markdown b/Quicksort/README.markdown index eda50aff5..120ddc346 100644 --- a/Quicksort/README.markdown +++ b/Quicksort/README.markdown @@ -7,16 +7,15 @@ 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] { - if a.count <= 1 { - return a - } else { - let pivot = a[a.count/2] - let less = a.filter { $0 < pivot } - let equal = a.filter { $0 == pivot } - let greater = a.filter { $0 > pivot } - return quicksort(less) + equal + quicksort(greater) - } +func quicksort(_ a: [T]) -> [T] { + guard a.count > 1 else { return a } + + let pivot = a[a.count/2] + let less = a.filter { $0 < pivot } + let equal = a.filter { $0 == pivot } + let greater = a.filter { $0 > pivot } + + return quicksort(less) + equal + quicksort(greater) } ``` @@ -31,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 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 @@ -45,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. @@ -74,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: [ ] @@ -123,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 @@ -132,18 +131,18 @@ 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 for j in low..(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) @@ -278,17 +277,17 @@ 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 - + while true { repeat { j -= 1 } while a[j] > pivot repeat { i += 1 } while a[i] < pivot - + if i < j { - swap(&a[i], &a[j]) + a.swapAt(i, j) } else { return j } @@ -310,16 +309,16 @@ 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. 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) @@ -358,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: @@ -372,7 +371,7 @@ You might think this means we should always choose the middle element rather tha Now the middle element is `1` and that gives the same lousy results as in the previous example. -Ideally, the pivot is the *median* element of the array that you're partitioning. Of course, you won't know what the median is until after you've sorted the array, so this is a bit of a chicken-and-egg problem. However, there are some tricks to choose good, if not ideal, pivots. +Ideally, the pivot is the *median* element of the array that you're partitioning, i.e. the element that sits in the middle of the sorted array. Of course, you won't know what the median is until after you've sorted the array, so this is a bit of a chicken-and-egg problem. However, there are some tricks to choose good, if not ideal, pivots. One trick is "median-of-three", where you find the median of the first, middle, and last element in this subarray. In theory that often gives a good approximation of the true median. @@ -381,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 @@ -413,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 @@ -462,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) @@ -478,6 +477,6 @@ Using Dutch flag partitioning makes for a more efficient quicksort if the array ## See also -See also [Wikipedia](https://en.wikipedia.org/wiki/Quicksort). +[Quicksort on Wikipedia](https://en.wikipedia.org/wiki/Quicksort) -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Quicksort/Tests/Info.plist b/Quicksort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Quicksort/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/Quicksort/Quicksort Tests/QuicksortTests/QuicksortTests.swift b/Quicksort/Tests/QuicksortTests.swift similarity index 68% rename from Quicksort/Quicksort Tests/QuicksortTests/QuicksortTests.swift rename to Quicksort/Tests/QuicksortTests.swift index 215991e98..c8d9a62e6 100644 --- a/Quicksort/Quicksort Tests/QuicksortTests/QuicksortTests.swift +++ b/Quicksort/Tests/QuicksortTests.swift @@ -1,17 +1,16 @@ import XCTest -@testable import Quicksort class QuicksortTests: XCTestCase { func testQuicksort() { checkSortAlgorithm(quicksort) } - - private typealias QuicksortFunction = (inout [Int], low: Int, high: Int) -> Void - - private func checkQuicksort(function: QuicksortFunction) { + + fileprivate typealias QuicksortFunction = (inout [Int], _ low: Int, _ high: Int) -> Void + + 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/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift b/Quicksort/Tests/SortingTestHelpers.swift similarity index 63% rename from Quicksort/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift rename to Quicksort/Tests/SortingTestHelpers.swift index 3b56d3c3e..0c47cde4e 100644 --- a/Quicksort/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift +++ b/Quicksort/Tests/SortingTestHelpers.swift @@ -1,7 +1,6 @@ -import Foundation import XCTest -func randomArray(size: Int) -> [Int] { +func randomArray(_ size: Int) -> [Int] { var a = [Int]() for _ in 1...size { a.append(Int(arc4random_uniform(1000))) @@ -9,16 +8,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 +27,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 +108,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, <) } } diff --git a/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj new file mode 100644 index 000000000..923195121 --- /dev/null +++ b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj @@ -0,0 +1,295 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3E61C77A4CA003CECC7 /* Quicksort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E51C77A4CA003CECC7 /* Quicksort.swift */; }; + 7B80C3E91C77A4D0003CECC7 /* QuicksortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E71C77A4D0003CECC7 /* QuicksortTests.swift */; }; + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 7B2BBC801C779D720067B71D /* Tests-Quicksort.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests-Quicksort.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 7B80C3E51C77A4CA003CECC7 /* Quicksort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Quicksort.swift; path = ../Quicksort.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3E71C77A4D0003CECC7 /* QuicksortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuicksortTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortingTestHelpers.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-Quicksort.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 7B80C3E51C77A4CA003CECC7 /* Quicksort.swift */, + 7B80C3E71C77A4D0003CECC7 /* QuicksortTests.swift */, + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + path = TestsTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* Tests-Quicksort */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests-Quicksort" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Tests-Quicksort"; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* Tests-Quicksort.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests-Quicksort" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* Tests-Quicksort */, + ); + }; +/* 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 = ( + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */, + 7B80C3E61C77A4CA003CECC7 /* Quicksort.swift in Sources */, + 7B80C3E91C77A4D0003CECC7 /* QuicksortTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; + }; + 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_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.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_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests-Quicksort" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "Tests-Quicksort" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..c948249d9 --- /dev/null +++ b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme b/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme new file mode 100644 index 000000000..ec81527d1 --- /dev/null +++ b/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.markdown b/README.markdown index 1b5ff2a85..fbcde7c86 100644 --- a/README.markdown +++ b/README.markdown @@ -1,3 +1,5 @@ +![Swift Algorithm Club](Images/SwiftAlgorithm-410-transp.png) + # Welcome to the Swift Algorithm Club! Here you'll find implementations of popular algorithms and data structures in everyone's favorite new language Swift, with detailed explanations of how they work. @@ -6,21 +8,21 @@ 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.2** and **Swift 2.1**. We'll keep this updated with the latest version of Swift. +Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. If you're interested in a GitHub pages version of the repo, check out [this](https://aquarchitect.github.io/swift-algorithm-club/). -This is a work in progress. More algorithms will be added soon. :-) +:heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: ## 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. **Suggestions and contributions are welcome!** +[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? @@ -28,27 +30,32 @@ 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/) -- [Boyer-Moore string search](Boyer-Moore/) +- [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-Horspool/) ## 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. -- Union-Find +- [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 -- [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. -- Rabin-Karp +- [Brute-Force String Search](Brute-Force%20String%20Search/). A naive method. +- [Boyer-Moore](Boyer-Moore-Horspool/). 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/). 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. ### Sorting @@ -56,46 +63,65 @@ 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/) + +Hybrid sorts: + +- [Introsort](Introsort/) Special-purpose sorts: -- Bucket Sort -- Counting Sort -- Radix 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/) +- [Bubble Sort](Bubble%20Sort/) +- [Slow Sort](Slow%20Sort/) ### Compression -- Run-Length Encoding (RLE) -- Huffman Encoding +- [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%20Sort/). An improve upon the Bubble Sort algorithm. +- [Convex Hull](Convex%20Hull/). +- [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? +- [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. +- [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. +- [Myers Difference Algorithm](Myers%20Difference%20Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. - [Permutations and Combinations](Combinatorics/). Get your combinatorics on! -- Statistics +- [Shunting Yard Algorithm](Shunting%20Yard/). Convert infix expressions to postfix. +- [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. +- [CounterClockWise](/CounterClockWise/). Determining the area of a simple polygon. ### Machine learning +- [k-Means Clustering](K-Means/). Unsupervised classifier that partitions data into *k* clusters. - k-Nearest Neighbors +- [Linear Regression](Linear%20Regression/). A technique for creating a model of the relationship between two (or more) variable quantities. +- Logistic Regression +- Neural Networks - PageRank +- [Naive Bayes Classifier](Naive%20Bayes%20Classifier/) +- [Simulated annealing](Simulated%20annealing/). Probabilistic technique for approximating the global maxima in a (often discrete) large search space. ## Data structures @@ -103,93 +129,115 @@ The choice of data structure for a particular task depends on a few things. First, there is the shape of your data and the kinds of operations that you'll need to perform on it. If you want to look up objects by a key you need some kind of dictionary; if your data is hierarchical in nature you want a tree structure of some sort; if your data is sequential you want a stack or queue. -Second, it matters what particular operations you'll be performing most, as certain data structures are optimized for certain actions. For example, if you often need to find the most important object in a queue, then a heap or priority queue is more optimal than a plain array. +Second, it matters what particular operations you'll be performing most, as certain data structures are optimized for certain actions. For example, if you often need to find the most important object in a collection, then a heap or priority queue is more optimal than a plain array. Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types is sufficient, but sometimes you may want something more fancy... ### 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. +- [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. -- Skip List +- [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 probabilistic data-structure with same logarithmic time bound and efficiency as AVL/ or Red-Black tree and provides a clever compromise to efficiently support search and update operations. ### Trees - [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 with the special requirement that elements are inserted in a specific way, allowing for faster queries, like when using a [binary search](Binary Search/) algorithm. -- [AVL Tree](AVL Tree/). A binary search tree that balances itself using rotations. -- Red-Black Tree -- Splay Tree -- Threaded Binary Tree -- [Segment Tree](Segment Tree/). Can quickly compute a function over a portion of an array. +- [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%20Tree/). A self balancing binary search tree. +- [Splay Tree](Splay%20Tree/). A self balancing binary search tree that enables fast retrieval of recently updated elements. +- [Threaded Binary Tree](Threaded%20Binary%20Tree/). A binary tree that maintains a few extra variables for cheap and fast in-order traversals. +- [Segment Tree](Segment%20Tree/). Can quickly compute a function over a portion of an array. + - [Lazy Propagation](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation) - kd-Tree +- [Sparse Table](Sparse%20Table/). Another take on quickly computing a function over a portion of an array, but this time we'll make it even quicker!. - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. - Fibonacci Heap -- Trie +- [Trie](Trie/). A special type of tree used to store associative data structures. +- [B-Tree](B-Tree/). A self-balancing search tree, in which nodes can have more than two children. +- [QuadTree](QuadTree/). A tree with 4 children. +- [Octree](Octree/). A tree with 8 children. ### 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 -- [Hash Set](Hash Set/). A set implemented using a hash table. -- Multiset -- Ordered Set +- [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](Multiset/). A set where the number of times an element is added matters. (Also known as a bag.) +- [Ordered Set](Ordered%20Set/). A set where the order of items matters. ### Graphs -- Graph -- Breadth-First Search (BFS) -- Depth-First Search (DFS) -- Shortest Path -- Minimum Spanning Tree -- All Paths +- [Graph](Graph/) +- [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 +- [Minimum Spanning Tree](Minimum%20Spanning%20Tree/) +- [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) +- [Dijkstra's shortest path algorithm](Dijkstra%20Algorithm/) +- [A-Star](A-Star/) ## 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/) +- [Two-Sum Problem](Two-Sum%20Problem/) +- [Three-Sum/Four-Sum Problem](3Sum%20and%204Sum/) +- [Fizz Buzz](Fizz%20Buzz/) +- [Monty Hall Problem](Monty%20Hall%20Problem/) +- [Finding Palindromes](Palindromes/) +- [Dining Philosophers](DiningPhilosophers/) +- [Egg Drop Problem](Egg%20Drop%20Problem/) +- [Encoding and Decoding Binary Tree](Encode%20and%20Decode%20Tree/) +- [Closest Pair](Closest%20Pair/) ## Learn more! -For more information, check out these great books: +Like what you see? Check out [Data Structures & Algorithms in Swift](https://store.raywenderlich.com/products/data-structures-and-algorithms-in-swift), the official book by the Swift Algorithm Club team! + +![Data Structures & Algorithms in Swift Book](Images/DataStructuresAndAlgorithmsInSwiftBook.png) -- [Introduction to Algorithms](https://mitpress.mit.edu/books/introduction-algorithms) by Cormen, Leiserson, Rivest, Stein -- [The Algorithm Design Manual](http://www.algorist.com) by Skiena -- [Elements of Programming Interviews](http://elementsofprogramminginterviews.com) by Aziz, Lee, Prakash -- [Algorithms](http://www.cs.princeton.edu/~rs/) by Sedgewick +You’ll start with the fundamental structures of linked lists, queues and stacks, and see how to implement them in a highly Swift-like way. Move on to working with various types of trees, including general purpose trees, binary trees, AVL trees, binary search trees, and tries. -The following books are available for free online: +Go beyond bubble and insertion sort with better-performing algorithms, including mergesort, radix sort, heap sort, and quicksort. Learn how to construct directed, non-directed and weighted graphs to represent many real-world models, and traverse graphs and trees efficiently with breadth-first, depth-first, Dijkstra’s and Prim’s algorithms to solve problems such as finding the shortest path or lowest cost in a network. -- [Algorithms](http://www.beust.com/algorithms.pdf) by Dasgupta, Papadimitriou, Vazirani -- [Algorithms, Etc.](http://jeffe.cs.illinois.edu/teaching/algorithms/) by Erickson -- [Algorithms + Data Structures = Programs](http://www.ethoberon.ethz.ch/WirthPubl/AD.pdf) by Wirth -- Algorithms and Data Structures: The Basic Toolbox by Mehlhorn and Sanders +By the end of this book, you’ll have hands-on experience solving common issues with data structures and algorithms — and you’ll be well on your way to developing your own efficient and useful implementations! -Friends of the club: +You can find the book on the [raywenderlich.com store](https://store.raywenderlich.com/products/data-structures-and-algorithms-in-swift). -- [EKAlgorithms](https://github.com/EvgenyKarkan/EKAlgorithms). A great collection of algorithms in Objective-C. +## Credits + +The Swift Algorithm Club was originally created by [Matthijs Hollemans](https://github.com/hollance). + +It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), [Kelvin Lau](https://github.com/kelvinlauKL), and [Richard Ash](https://github.com/richard-ash). + +The Swift Algorithm Club is a collaborative effort from the [most algorithmic members](https://github.com/raywenderlich/swift-algorithm-club/graphs/contributors) of the [raywenderlich.com](https://www.raywenderlich.com) community. We're always looking for help - why not [join the club](.github/CONTRIBUTING.md)? :] ## License 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) diff --git a/Rabin-Karp/README.markdown b/Rabin-Karp/README.markdown new file mode 100644 index 000000000..a618d3981 --- /dev/null +++ b/Rabin-Karp/README.markdown @@ -0,0 +1,79 @@ +# Rabin-Karp string search algorithm + +The Rabin-Karp string search algorithm is used to search text for a pattern. + +A practical application of the algorithm is detecting plagiarism. Given source material, the algorithm can rapidly search through a paper for instances of sentences from the source material, ignoring details such as case and punctuation. Because of the abundance of the sought strings, single-string searching algorithms are impractical. + +## 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 algorithm uses a sliding window the size of the search pattern. It starts by hashing the search pattern, then +hashing the first x characters of the text string where x is the length of the search pattern. It then slides the window one character over and uses +the previous hash value to calculate the new hash faster. Only when it finds a hash that matches the hash of the search pattern will it compare +the two strings it see if they are the same (to 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.flatMap { $0.asInt } + let textArray = text.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 collision + 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)* diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift new file mode 100644 index 000000000..e087caa49 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -0,0 +1,101 @@ +//: Taking our rabin-karp algorithm for a walk + +// last checked with Xcode 9.4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +import UIKit + +struct Constants { + static let hashMultiplier = 69061 +} + +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.compactMap { $0.asInt } + let textArray = text.compactMap { $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") 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.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Rabin-Karp/rabin-karp.swift b/Rabin-Karp/rabin-karp.swift new file mode 100644 index 000000000..c337de1a7 --- /dev/null +++ b/Rabin-Karp/rabin-karp.swift @@ -0,0 +1,114 @@ +// 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") diff --git a/Radix Sort/RadixSort.playground/Contents.swift b/Radix Sort/RadixSort.playground/Contents.swift new file mode 100644 index 000000000..0b549fc9e --- /dev/null +++ b/Radix Sort/RadixSort.playground/Contents.swift @@ -0,0 +1,10 @@ +//: Playground - noun: a place where people can play + +// 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 = (0..<1000).map { _ in Int.random(in: 1...1000) } +bigArray +radixSort(&bigArray) diff --git a/Radix Sort/RadixSort.playground/Sources/radixSort.swift b/Radix Sort/RadixSort.playground/Sources/radixSort.swift new file mode 100644 index 000000000..af382f481 --- /dev/null +++ b/Radix Sort/RadixSort.playground/Sources/radixSort.swift @@ -0,0 +1,43 @@ +/* + + Sorting Algorithm that sorts an input array of integers digit by digit. + + */ + +// 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 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/RadixSortExample.swift b/Radix Sort/RadixSortExample.swift new file mode 100644 index 000000000..f64dcfeb9 --- /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.. + + + + 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..bef4ead9b --- /dev/null +++ b/Radix Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,279 @@ +// !$*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"; + SWIFT_VERSION = 4.0; + }; + 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"; + SWIFT_VERSION = 4.0; + }; + 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 = 4.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 = 4.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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Radix Sort/radixSort.swift b/Radix Sort/radixSort.swift new file mode 100644 index 000000000..302ea6056 --- /dev/null +++ b/Radix Sort/radixSort.swift @@ -0,0 +1,43 @@ +/* + + Sorting Algorithm that sorts an input array of integers digit by digit. + +*/ + +// 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 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.. "om" -> "an"`. + +On the other hand, `find("romans")` will return false. + +### Insertion + +The `insert()` function lets you add new strings to the radix tree. + +This function returns true if the string you are trying to insert was successfully inserted into the `RadixTree` and false if the string is already in the tree. + +### Deletion + +The `remove()` removes a string from the tree. When a string is removed, any other strings that have a prefix of the removed string are removed as well. + +For example, `remove("rom")` will also remove `"roman"`, `"rome"`, and `"romulus"` if those strings are in the tree as well. Calling `remove("")` will remove all strings in the tree. + +### printTree() + +You can use the `printTree()` function to visualize the tree. This function is a little buggy and not perfect yet but gets the job done thus far. + +### Helper functions + +The `sharedPrefix()` function is a non-member function in the **RadixTree.swift** file. It takes in two `String` objects and returns the shared prefix between them. + +For example, `sharedPrefix("apples", "oranges")` will return `""`, and `sharedPrefix("court", "coral")` will return `"co"`. + +This function is used in the implementation of the `find()`, `insert()`, and `remove()` functions. + +## See also + +[Radix Tree - Wikipedia](https://en.wikipedia.org/wiki/Radix_tree) + +*Written for Swift Algorithm Club by Steven Scally* diff --git a/Radix Tree/RadixTree.playground/Contents.swift b/Radix Tree/RadixTree.playground/Contents.swift new file mode 100644 index 000000000..a5e614849 --- /dev/null +++ b/Radix Tree/RadixTree.playground/Contents.swift @@ -0,0 +1,62 @@ +// Radix Tree + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +var radix = RadixTree() +var radixWiki = RadixTree() + +radixWiki.insert("romanus") +radixWiki.insert("rubicundus") +radixWiki.insert("rubicon") +radixWiki.insert("romane") +radixWiki.insert("ruber") +radixWiki.insert("rubens") +radixWiki.insert("romulus") +radixWiki.insert("start") +radixWiki.insert("shoot") +radixWiki.insert("shit") +radixWiki.insert("starch") +radixWiki.insert("steven") +radixWiki.insert("shart") +radixWiki.insert("shard") + +radixWiki.insert("compute") +radixWiki.insert("compatible") +radixWiki.insert("construction") +radixWiki.insert("coral") +radixWiki.insert("crude") +radixWiki.insert("chalk") +radixWiki.insert("chime") +radixWiki.insert("courting") +radixWiki.insert("courted") + +radixWiki.insert("rubicunduses") + +radixWiki.printTree() + +print("\n\nFIND TESTS") +print(radixWiki.find("courts")) // false +print(radixWiki.find("r")) // true +print(radixWiki.find("ro")) // true +print(radixWiki.find("rom")) // true +print(radixWiki.find("roma")) // true +print(radixWiki.find("roman")) // true +print(radixWiki.find("romane")) // true +print(radixWiki.find("romans")) // false +print(radixWiki.find("steve")) // true + +print("\n\nREMOVE TESTS") + +print(radixWiki.remove("c")) +radixWiki.printTree() + +print(radixWiki.remove("rub")) +radixWiki.printTree() + +print(radixWiki.remove("stevenson")) + +print(radixWiki.remove("")) +radixWiki.printTree() diff --git a/Radix Tree/RadixTree.playground/Sources/RadixTree.swift b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift new file mode 100644 index 000000000..77e289f7d --- /dev/null +++ b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift @@ -0,0 +1,381 @@ +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() + } +} + +// 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.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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[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.count > 0 { + var labelIndex = e.label.startIndex + + // Create index objects and move them to after the shared prefix + for _ in 1...shared.count { + index = searchStr.index(after: index) + labelIndex = e.label.index(after: labelIndex) + } + + // Substring both the search string and the label from the shared prefix + searchStr = String(searchStr[index...]) + e.label = String(e.label[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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[tempIndex...]) + found = true + break + } + + // If the shared string is empty, go to the next child + else if shared.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.count < c.label.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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[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.startIndex + var c2 = str2.startIndex + for _ in 0...min(str1.count-1, str2.count-1) { + if str1[c1] == str2[c2] { + temp.append( str1[c1] ) + c1 = str1.index(after:c1) + c2 = str2.index(after:c2) + } else { + return temp + } + } + return temp +} diff --git a/Radix Tree/RadixTree.playground/contents.xcplayground b/Radix Tree/RadixTree.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Radix Tree/RadixTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Radix Tree/RadixTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Radix Tree/RadixTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Radix Tree/RadixTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Radix Tree/RadixTree.swift b/Radix Tree/RadixTree.swift new file mode 100644 index 000000000..943000dd3 --- /dev/null +++ b/Radix Tree/RadixTree.swift @@ -0,0 +1,381 @@ +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() + } +} + +// 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.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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[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.count > 0 { + var labelIndex = e.label.startIndex + + // Create index objects and move them to after the shared prefix + for _ in 1...shared.count { + index = searchStr.index(after: index) + labelIndex = e.label.index(after: labelIndex) + } + + // Substring both the search string and the label from the shared prefix + searchStr = String(searchStr[index...]) + e.label = String(e.label[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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[tempIndex...]) + found = true + break + } + + // If the shared string is empty, go to the next child + else if shared.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.count < c.label.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.count { + tempIndex = searchStr.index(after: tempIndex) + } + searchStr = String(searchStr[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.startIndex + var c2 = str2.startIndex + for _ in 0...min(str1.count-1, str2.count-1) { + if str1[c1] == str2[c2] { + temp.append( str1[c1] ) + c1 = str1.index(after:c1) + c2 = str2.index(after:c2) + } else { + return temp + } + } + return temp +} diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown new file mode 100644 index 000000000..2108b9055 --- /dev/null +++ b/Red-Black Tree/README.markdown @@ -0,0 +1,193 @@ +# Red-Black Tree + +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. + +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: + +``` +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: + +## Properties + +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 + +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] + +## Methods + +Nodes: +* `nodeX.getPredecessor()` Returns the inorder predecessor of nodeX +* `nodeX.getSuccessor()` Returns the inorder successor of nodeX +* `nodeX.minimum()` Returns the node with the minimum key of the subtree of nodeX +* `nodeX.maximum()` Returns the node with the maximum key of the subtree of nodeX +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 +* `count()` Returns how many nodes in the tree +* `isEmpty()` Returns if the tree has no nodes +* `allElements()` Returns an array containing all nodes (in-order traversal) in the tree. + +The rotation, insertion and deletion algorithms are implemented based on the pseudo-code provided in [CLRS] + +## Implementation Details + +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. + +## Rotation + +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). + +## Insertion + +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] + +``` +**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] + +``` +**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] + +``` +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] + +``` +**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] + +``` +**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] + +``` +**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] + +``` +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. Swift 4.2 check by Bruno Scheele.* diff --git a/Red-Black Tree/RedBlackTree.playground/Contents.swift b/Red-Black Tree/RedBlackTree.playground/Contents.swift new file mode 100644 index 000000000..d1133bc98 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/Contents.swift @@ -0,0 +1,30 @@ +//: 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 i in 0..<1000 { + let value = Double(arc4random()) / randomMax + values.append(value) + redBlackTree.insert(key: value) + + if i % 100 == 0 { + redBlackTree.verify() + } +} +redBlackTree.verify() + +for i in 0..<1000 { + let rand = arc4random_uniform(UInt32(values.count)) + let index = Int(rand) + let value = values.remove(at: index) + redBlackTree.delete(key: value) + + if i % 100 == 0 { + redBlackTree.verify() + } +} +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..9b067de55 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -0,0 +1,820 @@ +//Copyright (c) 2016 Matthijs Hollemans and contributors +// +//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 + +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: T? + var leftChild: RBNode? + var rightChild: RBNode? + fileprivate weak var parent: RBNode? + + public init(key: T?, 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: T?) { + self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) + } + + // For initialising the nullLeaf + public convenience init() { + self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) + self.color = .black + } + + var isRoot: Bool { + return parent == nil + } + + var isLeaf: Bool { + return rightChild == nil && leftChild == nil + } + + var isNullLeaf: Bool { + return key == nil && isLeaf && color == .black + } + + var isLeftChild: Bool { + return parent?.leftChild === self + } + + var isRightChild: Bool { + return parent?.rightChild === self + } + + var grandparent: RBNode? { + return parent?.parent + } + + var sibling: RBNode? { + if isLeftChild { + return parent?.rightChild + } else { + return parent?.leftChild + } + } + + var uncle: RBNode? { + return parent?.sibling + } + + public func getKey() -> T? { + return key + } +} + +// MARK: - RedBlackTree + +public class RedBlackTree { + public typealias RBNode = RBTreeNode + + fileprivate(set) var root: RBNode + fileprivate(set) var size = 0 + fileprivate let nullLeaf = RBNode() + fileprivate let allowDuplicateNode: Bool + + public init(_ allowDuplicateNode: Bool = false) { + root = nullLeaf + self.allowDuplicateNode = allowDuplicateNode + } +} + +// MARK: - Size + +extension RedBlackTree { + public func count() -> Int { + return size + } + + public func isEmpty() -> Bool { + return size == 0 + } + + public func allElements() -> [T] { + var nodes: [T] = [] + + getAllElements(node: root, nodes: &nodes) + + return nodes + } + + private func getAllElements(node: RBTreeNode, nodes: inout [T]) { + guard !node.isNullLeaf else { + return + } + + if let left = node.leftChild { + getAllElements(node: left, nodes: &nodes) + } + + if let key = node.key { + nodes.append(key) + } + + if let right = node.rightChild { + getAllElements(node: right, nodes: &nodes) + } + } +} + +// MARK: - Equatable protocol + +extension RBTreeNode { + static public func == (lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { + return lhs.key == rhs.key + } +} + +// MARK: - Finding a nodes successor and predecessor + +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 + } + + /* + * Returns the inorder predecessor node of a node + * The predecessor is a node with the next smaller key value of the current node + */ + public func getPredecessor() -> RBNode? { + // if node has left child: predecessor is min of this left tree + if let leftChild = leftChild, !leftChild.isNullLeaf { + return leftChild.maximum() + } + // else go upward while node is left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isLeftChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } +} + +// 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: T) -> RBNode? { + return search(key: input, node: root) + } + + /* + * Returns the node with given |key| in subtree of |node| + */ + fileprivate func search(key: T, 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() -> T? { + guard let minNode = root.minimum() else { + return nil + } + return minNode.key + } + + /* + * Returns the maximum key value of the whole tree + */ + public func maxValue() -> T? { + guard let maxNode = root.maximum() else { + return nil + } + return maxNode.key + } +} + +// 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: T) { + // If key must be unique and find the key already existed, quit + if search(input: key) != nil && !allowDuplicateNode { + return + } + + 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.isLeftChild && z.isRightChild { + zNew = parentZ + leftRotate(node: zNew) + } else if parentZ.isRightChild && z.isLeftChild { + 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.isLeftChild { + 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: T) { + 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.isLeftChild { + 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.isLeftChild { + 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.isLeftChild && 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.isLeftChild { + 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.isLeftChild { + 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 \(String(describing: node.key)) has red left child") + return false + } + if !rightChild.isNullLeaf && rightChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) 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 \(String(describing: node.key))") + 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: \(String(describing: 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 diff --git a/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Red-Black Tree/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.swift new file mode 100644 index 000000000..fc0411b42 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.swift @@ -0,0 +1,795 @@ +//Copyright (c) 2016 Matthijs Hollemans and contributors +// +//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 + +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: T? + var leftChild: RBNode? + var rightChild: RBNode? + fileprivate weak var parent: RBNode? + + public init(key: T?, 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: T?) { + self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) + } + + // For initialising the nullLeaf + public convenience init() { + self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) + self.color = .black + } + + var isRoot: Bool { + return parent == nil + } + + var isLeaf: Bool { + return rightChild == nil && leftChild == nil + } + + var isNullLeaf: Bool { + return key == nil && isLeaf && color == .black + } + + var isLeftChild: Bool { + return parent?.leftChild === self + } + + var isRightChild: Bool { + return parent?.rightChild === self + } + + var grandparent: RBNode? { + return parent?.parent + } + + var sibling: RBNode? { + if isLeftChild { + 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() + fileprivate let allowDuplicateNode: Bool + + public init(_ allowDuplicateNode: Bool = false) { + root = nullLeaf + self.allowDuplicateNode = allowDuplicateNode + } +} + +// MARK: - Size + +extension RedBlackTree { + public func count() -> Int { + return size + } + + public func isEmpty() -> Bool { + return size == 0 + } + + public func allElements() -> [T] { + var nodes: [T] = [] + + getAllElements(node: root, nodes: &nodes) + + return nodes + } + + private func getAllElements(node: RBTreeNode, nodes: inout [T]) { + guard !node.isNullLeaf else { + return + } + + if let left = node.leftChild { + getAllElements(node: left, nodes: &nodes) + } + + if let key = node.key { + nodes.append(key) + } + + if let right = node.rightChild { + getAllElements(node: right, nodes: &nodes) + } + } +} + +// 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: T) -> RBNode? { + return search(key: input, node: root) + } + + /* + * Returns the node with given |key| in subtree of |node| + */ + fileprivate func search(key: T, 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() -> T? { + guard let minNode = root.minimum() else { + return nil + } + return minNode.key + } + + /* + * Returns the maximum key value of the whole tree + */ + public func maxValue() -> T? { + guard let maxNode = root.maximum() else { + return nil + } + return maxNode.key + } +} + +// 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: T) { + // If key must be unique and find the key already existed, quit + if search(input: key) != nil && !allowDuplicateNode { + return + } + + 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.isLeftChild && z.isRightChild { + zNew = parentZ + leftRotate(node: zNew) + } else if parentZ.isRightChild && z.isLeftChild { + 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.isLeftChild { + 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: T) { + 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.isLeftChild { + 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.isLeftChild { + 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.isLeftChild && 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.isLeftChild { + 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.isLeftChild { + 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 \(String(describing: node.key)) has red left child") + return false + } + if !rightChild.isNullLeaf && rightChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) 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 \(String(describing: node.key))") + 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: \(String(describing: 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/Ring Buffer/README.markdown b/Ring Buffer/README.markdown index 72fb08ebd..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: @@ -41,12 +41,12 @@ Now the app decides it's time to write again and enqueues two more data items, ` [ 123, 456, 789, 666, 333 ] r ---> w -Whoops, the write pointer has reached the end of the array, so there is no more room. What now? Well, this is why it's a circular buffer: we wrap the write pointer back to the beginning and write the remaining data: +Whoops, the write pointer has reached the end of the array, so there is no more room for object `555`. What now? Well, this is why it's a circular buffer: we wrap the write pointer back to the beginning and write the remaining data: [ 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 } @@ -113,7 +111,7 @@ public struct RingBuffer { The `RingBuffer` object has an array for the actual storage of the data, and `readIndex` and `writeIndex` variables for the "pointers" into the array. The `write()` function puts the new element into the array at the `writeIndex`, and the `read()` function returns the element at the `readIndex`. -But hold up, you say, how does this wrapping around work? There are several ways to accomplish this and I chose a slightly controversial one. In this implementation, the `writeIndex` and `readIndex` always increment and never actually wrap around. Instead, we do this to find the actual index into the array: +But hold up, you say, how does this wrapping around work? There are several ways to accomplish this and I chose a slightly controversial one. In this implementation, the `writeIndex` and `readIndex` always increment and never actually wrap around. Instead, we do the following to find the actual index into the array: ```swift array[writeIndex % array.count] @@ -125,12 +123,12 @@ and: array[readIndex % array.count] ``` -In other words, we take the modulo (or the remainder) of the read and write index divided by the size of the underlying array. +In other words, we take the modulo (or the remainder) of the read index and write index divided by the size of the underlying array. 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 @@ -158,8 +156,8 @@ You've seen that a ring buffer can make a more optimal queue but it also has a d A ring buffer is also very useful for when a producer of data writes into the array at a different rate than the consumer of the data reads it. This happens often with file or network I/O. Ring buffers are also the preferred way of communicating between high priority threads (such as an audio rendering callback) and other, slower, parts of the system. -The implementation given here is not thread safe. It only serves as an example of how a ring buffer works. That said, it should be fairly straightforward to make it thread-safe for a single reader and single writer by using `OSAtomicIncrement64()` to change the read and write pointers. +The implementation given here is not thread-safe. It only serves as an example of how a ring buffer works. That said, it should be fairly straightforward to make it thread-safe for a single reader and single writer by using `OSAtomicIncrement64()` to change the read and write pointers. A cool trick to make a really fast ring buffer is to use the operating system's virtual memory system to map the same buffer onto different memory pages. Crazy stuff but worth looking into if you need to use a ring buffer in a high performance environment. -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Ring Buffer/RingBuffer.playground/Contents.swift b/Ring Buffer/RingBuffer.playground/Contents.swift index 5e6c4d6eb..adcf146b4 100644 --- a/Ring Buffer/RingBuffer.playground/Contents.swift +++ b/Ring Buffer/RingBuffer.playground/Contents.swift @@ -1,43 +1,44 @@ //: 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 { - if !isFull { - array[writeIndex % array.count] = element - writeIndex += 1 - return true - } else { - return false + + /* Returns false if out of space. */ + @discardableResult + public mutating func write(_ element: T) -> Bool { + guard !isFull else { return false } + defer { + writeIndex += 1 } + array[wrapped: writeIndex] = element + return true } - + + /* Returns nil if the buffer is empty. */ public mutating func read() -> T? { - if !isEmpty { - let element = array[readIndex % array.count] - readIndex += 1 - return element - } else { - return nil + guard !isEmpty else { return nil } + defer { + array[wrapped: readIndex] = nil + readIndex += 1 } + return array[wrapped: readIndex] } - 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 } @@ -46,6 +47,30 @@ public struct RingBuffer { } } +extension RingBuffer: Sequence { + public func makeIterator() -> AnyIterator { + var index = readIndex + return AnyIterator { + guard index < self.writeIndex else { return nil } + defer { + index += 1 + } + return self.array[wrapped: index] + } + } +} + +private extension Array { + subscript (wrapped index: Int) -> Element { + get { + return self[index % count] + } + set { + self[index % count] = newValue + } + } +} + var buffer = RingBuffer(count: 5) buffer.array // [nil, nil, nil, nil, nil] buffer.readIndex // 0 diff --git a/Ring Buffer/RingBuffer.playground/playground.xcworkspace/contents.xcworkspacedata b/Ring Buffer/RingBuffer.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Ring Buffer/RingBuffer.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 @@ - - - - - diff --git a/Ring Buffer/RingBuffer.swift b/Ring Buffer/RingBuffer.swift index 3176ab1fc..0006afea6 100644 --- a/Ring Buffer/RingBuffer.swift +++ b/Ring Buffer/RingBuffer.swift @@ -14,46 +14,69 @@ public struct RingBuffer { private var array: [T?] private var readIndex = 0 private 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 { - if !isFull { - array[writeIndex % array.count] = element - writeIndex += 1 - return true - } else { - return false + @discardableResult + public mutating func write(_ element: T) -> Bool { + guard !isFull else { return false } + defer { + writeIndex += 1 } + array[wrapped: writeIndex] = element + return true } - + /* Returns nil if the buffer is empty. */ public mutating func read() -> T? { - if !isEmpty { - let element = array[readIndex % array.count] - readIndex += 1 - return element - } else { - return nil + guard !isEmpty else { return nil } + defer { + array[wrapped: readIndex] = nil + readIndex += 1 } + return array[wrapped: readIndex] } - + private var availableSpaceForReading: Int { return writeIndex - readIndex } - + public var isEmpty: Bool { return availableSpaceForReading == 0 } - + private var availableSpaceForWriting: Int { return array.count - availableSpaceForReading } - + public var isFull: Bool { return availableSpaceForWriting == 0 } -} \ No newline at end of file +} + +public extension RingBuffer: Sequence { + public func makeIterator() -> AnyIterator { + var index = readIndex + return AnyIterator { + guard index < self.writeIndex else { return nil } + defer { + index += 1 + } + return self.array[wrapped: index] + } + } +} + +private extension Array { + subscript (wrapped index: Int) -> Element { + get { + return self[index % count] + } + set { + self[index % count] = newValue + } + } +} diff --git a/Rootish Array Stack/README.md b/Rootish Array Stack/README.md new file mode 100644 index 000000000..6a45b262a --- /dev/null +++ b/Rootish Array Stack/README.md @@ -0,0 +1,243 @@ +# 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 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 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 +``` +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..._ + +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. _5 rows and 6 columns_. + +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) +``` +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 +``` +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! +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 +``` +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 +``` +This can be rewritten as: +``` +(block)^2 + (3 * block) - (2 * index) >= 0 +``` +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. 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 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⌉ +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) + +### 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 +Let's start with instance variables and struct declaration: +```swift +import Darwin + +public struct RootishArrayStack { + + fileprivate var blocks = [Array]() + fileprivate var internalCount = 0 + + public init() { } + + 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 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 +var capacity: Int { + return blocks.count * (blocks.count + 1) / 2 +} +``` + +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)) + 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 = 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 + } +} +``` +`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, let's look at how we would `growIfNeeded()` and `shrinkIfNeeded()`. +```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 { + 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. +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)` 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. + +* `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(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 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)**. + + +_Written for Swift Algorithm Club by @BenEmdon_ + +_With help from [OpenDataStructures.org](http://opendatastructures.org)_ diff --git a/Rootish Array Stack/RootishArrayStack.playground/Contents.swift b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift new file mode 100644 index 000000000..ade32a3e7 --- /dev/null +++ b/Rootish Array Stack/RootishArrayStack.playground/Contents.swift @@ -0,0 +1,222 @@ +//: Playground - noun: a place where people can play + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +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.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/RootishArrayStack.swift b/Rootish Array Stack/RootishArrayStack.swift new file mode 100644 index 000000000..af95a4316 --- /dev/null +++ b/Rootish Array Stack/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.. + + + + 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..) -> Bool { + for index in 0.. RootishArrayStack { + var list = RootishArrayStack() + + if let numbers = numbers { + for number in numbers { + list.append(element: number) + } + } + return list + } + + 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 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 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 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)) + } + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } +} 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..bbc3967e5 --- /dev/null +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*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 = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; + }; + }; + }; + 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_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 = 4.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 = 4.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..dfcf6de42 --- /dev/null +++ b/Rootish Array Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Rootish Array Stack/images/RootishArrayStackExample.png b/Rootish Array Stack/images/RootishArrayStackExample.png new file mode 100644 index 000000000..4e5e3e77b Binary files /dev/null and b/Rootish Array Stack/images/RootishArrayStackExample.png differ diff --git a/Rootish Array Stack/images/RootishArrayStackExample2.png b/Rootish Array Stack/images/RootishArrayStackExample2.png new file mode 100644 index 000000000..d032833bc Binary files /dev/null and b/Rootish Array Stack/images/RootishArrayStackExample2.png differ diff --git a/Rootish Array Stack/images/RootishArrayStackIntro.png b/Rootish Array Stack/images/RootishArrayStackIntro.png new file mode 100644 index 000000000..74802e4ba Binary files /dev/null and b/Rootish Array Stack/images/RootishArrayStackIntro.png differ diff --git a/Run-Length Encoding/README.markdown b/Run-Length Encoding/README.markdown new file mode 100644 index 000000000..b29a49dd1 --- /dev/null +++ b/Run-Length Encoding/README.markdown @@ -0,0 +1,143 @@ +# Run-Length Encoding (RLE) + +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 `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: + +- Each byte run, i.e. when a certain byte value occurs more than once in a row, is compressed using two bytes: the first byte records the number of repetitions, the second records the actual value. The first byte is stored as: `191 + count`. This means encoded byte runs can never be more than 64 bytes long. + +- A single byte in the range 0 - 191 is not compressed and is copied without change. + +- 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 `Data` object containing the run-length encoded bytes: + +```swift +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 + } + } +``` + +How it works: + +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. + +3. Here, we have to decide how to encode the bytes we just read. The first possibility is that we've read a run of 2 or more bytes (up to 64). In that case we write out two bytes: the length of the run followed by the byte value. But it's also possible we've read a single byte with a value >= 192. That will also be encoded with two bytes. + +4. The third possibility is that we've read a single byte < 192. That simply gets copied to the output verbatim. + +You can test it like this in a playground: + +```swift +let originalString = "aaaaabbbcdeeeeeeef" +let utf8 = originalString.data(using: String.Encoding.utf8)! +let compressed = utf8.compressRLE() +``` + +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". + c2 The next byte appears 3 times. + 62 The data byte "b". + 63 The data byte "c". Because this is < 192, it's a single data byte. + 64 The data byte "d". Also appears just once. + c6 The next byte will appear 7 times. + 65 The data byte "e". + 66 The data byte "f". Appears just once. + +So that's 9 bytes encoded versus 18 original. That's a savings of 50%. Of course, this was only a simple test case... If you get unlucky and there are no byte runs at all in your original data, then this method will actually make the encoded data twice as large! So it really depends on the input data. + +Here is the decompression code: + +```swift +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 + } + +``` + +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. + +3. But if the byte is the start of a run, we have to first read the actual data value and then write it out repeatedly. + +To turn the compressed data back into the original, you'd do: + +```swift +let decompressed = compressed.decompressRLE() +let restoredString = String(data: decompressed, encoding: NSUTF8StringEncoding) +``` + +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. + +*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 new file mode 100644 index 000000000..8d6a0a403 --- /dev/null +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -0,0 +1,116 @@ +//: Playground - noun: a place where people can play + +import Foundation + +let originalString = "aaaaabbbcdeeeeeeef" +let utf8 = originalString.data(using: String.Encoding.utf8)! +let compressed = utf8.compressRLE() + +let decompressed = compressed.decompressRLE() +let restoredString = String(data: decompressed, encoding: String.Encoding.utf8) +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 +} + +func testEmpty() -> Bool { + let bytes: [UInt8] = [] + return encodeAndDecode(bytes) +} + +func testOneByteWithLowValue() -> Bool { + let bytes: [UInt8] = [0x80] + return encodeAndDecode(bytes) +} + +func testOneByteWithHighValue() -> Bool { + let bytes: [UInt8] = [0xD0] + return encodeAndDecode(bytes) +} + +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) +} + +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) +} + +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 +} + +runTests() 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..0bb6fa00d --- /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.playground/contents.xcplayground b/Run-Length Encoding/RLE.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Run-Length Encoding/RLE.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Run-Length Encoding/RLE.playground/playground.xcworkspace/contents.xcworkspacedata b/Run-Length Encoding/RLE.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Run-Length Encoding/RLE.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Segment Tree/LazyPropagation/Images/Segment-tree.png b/Segment Tree/LazyPropagation/Images/Segment-tree.png new file mode 100644 index 000000000..283bcca5d Binary files /dev/null and b/Segment Tree/LazyPropagation/Images/Segment-tree.png differ diff --git a/Segment Tree/LazyPropagation/Images/lazy-sample-2.png b/Segment Tree/LazyPropagation/Images/lazy-sample-2.png new file mode 100644 index 000000000..f8105fbc6 Binary files /dev/null and b/Segment Tree/LazyPropagation/Images/lazy-sample-2.png differ diff --git a/Segment Tree/LazyPropagation/Images/pushUp.png b/Segment Tree/LazyPropagation/Images/pushUp.png new file mode 100644 index 000000000..ae868037f Binary files /dev/null and b/Segment Tree/LazyPropagation/Images/pushUp.png differ diff --git a/Segment Tree/LazyPropagation/Images/pushdown.png b/Segment Tree/LazyPropagation/Images/pushdown.png new file mode 100644 index 000000000..0c763c782 Binary files /dev/null and b/Segment Tree/LazyPropagation/Images/pushdown.png differ diff --git a/Segment Tree/LazyPropagation/LazyPropagation.playground/Contents.swift b/Segment Tree/LazyPropagation/LazyPropagation.playground/Contents.swift new file mode 100644 index 000000000..38dd51859 --- /dev/null +++ b/Segment Tree/LazyPropagation/LazyPropagation.playground/Contents.swift @@ -0,0 +1,129 @@ +public class LazySegmentTree { + + private var value: Int + + private var leftBound: Int + + private var rightBound: Int + + private var leftChild: LazySegmentTree? + + private var rightChild: LazySegmentTree? + + // Interval Update Lazy Element + private var lazyValue: Int + + // MARK: - Push Up Operation + // Description: pushUp() - update items to the top + private func pushUp(lson: LazySegmentTree, rson: LazySegmentTree) { + self.value = lson.value + rson.value + } + + // MARK: - Push Down Operation + // Description: pushDown() - update items to the bottom + private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) { + guard lazyValue != 0 else { return } + lson.lazyValue += lazyValue + rson.lazyValue += lazyValue + lson.value += lazyValue * (round - (round >> 1)) + rson.value += lazyValue * (round >> 1) + lazyValue = 0 + } + + public init(array: [Int], leftBound: Int, rightBound: Int) { + self.leftBound = leftBound + self.rightBound = rightBound + self.value = 0 + self.lazyValue = 0 + + guard leftBound != rightBound else { + value = array[leftBound] + return + } + + let middle = leftBound + (rightBound - leftBound) / 2 + leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle) + rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound) + if let leftChild = leftChild, let rightChild = rightChild { + pushUp(lson: leftChild, rson: rightChild) + } + } + + public convenience init(array: [Int]) { + self.init(array: array, leftBound: 0, rightBound: array.count - 1) + } + + public func query(leftBound: Int, rightBound: Int) -> Int { + if leftBound <= self.leftBound && self.rightBound <= rightBound { + return value + } + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild) + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + var result = 0 + + if leftBound <= middle { result += leftChild.query(leftBound: leftBound, rightBound: rightBound) } + if rightBound > middle { result += rightChild.query(leftBound: leftBound, rightBound: rightBound) } + + return result + } + + // MARK: - One Item Update + public func update(index: Int, incremental: Int) { + guard self.leftBound != self.rightBound else { + self.value += incremental + return + } + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + + if index <= middle { leftChild.update(index: index, incremental: incremental) } + else { rightChild.update(index: index, incremental: incremental) } + pushUp(lson: leftChild, rson: rightChild) + } + + // MARK: - Interval Item Update + public func update(leftBound: Int, rightBound: Int, incremental: Int) { + if leftBound <= self.leftBound && self.rightBound <= rightBound { + self.lazyValue += incremental + self.value += incremental * (self.rightBound - self.leftBound + 1) + return + } + + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild) + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + + if leftBound <= middle { leftChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) } + if middle < rightBound { rightChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) } + + pushUp(lson: leftChild, rson: rightChild) + } + +} + +let array = [1, 2, 3, 4, 1, 3, 2] + +let sumSegmentTree = LazySegmentTree(array: array) + +print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 10 = 1 + 2 + 3 + 4 +sumSegmentTree.update(index: 1, incremental: 2) +print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 12 = 1 + 4 + 3 + 4 +sumSegmentTree.update(leftBound: 0, rightBound: 2, incremental: 2) +print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 18 = 3 + 6 + 5 + 4 + +for index in 2 ... 5 { + sumSegmentTree.update(index: index, incremental: 3) +} + + +sumSegmentTree.update(leftBound: 0, rightBound: 5, incremental: 2) +print(sumSegmentTree.query(leftBound: 0, rightBound: 2)) \ No newline at end of file diff --git a/Segment Tree/LazyPropagation/LazyPropagation.playground/contents.xcplayground b/Segment Tree/LazyPropagation/LazyPropagation.playground/contents.xcplayground new file mode 100644 index 000000000..16f9952aa --- /dev/null +++ b/Segment Tree/LazyPropagation/LazyPropagation.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Segment Tree/LazyPropagation/LazyPropagation.playground/playground.xcworkspace/contents.xcworkspacedata b/Segment Tree/LazyPropagation/LazyPropagation.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Segment Tree/LazyPropagation/LazyPropagation.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Segment Tree/LazyPropagation/README.markdown b/Segment Tree/LazyPropagation/README.markdown new file mode 100644 index 000000000..c625a7dc8 --- /dev/null +++ b/Segment Tree/LazyPropagation/README.markdown @@ -0,0 +1,306 @@ +# Lazy Propagation in Segment Tree + +In previous implement about the Segment Tree by **Artur Antonov**, it's a strong data structure with *Generic* ``. And we can pass a closure parameter `function: (T, T) -> T` to reflect the relationship between parent and child node. And in particular, Generic can solve multiple strings stitching problem. It's just like the sample in Playground: + +```swift +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.query(leftBound: 0, rightBound: 5)) +// "I like algorithms and swift!" +``` + +The use of `` is so exciting. But we seldom use the Segment Tree to solve string problem instead of *Suffix Array*. And the Segment Tree is a kind of *Interval Tree* to solve the Interval Problem in mathemtics and statistics, which is a structure for storing intervals, or segments, and allows querying which of the stored segments contain a given point. A segment tree for a set *I* of n intervals uses `O(nlogn)` storage and can be built in `O(nlogn)` time. Segment trees support searching for all the intervals that contain a query point in O(log n+k), k being the number of retrieved intervals or segments. + +But that is common Segment Tree. By **Lazy Propagation**, we can implement to modify an interval in `O(logn)` time. Let's explore together in following: + +## `PushUp` - update to the top + +At first, we reference the implement of **Artur Antonov** about Segment Tree. This code contained *build*, *single update* and *interval query* three operation. The implement of *build* and *single update* operation is following: + +```swift +// Author: Artur Antonov +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) + } +} +``` + +In position ①, it means the current node is *leaf* because its left bound data is equal to the right. So we assign a value to it directly. In position ②, it means the current node is *parent* (which has one or more children), and we need to recursion down and update current node's data in the follow-up process. + +And then, we have a look for *interval query* operation: + +```swift +// Author: Artur Antonov +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 { + return leftChild.query(leftBound: leftBound, rightBound: rightBound) + } + // ③ + else { + let leftResult = leftChild.query(leftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(leftBound:rightChild.leftBound, rightBound: rightBound) + return function(leftResult, rightResult) + } +} +``` + +Position ① means that the left bound of current query interval is on the right of this right bound, so recurs to right direction. Position ② is opposite of position ①, recurs to left direction. Position ③ means our check interval is included the interval we need, so recurs deeply. + +![pushUp](Images/pushUp.png) + +There are common part from the two parts of code above - **recurs deeply below, and update data up**. So we can decouple this operation named `func pushUp(lson: LazySegmentTree, rson: LazySegmentTree)`: + +```swift +// MARK: - Push Up Operation +private func pushUp(lson: LazySegmentTree, rson: LazySegmentTree) { + self.value = lson.value + rson.value +} +``` + +(This code only describe the *Sum Segment Tree*) + +And then, we can update the implement before: + +```swift +public init(array: [Int], leftBound: Int, rightBound: Int) { + self.leftBound = leftBound + self.rightBound = rightBound + self.value = 0 + self.lazyValue = 0 + + guard leftBound != rightBound else { + value = array[leftBound] + return + } + + let middle = leftBound + (rightBound - leftBound) / 2 + leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle) + rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound) + if let leftChild = leftChild, let rightChild = rightChild { + pushUp(lson: leftChild, rson: rightChild) + } +} +// MARK: - One Item Update +public func update(index: Int, incremental: Int) { + guard self.leftBound != self.rightBound else { + self.value += incremental + return + } + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + + if index <= middle { leftChild.update(index: index, incremental: incremental) } + else { rightChild.update(index: index, incremental: incremental) } + pushUp(lson: leftChild, rson: rightChild) +} +``` + +## `PushDown` - Lazy Propagation + +You may feel that the `pushUp` is so simple. In fact, this's just to lead `pushDown` this function. + +Before this, I want to talk about the topic about **interval operation**. The interval operation is a way to update all elements of a continuous subset. But these isn't in the version of **Artur Antonov**. You might disdain with this, because it's solved with a `for` loop: + +```swift +// Sample: update the elements with subscript [2, 5] +for index in 2 ... 5 { + sumSegmentTree.update(index: index, incremental: 3) +} +``` + +It is a `O(n)` time operation, which make the interval operation uses `O(nlogn)` time to update these elements. We need a `O(logn)` way to maintain the elegance of Segment Tree. + + Check the data structure of Segment Tree again: + + ![Segment-tree](Images/Segment-tree.png) + +We only catch the root node in programming. If we want to explore the bottom of the tree, and use `pushUp` to update every node, the task will be reached. So it asked us to traverse the tree, that spent `O(n)` time to do this with any way. This can't conform our expectations. + +Then we started to think about `pushDown` to update down from the root. **After we update the parent, the data continued to distributed to its children according to law.** But it still need `O(n)` time to do this. Keep thinking, we **only update the parent, and to update the children when `query` time**. Yeah, that's the key of **lazy propagation**. Because the recursing direct of the `query` and `update interval` is same. So we got it! 😁 Let's check this sample: + +![lazy-sample-2](Images/lazy-sample-2.png) + +`update` make the subscript 1...3 elements plus 2, so we make the 1st node in 2 depth and 3rd in 3 depth get a *lazy mark*, which means these node need to be updated. And we shouldn't add a *lazy mark* for root node, because it was updated before the `pushDown` in the first recursing. + +In `query` operation, we accord to the original method to recurs the tree, and find the 1st node held *lazy mark* in 2 depth, so to update it. It's the same situation about the 1st node in 3 depth. + +Do you understand the **lazy propagation**? **In short, we only update the wide range node data and add it a lazy mark. Then they will be update when we need to query them.** And the *Update Down* operation is the function of `pushDown`. + +This is the complete implementation about the Sum Segment Tree with interval update operation: + +```swift +public class LazySegmentTree { + + private var value: Int + + private var leftBound: Int + + private var rightBound: Int + + private var leftChild: LazySegmentTree? + + private var rightChild: LazySegmentTree? + + // Interval Update Lazy Element + private var lazyValue: Int + + // MARK: - Push Up Operation + // Description: pushUp() - update items to the top + private func pushUp(lson: LazySegmentTree, rson: LazySegmentTree) { + self.value = lson.value + rson.value + } + + // MARK: - Push Down Operation + // Description: pushDown() - update items to the bottom + private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) { + guard lazyValue != 0 else { return } + lson.lazyValue += lazyValue + rson.lazyValue += lazyValue + lson.value += lazyValue * (round - (round >> 1)) + rson.value += lazyValue * (round >> 1) + lazyValue = 0 + } + + public init(array: [Int], leftBound: Int, rightBound: Int) { + self.leftBound = leftBound + self.rightBound = rightBound + self.value = 0 + self.lazyValue = 0 + + guard leftBound != rightBound else { + value = array[leftBound] + return + } + + let middle = leftBound + (rightBound - leftBound) / 2 + leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle) + rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound) + if let leftChild = leftChild, let rightChild = rightChild { + pushUp(lson: leftChild, rson: rightChild) + } + } + + public convenience init(array: [Int]) { + self.init(array: array, leftBound: 0, rightBound: array.count - 1) + } + + public func query(leftBound: Int, rightBound: Int) -> Int { + if leftBound <= self.leftBound && self.rightBound <= rightBound { + return value + } + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild) + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + var result = 0 + + if leftBound <= middle { result += leftChild.query(leftBound: leftBound, rightBound: rightBound) } + if rightBound > middle { result += rightChild.query(leftBound: leftBound, rightBound: rightBound) } + + return result + } + + // MARK: - One Item Update + public func update(index: Int, incremental: Int) { + guard self.leftBound != self.rightBound else { + self.value += incremental + return + } + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + + if index <= middle { leftChild.update(index: index, incremental: incremental) } + else { rightChild.update(index: index, incremental: incremental) } + pushUp(lson: leftChild, rson: rightChild) + } + + // MARK: - Interval Item Update + public func update(leftBound: Int, rightBound: Int, incremental: Int) { + if leftBound <= self.leftBound && self.rightBound <= rightBound { + self.lazyValue += incremental + self.value += incremental * (self.rightBound - self.leftBound + 1) + return + } + + guard let leftChild = leftChild else { fatalError("leftChild should not be nil") } + guard let rightChild = rightChild else { fatalError("rightChild should not be nil") } + + pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild) + + let middle = self.leftBound + (self.rightBound - self.leftBound) / 2 + + if leftBound <= middle { leftChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) } + if middle < rightBound { rightChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) } + + pushUp(lson: leftChild, rson: rightChild) + } + +} +``` + +Explain some sample snippets: + +```swift +private var lazyValue: Int +``` + +Here we add a new property for Segment Tree to represent *lazy mark*. And it is a incremental value for Sum Segment Tree. If the `lazyValue` isn't equal to zero, the current node need to be updated. And its real value is equal to `value + lazyValue * (rightBound - leftBound + 1)`. + +```swift + // MARK: - Push Down Operation + // Description: pushDown() - update items to the bottom +private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) { + guard lazyValue != 0 else { return } + lson.lazyValue += lazyValue + rson.lazyValue += lazyValue + lson.value += lazyValue * (round - (round >> 1)) + rson.value += lazyValue * (round >> 1) + lazyValue = 0 +} +``` + +![pushdown](Images/pushdown.png) + +At first we check whether the node needs to be updated. If the `lazyValue` isn't equal to zero, we need to `pushDown`. And the update rules are the `lazyValue * (rightBound - leftBound + 1)`. At last, reset the `lazyValue` to zero. + +## Conclusion + +This is the introduce of the Lazy Propagation in Segment Tree. You can also learn **Functional Segment Tree** to understand the Lazy Propagation deeply. In addition, I learn from the *notonlysuccess*'s code about Segment Tree described by C, this is the [link](http://www.cnblogs.com/Destiny-Gem/articles/3875243.html). + +In fact, the operation of Segment Tree is far more than that. It can also be used to handle problems between collections. I want to implement it with Swift in the future and make the Swift Segment Tree stronger and stronger. 😁 + +--- + +*Written for Swift Algorithm Club by [Desgard_Duan](https://github.com/desgard)* diff --git a/Segment Tree/README.markdown b/Segment Tree/README.markdown index fb9b6aaa1..99ec85cd8 100644 --- a/Segment Tree/README.markdown +++ b/Segment Tree/README.markdown @@ -1,14 +1,28 @@ # Segment Tree +> For an example on lazy propagation, see this [article](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation). + I'm pleased to present to you Segment Tree. It's actually one of my favorite data structures because it's very flexible and simple in realization. Let's suppose that you have an array **a** of some type and some associative function **f**. For example, the function can be sum, multiplication, min, max, [gcd](../GCD/), and so on. -Your task is: +Your task is to: - answer a query for an interval given by **l** and **r**, i.e. perform `f(a[l], a[l+1], ..., a[r-1], a[r])` - support replacing an item at some index `a[index] = newItem` +For example, if we have an array of numbers: + +```swift +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: ```swift @@ -21,7 +35,7 @@ func query(array: [Int], l: Int, r: Int) -> Int { } ``` -The running time of this algorithm is **O(n)** in the worst case, that is when **l = 0, r = n-1**. And if we have **m** queries to answer we get **O(m*n)** complexity. +The running time of this algorithm is **O(n)** in the worst case, that is when **l = 0, r = n-1** (where **n** is the number of elements in the array). And if we have **m** queries to answer we get **O(m*n)** complexity. If we have an array with 100,000 items (**n = 10^5**) and we have to do 100 queries (**m = 100**), then our algorithm will do **10^7** units of work. Ouch, that doesn't sound very good. Let's look at how we can improve it. @@ -31,7 +45,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 { @@ -48,7 +62,7 @@ Each node has the following data: - `leftBound` and `rightBound` describe an interval - `leftChild` and `rightChild` are pointers to child nodes -- `value` is actually the application of the function `f(a[leftBound], a[leftBound+1], ..., a[rightBound-1], a[rightBound])` +- `value` is the result of applying the function `f(a[leftBound], a[leftBound+1], ..., a[rightBound-1], a[rightBound])` If our array is `[1, 2, 3, 4]` and the function `f = a + b`, the segment tree looks like this: @@ -61,7 +75,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 @@ -80,11 +94,11 @@ public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) } ``` -Notice that this is a recursive method! You give it an array, such as `[1, 2, 3, 4]` and it creates the root node of the tree and all the child nodes as well. +Notice that this is a recursive method. You give it an array such as `[1, 2, 3, 4]` and it builds up the entire tree, from the root node to all the child nodes. -1. The recursion terminates if `leftBound` and `rightBound` are equal. That means this `SegmentTree` instance will represent a leaf node. For the input array `[1, 2, 3, 4]`, it will create four such leaf nodes: `1`, `2`, `3`, and `4`. We just fill in the `value` property with the number from the array. +1. The recursion terminates if `leftBound` and `rightBound` are equal. Such a `SegmentTree` instance represents a leaf node. For the input array `[1, 2, 3, 4]`, this process will create four such leaf nodes: `1`, `2`, `3`, and `4`. We just fill in the `value` property with the number from the array. -2. However, if `rightBound` is still greater than `leftBound`, we create two child nodes. We divide the current segment into two equal (if length is even) segments. +2. However, if `rightBound` is still greater than `leftBound`, we create two child nodes. We divide the current segment into two equal segments (at least, if the length is even; if it's odd, one segment will be slightly larger). 3. Recursively build child nodes for those two segments. The left child node covers the interval **[leftBound, middle]** and the right child node covers **[middle+1, rightBound]**. @@ -99,27 +113,27 @@ 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 } - + 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.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) } } @@ -143,17 +157,17 @@ Again, this is a recursive method. It checks four different possibilities. ![mixedSegment](Images/MixedSegment.png) -For example, this is how you could test it out in a playground: +This is how you can test it out in a playground: ```swift 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. @@ -165,21 +179,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. @@ -187,6 +201,8 @@ See the playground for more examples of how to use the segment tree. ## See also +[Lazy Propagation](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation) implementation and explanation. + [Segment tree at PEGWiki](http://wcipeg.com/wiki/Segment_tree) *Written for Swift Algorithm Club by [Artur Antonov](https://github.com/goingreen)* diff --git a/Segment Tree/SegmentTree.playground/Contents.swift b/Segment Tree/SegmentTree.playground/Contents.swift index e74591e56..25116c285 100644 --- a/Segment Tree/SegmentTree.playground/Contents.swift +++ b/Segment Tree/SegmentTree.playground/Contents.swift @@ -1,140 +1,138 @@ //: 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) - } - } -} - +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif +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 { + 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(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 { + return leftChild.query(leftBound: leftBound, rightBound: rightBound) + } else { + let leftResult = leftChild.query(leftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(leftBound: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) + } + } +} 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(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.replaceItemAtIndex(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 +sumSegmentTree.replaceItem(at: 0, withItem: 2) //our array now is [2, 2, 3, 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 -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 - -gcdSegmentTree.replaceItemAtIndex(3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5] +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 -print(gcdSegmentTree.queryWithLeftBound(3, rightBound: 4)) // gcd(10, 5) = 5 +gcdSegmentTree.replaceItem(at: 3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5] +print(gcdSegmentTree.query(leftBound: 3, rightBound: 4)) // gcd(10, 5) = 5 //example of segment tree which finds minimum on given range 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(leftBound: 0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1 +print(minSegmentTree.query(leftBound: 0, rightBound: 1)) // min(2, 4) = 2 -minSegmentTree.replaceItemAtIndex(2, withItem: 10) // minArray now is [2, 4, 10, 5, 3] - -print(minSegmentTree.queryWithLeftBound(0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2 +minSegmentTree.replaceItem(at: 2, withItem: 10) // minArray now is [2, 4, 10, 5, 3] +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 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" - -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: "!") +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" -print(stringSegmentTree.queryWithLeftBound(0, rightBound: 5)) +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.query(leftBound: 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/playground.xcworkspace/contents.xcworkspacedata b/Segment Tree/SegmentTree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Segment Tree/SegmentTree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 e616255ec..6f4edd306 100644 --- a/Segment Tree/SegmentTree.swift +++ b/Segment Tree/SegmentTree.swift @@ -1,6 +1,6 @@ /* Segment tree - + Performance: building the tree is O(n) query is O(log n) @@ -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) - } - } + 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(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 { + return leftChild.query(leftBound: leftBound, rightBound: rightBound) + } else { + let leftResult = leftChild.query(leftBound: leftBound, rightBound: leftChild.rightBound) + let rightResult = rightChild.query(leftBound: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) - } - } + 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) + } + } } diff --git a/Select Minimum Maximum/Maximum.swift b/Select Minimum Maximum/Maximum.swift index eb0204b0e..82b76fd73 100644 --- a/Select Minimum Maximum/Maximum.swift +++ b/Select Minimum Maximum/Maximum.swift @@ -1,15 +1,12 @@ /* - 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 - } - - var maximum = array.removeFirst() - for element in array { - maximum = element > maximum ? element : maximum - } - return maximum +func maximum(_ array: [T]) -> T? { + guard var maximum = array.first else { return nil } + + for element in array.dropFirst() { + maximum = element > maximum ? element : maximum + } + return maximum } diff --git a/Select Minimum Maximum/Minimum.swift b/Select Minimum Maximum/Minimum.swift index 9b08deb4f..75ecfc3b1 100644 --- a/Select Minimum Maximum/Minimum.swift +++ b/Select Minimum Maximum/Minimum.swift @@ -1,15 +1,12 @@ /* - 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 - } - - var minimum = array.removeFirst() - for element in array { - minimum = element < minimum ? element : minimum - } - return minimum +func minimum(_ array: [T]) -> T? { + guard var minimum = array.first else { return nil } + + for element in array.dropFirst() { + minimum = element < minimum ? element : minimum + } + return minimum } diff --git a/Select Minimum Maximum/MinimumMaximumPairs.swift b/Select Minimum Maximum/MinimumMaximumPairs.swift index 537210058..a19b037d1 100644 --- a/Select Minimum Maximum/MinimumMaximumPairs.swift +++ b/Select Minimum Maximum/MinimumMaximumPairs.swift @@ -1,40 +1,32 @@ /* - 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)? { + guard var minimum = array.first else { return nil } + var maximum = minimum - 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 start = array.count % 2 // 1 if odd, skipping the first element + for i in stride(from: start, to: array.count, by: 2) { + let pair = (array[i], array[i+1]) - 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 - } + 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 5d7c11731..c55272c63 100644 --- a/Select Minimum Maximum/README.markdown +++ b/Select Minimum Maximum/README.markdown @@ -2,46 +2,44 @@ Goal: Find the minimum/maximum object in an unsorted array. -### Maximum or minimum +## Maximum or minimum We have an array of generic objects and we iterate over all the objects keeping track of the minimum/maximum element so far. -#### An example +### An example Let's say the we want to find the maximum value in the unsorted list `[ 8, 3, 9, 4, 6 ]`. Pick the first number, `8`, and store it as the maximum element so far. -Pick the next number from the list, `3`, and compare it to the current maximum `8`. `3` is less than `8` so the maximum `8` does not change. +Pick the next number from the list, `3`, and compare it to the current maximum. `3` is less than `8` so the maximum `8` does not change. -Pick the next number from the list, `9`, and compare it to the current maximum `8`. `9` is greater than `8` so we store `9` as the maximum. +Pick the next number from the list, `9`, and compare it to the current maximum. `9` is greater than `8` so we store `9` as the maximum. Repeat this process until the all elements in the list have been processed. -#### The code +### The code Here is a simple implementation in Swift: ```swift -func minimum(var array: [T]) -> T? { - guard !array.isEmpty else { +func minimum(_ array: [T]) -> T? { + guard var minimum = array.first else { return nil } - var minimum = array.removeFirst() - for element in array { + for element in array.dropFirst() { minimum = element < minimum ? element : minimum } return minimum } -func maximum(var array: [T]) -> T? { - guard !array.isEmpty else { +func maximum(_ array: [T]) -> T? { + guard var maximum = array.first else { return nil } - var maximum = array.removeFirst() - for element in array { + for element in array.dropFirst() { maximum = element > maximum ? element : maximum } return maximum @@ -52,49 +50,60 @@ Put this code in a playground and test it like so: ```swift let array = [ 8, 3, 9, 4, 6 ] -minimum(array) // This will return 3 -maximum(array) // This will return 9 +minimum(array) // This will return 3 +maximum(array) // This will return 9 ``` -### Maximum and minimum +### In the Swift standard library + +The Swift library already contains an extension to `SequenceType` that returns the minimum/maximum element in a sequence. + +```swift +let array = [ 8, 3, 9, 4, 6 ] +array.minElement() // This will return 3 +array.maxElement() // This will return 9 +``` + +```swift +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. -#### An example +### An example -Let's say the we want to find the minimum and maximum value in the unsorted list `[ 8, 3, 9, 4, 6 ]`. +Let's say the we want to find the minimum and maximum value in the unsorted list `[ 8, 3, 9, 6, 4 ]`. Pick the first number, `8`, and store it as the minimum and maximum element so far. -Because we have an odd number of items we remove `8` from the list which leaves the pairs `[ 3, 9 ]` and `[ 4, 6 ]`. +Because we have an odd number of items we remove `8` from the list which leaves the pairs `[ 3, 9 ]` and `[ 6, 4 ]`. -Pick the next pair of numbers from the list, `[ 3, 9 ]`, `3` is less than `9` so we compare `3` to the current minimum `8` and `9` to the current maximum `8`. `3` is less than `8` so the new minimum is `3`. `9` is greater than `8` so the new maximum is `9`. +Pick the next pair of numbers from the list, `[ 3, 9 ]`. Of these two numbers, `3` is the smaller one, so we compare `3` to the current minimum `8`, and we compare `9` to the current maximum `8`. `3` is less than `8` so the new minimum is `3`. `9` is greater than `8` so the new maximum is `9`. -Pick the next pair of numbers from the list, `[ 4, 6 ]`, `4` is less than `6` so we compare `4` to the current minimum `3` and `6` to the current maximum `9`. `4` is greater than `3` so the minimum does not change. `6` is less than `9` so the maximum does not change. +Pick the next pair of numbers from the list, `[ 6, 4 ]`. Here, `4` is the smaller one, so we compare `4` to the current minimum `3`, and we compare `6` to the current maximum `9`. `4` is greater than `3` so the minimum does not change. `6` is less than `9` so the maximum does not change. The result is a minimum of `3` and a maximum of `9`. -#### The code +### The code Here is a simple implementation in Swift: ```swift -func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? -{ - guard !array.isEmpty else { +func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { + guard var minimum = array.first else { return nil } + var maximum = minimum - 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 'array' has an odd number of items, let 'minimum' or 'maximum' deal with the leftover + let start = array.count % 2 // 1 if odd, skipping the first element + 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 { @@ -120,26 +129,15 @@ func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? Put this code in a playground and test it like so: ```swift - let result = minimumMaximum(array)! -result.minimum // This will return 3 -result.maximum // This will return 9 +result.minimum // This will return 3 +result.maximum // This will return 9 ``` By picking elements in pairs and comparing their maximum and minimum with the running minimum and maximum we reduce the number of comparisons to 3 for every 2 elements. -### Performance +## Performance These algorithms run at **O(n)**. Each object in the array is compared with the running minimum/maximum so the time it takes is proportional to the array length. -### Swift library - -The Swift library already contains an extension to `SequenceType` that returns the minimum/maximum element in a sequence. - -```swift -let array = [ 8, 3, 9, 4, 6 ] -array.minElement() // This will return 3 -array.maxElement() // This will return 9 -``` - *Written by [Chris Pilcher](https://github.com/chris-pilcher)* diff --git a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum.xcodeproj/project.pbxproj b/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum.xcodeproj/project.pbxproj deleted file mode 100644 index dc319937a..000000000 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum.xcodeproj/project.pbxproj +++ /dev/null @@ -1,393 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E0971C5BFA2E005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */; }; - 7B18E0A71C5BFA2E005A2B8E /* SelectMinimumMaximumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0A61C5BFA2E005A2B8E /* SelectMinimumMaximumTests.swift */; }; - 838A4FB41C64AED00092AA8F /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 838A4FB31C64AED00092AA8F /* TestHelper.swift */; }; - 83F3255D1C64A0E700EB0421 /* Maximum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F3255A1C64A0E700EB0421 /* Maximum.swift */; }; - 83F3255E1C64A0E700EB0421 /* Minimum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F3255B1C64A0E700EB0421 /* Minimum.swift */; }; - 83F3255F1C64A0E700EB0421 /* MinimumMaximumPairs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F3255C1C64A0E700EB0421 /* MinimumMaximumPairs.swift */; }; - 83F325611C64A3E000EB0421 /* MinimumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F325601C64A3E000EB0421 /* MinimumTests.swift */; }; - 83F325631C64A4D400EB0421 /* MaximumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F325621C64A4D400EB0421 /* MaximumTests.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E0A31C5BFA2E005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E08B1C5BFA2E005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E0921C5BFA2E005A2B8E; - remoteInfo = SelectMinimumMaximum; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E0931C5BFA2E005A2B8E /* SelectMinimumMaximum.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SelectMinimumMaximum.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E09D1C5BFA2E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0A21C5BFA2E005A2B8E /* SelectMinimumMaximumTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelectMinimumMaximumTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0A61C5BFA2E005A2B8E /* SelectMinimumMaximumTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectMinimumMaximumTests.swift; sourceTree = ""; }; - 7B18E0A81C5BFA2E005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 838A4FB31C64AED00092AA8F /* TestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelper.swift; sourceTree = ""; }; - 83F3255A1C64A0E700EB0421 /* Maximum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Maximum.swift; path = ../../Maximum.swift; sourceTree = ""; }; - 83F3255B1C64A0E700EB0421 /* Minimum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Minimum.swift; path = ../../Minimum.swift; sourceTree = ""; }; - 83F3255C1C64A0E700EB0421 /* MinimumMaximumPairs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MinimumMaximumPairs.swift; path = ../../MinimumMaximumPairs.swift; sourceTree = ""; }; - 83F325601C64A3E000EB0421 /* MinimumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimumTests.swift; sourceTree = ""; }; - 83F325621C64A4D400EB0421 /* MaximumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximumTests.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E0901C5BFA2E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E09F1C5BFA2E005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E08A1C5BFA2E005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E0951C5BFA2E005A2B8E /* SelectMinimumMaximum */, - 7B18E0A51C5BFA2E005A2B8E /* SelectMinimumMaximumTests */, - 7B18E0941C5BFA2E005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0941C5BFA2E005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E0931C5BFA2E005A2B8E /* SelectMinimumMaximum.app */, - 7B18E0A21C5BFA2E005A2B8E /* SelectMinimumMaximumTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E0951C5BFA2E005A2B8E /* SelectMinimumMaximum */ = { - isa = PBXGroup; - children = ( - 7B18E0961C5BFA2E005A2B8E /* AppDelegate.swift */, - 83F3255A1C64A0E700EB0421 /* Maximum.swift */, - 83F3255B1C64A0E700EB0421 /* Minimum.swift */, - 83F3255C1C64A0E700EB0421 /* MinimumMaximumPairs.swift */, - 7B18E09D1C5BFA2E005A2B8E /* Info.plist */, - ); - path = SelectMinimumMaximum; - sourceTree = ""; - }; - 7B18E0A51C5BFA2E005A2B8E /* SelectMinimumMaximumTests */ = { - isa = PBXGroup; - children = ( - 7B18E0A81C5BFA2E005A2B8E /* Info.plist */, - 7B18E0A61C5BFA2E005A2B8E /* SelectMinimumMaximumTests.swift */, - 83F325601C64A3E000EB0421 /* MinimumTests.swift */, - 83F325621C64A4D400EB0421 /* MaximumTests.swift */, - 838A4FB31C64AED00092AA8F /* TestHelper.swift */, - ); - path = SelectMinimumMaximumTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E0921C5BFA2E005A2B8E /* SelectMinimumMaximum */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0AB1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "SelectMinimumMaximum" */; - buildPhases = ( - 7B18E08F1C5BFA2E005A2B8E /* Sources */, - 7B18E0901C5BFA2E005A2B8E /* Frameworks */, - 7B18E0911C5BFA2E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SelectMinimumMaximum; - productName = SelectMinimumMaximum; - productReference = 7B18E0931C5BFA2E005A2B8E /* SelectMinimumMaximum.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E0A11C5BFA2E005A2B8E /* SelectMinimumMaximumTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0AE1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "SelectMinimumMaximumTests" */; - buildPhases = ( - 7B18E09E1C5BFA2E005A2B8E /* Sources */, - 7B18E09F1C5BFA2E005A2B8E /* Frameworks */, - 7B18E0A01C5BFA2E005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0A41C5BFA2E005A2B8E /* PBXTargetDependency */, - ); - name = SelectMinimumMaximumTests; - productName = SelectMinimumMaximumTests; - productReference = 7B18E0A21C5BFA2E005A2B8E /* SelectMinimumMaximumTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E08B1C5BFA2E005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E0921C5BFA2E005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E0A11C5BFA2E005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E0921C5BFA2E005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E08E1C5BFA2E005A2B8E /* Build configuration list for PBXProject "SelectMinimumMaximum" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E08A1C5BFA2E005A2B8E; - productRefGroup = 7B18E0941C5BFA2E005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E0921C5BFA2E005A2B8E /* SelectMinimumMaximum */, - 7B18E0A11C5BFA2E005A2B8E /* SelectMinimumMaximumTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E0911C5BFA2E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0A01C5BFA2E005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E08F1C5BFA2E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 83F3255E1C64A0E700EB0421 /* Minimum.swift in Sources */, - 83F3255F1C64A0E700EB0421 /* MinimumMaximumPairs.swift in Sources */, - 83F3255D1C64A0E700EB0421 /* Maximum.swift in Sources */, - 7B18E0971C5BFA2E005A2B8E /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E09E1C5BFA2E005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 83F325611C64A3E000EB0421 /* MinimumTests.swift in Sources */, - 83F325631C64A4D400EB0421 /* MaximumTests.swift in Sources */, - 7B18E0A71C5BFA2E005A2B8E /* SelectMinimumMaximumTests.swift in Sources */, - 838A4FB41C64AED00092AA8F /* TestHelper.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0A41C5BFA2E005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E0921C5BFA2E005A2B8E /* SelectMinimumMaximum */; - targetProxy = 7B18E0A31C5BFA2E005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 7B18E0A91C5BFA2E005A2B8E /* 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; - }; - 7B18E0AA1C5BFA2E005A2B8E /* 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; - }; - 7B18E0AC1C5BFA2E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectMinimumMaximum/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectMinimumMaximum; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0AD1C5BFA2E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectMinimumMaximum/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectMinimumMaximum; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0AF1C5BFA2E005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectMinimumMaximumTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectMinimumMaximumTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SelectMinimumMaximum.app/Contents/MacOS/SelectMinimumMaximum"; - }; - name = Debug; - }; - 7B18E0B01C5BFA2E005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectMinimumMaximumTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectMinimumMaximumTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SelectMinimumMaximum.app/Contents/MacOS/SelectMinimumMaximum"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E08E1C5BFA2E005A2B8E /* Build configuration list for PBXProject "SelectMinimumMaximum" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0A91C5BFA2E005A2B8E /* Debug */, - 7B18E0AA1C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0AB1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "SelectMinimumMaximum" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0AC1C5BFA2E005A2B8E /* Debug */, - 7B18E0AD1C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0AE1C5BFA2E005A2B8E /* Build configuration list for PBXNativeTarget "SelectMinimumMaximumTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0AF1C5BFA2E005A2B8E /* Debug */, - 7B18E0B01C5BFA2E005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E08B1C5BFA2E005A2B8E /* Project object */; -} diff --git a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/AppDelegate.swift b/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/AppDelegate.swift deleted file mode 100644 index 9c4f92293..000000000 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/AppDelegate.swift +++ /dev/null @@ -1,16 +0,0 @@ -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/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/TestHelper.swift b/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/TestHelper.swift deleted file mode 100644 index 7afe751d0..000000000 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/TestHelper.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -func createRandomList(numberOfElements: Int) -> [UInt32] { - return (1...numberOfElements).map{_ in arc4random()} -} diff --git a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift index 450b6624e..e1101a864 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/Contents.swift @@ -1,32 +1,34 @@ +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + // Compare each item to find minimum -func minimum(var array: [T]) -> T? { - guard !array.isEmpty else { +func minimum(_ array: [T]) -> T? { + guard var minimum = array.first else { return nil } - - var minimum = array.removeFirst() - for element in array { + + for element in array.dropFirst() { minimum = element < minimum ? element : minimum } return minimum } // Compare each item to find maximum -func maximum(var array: [T]) -> T? { - guard !array.isEmpty else { +func maximum(_ array: [T]) -> T? { + guard var maximum = array.first else { return nil } - - var maximum = array.removeFirst() - for element in array { + + for element in array.dropFirst() { maximum = element > maximum ? element : maximum } return maximum } // Compare in pairs to find minimum and maximum -func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? -{ +func minimumMaximum(_ array: [T]) -> (minimum: T, maximum: T)? { guard !array.isEmpty else { return nil } @@ -34,13 +36,10 @@ func minimumMaximum(var array: [T]) -> (minimum: T, maximum: T)? 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 'array' has an odd number of items, let 'minimum' or 'maximum' deal with the leftover + let start = array.count % 2 // 1 if odd, skipping the first element + 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 { @@ -73,5 +72,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/playground.xcworkspace/contents.xcworkspacedata b/Select Minimum Maximum/SelectMinimumMaximum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Select Minimum Maximum/SelectMinimumMaximum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 @@ - - - - - diff --git a/Select Minimum Maximum/Tests/Info.plist b/Select Minimum Maximum/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Select Minimum Maximum/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/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MaximumTests.swift b/Select Minimum Maximum/Tests/MaximumTests.swift similarity index 91% rename from Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MaximumTests.swift rename to Select Minimum Maximum/Tests/MaximumTests.swift index bd58187fc..4a956dbfb 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MaximumTests.swift +++ b/Select Minimum Maximum/Tests/MaximumTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import SelectMinimumMaximum class MaximumTests: XCTestCase { @@ -31,7 +30,7 @@ class MaximumTests: XCTestCase { let array = [ 9, 8, 6, 4, 3 ] let result = maximum(array) - + XCTAssertEqual(result, 9) } @@ -50,7 +49,7 @@ class MaximumTests: XCTestCase { let result = maximum(array) - XCTAssertEqual(result, array.maxElement()) + XCTAssertEqual(result, array.max()) } } } diff --git a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/SelectMinimumMaximumTests.swift b/Select Minimum Maximum/Tests/MinimumMaximumPairsTests.swift similarity index 89% rename from Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/SelectMinimumMaximumTests.swift rename to Select Minimum Maximum/Tests/MinimumMaximumPairsTests.swift index 330f0e902..4d2162617 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/SelectMinimumMaximumTests.swift +++ b/Select Minimum Maximum/Tests/MinimumMaximumPairsTests.swift @@ -1,7 +1,6 @@ import XCTest -@testable import SelectMinimumMaximum -class SelectMinimumMaximumTests: XCTestCase { +class MinimumMaximumPairsTests: XCTestCase { func testMinimumAndMaximumGivenAListContainingOneElement() { let array = [ 8 ] @@ -72,8 +71,8 @@ class SelectMinimumMaximumTests: XCTestCase { let result = minimumMaximum(array)! - XCTAssertEqual(result.minimum, array.minElement()) - XCTAssertEqual(result.maximum, array.maxElement()) + XCTAssertEqual(result.minimum, array.min()) + XCTAssertEqual(result.maximum, array.max()) } } } diff --git a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MinimumTests.swift b/Select Minimum Maximum/Tests/MinimumTests.swift similarity index 91% rename from Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MinimumTests.swift rename to Select Minimum Maximum/Tests/MinimumTests.swift index 235673320..c01d25fac 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximumTests/MinimumTests.swift +++ b/Select Minimum Maximum/Tests/MinimumTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import SelectMinimumMaximum class MinimumTests: XCTestCase { @@ -50,7 +49,7 @@ class MinimumTests: XCTestCase { let result = minimum(array) - XCTAssertEqual(result, array.minElement()) + XCTAssertEqual(result, array.min()) } } } diff --git a/Select Minimum Maximum/Tests/TestHelper.swift b/Select Minimum Maximum/Tests/TestHelper.swift new file mode 100644 index 000000000..062025a2b --- /dev/null +++ b/Select Minimum Maximum/Tests/TestHelper.swift @@ -0,0 +1,5 @@ +import Foundation + +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 new file mode 100644 index 000000000..fb70d6970 --- /dev/null +++ b/Select Minimum Maximum/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,289 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C40C1C77A768003CECC7 /* Maximum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4091C77A768003CECC7 /* Maximum.swift */; }; + 7B80C40D1C77A768003CECC7 /* Minimum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C40A1C77A768003CECC7 /* Minimum.swift */; }; + 7B80C40E1C77A768003CECC7 /* MinimumMaximumPairs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C40B1C77A768003CECC7 /* MinimumMaximumPairs.swift */; }; + 7B80C4131C77A770003CECC7 /* MaximumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C40F1C77A770003CECC7 /* MaximumTests.swift */; }; + 7B80C4141C77A770003CECC7 /* MinimumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4101C77A770003CECC7 /* MinimumTests.swift */; }; + 7B80C4151C77A770003CECC7 /* MinimumMaximumPairsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4111C77A770003CECC7 /* MinimumMaximumPairsTests.swift */; }; + 7B80C4161C77A770003CECC7 /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4121C77A770003CECC7 /* TestHelper.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; }; + 7B80C4091C77A768003CECC7 /* Maximum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Maximum.swift; path = ../Maximum.swift; sourceTree = SOURCE_ROOT; }; + 7B80C40A1C77A768003CECC7 /* Minimum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Minimum.swift; path = ../Minimum.swift; sourceTree = SOURCE_ROOT; }; + 7B80C40B1C77A768003CECC7 /* MinimumMaximumPairs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MinimumMaximumPairs.swift; path = ../MinimumMaximumPairs.swift; sourceTree = SOURCE_ROOT; }; + 7B80C40F1C77A770003CECC7 /* MaximumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximumTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C4101C77A770003CECC7 /* MinimumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimumTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C4111C77A770003CECC7 /* MinimumMaximumPairsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimumMaximumPairsTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C4121C77A770003CECC7 /* TestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelper.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 = ( + 7B2BBC941C779E7B0067B71D /* Info.plist */, + 7B80C4091C77A768003CECC7 /* Maximum.swift */, + 7B80C40F1C77A770003CECC7 /* MaximumTests.swift */, + 7B80C40A1C77A768003CECC7 /* Minimum.swift */, + 7B80C4101C77A770003CECC7 /* MinimumTests.swift */, + 7B80C40B1C77A768003CECC7 /* MinimumMaximumPairs.swift */, + 7B80C4111C77A770003CECC7 /* MinimumMaximumPairsTests.swift */, + 7B80C4121C77A770003CECC7 /* TestHelper.swift */, + ); + 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 = 0820; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; + }; + }; + }; + 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 = ( + 7B80C40D1C77A768003CECC7 /* Minimum.swift in Sources */, + 7B80C40E1C77A768003CECC7 /* MinimumMaximumPairs.swift in Sources */, + 7B80C4141C77A770003CECC7 /* MinimumTests.swift in Sources */, + 7B80C40C1C77A768003CECC7 /* Maximum.swift in Sources */, + 7B80C4131C77A770003CECC7 /* MaximumTests.swift in Sources */, + 7B80C4161C77A770003CECC7 /* TestHelper.swift in Sources */, + 7B80C4151C77A770003CECC7 /* MinimumMaximumPairsTests.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/Select Minimum Maximum/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Select Minimum Maximum/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Select Minimum Maximum/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..dfcf6de42 --- /dev/null +++ b/Select Minimum Maximum/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Selection Sampling/README.markdown b/Selection Sampling/README.markdown index 174b3a3da..5c2ff5e25 100644 --- a/Selection Sampling/README.markdown +++ b/Selection Sampling/README.markdown @@ -12,14 +12,14 @@ func select(from a: [T], count k: Int) -> [T] { for i in 0..(from a: [T], count k: Int) -> [T] { + precondition(a.count >= k) + + var result = [T]() // 1 + for i in 0..(from a: [T], count requested: Int) -> [T] { var b = [T]() while selected < requested { // 1 - examined += 1 - let r = Double(arc4random()) / 0x100000000 // 2 - let leftToExamine = a.count - examined + 1 // 3 + let leftToExamine = a.count - examined // 3 let leftToAdd = requested - selected if Double(leftToExamine) * r < Double(leftToAdd) { // 4 selected += 1 - b.append(a[examined - 1]) + b.append(a[examined]) } + + examined += 1 } return b } @@ -115,7 +143,7 @@ Only one item left to select but there are still 4 candidates to look at. Suppos 4 * 0.718 = 2.872 -For this element to be selected the number has to be less than 1, since there is only 1 element left to be picked. It isn't, so we skip `"d"`. Only three possibilities left -- will we make it? +For this element to be selected the number has to be less than 1, as there is only 1 element left to be picked. It isn't, so we skip `"d"`. Only three possibilities left -- will we make it before we run out of elements? The random number is 0.346. The formula gives: @@ -123,7 +151,7 @@ The random number is 0.346. The formula gives: Just a tiny bit too high. We skip `"e"`. Only two candidates left... -Note that now literally we're dealing with a toin coss: if the random number is less than 0.5 we select `"f"` and we're done. If it's greater than 0.5, we go on to the final element. Let's say we get 0.583: +Note that now literally we're dealing with a coin toss: if the random number is less than 0.5 we select `"f"` and we're done. If it's greater than 0.5, we go on to the final element. Let's say we get 0.583: 2 * 0.583 = 1.166 @@ -135,7 +163,7 @@ Let's say our final random number is 0.999 (remember, it can never be 1.0 or hig And so the last element will always be chosen if we didn't have a big enough selection yet. The final selection is `[ "b", "c", "g" ]`. Notice that the elements are still in their original order, because we examined the array from left to right. -Maybe you're not convinced yet... What if we always got 0.999 as the random value, would that still select 3 items? Well, let's do the math: +Maybe you're not convinced yet... What if we always got 0.999 as the random value (the maximum possible), would that still select 3 items? Well, let's do the math: 7 * 0.999 = 6.993 is this less than 3? no 6 * 0.999 = 5.994 is this less than 3? no @@ -165,7 +193,7 @@ print(output.count) The performance of this second algorithm is **O(n)** as it may require a pass through the entire input array. -> **Note:** If `k > n/2`, then it's more efficient to do it the other way around and choose `k` items to remove. +> **Note:** If `k > n/2`, then it's more efficient to do it the other way around and choose `a.count - k` items to remove. Based on code from Algorithm Alley, Dr. Dobb's Magazine, October 1993. diff --git a/Selection Sampling/SelectionSampling.playground/Contents.swift b/Selection Sampling/SelectionSampling.playground/Contents.swift index 4afbe4f03..7443db67c 100644 --- a/Selection Sampling/SelectionSampling.playground/Contents.swift +++ b/Selection Sampling/SelectionSampling.playground/Contents.swift @@ -1,9 +1,14 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + import Foundation /* 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))) } @@ -25,27 +30,25 @@ func select(from a: [T], count requested: Int) -> [T] { var examined = 0 var selected = 0 var b = [T]() - + while selected < requested { - examined += 1 - // Calculate random variable 0.0 <= r < 1.0 (exclusive!). let r = Double(arc4random()) / 0x100000000 - - let leftToExamine = a.count - examined + 1 + + let leftToExamine = a.count - examined let leftToAdd = requested - selected // Decide whether to use the next record from the input. if Double(leftToExamine) * r < Double(leftToAdd) { selected += 1 - b.append(a[examined - 1]) + b.append(a[examined]) } + + examined += 1 } return b } - - let poem = [ "there", "once", "was", "a", "man", "from", "nantucket", "who", "kept", "all", "of", "his", "cash", "in", "a", "bucket", @@ -58,8 +61,6 @@ let output = select(from: poem, count: 10) print(output) output.count - - // Use this to verify that all input elements have the same probability // of being chosen. The "counts" dictionary should have a roughly equal // count for each input element. diff --git a/Selection Sampling/SelectionSampling.playground/playground.xcworkspace/contents.xcworkspacedata b/Selection Sampling/SelectionSampling.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Selection Sampling/SelectionSampling.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 @@ - - - - - diff --git a/Selection Sampling/SelectionSampling.swift b/Selection Sampling/SelectionSampling.swift index 8b9653d45..711460f47 100644 --- a/Selection Sampling/SelectionSampling.swift +++ b/Selection Sampling/SelectionSampling.swift @@ -17,12 +17,35 @@ func select(from a: [T], count k: Int) -> [T] { for i in 0..(from a: [T], count k: Int) -> [T] { + precondition(a.count >= k) + + var result = [T]() + + // Fill the result array with first k elements. + for i in 0..(from a: [T], count requested: Int) -> [T] { var examined = 0 var selected = 0 var b = [T]() - + while selected < requested { - examined += 1 - // Calculate random variable 0.0 <= r < 1.0 (exclusive!). let r = Double(arc4random()) / 0x100000000 - - let leftToExamine = a.count - examined + 1 + + let leftToExamine = a.count - examined let leftToAdd = requested - selected // Decide whether to use the next record from the input. if Double(leftToExamine) * r < Double(leftToAdd) { selected += 1 - b.append(a[examined - 1]) + b.append(a[examined]) } + + examined += 1 } return b } diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index 57b1d09f5..b958da927 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -1,29 +1,29 @@ # 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 need 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... ] -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: -- 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 is called a "selection" sort because at every step you search through the rest of the array to select the next lowest number. -### An example +## 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,36 +43,38 @@ 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 ] * -This process repeats until the array is sorted. Note that everything to the left of the `|` bar is always in sorted order and always contains the lowest numbers in the array. +This process repeats until the array is sorted. Note that everything to the left of the `|` bar is always in sorted order and always contains the lowest numbers in the array. Finally, we end up with: -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 below isn't stable). + [ 3, 4, 5, 6, 8 |] -### The code +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 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 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]) + a.swapAt(x, lowest) } } return a @@ -88,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. 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. @@ -98,18 +100,20 @@ 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, it 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 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 always 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 data 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 types. +## Performance -### Performance +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. -Selection sort is easy to understand but it performs quite badly, **O(n^2)**. It's worse than insertion sort but better than 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. +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 +## See also -See also [Wikipedia](https://en.wikipedia.org/wiki/Selection_sort). +[Selection sort on Wikipedia](https://en.wikipedia.org/wiki/Selection_sort) -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Selection Sort/SelectionSort Tests/SelectionSort.xcodeproj/project.pbxproj b/Selection Sort/SelectionSort Tests/SelectionSort.xcodeproj/project.pbxproj deleted file mode 100644 index 25bfba716..000000000 --- a/Selection Sort/SelectionSort Tests/SelectionSort.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E0C21C5BFB2D005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0C11C5BFB2D005A2B8E /* AppDelegate.swift */; }; - 7B18E0C41C5BFB2D005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E0C31C5BFB2D005A2B8E /* Assets.xcassets */; }; - 7B18E0C71C5BFB2D005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E0C51C5BFB2D005A2B8E /* MainMenu.xib */; }; - 7B18E0D21C5BFB2D005A2B8E /* SelectionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0D11C5BFB2D005A2B8E /* SelectionSortTests.swift */; }; - 7B18E0DD1C5BFB40005A2B8E /* SelectionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0DC1C5BFB40005A2B8E /* SelectionSort.swift */; }; - 7B18E0DF1C5BFB55005A2B8E /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0DE1C5BFB55005A2B8E /* SortingTestHelpers.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E0CE1C5BFB2D005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E0B61C5BFB2D005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E0BD1C5BFB2D005A2B8E; - remoteInfo = SelectionSort; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E0BE1C5BFB2D005A2B8E /* SelectionSort.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SelectionSort.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0C11C5BFB2D005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E0C31C5BFB2D005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18E0C61C5BFB2D005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18E0C81C5BFB2D005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0CD1C5BFB2D005A2B8E /* SelectionSortTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelectionSortTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0D11C5BFB2D005A2B8E /* SelectionSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionSortTests.swift; sourceTree = ""; }; - 7B18E0D31C5BFB2D005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E0DC1C5BFB40005A2B8E /* SelectionSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SelectionSort.swift; path = ../../SelectionSort.swift; sourceTree = ""; }; - 7B18E0DE1C5BFB55005A2B8E /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = "../../../Quicksort/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E0BB1C5BFB2D005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0CA1C5BFB2D005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E0B51C5BFB2D005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E0C01C5BFB2D005A2B8E /* SelectionSort */, - 7B18E0D01C5BFB2D005A2B8E /* SelectionSortTests */, - 7B18E0BF1C5BFB2D005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0BF1C5BFB2D005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E0BE1C5BFB2D005A2B8E /* SelectionSort.app */, - 7B18E0CD1C5BFB2D005A2B8E /* SelectionSortTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E0C01C5BFB2D005A2B8E /* SelectionSort */ = { - isa = PBXGroup; - children = ( - 7B18E0C11C5BFB2D005A2B8E /* AppDelegate.swift */, - 7B18E0C31C5BFB2D005A2B8E /* Assets.xcassets */, - 7B18E0C81C5BFB2D005A2B8E /* Info.plist */, - 7B18E0C51C5BFB2D005A2B8E /* MainMenu.xib */, - 7B18E0DC1C5BFB40005A2B8E /* SelectionSort.swift */, - ); - path = SelectionSort; - sourceTree = ""; - }; - 7B18E0D01C5BFB2D005A2B8E /* SelectionSortTests */ = { - isa = PBXGroup; - children = ( - 7B18E0D31C5BFB2D005A2B8E /* Info.plist */, - 7B18E0D11C5BFB2D005A2B8E /* SelectionSortTests.swift */, - 7B18E0DE1C5BFB55005A2B8E /* SortingTestHelpers.swift */, - ); - path = SelectionSortTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E0BD1C5BFB2D005A2B8E /* SelectionSort */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0D61C5BFB2D005A2B8E /* Build configuration list for PBXNativeTarget "SelectionSort" */; - buildPhases = ( - 7B18E0BA1C5BFB2D005A2B8E /* Sources */, - 7B18E0BB1C5BFB2D005A2B8E /* Frameworks */, - 7B18E0BC1C5BFB2D005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SelectionSort; - productName = SelectionSort; - productReference = 7B18E0BE1C5BFB2D005A2B8E /* SelectionSort.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E0CC1C5BFB2D005A2B8E /* SelectionSortTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0D91C5BFB2D005A2B8E /* Build configuration list for PBXNativeTarget "SelectionSortTests" */; - buildPhases = ( - 7B18E0C91C5BFB2D005A2B8E /* Sources */, - 7B18E0CA1C5BFB2D005A2B8E /* Frameworks */, - 7B18E0CB1C5BFB2D005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0CF1C5BFB2D005A2B8E /* PBXTargetDependency */, - ); - name = SelectionSortTests; - productName = SelectionSortTests; - productReference = 7B18E0CD1C5BFB2D005A2B8E /* SelectionSortTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E0B61C5BFB2D005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E0BD1C5BFB2D005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E0CC1C5BFB2D005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E0BD1C5BFB2D005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E0B91C5BFB2D005A2B8E /* Build configuration list for PBXProject "SelectionSort" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E0B51C5BFB2D005A2B8E; - productRefGroup = 7B18E0BF1C5BFB2D005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E0BD1C5BFB2D005A2B8E /* SelectionSort */, - 7B18E0CC1C5BFB2D005A2B8E /* SelectionSortTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E0BC1C5BFB2D005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0C41C5BFB2D005A2B8E /* Assets.xcassets in Resources */, - 7B18E0C71C5BFB2D005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0CB1C5BFB2D005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E0BA1C5BFB2D005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0DD1C5BFB40005A2B8E /* SelectionSort.swift in Sources */, - 7B18E0C21C5BFB2D005A2B8E /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E0C91C5BFB2D005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0DF1C5BFB55005A2B8E /* SortingTestHelpers.swift in Sources */, - 7B18E0D21C5BFB2D005A2B8E /* SelectionSortTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0CF1C5BFB2D005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E0BD1C5BFB2D005A2B8E /* SelectionSort */; - targetProxy = 7B18E0CE1C5BFB2D005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18E0C51C5BFB2D005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18E0C61C5BFB2D005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E0D41C5BFB2D005A2B8E /* 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; - }; - 7B18E0D51C5BFB2D005A2B8E /* 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; - }; - 7B18E0D71C5BFB2D005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectionSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectionSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0D81C5BFB2D005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectionSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectionSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E0DA1C5BFB2D005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectionSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectionSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SelectionSort.app/Contents/MacOS/SelectionSort"; - }; - name = Debug; - }; - 7B18E0DB1C5BFB2D005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = SelectionSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.SelectionSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SelectionSort.app/Contents/MacOS/SelectionSort"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E0B91C5BFB2D005A2B8E /* Build configuration list for PBXProject "SelectionSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0D41C5BFB2D005A2B8E /* Debug */, - 7B18E0D51C5BFB2D005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0D61C5BFB2D005A2B8E /* Build configuration list for PBXNativeTarget "SelectionSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0D71C5BFB2D005A2B8E /* Debug */, - 7B18E0D81C5BFB2D005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0D91C5BFB2D005A2B8E /* Build configuration list for PBXNativeTarget "SelectionSortTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0DA1C5BFB2D005A2B8E /* Debug */, - 7B18E0DB1C5BFB2D005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E0B61C5BFB2D005A2B8E /* Project object */; -} diff --git a/Selection Sort/SelectionSort Tests/SelectionSort/AppDelegate.swift b/Selection Sort/SelectionSort Tests/SelectionSort/AppDelegate.swift deleted file mode 100644 index 79cd1a92a..000000000 --- a/Selection Sort/SelectionSort Tests/SelectionSort/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// SelectionSort -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Selection Sort/SelectionSort Tests/SelectionSort/Assets.xcassets/AppIcon.appiconset/Contents.json b/Selection Sort/SelectionSort Tests/SelectionSort/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Selection Sort/SelectionSort Tests/SelectionSort/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/Selection Sort/SelectionSort Tests/SelectionSort/Base.lproj/MainMenu.xib b/Selection Sort/SelectionSort Tests/SelectionSort/Base.lproj/MainMenu.xib deleted file mode 100644 index 47b389b06..000000000 --- a/Selection Sort/SelectionSort Tests/SelectionSort/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Selection Sort/SelectionSort Tests/SelectionSort/Info.plist b/Selection Sort/SelectionSort Tests/SelectionSort/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Selection Sort/SelectionSort Tests/SelectionSort/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index dd57e9c3a..a552c9edb 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -1,22 +1,6 @@ //: Playground - noun: a place where people can play -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 { - var lowest = x - for y in x + 1 ..< a.count { - if isOrderedBefore(a[y], a[lowest]) { - lowest = y - } - } - if x != lowest { - swap(&a[x], &a[lowest]) - } - } - return a -} - let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] +selectionSort(list) selectionSort(list, <) selectionSort(list, >) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift new file mode 100644 index 000000000..e157319b4 --- /dev/null +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -0,0 +1,35 @@ +/// Performs the Selection sort algorithm on a array +/// +/// - Parameter array: array of elements that conform to the Comparable protocol +/// - Returns: an array in ascending order +public func selectionSort(_ array: [T]) -> [T] { + return selectionSort(array, <) +} + +/// Performs the Selection sort algorithm on a array using the provided comparisson method +/// +/// - Parameters: +/// - array: array of elements that conform to the Comparable protocol +/// - isLowerThan: returns true if the two provided elements are in the correct order +/// - Returns: a sorted array +public func selectionSort(_ array: [T], _ isLowerThan: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + + var a = array + for x in 0 ..< a.count - 1 { + + // Find the lowest value in the rest of the array. + var lowest = x + for y in x + 1 ..< a.count { + if isLowerThan(a[y], a[lowest]) { + lowest = y + } + } + + // Swap the lowest value with the current array index. + if x != lowest { + a.swapAt(x, lowest) + } + } + return a +} diff --git a/Selection Sort/SelectionSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Selection Sort/SelectionSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Selection Sort/SelectionSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Selection Sort/SelectionSort.playground/timeline.xctimeline b/Selection Sort/SelectionSort.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Selection Sort/SelectionSort.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Selection Sort/SelectionSort.swift b/Selection Sort/SelectionSort.swift index 4c50688e5..943ae628d 100644 --- a/Selection Sort/SelectionSort.swift +++ b/Selection Sort/SelectionSort.swift @@ -1,21 +1,21 @@ -func selectionSort(array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { - guard array.count > 1 else { return array } +public 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 { - - // Find the lowest value in the rest of the array. - var lowest = x - for y in x + 1 ..< a.count { - if isOrderedBefore(a[y], a[lowest]) { - lowest = y - } - } - - // Swap the lowest value with the current array index. - if x != lowest { - swap(&a[x], &a[lowest]) + var a = array + for x in 0 ..< a.count - 1 { + + // Find the lowest value in the rest of the array. + var lowest = x + for y in x + 1 ..< a.count { + if isOrderedBefore(a[y], a[lowest]) { + lowest = y + } + } + + // Swap the lowest value with the current array index. + if x != lowest { + a.swapAt(x, lowest) + } } - } - return a + return a } diff --git a/Selection Sort/Tests/Info.plist b/Selection Sort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Selection Sort/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/Selection Sort/SelectionSort Tests/SelectionSortTests/SelectionSortTests.swift b/Selection Sort/Tests/SelectionSortTests.swift similarity index 80% rename from Selection Sort/SelectionSort Tests/SelectionSortTests/SelectionSortTests.swift rename to Selection Sort/Tests/SelectionSortTests.swift index 917332cae..3e26122b0 100644 --- a/Selection Sort/SelectionSort Tests/SelectionSortTests/SelectionSortTests.swift +++ b/Selection Sort/Tests/SelectionSortTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import SelectionSort class SelectionSortTests: XCTestCase { func testSelectionSort() { diff --git a/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj b/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a42f3dc3f --- /dev/null +++ b/Selection Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,273 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */; }; + 7B80C3F01C77A590003CECC7 /* SelectionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3EF1C77A590003CECC7 /* SelectionSortTests.swift */; }; + 7B80C3F21C77A598003CECC7 /* SelectionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F11C77A598003CECC7 /* SelectionSort.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; }; + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = ../../Quicksort/Tests/SortingTestHelpers.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3EF1C77A590003CECC7 /* SelectionSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionSortTests.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3F11C77A598003CECC7 /* SelectionSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SelectionSort.swift; path = ../SelectionSort.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 = ( + 7B80C3F11C77A598003CECC7 /* SelectionSort.swift */, + 7B80C3EF1C77A590003CECC7 /* SelectionSortTests.swift */, + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.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 = ( + 7B80C3F01C77A590003CECC7 /* SelectionSortTests.swift in Sources */, + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */, + 7B80C3F21C77A598003CECC7 /* SelectionSort.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/Selection Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Selection Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Selection Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Selection Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Set Cover (Unweighted)/README.markdown b/Set Cover (Unweighted)/README.markdown new file mode 100644 index 000000000..0b4ddfefe --- /dev/null +++ b/Set Cover (Unweighted)/README.markdown @@ -0,0 +1,34 @@ +# Set Cover (Unweighted) + +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. + +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 in the cover itself. + +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. 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) + +*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/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift new file mode 100644 index 000000000..065f5fd4d --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/Contents.swift @@ -0,0 +1,35 @@ +// SetCover + +let universe1 = Set(1...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 cover2 = universe2.cover(within: array2) + +let universe3 = Set(["tall", "heavy"]) +let array3: Array> = [["tall", "light"], ["short", "heavy"], ["tall", "heavy", "young"]] +let cover3 = universe3.cover(within: array3) + +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 cover5 = universe5.cover(within: array5) + +let universe6: Set = [24, 89, 132, 90, 22] +let array6 = randomArrayOfSets(covering: universe6) +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(within: array7) + +let emptySet = Set() +let coverTest1 = emptySet.cover(within: array1) +let coverTest2 = universe1.cover(within: Array>()) +let coverTest3 = emptySet.cover(within: Array>()) + + diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift new file mode 100644 index 000000000..ac4ff063e --- /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.random(in: 0...maxSetSize) + 1 + + while true { + let randomUniverseIndex = Int.random(in: 0...universe.count) + for (setIndex, value) in universe.enumerated() { + 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 +} 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..043cf46a0 --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/SetCover.swift @@ -0,0 +1,33 @@ +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.intersection(set).count + if intersectionLength > largestIntersectionLength { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while !remainingSet.isEmpty { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtracting(largestSet) + } + + if !remainingSet.isEmpty || isEmpty { + result = nil + } + + return result + } +} diff --git a/Set Cover (Unweighted)/SetCover.playground/contents.xcplayground b/Set Cover (Unweighted)/SetCover.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file 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 new file mode 100644 index 000000000..d67dfbfa9 --- /dev/null +++ b/Set Cover (Unweighted)/SetCover.swift @@ -0,0 +1,33 @@ +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 { + largestIntersectionLength = intersectionLength + largestSet = set + } + } + + return largestSet + } + + while !remainingSet.isEmpty { + guard let largestSet = largestIntersectingSet() else { break } + result!.append(largestSet) + remainingSet = remainingSet.subtract(largestSet) + } + + if !remainingSet.isEmpty || isEmpty { + result = nil + } + + return result + } +} diff --git a/Shell Sort/README.markdown b/Shell Sort/README.markdown index 8870ffea6..72375e51b 100644 --- a/Shell Sort/README.markdown +++ b/Shell Sort/README.markdown @@ -1,6 +1,6 @@ # Shell Sort -Shell sort is based on [insertion sort](../Insertion%20Sort/) as a general way to improve its performance, by breaking the original list into smaller sublists which can then be individually sorted using insertion sort. +Shell sort is based on [insertion sort](../Insertion%20Sort/) as a general way to improve its performance, by breaking the original list into smaller sublists which are then individually sorted using insertion sort. [There is a nice video created at Sapientia University](https://www.youtube.com/watch?v=CmPA7zE8mx0) which shows the process as a Hungarian folk dance. @@ -12,7 +12,7 @@ The distance between elements is known as the *gap*. If the elements being compa The idea is that by moving the elements over large gaps, the array becomes partially sorted quite quickly. This makes later passes faster because they don't have to swap so many items anymore. -Once a pass has been completed, the gap is made smaller and a new pass starts. This repeats until the gap is 1, at which point the algorithm functions just like insertion sort. But since the data is already fairly well sorted by then, the final pass can be very quick. +Once a pass has been completed, the gap is made smaller and a new pass starts. This repeats until the gap has size 1, at which point the algorithm functions just like insertion sort. But since the data is already fairly well sorted by then, the final pass can be very quick. ## An example @@ -26,36 +26,36 @@ This is the gap size. We create `n` sublists. In each sublist, the items are spaced apart by a gap of size `n`. In our example, we need to make four of these sublists. The sublists are sorted by the `insertionSort()` function. -That probably didn't make a whole lot of sense, so let's look at what happens. +That may not have made a whole lot of sense, so let's take a closer look at what happens. The first pass is as follows. We have `n = 4`, so we make four sublists: - list 0: [ 64, xx, xx, xx, 72, xx, xx, xx, 4 ] - list 1: [ xx, 20, xx, xx, xx, 10, xx, xx, xx ] - list 2: [ xx, xx, 50, xx, xx, xx, 23, xx, xx ] - list 3: [ xx, xx, xx, 33, xx, xx, xx, -1, xx ] + sublist 0: [ 64, xx, xx, xx, 72, xx, xx, xx, 4 ] + sublist 1: [ xx, 20, xx, xx, xx, 10, xx, xx, xx ] + sublist 2: [ xx, xx, 50, xx, xx, xx, 23, xx, xx ] + sublist 3: [ xx, xx, xx, 33, xx, xx, xx, -1, xx ] -As you can see, each list contains only every 4th item from the original array. The items that are not in a sublist are marked with `xx`. So the first list is `[ 64, 72, 4]` and the second is `[ 20, 10 ]`, and so on. The reason we use this "gap" is so that we don't have to actually make new arrays. Instead, we interleave them in the original array. +As you can see, each sublist contains only every 4th item from the original array. The items that are not in a sublist are marked with `xx`. So the first sublist is `[ 64, 72, 4 ]` and the second is `[ 20, 10 ]`, and so on. The reason we use this "gap" is so that we don't have to actually make new arrays. Instead, we interleave them in the original array. 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 list. +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 list 0, we swap `4` with `72`, then swap `4` with `64`. After sorting, this sublist looks like: +So for sublist 0, we swap `4` with `72`, then swap `4` with `64`. After sorting, this sublist looks like: - list 0: [ 4, xx, xx, xx, 64, xx, xx, xx, 72 ] + sublist 0: [ 4, xx, xx, xx, 64, xx, xx, xx, 72 ] The other three sublists after sorting: - list 1: [ xx, 10, xx, xx, xx, 20, xx, xx, xx ] - list 2: [ xx, xx, 23, xx, xx, xx, 50, xx, xx ] - list 3: [ xx, xx, xx, -1, xx, xx, xx, 33, xx ] + sublist 1: [ xx, 10, xx, xx, xx, 20, xx, xx, xx ] + sublist 2: [ xx, xx, 23, xx, xx, xx, 50, xx, xx ] + sublist 3: [ xx, xx, xx, -1, xx, xx, xx, 33, xx ] The total array looks like this now: [ 4, 10, 23, -1, 64, 20, 50, 33, 72 ] -It's not sorted yet but it's more sorted than before. This completes the first pass. +It's not entirely sorted yet but it's more sorted than before. This completes the first pass. In the second pass, we divide the gap size by two: @@ -63,13 +63,13 @@ In the second pass, we divide the gap size by two: That means we now create only two sublists: - list 0: [ 4, xx, 23, xx, 64, xx, 50, xx, 72 ] - list 1: [ xx, 10, xx, -1, xx, 20, xx, 33, xx ] + sublist 0: [ 4, xx, 23, xx, 64, xx, 50, xx, 72 ] + sublist 1: [ xx, 10, xx, -1, xx, 20, xx, 33, xx ] Each sublist contains every 2nd item. Again, we call `insertionSort()` to sort these sublists. The result is: - list 0: [ 4, xx, 23, xx, 50, xx, 64, xx, 72 ] - list 1: [ xx, -1, xx, 10, xx, 20, xx, 33, xx ] + sublist 0: [ 4, xx, 23, xx, 50, xx, 64, xx, 72 ] + sublist 1: [ xx, -1, xx, 10, xx, 20, xx, 33, xx ] Note that in each list only two elements were out of place. So the insertion sort is really fast. That's because we already sorted the array a little in the first pass. @@ -85,7 +85,7 @@ A gap size of 1 means we only have a single sublist, the array itself, and once [ -1, 4, 10, 20, 23, 33, 50, 64, 72 ] -The performance of shell sort is **O(n^2)** or **O(n log n)** if you get lucky. This algorithm produces an unstable sort; it may change the relative order of elements with equal values. +The performance of shell sort is **O(n^2)** in most cases or **O(n log n)** if you get lucky. This algorithm produces an unstable sort; it may change the relative order of elements with equal values. ## The gap sequence @@ -111,6 +111,24 @@ 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] + +public func shellSort(_ list: inout [Int]) { + var sublistCount = list.count / 2 + while sublistCount > 0 { + for pos in 0..=4.0) + print("Hello, Swift 4!") +#endif + +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 { + list[pos] = list[pos - gap] + pos -= gap + } + list[pos] = currentValue + } +} + +public func shellSort(_ list: inout [Int]) { + var sublistCount = list.count / 2 + while sublistCount > 0 { + for pos in 0.. + + + \ No newline at end of file diff --git a/Shell Sort/ShellSort Tests/ShellSort.xcodeproj/project.pbxproj b/Shell Sort/ShellSort Tests/ShellSort.xcodeproj/project.pbxproj deleted file mode 100644 index c012a7cff..000000000 --- a/Shell Sort/ShellSort Tests/ShellSort.xcodeproj/project.pbxproj +++ /dev/null @@ -1,398 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B1BFA701C6A40370051C9A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA6F1C6A40370051C9A4 /* AppDelegate.swift */; }; - 7B1BFA721C6A40370051C9A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA711C6A40370051C9A4 /* Assets.xcassets */; }; - 7B1BFA751C6A40380051C9A4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B1BFA731C6A40380051C9A4 /* MainMenu.xib */; }; - 7B1BFA801C6A40380051C9A4 /* ShellSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA7F1C6A40380051C9A4 /* ShellSortTests.swift */; }; - 7B1BFA8B1C6A40560051C9A4 /* ShellSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA8A1C6A40560051C9A4 /* ShellSort.swift */; }; - 7B1BFA8D1C6A40820051C9A4 /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1BFA8C1C6A40820051C9A4 /* SortingTestHelpers.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B1BFA7C1C6A40380051C9A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B1BFA641C6A40370051C9A4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B1BFA6B1C6A40370051C9A4; - remoteInfo = ShellSort; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B1BFA6C1C6A40370051C9A4 /* ShellSort.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShellSort.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA6F1C6A40370051C9A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B1BFA711C6A40370051C9A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B1BFA741C6A40380051C9A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B1BFA761C6A40380051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA7B1C6A40380051C9A4 /* ShellSortTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShellSortTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B1BFA7F1C6A40380051C9A4 /* ShellSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellSortTests.swift; sourceTree = ""; }; - 7B1BFA811C6A40380051C9A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B1BFA8A1C6A40560051C9A4 /* ShellSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShellSort.swift; path = ../../ShellSort.swift; sourceTree = ""; }; - 7B1BFA8C1C6A40820051C9A4 /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = "../../../Quicksort/Quicksort Tests/QuicksortTests/SortingTestHelpers.swift"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B1BFA691C6A40370051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA781C6A40380051C9A4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B1BFA631C6A40370051C9A4 = { - isa = PBXGroup; - children = ( - 7B1BFA6E1C6A40370051C9A4 /* ShellSort */, - 7B1BFA7E1C6A40380051C9A4 /* ShellSortTests */, - 7B1BFA6D1C6A40370051C9A4 /* Products */, - ); - sourceTree = ""; - }; - 7B1BFA6D1C6A40370051C9A4 /* Products */ = { - isa = PBXGroup; - children = ( - 7B1BFA6C1C6A40370051C9A4 /* ShellSort.app */, - 7B1BFA7B1C6A40380051C9A4 /* ShellSortTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B1BFA6E1C6A40370051C9A4 /* ShellSort */ = { - isa = PBXGroup; - children = ( - 7B1BFA6F1C6A40370051C9A4 /* AppDelegate.swift */, - 7B1BFA711C6A40370051C9A4 /* Assets.xcassets */, - 7B1BFA761C6A40380051C9A4 /* Info.plist */, - 7B1BFA731C6A40380051C9A4 /* MainMenu.xib */, - 7B1BFA8A1C6A40560051C9A4 /* ShellSort.swift */, - ); - path = ShellSort; - sourceTree = ""; - }; - 7B1BFA7E1C6A40380051C9A4 /* ShellSortTests */ = { - isa = PBXGroup; - children = ( - 7B1BFA811C6A40380051C9A4 /* Info.plist */, - 7B1BFA7F1C6A40380051C9A4 /* ShellSortTests.swift */, - 7B1BFA8C1C6A40820051C9A4 /* SortingTestHelpers.swift */, - ); - path = ShellSortTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B1BFA6B1C6A40370051C9A4 /* ShellSort */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA841C6A40380051C9A4 /* Build configuration list for PBXNativeTarget "ShellSort" */; - buildPhases = ( - 7B1BFA681C6A40370051C9A4 /* Sources */, - 7B1BFA691C6A40370051C9A4 /* Frameworks */, - 7B1BFA6A1C6A40370051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ShellSort; - productName = ShellSort; - productReference = 7B1BFA6C1C6A40370051C9A4 /* ShellSort.app */; - productType = "com.apple.product-type.application"; - }; - 7B1BFA7A1C6A40380051C9A4 /* ShellSortTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B1BFA871C6A40380051C9A4 /* Build configuration list for PBXNativeTarget "ShellSortTests" */; - buildPhases = ( - 7B1BFA771C6A40380051C9A4 /* Sources */, - 7B1BFA781C6A40380051C9A4 /* Frameworks */, - 7B1BFA791C6A40380051C9A4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B1BFA7D1C6A40380051C9A4 /* PBXTargetDependency */, - ); - name = ShellSortTests; - productName = ShellSortTests; - productReference = 7B1BFA7B1C6A40380051C9A4 /* ShellSortTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B1BFA641C6A40370051C9A4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B1BFA6B1C6A40370051C9A4 = { - CreatedOnToolsVersion = 7.2; - }; - 7B1BFA7A1C6A40380051C9A4 = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B1BFA6B1C6A40370051C9A4; - }; - }; - }; - buildConfigurationList = 7B1BFA671C6A40370051C9A4 /* Build configuration list for PBXProject "ShellSort" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B1BFA631C6A40370051C9A4; - productRefGroup = 7B1BFA6D1C6A40370051C9A4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B1BFA6B1C6A40370051C9A4 /* ShellSort */, - 7B1BFA7A1C6A40380051C9A4 /* ShellSortTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B1BFA6A1C6A40370051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA721C6A40370051C9A4 /* Assets.xcassets in Resources */, - 7B1BFA751C6A40380051C9A4 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA791C6A40380051C9A4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B1BFA681C6A40370051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA8B1C6A40560051C9A4 /* ShellSort.swift in Sources */, - 7B1BFA701C6A40370051C9A4 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B1BFA771C6A40380051C9A4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B1BFA8D1C6A40820051C9A4 /* SortingTestHelpers.swift in Sources */, - 7B1BFA801C6A40380051C9A4 /* ShellSortTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B1BFA7D1C6A40380051C9A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B1BFA6B1C6A40370051C9A4 /* ShellSort */; - targetProxy = 7B1BFA7C1C6A40380051C9A4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B1BFA731C6A40380051C9A4 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B1BFA741C6A40380051C9A4 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B1BFA821C6A40380051C9A4 /* 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; - }; - 7B1BFA831C6A40380051C9A4 /* 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; - }; - 7B1BFA851C6A40380051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ShellSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.ShellSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B1BFA861C6A40380051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ShellSort/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.ShellSort; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B1BFA881C6A40380051C9A4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ShellSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.ShellSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ShellSort.app/Contents/MacOS/ShellSort"; - }; - name = Debug; - }; - 7B1BFA891C6A40380051C9A4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ShellSortTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.ShellSortTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ShellSort.app/Contents/MacOS/ShellSort"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B1BFA671C6A40370051C9A4 /* Build configuration list for PBXProject "ShellSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA821C6A40380051C9A4 /* Debug */, - 7B1BFA831C6A40380051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA841C6A40380051C9A4 /* Build configuration list for PBXNativeTarget "ShellSort" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA851C6A40380051C9A4 /* Debug */, - 7B1BFA861C6A40380051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B1BFA871C6A40380051C9A4 /* Build configuration list for PBXNativeTarget "ShellSortTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B1BFA881C6A40380051C9A4 /* Debug */, - 7B1BFA891C6A40380051C9A4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B1BFA641C6A40370051C9A4 /* Project object */; -} diff --git a/Shell Sort/ShellSort Tests/ShellSort/AppDelegate.swift b/Shell Sort/ShellSort Tests/ShellSort/AppDelegate.swift deleted file mode 100644 index 8e8d28d24..000000000 --- a/Shell Sort/ShellSort Tests/ShellSort/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// ShellSort -// -// Created by Matthijs Hollemans on 09-02-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Shell Sort/ShellSort Tests/ShellSort/Assets.xcassets/AppIcon.appiconset/Contents.json b/Shell Sort/ShellSort Tests/ShellSort/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Shell Sort/ShellSort Tests/ShellSort/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/Shell Sort/ShellSort Tests/ShellSort/Base.lproj/MainMenu.xib b/Shell Sort/ShellSort Tests/ShellSort/Base.lproj/MainMenu.xib deleted file mode 100644 index 22614e1d7..000000000 --- a/Shell Sort/ShellSort Tests/ShellSort/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Shell Sort/ShellSort Tests/ShellSort/Info.plist b/Shell Sort/ShellSort Tests/ShellSort/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Shell Sort/ShellSort Tests/ShellSort/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Shell Sort/ShellSortExample.swift b/Shell Sort/ShellSortExample.swift new file mode 100644 index 000000000..df0842770 --- /dev/null +++ b/Shell Sort/ShellSortExample.swift @@ -0,0 +1,32 @@ +// +// 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 var index in 0.. list[index + sublistCount] { + swap(&list[index], &list[index + sublistCount]) + } + + guard sublistCount == 1 && index > 0 else { continue } + + while index > 0 && list[index - 1] > list[index] { + swap(&list[index - 1], &list[index]) + index -= 1 + } + } + sublistCount = sublistCount / 2 + } +} diff --git a/Shell Sort/Tests/Info.plist b/Shell Sort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Shell Sort/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/Shell Sort/ShellSort Tests/ShellSortTests/ShellSortTests.swift b/Shell Sort/Tests/ShellSortTests.swift similarity index 59% rename from Shell Sort/ShellSort Tests/ShellSortTests/ShellSortTests.swift rename to Shell Sort/Tests/ShellSortTests.swift index 780ce1d3b..494d6841e 100644 --- a/Shell Sort/ShellSort Tests/ShellSortTests/ShellSortTests.swift +++ b/Shell Sort/Tests/ShellSortTests.swift @@ -1,7 +1,13 @@ import XCTest -@testable import ShellSort class ShellSortTests: XCTestCase { + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + func testShellSort() { checkSortAlgorithm { (a: [Int]) -> [Int] in var b = a diff --git a/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj b/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..c2966af46 --- /dev/null +++ b/Shell Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,270 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */; }; + 7B80C3F41C77A5D3003CECC7 /* ShellSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F31C77A5D3003CECC7 /* ShellSort.swift */; }; + 7B80C3F61C77A5D9003CECC7 /* ShellSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3F51C77A5D9003CECC7 /* ShellSortTests.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; }; + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortingTestHelpers.swift; path = ../../Quicksort/Tests/SortingTestHelpers.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3F31C77A5D3003CECC7 /* ShellSort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShellSort.swift; path = ../ShellSort.swift; sourceTree = SOURCE_ROOT; }; + 7B80C3F51C77A5D9003CECC7 /* ShellSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShellSortTests.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 = ( + 7B80C3F31C77A5D3003CECC7 /* ShellSort.swift */, + 7B80C3F51C77A5D9003CECC7 /* ShellSortTests.swift */, + 7B80C3E81C77A4D0003CECC7 /* SortingTestHelpers.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 = ( + 7B80C3F61C77A5D9003CECC7 /* ShellSortTests.swift in Sources */, + 7B80C3EA1C77A4D0003CECC7 /* SortingTestHelpers.swift in Sources */, + 7B80C3F41C77A5D3003CECC7 /* ShellSort.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"; + SWIFT_VERSION = 4.0; + }; + 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; + SWIFT_VERSION = 4.0; + }; + 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 = 4.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 = 4.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/Shell Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Shell Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Shell Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Shell Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Shell Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8ef8d8581 --- /dev/null +++ b/Shell Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Shell Sort/shellsort.swift b/Shell Sort/shellsort.swift index 5b2c73763..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.. Graph { + let shortestPathGraph = graph.duplicate() + + var queue = Queue() + 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(element: neighborNode) + neighborNode.distance = current.distance! + 1 + } + } + } + + return shortestPathGraph +} +``` + +Put this code in a playground and test it like so: + +```swift +let shortestPathGraph = breadthFirstSearchShortestPath(graph: graph, source: nodeA) +print(shortestPathGraph.nodes) +``` + +This will output: + + Node(label: a, distance: 0), Node(label: b, distance: 1), Node(label: c, distance: 1), + 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%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/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 new file mode 100644 index 000000000..2404f5b8c --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift @@ -0,0 +1,47 @@ +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { + let shortestPathGraph = graph.duplicate() + + var queue = Queue() + 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(element: neighborNode) + neighborNode.distance = current.distance! + 1 + } + } + } + + return shortestPathGraph +} + +let graph = Graph() + +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) +graph.addEdge(nodeB, neighbor: nodeD) +graph.addEdge(nodeB, neighbor: nodeE) +graph.addEdge(nodeC, neighbor: nodeF) +graph.addEdge(nodeC, neighbor: nodeG) +graph.addEdge(nodeE, neighbor: nodeH) + +let shortestPathGraph = breadthFirstSearchShortestPath(graph: graph, source: nodeA) +print(shortestPathGraph.nodes) diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Edge.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Edge.swift new file mode 100644 index 000000000..9a58a1f96 --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Edge.swift @@ -0,0 +1,11 @@ +public class Edge: Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift new file mode 100644 index 000000000..8c3281aa8 --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Graph.swift @@ -0,0 +1,55 @@ +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})]" + } + } + 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 + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift new file mode 100644 index 000000000..ebdb6f4e3 --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Node.swift @@ -0,0 +1,32 @@ +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))" + } + 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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Queue.swift b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Queue.swift new file mode 100644 index 000000000..bf462bbdd --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/Sources/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + private var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/contents.xcplayground b/Shortest Path (Unweighted)/ShortestPath.playground/contents.xcplayground new file mode 100644 index 000000000..513c2e7e9 --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Shortest Path (Unweighted)/ShortestPath.playground/playground.xcworkspace/contents.xcworkspacedata b/Shortest Path (Unweighted)/ShortestPath.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Shortest Path (Unweighted)/ShortestPath.swift b/Shortest Path (Unweighted)/ShortestPath.swift new file mode 100644 index 000000000..555ad893b --- /dev/null +++ b/Shortest Path (Unweighted)/ShortestPath.swift @@ -0,0 +1,20 @@ +func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { + let shortestPathGraph = graph.duplicate() + + var queue = Queue() + 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(element: neighborNode) + neighborNode.distance = current.distance! + 1 + } + } + } + + return shortestPathGraph +} diff --git a/Shortest Path (Unweighted)/Tests/Graph.swift b/Shortest Path (Unweighted)/Tests/Graph.swift new file mode 100644 index 000000000..cce697344 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/Graph.swift @@ -0,0 +1,106 @@ +// MARK: - Edge + +open class Edge: Equatable { + open var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func == (lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} + +// MARK: - Node + +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 }!) + } +} + +public func == (lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} + +// MARK: - Graph + +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})]" + } + } + 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) + let neighbour = duplicated.findNodeWithLabel(label: edge.neighbor.label) + duplicated.addEdge(source, neighbor: neighbour) + } + } + + return duplicated + } +} + +public func == (lhs: Graph, rhs: Graph) -> Bool { + return lhs.nodes == rhs.nodes +} diff --git a/Shortest Path (Unweighted)/Tests/Info.plist b/Shortest Path (Unweighted)/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Shortest Path (Unweighted)/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/Shortest Path (Unweighted)/Tests/Queue.swift b/Shortest Path (Unweighted)/Tests/Queue.swift new file mode 100644 index 000000000..0d8752466 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/Queue.swift @@ -0,0 +1,31 @@ +public struct Queue { + fileprivate var array: [T] + + public init() { + array = [] + } + + 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 dequeue() -> T? { + if isEmpty { + return nil + } else { + return array.removeFirst() + } + } + + public func peek() -> T? { + return array.first + } +} diff --git a/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift b/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift new file mode 100644 index 000000000..4d79eeaa7 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/ShortestPathTests.swift @@ -0,0 +1,96 @@ +import XCTest + +class ShortestPathTests: XCTestCase { + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + func testShortestPathWhenGivenTree() { + let tree = Graph() + 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) + tree.addEdge(nodeB, neighbor: nodeE) + tree.addEdge(nodeC, neighbor: nodeF) + tree.addEdge(nodeC, neighbor: nodeG) + tree.addEdge(nodeE, neighbor: nodeH) + + let shortestPaths = breadthFirstSearchShortestPath(graph: tree, source: nodeA) + + 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(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) + graph.addEdge(nodeB, neighbor: nodeA) + graph.addEdge(nodeB, neighbor: nodeC) + graph.addEdge(nodeB, neighbor: nodeH) + graph.addEdge(nodeC, neighbor: nodeB) + graph.addEdge(nodeC, neighbor: nodeD) + graph.addEdge(nodeC, neighbor: nodeF) + graph.addEdge(nodeC, neighbor: nodeI) + graph.addEdge(nodeD, neighbor: nodeC) + graph.addEdge(nodeD, neighbor: nodeE) + graph.addEdge(nodeD, neighbor: nodeF) + graph.addEdge(nodeE, neighbor: nodeD) + graph.addEdge(nodeE, neighbor: nodeF) + graph.addEdge(nodeF, neighbor: nodeC) + graph.addEdge(nodeF, neighbor: nodeD) + graph.addEdge(nodeF, neighbor: nodeE) + graph.addEdge(nodeF, neighbor: nodeG) + graph.addEdge(nodeG, neighbor: nodeF) + graph.addEdge(nodeG, neighbor: nodeH) + graph.addEdge(nodeG, neighbor: nodeI) + graph.addEdge(nodeH, neighbor: nodeA) + graph.addEdge(nodeH, neighbor: nodeB) + graph.addEdge(nodeH, neighbor: nodeG) + graph.addEdge(nodeH, neighbor: nodeI) + graph.addEdge(nodeI, neighbor: nodeC) + graph.addEdge(nodeI, neighbor: nodeG) + graph.addEdge(nodeI, neighbor: nodeH) + + let shortestPaths = breadthFirstSearchShortestPath(graph: graph, source: nodeA) + + 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) + } +} diff --git a/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..b601a1665 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,277 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 83AACB441C8456D200DDAFC7 /* ShortestPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AACB431C8456D200DDAFC7 /* ShortestPathTests.swift */; }; + 83F9C96A1C84437C00B3A87F /* ShortestPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9671C84437C00B3A87F /* ShortestPath.swift */; }; + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9701C84449D00B3A87F /* Queue.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; }; + 83AACB431C8456D200DDAFC7 /* ShortestPathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortestPathTests.swift; sourceTree = SOURCE_ROOT; }; + 83F9C9671C84437C00B3A87F /* ShortestPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShortestPath.swift; path = ../ShortestPath.swift; sourceTree = SOURCE_ROOT; }; + 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = SOURCE_ROOT; }; + 83F9C9701C84449D00B3A87F /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.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 = ( + 83F9C9671C84437C00B3A87F /* ShortestPath.swift */, + 83AACB431C8456D200DDAFC7 /* ShortestPathTests.swift */, + 83F9C96E1C84449D00B3A87F /* Graph.swift */, + 83F9C9701C84449D00B3A87F /* Queue.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 = 0820; + }; + }; + }; + 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 = ( + 83AACB441C8456D200DDAFC7 /* ShortestPathTests.swift in Sources */, + 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */, + 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */, + 83F9C96A1C84437C00B3A87F /* ShortestPath.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"; + SWIFT_VERSION = 4.0; + }; + 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; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.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/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..8ef8d8581 --- /dev/null +++ b/Shortest Path (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index 6cbb23016..d9c35868a 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 @@ -29,23 +29,21 @@ list.shuffle() list.shuffle() ``` -You should see three different arrangements -- or permutations to use math-speak -- of the objects in the array. +You should see three different arrangements -- or [permutations](../Combinatorics/) to use math-speak -- of the objects in the array. This shuffle works *in place*, it modifies the contents of the original array. The algorithm works by creating a new array, `temp`, that is initially empty. Then we randomly choose an element from the original array and append it to `temp`, until the original array is empty. Finally, the temporary array is copied back into the original one. -> **Note:** `random()` is a helper function that returns a random integer between 0 and the given maximum. - This code works just fine but it's not very efficient. Removing an element from an array is an **O(n)** operation and we perform this **n** times, making the total algorithm **O(n^2)**. We can do better! ## The Fisher-Yates / Knuth shuffle -Here is a much improved version of the shuffle algorithm: +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) { - let j = random(i + 1) + for i in stride(from: count - 1, through: 1, by: -1) { + let j = Int.random(in: 0...i) if i != j { swap(&self[i], &self[j]) } @@ -54,9 +52,7 @@ extension Array { } ``` -Again, this picks objects at random. In the naive version we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array. - -> **Note**: When you write `random(x)`, the largest number it will return is `x - 1`. We want to have `j <= i`, not `j < i`, so the largest number from the random number generator needs to be `i`, not `i - 1`. That's why we do `random(i + 1)`. If we didn't add that 1 to compensate, it would make some shuffle orders more likely to occur than others. +Again, this picks objects at random. In the naive version, we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array. Let's walk through the example. We have the array: @@ -96,13 +92,12 @@ 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.. Int { - return Int(arc4random_uniform(UInt32(n))) -} - - - -/* Fisher-Yates / Knuth shuffle */ -extension Array { - public mutating func shuffle() { - for i in (count - 1).stride(through: 1, by: -1) { - let j = random(i + 1) - if i != j { - swap(&self[i], &self[j]) - } - } - } -} - var list = [ "a", "b", "c", "d", "e", "f", "g" ] list.shuffle() list.shuffle() 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) - for i in 0.. [Int] { + var a = Array(repeating: 0, count: n) + for i in 0.. + + + + diff --git a/Shuffle/Shuffle.playground/timeline.xctimeline b/Shuffle/Shuffle.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Shuffle/Shuffle.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Shuffle/Shuffle.swift b/Shuffle/Shuffle.swift index 8fe8b4e87..1d2758c11 100644 --- a/Shuffle/Shuffle.swift +++ b/Shuffle/Shuffle.swift @@ -1,32 +1,38 @@ import Foundation +/* Returns a random integer between 0 and n-1. */ +public func random(_ n: Int) -> Int { + return Int(arc4random_uniform(UInt32(n))) +} + extension Array { /* - Randomly shuffles the array in-place - This is the Fisher-Yates algorithm, also known as the Knuth shuffle. - Time complexity: O(n) - */ + Randomly shuffles the array in-place + This is the Fisher-Yates algorithm, also known as the Knuth shuffle. + Time complexity: O(n) + */ public mutating func shuffle() { - for i in (count - 1).stride(through: 1, by: -1) { + for i in (1...count-1).reversed() { let j = random(i + 1) if i != j { - swap(&self[i], &self[j]) + let t = self[i] + self[i] = self[j] + self[j] = t } } } } /* - Simultaneously initializes an array with the values 0...n-1 and shuffles it. -*/ -public func shuffledArray(n: Int) -> [Int] { - var a = [Int](count: n, repeatedValue: 0) + Simultaneously initializes an array with the values 0...n-1 and shuffles it. + */ +public func shuffledArray(_ n: Int) -> [Int] { + var a = Array(repeating: 0, count: n) for i in 0.. Bool { + return left.precedence <= right.precedence +} + +func < (left: OperatorToken, right: OperatorToken) -> Bool { + 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 + } +} + +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 + } +} + +// 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) + } + } + + while tokenStack.count > 0 { + reversePolishNotation.append(tokenStack.pop()!) + } + + return reversePolishNotation.map({token in token.description}).joined(separator: " ") +} + +// Simple demo + +let expr = InfixExpressionBuilder() + .addOperand(3) + .addOperator(.add) + .addOperand(4) + .addOperator(.multiply) + .addOperand(2) + .addOperator(.divide) + .addOpenBracket() + .addOperand(1) + .addOperator(.subtract) + .addOperand(5) + .addCloseBracket() + .addOperator(.exponent) + .addOperand(2) + .addOperator(.exponent) + .addOperand(3) + .build() + +print(expr.description) +print(reversePolishNotation(expr)) diff --git a/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift new file mode 100644 index 000000000..54ffe02ce --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/Sources/Stack.swift @@ -0,0 +1,36 @@ +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 + } +} + +extension Stack: Sequence { + public func makeIterator() -> AnyIterator { + var curr = self + return AnyIterator { curr.pop() } + } +} diff --git a/Shunting Yard/ShuntingYard.playground/contents.xcplayground b/Shunting Yard/ShuntingYard.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/contents.xcworkspacedata b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Shunting Yard/ShuntingYard.swift b/Shunting Yard/ShuntingYard.swift new file mode 100644 index 000000000..201264650 --- /dev/null +++ b/Shunting Yard/ShuntingYard.swift @@ -0,0 +1,219 @@ +// +// ShuntingYardAlgorithm.swift +// +// +// Created by Ali Hafizji on 2016-02-25. +// +// + +internal enum OperatorAssociativity { + 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 "^" + } + } +} + +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)" + } + } +} + +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 + } +} + +func <= (left: OperatorToken, right: OperatorToken) -> Bool { + return left.precedence <= right.precedence +} + +func < (left: OperatorToken, right: OperatorToken) -> Bool { + 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 + } +} + +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 + } +} + +// 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) + } + } + + while tokenStack.count > 0 { + reversePolishNotation.append(tokenStack.pop()!) + } + + return reversePolishNotation.map({token in token.description}).joined(separator: " ") +} diff --git a/Simulated annealing/README.md b/Simulated annealing/README.md new file mode 100644 index 000000000..3a36464d7 --- /dev/null +++ b/Simulated annealing/README.md @@ -0,0 +1,36 @@ +# 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..5dc624d04 --- /dev/null +++ b/Simulated annealing/simann.swift @@ -0,0 +1,95 @@ +// 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 + +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.random(in: 0 ..< newSolution.count) + let pos2: Int = Int.random(in: 0 ..< newSolution.count) + newSolution.randSwap(a: pos1, b: pos2) + let currentEnergy: Double = currentSolution.currentEnergy() + let newEnergy: Double = newSolution.currentEnergy() + + if acceptance(currentEnergy, newEnergy, temp) > Double.random(in: 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..e7933c89a --- /dev/null +++ b/Simulated annealing/simann_example.swift @@ -0,0 +1,206 @@ +// 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 + import Cocoa +#elseif os(Linux) + import Glibc +#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((xDistance * xDistance) + (yDistance * yDistance)).squareRoot() + } +} + + +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 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 + } + + func shuffle() { + self.tour.shuffle() + } +} + +// 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.random(in: 0 ..< newSolution.count) + let pos2: Int = Int.random(in: 0 ..< newSolution.count) + newSolution.randSwap(a: pos1, b: pos2) + let currentEnergy: Double = currentSolution.currentEnergy() + let newEnergy: Double = newSolution.currentEnergy() + + if acceptance(currentEnergy, newEnergy, temp) > Double.random(in: 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) diff --git a/Single-Source Shortest Paths (Weighted)/README.markdown b/Single-Source Shortest Paths (Weighted)/README.markdown new file mode 100644 index 000000000..af66b45aa --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/README.markdown @@ -0,0 +1,125 @@ +# Single-Source Shortest Paths + +The Single-Source shortest path problem finds the shortest paths from a given source vertex to all other vertices in a directed weighted graph. Many variations exist on the problem, specifying whether or not edges may have negative values, whether cycles exist, or whether a path between a specific pair of vertices. + +## Bellman-Ford + +The Bellman-Ford shortest paths algorithm finds the shortest paths to all vertices from a given source vertex `s` in a directed graph that may contain negative edge weights. It iterates over all edges for each other vertex in the graph, applying a relaxation to the current state of known shortest path weights. The intuition here is that a path will not contain more vertices than are present in the graph, so performing a pass over all edges `|V|-1` number of times is sufficient to compare all possible paths. + +At each step, a value is stored for each vertex `v`, which is the weight of the current known shortest path `s`~>`v`. This value remains 0 for the source vertex itself, and all others are initially `∞`. Then, they are "relaxed" by applying the following test to each edge `e = (u, v)` (where `u` is a source vertex and `v` is a destination vertex for the directed edge): + + if weights[v] > weights[u] + e.weight { + weights[v] = weights[u] + e.weight + } + +Bellman-Ford in essence only computes the lengths of the shortest paths, but can optionally maintain a structure that memoizes the predecessor of each vertex on its shortest path from the source vertex. Then the paths themselves can be reconstructed by recursing through this structure from a destination vertex to the source vertex. This is maintained by simply adding the statement + + predecessors[v] = u + +inside of the `if` statement's body above. + +### Example + +For the following weighted directed graph: + + + +let's compute the shortest paths from vertex `s`. First, we prepare our `weights` and `predecessors` structures thusly: + +| weights | predecessors | +| ------------- |:-------------:| +| `weights[s] = 0` | `predecessors[s] = 1` | +| `weights[t] = ∞` | `predecessors[t] = ø` | +| `weights[x] = ∞` | `predecessors[x] = ø` | +| `weights[y] = ∞` | `predecessors[y] = ø` | +| `weights[z] = ∞` | `predecessors[z] = ø` | + +Here are their states after each relaxation iteration (each iteration is a pass over all edges, and there are 4 iterations total for this graph): + +###### Iteration 1: + +| weights | predecessors | +| ------------- |:-------------:| +| `weights[s] = 0` | `predecessors[s] = s` | +| `weights[t] = 6` | `predecessors[t] = s` | +| `weights[x] = 4` | `predecessors[x] = y` | +| `weights[y] = 7` | `predecessors[y] = s` | +| `weights[z] = 2` | `predecessors[z] = t` | + +###### Iteration 2: + +| weights | predecessors | +| ------------- |:-------------:| +| `weights[s] = 0` | `predecessors[s] = s` | +| `weights[t] = 2` | `predecessors[t] = x` | +| `weights[x] = 4` | `predecessors[x] = y` | +| `weights[y] = 7` | `predecessors[y] = s` | +| `weights[z] = 2` | `predecessors[z] = t` | + +###### Iteration 3: + +| weights | predecessors | +| ------------- |:-------------:| +| `weights[s] = 0` | `predecessors[s] = s` | +| `weights[t] = 2` | `predecessors[t] = x` | +| `weights[x] = 4` | `predecessors[x] = y` | +| `weights[y] = 7` | `predecessors[y] = s` | +| `weights[z] = -2` | `predecessors[z] = t` | + +###### Iteration 4: + +| weights | predecessors | +| ------------- |:-------------:| +| `weights[s] = 0` | `predecessors[s] = s` | +| `weights[t] = 2` | `predecessors[t] = x` | +| `weights[x] = 4` | `predecessors[x] = y` | +| `weights[y] = 7` | `predecessors[y] = s` | +| `weights[z] = -2` | `predecessors[z] = t` | + +#### Negative weight cycles + +An additional useful property of the solution structure is that it can answer whether or not a negative weight cycle exists in the graph and is reachable from the source vertex. A negative weight cycle is a cycle whose sum of edge weights is negative. This means that shortest paths are not well defined in the graph from the specified source, because you can decrease the weight of a path by reentering the cycle, pushing the path's weight towards `-∞`. After fully relaxing the paths, simply running a check over each edge `e = (u, v)` to see if the weight of the shortest path to `v` is greater than the path to `u`, plus the edge weight itself, signals that the edge has a negative weight and would decrease the shortest path's weight further. Since we know we've already performed the relaxations enough times according to the intuition stated above, we can safely assume this further decrease of weight will continue infinitely. + +##### Example + +For this example, we try to compute the shortest paths from `a`: + + + +The cycle `a`->`t`->`s`->`a` has a total edge weight of -9, therefore shortest paths for `a`~>`t` and `a`~>`s` are not well-defined. `a`~>`b` is also not well-defined because `b`->`t`->`s` is also a negative weight cycle. + +This is confirmed after running the relaxation loop, and checking all the edges as mentioned above. For this graph, we would have after relaxation: + +| weights | +| ------------- | +| `weights[a] = -5` | +| `weights[b] = -5` | +| `weights[s] = -18` | +| `weights[t] = -3` | + +One of the edge checks we would perform afterwards would be the following: + + e = (s, a) + e.weight = 4 + weight[a] > weight[s] + e.weight => -5 > -18 + 4 => -5 > -14 => true + +Because this check is true, we know the graph has a negative weight cycle reachable from `a`. + +#### Complexity + +The relaxation step requires constant time (`O(1)`) as it simply performs comparisons. That step is performed once per edge (`Θ(|E|)`), and the edges are iterated over `|V|-1` times. This would mean a total complexity of `Θ(|V||E|)`, but there is an optimization we can make: if the outer loop executes and no changes are made to the recorded weights, we can safely terminate the relaxation phase, which means it may execute in `O(|V|)` steps instead of `Θ(|V|)` steps (that is, the best case for any size graph is actually a constant number of iterations; the worst case is still iterating `|V|-1` times). + +The check for negative weight cycles at the end is `O(|E|)` if we return once we find a hit. To find all negative weight cycles reachable from the source vertex, we'd have to iterate `Θ(|E|)` times (we currently do not attempt to report the cycles, we simply return a `nil` result if such a cycle is present). + +The total running time of Bellman-Ford is therefore `O(|V||E|)`. + +## TODO + +- Dijkstra's algorithm for computing SSSP on a directed non-negative weighted graph + +# References + +- Chapter 24 of Introduction to Algorithms, Third Edition by Cormen, Leiserson, Rivest and Stein [https://mitpress.mit.edu/books/introduction-algorithms](https://mitpress.mit.edu/books/introduction-algorithms) +- Wikipedia: [Bellman–Ford algorithm](https://en.wikipedia.org/wiki/Bellman–Ford_algorithm) + +*Written for Swift Algorithm Club by [Andrew McKnight](https://github.com/armcknight)* \ No newline at end of file diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift b/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift new file mode 100644 index 000000000..e897ada4a --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.playground/Contents.swift @@ -0,0 +1,33 @@ +import Graph +import SSSP + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +let graph = AdjacencyMatrixGraph() +let s = graph.createVertex("s") +let t = graph.createVertex("t") +let x = graph.createVertex("x") +let y = graph.createVertex("y") +let z = graph.createVertex("z") + +graph.addDirectedEdge(s, to: t, withWeight: 6) +graph.addDirectedEdge(s, to: y, withWeight: 7) + +graph.addDirectedEdge(t, to: x, withWeight: 5) +graph.addDirectedEdge(t, to: y, withWeight: 8) +graph.addDirectedEdge(t, to: z, withWeight: -4) + +graph.addDirectedEdge(x, to: t, withWeight: -2) + +graph.addDirectedEdge(y, to: x, withWeight: -3) +graph.addDirectedEdge(y, to: z, withWeight: 9) + +graph.addDirectedEdge(z, to: s, withWeight: 2) +graph.addDirectedEdge(z, to: x, withWeight: 7) + +let result = BellmanFord.apply(graph, source: s)! + +let path = result.path(to: z, inGraph: graph) diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.playground/contents.xcplayground b/Single-Source Shortest Paths (Weighted)/SSSP.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.playground/playground.xcworkspace/contents.xcworkspacedata b/Single-Source Shortest Paths (Weighted)/SSSP.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj new file mode 100644 index 000000000..44365e5aa --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/project.pbxproj @@ -0,0 +1,485 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 49763FF21CF08FC500202EA9 /* Graph.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49763FEF1CF08FB100202EA9 /* Graph.framework */; }; + 49BFA2971CDF86E100522D66 /* SSSP.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BFA2961CDF86E100522D66 /* SSSP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49BFA29E1CDF86E100522D66 /* SSSP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49BFA2931CDF86E100522D66 /* SSSP.framework */; }; + 49BFA2A31CDF86E100522D66 /* SSSPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2A21CDF86E100522D66 /* SSSPTests.swift */; }; + 49BFA2AE1CDF86FD00522D66 /* SSSP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2AD1CDF86FD00522D66 /* SSSP.swift */; }; + 49BFA2B01CDF870600522D66 /* BellmanFord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2AF1CDF870600522D66 /* BellmanFord.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 49763FEE1CF08FB100202EA9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 49BFA2FD1CDF886B00522D66; + remoteInfo = Graph; + }; + 49763FF01CF08FB100202EA9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 49BFA3071CDF886B00522D66; + remoteInfo = GraphTests; + }; + 49763FF31CF08FC900202EA9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 49BFA2FC1CDF886B00522D66; + remoteInfo = Graph; + }; + 49BFA29F1CDF86E100522D66 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 49BFA28A1CDF86E100522D66 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 49BFA2921CDF86E100522D66; + remoteInfo = SSSP; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Graph.xcodeproj; path = ../Graph/Graph.xcodeproj; sourceTree = ""; }; + 49BFA2931CDF86E100522D66 /* SSSP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SSSP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 49BFA2961CDF86E100522D66 /* SSSP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSSP.h; sourceTree = ""; }; + 49BFA2981CDF86E100522D66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49BFA29D1CDF86E100522D66 /* SSSPTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSSPTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 49BFA2A21CDF86E100522D66 /* SSSPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSSPTests.swift; sourceTree = ""; }; + 49BFA2A41CDF86E100522D66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49BFA2AD1CDF86FD00522D66 /* SSSP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSSP.swift; sourceTree = ""; }; + 49BFA2AF1CDF870600522D66 /* BellmanFord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BellmanFord.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 49BFA28F1CDF86E100522D66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49763FF21CF08FC500202EA9 /* Graph.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA29A1CDF86E100522D66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA29E1CDF86E100522D66 /* SSSP.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 49763FEA1CF08FB100202EA9 /* Products */ = { + isa = PBXGroup; + children = ( + 49763FEF1CF08FB100202EA9 /* Graph.framework */, + 49763FF11CF08FB100202EA9 /* GraphTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 49BFA2891CDF86E100522D66 = { + isa = PBXGroup; + children = ( + 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */, + 49BFA2951CDF86E100522D66 /* SSSP */, + 49BFA2A11CDF86E100522D66 /* SSSPTests */, + 49BFA2941CDF86E100522D66 /* Products */, + ); + sourceTree = ""; + }; + 49BFA2941CDF86E100522D66 /* Products */ = { + isa = PBXGroup; + children = ( + 49BFA2931CDF86E100522D66 /* SSSP.framework */, + 49BFA29D1CDF86E100522D66 /* SSSPTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 49BFA2951CDF86E100522D66 /* SSSP */ = { + isa = PBXGroup; + children = ( + 49BFA2961CDF86E100522D66 /* SSSP.h */, + 49BFA2AD1CDF86FD00522D66 /* SSSP.swift */, + 49BFA2AF1CDF870600522D66 /* BellmanFord.swift */, + 49BFA2981CDF86E100522D66 /* Info.plist */, + ); + path = SSSP; + sourceTree = ""; + }; + 49BFA2A11CDF86E100522D66 /* SSSPTests */ = { + isa = PBXGroup; + children = ( + 49BFA2A21CDF86E100522D66 /* SSSPTests.swift */, + 49BFA2A41CDF86E100522D66 /* Info.plist */, + ); + path = SSSPTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 49BFA2901CDF86E100522D66 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA2971CDF86E100522D66 /* SSSP.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 49BFA2921CDF86E100522D66 /* SSSP */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49BFA2A71CDF86E100522D66 /* Build configuration list for PBXNativeTarget "SSSP" */; + buildPhases = ( + 49BFA28E1CDF86E100522D66 /* Sources */, + 49BFA28F1CDF86E100522D66 /* Frameworks */, + 49BFA2901CDF86E100522D66 /* Headers */, + 49BFA2911CDF86E100522D66 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 49763FF41CF08FC900202EA9 /* PBXTargetDependency */, + ); + name = SSSP; + productName = SSSP; + productReference = 49BFA2931CDF86E100522D66 /* SSSP.framework */; + productType = "com.apple.product-type.framework"; + }; + 49BFA29C1CDF86E100522D66 /* SSSPTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49BFA2AA1CDF86E100522D66 /* Build configuration list for PBXNativeTarget "SSSPTests" */; + buildPhases = ( + 49BFA2991CDF86E100522D66 /* Sources */, + 49BFA29A1CDF86E100522D66 /* Frameworks */, + 49BFA29B1CDF86E100522D66 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 49BFA2A01CDF86E100522D66 /* PBXTargetDependency */, + ); + name = SSSPTests; + productName = SSSPTests; + productReference = 49BFA29D1CDF86E100522D66 /* SSSPTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 49BFA28A1CDF86E100522D66 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 0810; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 49BFA2921CDF86E100522D66 = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0810; + }; + 49BFA29C1CDF86E100522D66 = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0810; + }; + }; + }; + buildConfigurationList = 49BFA28D1CDF86E100522D66 /* Build configuration list for PBXProject "SSSP" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 49BFA2891CDF86E100522D66; + productRefGroup = 49BFA2941CDF86E100522D66 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 49763FEA1CF08FB100202EA9 /* Products */; + ProjectRef = 49763FE91CF08FB100202EA9 /* Graph.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 49BFA2921CDF86E100522D66 /* SSSP */, + 49BFA29C1CDF86E100522D66 /* SSSPTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 49763FEF1CF08FB100202EA9 /* Graph.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Graph.framework; + remoteRef = 49763FEE1CF08FB100202EA9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 49763FF11CF08FB100202EA9 /* GraphTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = GraphTests.xctest; + remoteRef = 49763FF01CF08FB100202EA9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 49BFA2911CDF86E100522D66 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA29B1CDF86E100522D66 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 49BFA28E1CDF86E100522D66 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA2B01CDF870600522D66 /* BellmanFord.swift in Sources */, + 49BFA2AE1CDF86FD00522D66 /* SSSP.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49BFA2991CDF86E100522D66 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49BFA2A31CDF86E100522D66 /* SSSPTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 49763FF41CF08FC900202EA9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Graph; + targetProxy = 49763FF31CF08FC900202EA9 /* PBXContainerItemProxy */; + }; + 49BFA2A01CDF86E100522D66 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 49BFA2921CDF86E100522D66 /* SSSP */; + targetProxy = 49BFA29F1CDF86E100522D66 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 49BFA2A51CDF86E100522D66 /* 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_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; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 49BFA2A61CDF86E100522D66 /* 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_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; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 49BFA2A81CDF86E100522D66 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SSSP/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.SSSP"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 49BFA2A91CDF86E100522D66 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SSSP/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.SSSP"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 49BFA2AB1CDF86E100522D66 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = SSSPTests/Info.plist; + 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 = 4.0; + }; + name = Debug; + }; + 49BFA2AC1CDF86E100522D66 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = SSSPTests/Info.plist; + 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 = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 49BFA28D1CDF86E100522D66 /* Build configuration list for PBXProject "SSSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA2A51CDF86E100522D66 /* Debug */, + 49BFA2A61CDF86E100522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 49BFA2A71CDF86E100522D66 /* Build configuration list for PBXNativeTarget "SSSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA2A81CDF86E100522D66 /* Debug */, + 49BFA2A91CDF86E100522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 49BFA2AA1CDF86E100522D66 /* Build configuration list for PBXNativeTarget "SSSPTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49BFA2AB1CDF86E100522D66 /* Debug */, + 49BFA2AC1CDF86E100522D66 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 49BFA28A1CDF86E100522D66 /* Project object */; +} 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 new file mode 100644 index 000000000..469159bd8 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSP.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSPTests.xcscheme b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSPTests.xcscheme new file mode 100644 index 000000000..043f296a5 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcodeproj/xcshareddata/xcschemes/SSSPTests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/contents.xcworkspacedata b/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..77aa9c473 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift b/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift new file mode 100644 index 000000000..41be9759b --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP/BellmanFord.swift @@ -0,0 +1,146 @@ +// +// BellmanFord.swift +// SSSP +// +// Created by Andrew McKnight on 5/8/16. +// + +import Foundation +import Graph + +public struct BellmanFord where T: Hashable { + public typealias Q = T +} + +/** + Encapsulation of the Bellman-Ford Single-Source Shortest Paths algorithm, + which operates on a general directed graph that may contain negative edge weights. + + - note: In all complexity bounds, `V` is the number of vertices in the graph, and `E` is the number of edges. + */ +extension BellmanFord: SSSPAlgorithm { + + /** + Compute the shortest path from `source` to each other vertex in `graph`, + if such paths exist. Also report negative weight cycles reachable from `source`, + which are cycles whose sum of edge weights is negative. + + - precondition: `graph` must have no negative weight cycles + - complexity: `O(VE)` time, `Θ(V)` space + - 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? { + let vertices = graph.vertices + let edges = graph.edges + + 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 + + for _ in 0 ..< vertices.count - 1 { + var weightsUpdated = false + edges.forEach { edge in + let weight = edge.weight! + let relaxedDistance = weights[edge.from.index] + weight + let nextVertexIdx = edge.to.index + if relaxedDistance < weights[nextVertexIdx] { + predecessors[nextVertexIdx] = edge.from.index + weights[nextVertexIdx] = relaxedDistance + weightsUpdated = true + } + } + if !weightsUpdated { + break + } + } + + // check for negative weight cycles reachable from the source vertex + // TO DO: modify to incorporate solution to 24.1-4, pg 654, to set the + // weight of a path containing a negative weight cycle to -∞, + // instead of returning nil for the entire result + for edge in edges { + if weights[edge.to.index] > weights[edge.from.index] + edge.weight! { + return nil + } + } + + return BellmanFordResult(predecessors: predecessors, weights: weights) + } + +} + +/** + `BellmanFordResult` encapsulates the result of the computation, + namely the minimized distances, and the predecessor indices. + + 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 where T: Hashable { + + fileprivate var predecessors: [Int?] + fileprivate var weights: [Double] + +} + +extension BellmanFordResult: SSSPResult { + + /** + - returns: the total weight of the path from the source vertex to a destination. + This value is the minimal connected weight between the two vertices, or `nil` if no path exists + - complexity: `Θ(1)` time/space + */ + public func distance(to: Vertex) -> Double? { + let distance = weights[to.index] + + guard distance != Double.infinity else { + return nil + } + + return distance + } + + /** + - returns: the reconstructed path from the source vertex to a destination, + as an array containing the data property of each vertex, or `nil` if no path exists + - complexity: `Θ(V)` time, `Θ(V^2)` space + */ + public func path(to: Vertex, inGraph graph: AbstractGraph) -> [T]? { + guard weights[to.index] != Double.infinity else { + return nil + } + + guard let path = recursePath(to: to, inGraph: graph, path: [to]) else { + return nil + } + + return path.map { vertex in + return vertex.data + } + } + + /** + The recursive component to rebuilding the shortest path between two vertices using predecessors. + + - returns: the list of predecessors discovered so far, or `nil` if the next vertex has no predecessor + */ + fileprivate func recursePath(to: Vertex, inGraph graph: AbstractGraph, path: [Vertex]) -> [Vertex]? { + guard let predecessorIdx = predecessors[to.index] else { + return nil + } + + let predecessor = graph.vertices[predecessorIdx] + if predecessor.index == to.index { + return [ to ] + } + + guard let buildPath = recursePath(to: predecessor, inGraph: graph, path: path) else { + return nil + } + + return buildPath + [ to ] + } + +} diff --git a/Heap/Heap Tests/Heap/Info.plist b/Single-Source Shortest Paths (Weighted)/SSSP/Info.plist similarity index 67% rename from Heap/Heap Tests/Heap/Info.plist rename to Single-Source Shortest Paths (Weighted)/SSSP/Info.plist index 0dca3caa8..d3de8eefb 100644 --- a/Heap/Heap Tests/Heap/Info.plist +++ b/Single-Source Shortest Paths (Weighted)/SSSP/Info.plist @@ -6,8 +6,6 @@ en CFBundleExecutable $(EXECUTABLE_NAME) - CFBundleIconFile - CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion @@ -15,20 +13,14 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu + $(CURRENT_PROJECT_VERSION) NSPrincipalClass - NSApplication + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.h b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.h new file mode 100644 index 000000000..46cc4de16 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.h @@ -0,0 +1,18 @@ +// +// SSSP.h +// SSSP +// +// Created by Andrew McKnight on 5/8/16. +// + +#import + +//! Project version number for SSSP. +FOUNDATION_EXPORT double SSSPVersionNumber; + +//! Project version string for SSSP. +FOUNDATION_EXPORT const unsigned char SSSPVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift new file mode 100644 index 000000000..3066f6516 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSP/SSSP.swift @@ -0,0 +1,36 @@ +// +// SSSP.swift +// SSSP +// +// Created by Andrew McKnight on 5/8/16. +// + +import Foundation +import Graph + +/** + `SSSPAlgorithm` is a protocol for encapsulating a Single-Source Shortest Path algorithm. + It provides a single function `apply` that accepts a subclass of `AbstractGraph` and returns + an object conforming to `SSSPResult`. + */ +protocol SSSPAlgorithm { + + associatedtype Q: Equatable, Hashable + associatedtype P: SSSPResult + + static func apply(_ graph: AbstractGraph, source: Vertex) -> P? + +} + +/** + `SSSPResult` is a protocol defining functions `distance` and `path`, allowing + for opaque queries into the actual data structures that represent the SSSP + solution according to the algorithm used. + */ +protocol SSSPResult { + + associatedtype T: Equatable, Hashable + + func distance(to: Vertex) -> Double? + func path(to: Vertex, inGraph graph: AbstractGraph) -> [T]? +} diff --git a/Single-Source Shortest Paths (Weighted)/SSSPTests/Info.plist b/Single-Source Shortest Paths (Weighted)/SSSPTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSPTests/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/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift b/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift new file mode 100644 index 000000000..924a487f5 --- /dev/null +++ b/Single-Source Shortest Paths (Weighted)/SSSPTests/SSSPTests.swift @@ -0,0 +1,141 @@ +// +// SSSPTests.swift +// SSSPTests +// +// Created by Andrew McKnight on 5/8/16. +// + +import Graph +import XCTest +@testable import SSSP + +class SSSPTests: XCTestCase { + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + /** + See Figure 24.4 of “Introduction to Algorithms” by Cormen et al, 3rd ed., pg 652 + */ + func testExampleFromBook() { + let graph = AdjacencyMatrixGraph() + let s = graph.createVertex("s") + let t = graph.createVertex("t") + let x = graph.createVertex("x") + let y = graph.createVertex("y") + let z = graph.createVertex("z") + + graph.addDirectedEdge(s, to: t, withWeight: 6) + graph.addDirectedEdge(s, to: y, withWeight: 7) + + graph.addDirectedEdge(t, to: x, withWeight: 5) + graph.addDirectedEdge(t, to: y, withWeight: 8) + graph.addDirectedEdge(t, to: z, withWeight: -4) + + graph.addDirectedEdge(x, to: t, withWeight: -2) + + graph.addDirectedEdge(y, to: x, withWeight: -3) + graph.addDirectedEdge(y, to: z, withWeight: 9) + + graph.addDirectedEdge(z, to: s, withWeight: 2) + graph.addDirectedEdge(z, to: x, withWeight: 7) + + let result = BellmanFord.apply(graph, source: s)! + + let expectedPath = ["s", "y", "x", "t", "z"] + 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(to: z) + XCTAssertEqual(expectedWeight, computedWeight, "expected weight of \(expectedWeight) but got \(computedWeight)") + } + + func testSimpleExample() { + let graph = AdjacencyMatrixGraph() + let a = graph.createVertex("a") + let b = graph.createVertex("b") + let c = graph.createVertex("c") + let d = graph.createVertex("d") + let e = graph.createVertex("e") + + graph.addDirectedEdge(a, to: b, withWeight: 4) + graph.addDirectedEdge(a, to: c, withWeight: 5) + graph.addDirectedEdge(a, to: d, withWeight: 8) + + graph.addDirectedEdge(b, to: c, withWeight: -2) + + graph.addDirectedEdge(c, to: e, withWeight: 4) + + graph.addDirectedEdge(d, to: e, withWeight: 2) + + graph.addDirectedEdge(e, to: d, withWeight: 1) + + let result = BellmanFord.apply(graph, source: a)! + + let expectedPath = ["a", "b", "c", "e", "d"] + 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(to: d) + XCTAssertEqual(expectedWeight, computedWeight, "expected weight of \(expectedWeight) but got \(computedWeight)") + } + + /** + Construct a nearly bipartite graph, except one vertex only has out-edges. Then no path should exist from the source to that vertex. + */ + func testGraphWithUnreachableVertex() { + let graph = AdjacencyMatrixGraph() + let a = graph.createVertex("a") + let b = graph.createVertex("b") + let s = graph.createVertex("s") + let t = graph.createVertex("t") + + graph.addDirectedEdge(a, to: s, withWeight: 9) + graph.addDirectedEdge(a, to: t, withWeight: 2) + + graph.addDirectedEdge(b, to: a, withWeight: 1) + graph.addDirectedEdge(b, to: s, withWeight: 2) + graph.addDirectedEdge(b, to: t, withWeight: 3) + + graph.addDirectedEdge(s, to: a, withWeight: 4) + graph.addDirectedEdge(s, to: t, withWeight: 1) + + graph.addDirectedEdge(t, to: a, withWeight: 7) + graph.addDirectedEdge(t, to: s, withWeight: 5) + + let result = BellmanFord.apply(graph, source: a)! + + 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() { + let graph = AdjacencyMatrixGraph() + let a = graph.createVertex("a") + let b = graph.createVertex("b") + let s = graph.createVertex("s") + let t = graph.createVertex("t") + + graph.addDirectedEdge(a, to: t, withWeight: 2) + + graph.addDirectedEdge(b, to: t, withWeight: 5) + + graph.addDirectedEdge(s, to: a, withWeight: 4) + graph.addDirectedEdge(s, to: b, withWeight: 4) + + graph.addDirectedEdge(t, to: s, withWeight: -15) + + XCTAssertNil(BellmanFord.apply(graph, source: s), "negative weight cycle not reported") + } + +} diff --git a/Single-Source Shortest Paths (Weighted)/img/example_graph.png b/Single-Source Shortest Paths (Weighted)/img/example_graph.png new file mode 100644 index 000000000..69674ba93 Binary files /dev/null and b/Single-Source Shortest Paths (Weighted)/img/example_graph.png differ diff --git a/Single-Source Shortest Paths (Weighted)/img/negative_cycle_example.png b/Single-Source Shortest Paths (Weighted)/img/negative_cycle_example.png new file mode 100644 index 000000000..e1cbc451c Binary files /dev/null and b/Single-Source Shortest Paths (Weighted)/img/negative_cycle_example.png differ diff --git a/Singly Linked List/Images/CopiedIndirectStorage.png b/Singly Linked List/Images/CopiedIndirectStorage.png new file mode 100644 index 000000000..7a2f7e68c Binary files /dev/null and b/Singly Linked List/Images/CopiedIndirectStorage.png differ diff --git a/Singly Linked List/Images/SharedIndirectStorage.png b/Singly Linked List/Images/SharedIndirectStorage.png new file mode 100644 index 000000000..51920c236 Binary files /dev/null and b/Singly Linked List/Images/SharedIndirectStorage.png differ diff --git a/Singly Linked List/KeyValuePair.swift b/Singly Linked List/KeyValuePair.swift new file mode 100644 index 000000000..9c6cacea4 --- /dev/null +++ b/Singly Linked List/KeyValuePair.swift @@ -0,0 +1,77 @@ +/// Conformers of this protocol represent a pair of comparable values +/// This can be useful in many data structures and algorithms where items +/// stored contain a value, but are ordered or retrieved according to a key. +public protocol KeyValuePair : Comparable { + + associatedtype K : Comparable, Hashable + associatedtype V : Comparable, Hashable + + // Identifier used in many algorithms to search by, order by, etc + var key : K {get set} + + // A data container + var value : V {get set} + + + /// Initializer + /// + /// - Parameters: + /// - key: Identifier used in many algorithms to search by, order by, etc. + /// - value: A data container. + init(key: K, value: V) + + + /// Creates a copy + /// + /// - Abstract: Conformers of this class can be either value or reference types. + /// Some algorithms might need to guarantee that a conformer instance gets copied. + /// This will perform an innecessary in the case of value types. + /// TODO: is there a better way? + /// - Returns: A new instance with the old one's values copied. + func copy() -> Self +} + + +/// Conformance to Equatable and Comparable protocols +extension KeyValuePair { + + // MARK: - Equatable protocol + public static func ==(lhs: Self, rhs: Self) -> Bool { + return lhs.key == rhs.key + } + + + + // MARK: - Comparable protocol + + public static func <(lhs: Self, rhs: Self) -> Bool { + return lhs.key < rhs.key + } + + public static func <=(lhs: Self, rhs: Self) -> Bool { + return lhs.key <= rhs.key + } + + public static func >=(lhs: Self, rhs: Self) -> Bool { + return lhs.key >= rhs.key + } + + public static func >(lhs: Self, rhs: Self) -> Bool { + return lhs.key > rhs.key + } +} + + + +/// Concrete impletation of a KeyValuePair where both the key and the value +/// are Integers. +struct IntegerPair : KeyValuePair { + + // MARK - KeyValuePair protocol + var key : Int + var value : Int + + func copy() -> IntegerPair { + return IntegerPair(key: self.key, value: self.value) + } +} diff --git a/Singly Linked List/README.markdown b/Singly Linked List/README.markdown new file mode 100644 index 000000000..6d896db88 --- /dev/null +++ b/Singly Linked List/README.markdown @@ -0,0 +1,136 @@ +# Singly-Linked List + +#### How is this different to the Linked List implementation? +The existing Linked list implementation represents the same concept. However, the existing implementation has reference semantics and does not conform to the Collection protocol implemented in the Swift's standard Library. What SinglyLinkedList aims to contribute is a more idiomatic Swift implementation, that uses value semantics and copy-on-write as well as conforms to the collection protocol. + +#### Conceptual representation +A Singly linked list is a non-contiguous sequence of data items in memory. Each element links to the next via a memory reference. Additionally, this implementation keeps track of the last element, which can be retrived in order O(1). However, the list can only be traversed from head to tail. + + +--------+ +--------+ +--------+ +--------+ + | | | | | | | | + | node 0 |--->| node 1 |--->| node 2 |--->| node 3 |---> nil + | | | | | | | | + +--------+ +--------+ +--------+ +--------+ + ^ ^ + | | + Head Tail + +Each element in the list is represented with an instance of SinglyLinkedListNode class, which basically contains some data and a reference of optional type to the next node, which means that the last node's next reference is `nil`. + +#### In-memory representation +In Swift, data types can have value or reference semantics. This implementation of a singly-linked list uses value semantics. Support for copy-on-write has been added in order to improve performance and delay copying the elements of the array until strictly necessary. + +The image below shows how initially, after variable `l2` is assigned `l1`, a new instance of the struct SinglyLinkedList is created. Nevertheless, the indirect storage is still shared as indicated by the references that both l1 and l2 have pointing to a common area in memory. + +![alt text](Images/SharedIndirectStorage.png "Two linked lists sharing the indirect storage") + +Once a mutating operation happens --for example on `l2` to append a new element--, then the indirect storage and all nodes in the list is actually copied and the references from `l1` and `l2` are updated. This is ilustrated in the following figure. + +![alt text](Images/CopiedIndirectStorage.png "A copy is created after editing one of the lists") + +#### Implementation details +1. Direct access to the tail in O(1) by keeping a reference that gets updated only when an operation to the list modifies the tail. +2. Value semantics. This implementation of a singly-linked list uses a struct. When the list struct is assigned into another variable or passed as an argument to a function, a copy of the struct is made. +3. Copy-on write. Instances of SinglyLinkedList have an internal reference to an indirect storage allocated in the heap. When a copy of the list is made (according to its value semantics) the indirect storage is initialy shared between the copies. This means that a potentially large list can be accessed to read values in it without an expensive copy having to take place. However, as soon as there is a write access to the indirect storage when there are more than one instances referencing to it, a copy will be performed to guarantee value semantics. +4. Conformance to the Collection protocol. + + + + + +## Performance of linked lists + +EDITION +- *append*: Appends a new node to the end of the list. This method will modify the list's tail. If the list is empty, it will also modify the head. This operation's time complexity is *O(1)* since there's a reference to the tail node in this implementation. +- *prepend*: Inserts a new node at the start of the list. If the list is empty, it will also modify the head. This operation's time complexity is *O(1)* since there's a reference to the head node. +- *delete*: Finds a node in the list and deletes it. This operation's time complexity has an upper bound described by a linear function; O(n). + +SEARCH +- find k-th to last element. Given a list with `n` number of elements and `k` being the passed parameter with `0` <= `k` <= `n`, this method has *O(k)*. + +## Conforming to the Collection protocol +Collections are sequences, therefore the first step is to conform to the Sequence protocol. + +``` +extension SinglyLinkedList: Sequence { + public func makeIterator() -> SinglyLinkedListForwardIterator { + return SinglyLinkedListForwardIterator(head: self.storage.head) + } +} +``` + +We have used `SinglyLinkedListForwardIterator` an iterator class to keep track of the progress while iterating the structure: + +``` +public struct SinglyLinkedListForwardIterator : IteratorProtocol { + + public typealias Element = T + + private(set) var head: SinglyLinkedListNode? + + mutating public func next() -> T? { + let result = self.head?.value + self.head = self.head?.next + return result + } +} +``` + +Next, a collection needs to be indexable. Indexes are implemented by the data structure class. We have encapsulated this knowledge in instances of the class `SinglyLinkedListIndex`. + +``` +public struct SinglyLinkedListIndex: Comparable { + fileprivate let node: SinglyLinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} +``` + +Finally, the methods in the collection to manipulate indexes are implemented below: +- startIndex: Index of the first element. Can be calculated with O(1). +- endIndex: Index that follows the last valid index in the collection. That is, the index that follows the tail's index. Can be calculated with O(1) if the count of elements is kept internally. However, the implementation below is O(n) with `n` being the number of elements in the list. + +``` +extension SinglyLinkedList : Collection { + + public typealias Index = SinglyLinkedListIndex + + public var startIndex: Index { + get { + return SinglyLinkedListIndex(node: self.storage.head, tag: 0) + } + } + +public var endIndex: Index { + get { + if let h = self.storage.head { + let (_, numberOfElements) = findTail(in: h) + return SinglyLinkedListIndex(node: h, tag: numberOfElements) + } else { + return SinglyLinkedListIndex(node: nil, tag: self.startIndex.tag) + } + } +} + +public subscript(position: Index) -> T { + get { + return position.node!.value + } +} + +public func index(after idx: Index) -> Index { + return SinglyLinkedListIndex(node: idx.node?.next, tag: idx.tag+1) + } +} +``` + +Conforming to the Collection protocol allows our class SinglyLinkedList to take adventage of all the collection methods included in the Stardard Library. + +*Written by Borja Arias Drake* diff --git a/Singly Linked List/SinglyLinkedList.playground/Contents.swift b/Singly Linked List/SinglyLinkedList.playground/Contents.swift new file mode 100644 index 000000000..8c62f9e78 --- /dev/null +++ b/Singly Linked List/SinglyLinkedList.playground/Contents.swift @@ -0,0 +1,727 @@ +//: # Linked Lists + +// For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu + +//: Linked List Class Declaration: +// last checked with Xcode 9M136h +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +//: We will start by defining a protocol that elements inserted into this implementation of a List will conform to. This is useful, because many algorithms are only interested in a key that all elements have. + +/// Conformers of this protocol represent a pair of comparable values +/// This can be useful in many data structures and algorithms where items +/// stored contain a value, but are ordered or retrieved according to a key. +public protocol KeyValuePair : Comparable { + + associatedtype K : Comparable, Hashable + associatedtype V : Comparable, Hashable + + // Identifier used in many algorithms to search by, order by, etc + var key : K {get set} + + // A data container + var value : V {get set} + + + /// Initializer + /// + /// - Parameters: + /// - key: Identifier used in many algorithms to search by, order by, etc. + /// - value: A data container. + init(key: K, value: V) + + + /// Creates a copy + /// + /// - Abstract: Conformers of this class can be either value or reference types. + /// Some algorithms might need to guarantee that a conformer instance gets copied. + /// This will perform an innecessary in the case of value types. + /// TODO: is there a better way? + /// - Returns: A new instance with the old one's values copied. + func copy() -> Self +} + + +/// Conformance to Equatable and Comparable protocols +extension KeyValuePair { + + // MARK: - Equatable protocol + public static func ==(lhs: Self, rhs: Self) -> Bool { + return lhs.key == rhs.key + } + + + + // MARK: - Comparable protocol + + public static func <(lhs: Self, rhs: Self) -> Bool { + return lhs.key < rhs.key + } + + public static func <=(lhs: Self, rhs: Self) -> Bool { + return lhs.key <= rhs.key + } + + public static func >=(lhs: Self, rhs: Self) -> Bool { + return lhs.key >= rhs.key + } + + public static func >(lhs: Self, rhs: Self) -> Bool { + return lhs.key > rhs.key + } +} + +//: Concrete impletation of a KeyValuePair where both the key and the value that we'll use in the examples in this playground + +struct IntegerPair : KeyValuePair { + + // MARK - KeyValuePair protocol + var key : Int + var value : Int + + func copy() -> IntegerPair { + return IntegerPair(key: self.key, value: self.value) + } +} + +//: Lists are usually used as queues. As an example, we'll define these expectations in a protocol and we'll make the the SinglyLinkedList class conform to it. + +/// Data structure that provides FIFO access +protocol Queue +{ + associatedtype Item + + + /// Adds an element to the queue + /// + /// - Parameter item: Item to be added + /// - Throws: There are cases where the operation might fail. For example if there is not enough space. + mutating func enqueue(item: Item) throws + + + /// Returns the oldest element in the queue. + /// + /// - Returns: The oldest element in the queue. It does not dequeue it. + func getFirst() -> Item? + + + /// Dequeues the oldest element in the queue. + /// + /// - Returns: The oldest element in the queue, which gets removed from it. + mutating func dequeue() -> Item? +} + + +//: Next, we are going to implement a list that has value semantics. Value semantics imply that the values will be copied when assigned and passed as a parameter to functions and methods. In order to prevent unnecesasry copies, Swift uses a technique called copy-on-write; copies are only performed when a mutating operation is performed on an instance that is referenced by more than one objects. In Swift, this is ahieved with an additional level of indirection, an internal class instance, therefore with reference semantics, that will be shared, until a mutating operation occurs. + + +/// Helper class to implement copy-on-write +fileprivate class IndirectStorage { + + var head: SinglyLinkedListNode? + + var tail: SinglyLinkedListNode? + + init(head: SinglyLinkedListNode?, tail: SinglyLinkedListNode?) { + self.head = head + self.tail = tail + } + + convenience init() { + self.init(head: nil, tail: nil) + } +} + + +//: Node of the list + + +// MARK: - NODE - + +/// A node is the building block of a linked list. +/// It can be used on its own to create linked lists. However users of this class, +/// will need to manipulate references directly. +public class SinglyLinkedListNode { + + /// Data container + public var value: T + + /// Link to the next node + public var next: SinglyLinkedListNode? + + /// Designated initializer + /// + /// - Parameter value: A value + public init(value: T) { + self.value = value + } +} + +//: The list with value semantics + +// MARK: - LINKED LIST - + +/// Data structure to hold a collection of items. +/// Each nodes contains a reference to the next node. +/// The last node does not reference any other node. +/// This class implements value semantics based on copy-on-write. +/// +/// However, the elements contained in the list, will be shallow copied if they +/// implement reference semantics. +public struct SinglyLinkedList +{ + // MARK: PROPERTIES + + // A level of inderiction, with reference semantics to allow easy + // detection of when there are more than one references of the storage. + private var storage: IndirectStorage + + /// Whenever there's a change that potentially can change the value, this reference to the + /// storage should be used to guarantee that a new copy is created and written on. + private var storageForWritting: IndirectStorage { + + mutating get { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.copyStorage() + } + return self.storage + } + } + + /// Returns the last element in the collection + public var last: T? { + get { + return self.storage.tail?.value + } + } + + + + // MARK: INITIALIZERS + + /// Creates a list with the given node. + /// NOTE: This method can break value semantics by accepting a node. + /// + /// - Parameter head: First node + internal init(head: SinglyLinkedListNode) + { + self.storage = IndirectStorage() + self.append(node: head) + } + + + /// Creates a list with a single element + /// + /// - Parameter value: element to populate the list with + public init(value: T) + { + let node = SinglyLinkedListNode(value: value) + self.init(head: node) + } + + + /// Creates an empty list + public init() + { + self.storage = IndirectStorage() + } + + + // MARK: EDITION + + /// Convenience method to append a value directly to the list + /// + /// - Parameter value: value to be added + public mutating func append(value: T) + { + let node = SinglyLinkedListNode(value: value) + self.append(node: node) + } + + + /// Convenience method to prepend a value directly to the list + /// + /// - Parameter value: value to be added as the new head of the list + public mutating func prepend(value: T) + { + let node = SinglyLinkedListNode(value: value) + self.prepend(node: node) + } + + + public mutating func deleteItem(at index:Int) -> T + { + precondition((index >= 0) && (index < self.count)) + + var previous: SinglyLinkedListNode? = nil + var current = self.storageForWritting.head + var i = 0 + var elementToDelete: SinglyLinkedListNode + + while (i < index) { + previous = current + current = current?.next + i += 1 + } + + // Current is now the element to delete (at index position.tag) + elementToDelete = current! + if (self.storage.head === current) { + self.storageForWritting.head = current?.next + } + + if (self.storage.tail === current) { + self.storageForWritting.tail = previous + } + + previous?.next = current?.next + + return elementToDelete.value + } + + + + // MARK: SEARCH + + /// Returns the node located at the k-th to last position + /// + /// - Parameter kthToLast: 1 <= k <= N + private func find(kthToLast: UInt, startingAt node: SinglyLinkedListNode?, count: UInt) -> SinglyLinkedListNode? + { + guard kthToLast <= count else { + return nil + } + + guard (node != nil) else { + return nil + } + + let i = (count - kthToLast) + + if (i == 0) { + return node + } + + return find(kthToLast: kthToLast, startingAt: node?.next, count: (count - 1)) + } + + + /// Returns the kth-to-last element in the list + /// + /// - Parameter kthToLast: Reversed ordinal number of the node to fetch. + public func find(kthToLast: UInt) -> SinglyLinkedListNode? + { + return self.find(kthToLast: kthToLast, startingAt: self.storage.head, count: UInt(self.count)) + } + + + + // MARK: LOOP DETECTION + + /// A singly linked list contains a loop if one node references back to a previous node. + /// + /// - Returns: Whether the linked list contains a loop + public func containsLoop() -> Bool + { + /// Advances a node at a time + var current = self.storage.head + + /// Advances twice as fast + var runner = self.storage.head + + while (runner != nil) && (runner?.next != nil) { + + current = current?.next + runner = runner?.next?.next + + if runner === current { + return true + } + } + + return false + } + +} + + + +// MARK:- Private Methods + +private extension SinglyLinkedList { + + /// Adds a new node to the current head. This method can easily break value semantics. It is left + /// for internal use. + /// + /// - Parameter node: the node that will be the new head of the list. + private mutating func prepend(node: SinglyLinkedListNode) + { + let (tailFromNewNode, _) = findTail(in: node) + tailFromNewNode.next = self.storageForWritting.head + self.storageForWritting.head = node + + if self.storage.tail == nil { + self.storageForWritting.tail = tailFromNewNode + } + } + + /// Appends a new node to the list. This method can easily break value semantics. It is left + /// for internal use. + /// - Discussion: If the node to be inserted contains a loop, the node is appended but tail is set to nil. + /// This is a private method, therefore this can only happen directly under the control of this class. + /// - Parameter node: node to be appended. (It can be a list, even contain loops). + private mutating func append(node: SinglyLinkedListNode) + { + if self.storage.tail != nil + { + // Copy on write: we are about to modify next a property in + // a potentially shared node. Make sure it's new if necessary. + self.storageForWritting.tail?.next = node + if !self.containsLoop() { + let (tail, _) = findTail(in: node) + self.storageForWritting.tail = tail // There + } else { + self.storageForWritting.tail = nil + } + } + else + { + // This also means that there's no head. + // Otherwise the state would be inconsistent. + // This will be checked when adding and deleting nodes. + self.storageForWritting.head = node + if !self.containsLoop() { + let (tail, _) = findTail(in: node) + self.storageForWritting.tail = tail // There + } else { + self.storageForWritting.tail = nil + } + } + } + + /// Creates a copy of the linked list in a diffent memory location. + /// + /// - Returns: The copy to a new storage or a reference to the old one if no copy was necessary. + private func copyStorage() -> IndirectStorage { + // If the list is empty, next time an item will be created, it won't affect + // other instances of the list that came from copies derived from value types. + // like assignments or parameters + guard (self.storage.head != nil) && (self.storage.tail != nil) else { + return IndirectStorage(head: nil, tail: nil) + } + + // Create a new position in memory. + // Note that we are shallow copying the value. If it was reference type + // we just make a copy of the reference. + let copiedHead = SinglyLinkedListNode(value: self.storage.head!.value) + var previousCopied: SinglyLinkedListNode = copiedHead + + // Iterate through current list of nodes and copy them. + var current: SinglyLinkedListNode? = self.storage.head?.next + + while (current != nil) { + // Create a copy + let currentCopy = SinglyLinkedListNode(value: current!.value) + + // Create links + previousCopied.next = currentCopy + + // Update pointers + current = current?.next + previousCopied = currentCopy + } + + return IndirectStorage(head: copiedHead, tail: previousCopied) + } +} + + + +// MARK:- Extensions when comparable + +extension SinglyLinkedList where T: Comparable +{ + /// Deletes node containing a given value + /// + /// - Parameter v: value of the node to be deleted. + public mutating func deleteNode(withValue v: T) { + + guard self.storage.head != nil else { + return + } + + var previous: SinglyLinkedListNode? = nil + var current = self.storage.head + + while (current != nil) && (current?.value != v) { + previous = current + current = current?.next + } + + if let foundNode = current { + + if (self.storage.head === foundNode) { + self.storageForWritting.head = foundNode.next + } + + if (self.storage.tail === foundNode) { + self.storage.tail = previous + } + + previous?.next = foundNode.next + foundNode.next = nil + } + } + + + /// Deletes duplicates without using additional structures like a set to keep track the visited nodes. + /// - Complexity: O(N^2) + public mutating func deleteDuplicatesInPlace() + { + // Copy on write: this updates self.storage if necessary. + var current = self.storageForWritting.head + + while (current != nil) + { + var previous: SinglyLinkedListNode? = current + var next = current?.next + + while (next != nil) + { + if (current?.value == next?.value) { + + if (self.storage.head === next) { + self.storage.head = next?.next + } + + if (self.storage.tail === next) { + self.storage.tail = previous + } + + // Delete next + previous?.next = next?.next + } + previous = next + next = next?.next + } + current = current?.next + } + } +} + + + +// MARK: - ITERATOR - + +public struct SinglyLinkedListForwardIterator : IteratorProtocol { + + public typealias Element = T + + private(set) var head: SinglyLinkedListNode? + + mutating public func next() -> T? + { + let result = self.head?.value + self.head = self.head?.next + return result + } +} + + + +// MARK: - SEQUENCE - + +extension SinglyLinkedList : Sequence +{ + public func makeIterator() -> SinglyLinkedListForwardIterator + { + return SinglyLinkedListForwardIterator(head: self.storage.head) + } +} + + + +// MARK: - COLLECTION - + +extension SinglyLinkedList : Collection { + + public typealias Index = SinglyLinkedListIndex + + public var startIndex: Index { + get { + return SinglyLinkedListIndex(node: self.storage.head, tag: 0) + } + } + + public var endIndex: Index { + get { + if let h = self.storage.head { + let (_, numberOfElements) = findTail(in: h) + return SinglyLinkedListIndex(node: h, tag: numberOfElements) + } else { + return SinglyLinkedListIndex(node: nil, tag: self.startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return SinglyLinkedListIndex(node: idx.node?.next, tag: idx.tag+1) + } +} + + + +// MARK: - QUEUE - + +extension SinglyLinkedList : Queue +{ + typealias Item = T + + /// Returns the oldest element in the queue. + /// + /// - Returns: The oldest element in the queue. It does not dequeue it. + func getFirst() -> T? { + return self.storage.head?.value + } + + /// Adds an element to the queue + /// + /// - Parameter item: Item to be added + /// - Throws: There are cases where the operation might fail. For example if there is not enough space. + mutating func enqueue(item: T) throws { + self.append(node: SinglyLinkedListNode(value: item)) + } + + /// Dequeues the oldest element in the queue. + /// + /// - Returns: The oldest element in the queue, which gets removed from it. + mutating func dequeue() -> T? + { + guard self.count > 0 else { + return nil + } + + return self.deleteItem(at: 0) + } +} + + + +// MARK: - EXPRESSIBLE-BY-ARRAY-LITERAL - + +extension SinglyLinkedList : ExpressibleByArrayLiteral +{ + public typealias Element = T + + public init(arrayLiteral elements: Element...) + { + var headSet = false + var current : SinglyLinkedListNode? + var numberOfElements = 0 + self.storage = IndirectStorage() + + for element in elements { + + numberOfElements += 1 + + if headSet == false { + self.storage.head = SinglyLinkedListNode(value: element) + current = self.storage.head + headSet = true + } else { + let newNode = SinglyLinkedListNode(value: element) + current?.next = newNode + current = newNode + } + } + self.storage.tail = current + } +} + + + +// MARK: - FORWARD-INDEX - + +public struct SinglyLinkedListIndex : Comparable +{ + fileprivate let node: SinglyLinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} + + +extension SinglyLinkedList where T : KeyValuePair { + + public func find(elementWithKey key: T.K) -> T? { + let searchResults = self.filter { (keyValuePair) -> Bool in + return keyValuePair.key == key + } + + return searchResults.first + } +} + +// MARK: - HELPERS - + +func findTail(in node: SinglyLinkedListNode) -> (tail: SinglyLinkedListNode, count: Int) +{ + // Assign the tail + // Note that the passed node can already be linking to other nodes, + // so the tail needs to be calculated. + var current: SinglyLinkedListNode? = node + var count = 1 + + while (current?.next != nil) { + current = current?.next + count += 1 + } + + if current != nil { + return (tail: current!, count: count) + } else { + return (tail: node, count: 1) + } +} + + + +//: EXAMPLES +//: Let's create a list + +var l1: SinglyLinkedList = [1,2,3,4,5,6,7] + +//: Because it has value semantics, if we assign it, a new value will be created. However, internally the storage is shared. + +var l2 = l1 + +//: If we modify l2, l1 will remain unaffected. +l2.append(value: 67) + +assert(l1.count == 7) +assert(l1.contains(67) == false) + +//: However, as expected, l2 has changed +assert(l2.count == 8) +assert(l2.contains(67) == true) + + +//: Notice that because our implementation conforms to the Collection protocol, we can use a lot of methods already implemented for us in Swift's standard library, for example, contains, dropLast, etc. + +let l3 = l2.dropLast() +assert(l3.count == 7) +assert(l3.contains(67) == false) diff --git a/Singly Linked List/SinglyLinkedList.playground/contents.xcplayground b/Singly Linked List/SinglyLinkedList.playground/contents.xcplayground new file mode 100644 index 000000000..fd676d5b4 --- /dev/null +++ b/Singly Linked List/SinglyLinkedList.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Singly Linked List/SinglyLinkedList.playground/playground.xcworkspace/contents.xcworkspacedata b/Singly Linked List/SinglyLinkedList.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Singly Linked List/SinglyLinkedList.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Singly Linked List/SinglyLinkedList.swift b/Singly Linked List/SinglyLinkedList.swift new file mode 100644 index 000000000..67e30eb7d --- /dev/null +++ b/Singly Linked List/SinglyLinkedList.swift @@ -0,0 +1,438 @@ +import Foundation + + +/// Helper class to implement copy-on-write +fileprivate class IndirectStorage { + + var head: SinglyLinkedListNode? + + var tail: SinglyLinkedListNode? + + init(head: SinglyLinkedListNode?, tail: SinglyLinkedListNode?) { + self.head = head + self.tail = tail + } + + convenience init() { + self.init(head: nil, tail: nil) + } +} + + + +// MARK: - NODE - + +/// A node is the building block of a linked list. +/// It can be used on its own to create linked lists. However users of this class, +/// will need to manipulate references directly. +public class SinglyLinkedListNode { + + /// Data container + public var value: T + + /// Link to the next node + public var next: SinglyLinkedListNode? + + /// Designated initializer + /// + /// - Parameter value: A value + public init(value: T) { + self.value = value + } +} + + + +// MARK: - LINKED LIST - + +/// Data structure to hold a collection of items. +/// Each nodes contains a reference to the next node. +/// The last node does not reference any other node. +/// This class implements value semantics based on copy-on-write. +/// +/// However, the elements contained in the list, will be shallow copied if they +/// implement reference semantics. +public struct SinglyLinkedList { + // MARK: PROPERTIES + + // A level of inderiction, with reference semantics to allow easy + // detection of when there are more than one references of the storage. + private var storage: IndirectStorage + + /// Whenever there's a change that potentially can change the value, this reference to the + /// storage should be used to guarantee that a new copy is created and written on. + private var storageForWritting: IndirectStorage { + + mutating get { + if !isKnownUniquelyReferenced(&storage) { + storage = copyStorage() + } + return storage + } + } + + /// Returns the last element in the collection + public var last: T? { + get { + return storage.tail?.value + } + } + + + + // MARK: INITIALIZERS + + /// Creates an empty list + public init() { + self.storage = IndirectStorage() + } + + + // MARK: EDITION + + /// Convenience method to append a value directly to the list + /// + /// - Parameter value: value to be added + public mutating func append(value: T) { + let node = SinglyLinkedListNode(value: value) + append(node: node) + } + + + /// Convenience method to prepend a value directly to the list + /// + /// - Parameter value: value to be added as the new head of the list + public mutating func prepend(value: T) { + let node = SinglyLinkedListNode(value: value) + prepend(node: node) + } + + + public mutating func deleteItem(at index:Int) -> T { + precondition((index >= 0) && (index < count)) + + var previous: SinglyLinkedListNode? = nil + var current = storageForWritting.head + var i = 0 + var elementToDelete: SinglyLinkedListNode + + while i < index { + previous = current + current = current?.next + i += 1 + } + + // Current is now the element to delete (at index position.tag) + elementToDelete = current! + if storage.head === current { + storageForWritting.head = current?.next + } + + if storage.tail === current { + storageForWritting.tail = previous + } + + previous?.next = current?.next + + return elementToDelete.value + } + + + + // MARK: SEARCH + + /// Returns the node located at the k-th to last position + /// + /// - Parameter kthToLast: 1 <= k <= N + private func find(kthToLast: UInt, startingAt node: SinglyLinkedListNode?, count: UInt) -> SinglyLinkedListNode? { + guard kthToLast <= count else { + return nil + } + + guard (node != nil) else { + return nil + } + + let i = (count - kthToLast) + + if i == 0 { + return node + } + + return find(kthToLast: kthToLast, startingAt: node?.next, count: (count - 1)) + } + + + /// Returns the kth-to-last element in the list + /// + /// - Parameter kthToLast: Reversed ordinal number of the node to fetch. + public func find(kthToLast: UInt) -> SinglyLinkedListNode? { + return find(kthToLast: kthToLast, startingAt: storage.head, count: UInt(count)) + } + +} + + + +// MARK:- Private Methods + +private extension SinglyLinkedList { + + /// Adds a new node to the current head. This method can easily break value semantics. It is left + /// for internal use. + /// + /// - Parameter node: the node that will be the new head of the list. + private mutating func prepend(node: SinglyLinkedListNode) { + let (tailFromNewNode, _) = findTail(in: node) + tailFromNewNode.next = storageForWritting.head + storageForWritting.head = node + + if storage.tail == nil { + storageForWritting.tail = tailFromNewNode + } + } + + /// Appends a new node to the list. This method can easily break value semantics. It is left + /// for internal use. + /// - Discussion: If the node to be inserted contains a loop, the node is appended but tail is set to nil. + /// This is a private method, therefore this can only happen directly under the control of this class. + /// - Parameter node: node to be appended. (It can be a list, even contain loops). + private mutating func append(node: SinglyLinkedListNode) { + if storage.tail != nil { + // Copy on write: we are about to modify next a property in + // a potentially shared node. Make sure it's new if necessary. + storageForWritting.tail?.next = node + let (tail, _) = findTail(in: node) + storageForWritting.tail = tail // There + } else { + // This also means that there's no head. + // Otherwise the state would be inconsistent. + // This will be checked when adding and deleting nodes. + storageForWritting.head = node + let (tail, _) = findTail(in: node) + storageForWritting.tail = tail // There + } + } + + /// Creates a copy of the linked list in a diffent memory location. + /// + /// - Returns: The copy to a new storage or a reference to the old one if no copy was necessary. + private func copyStorage() -> IndirectStorage { + // If the list is empty, next time an item will be created, it won't affect + // other instances of the list that came from copies derived from value types. + // like assignments or parameters + guard (storage.head != nil) && (storage.tail != nil) else { + return IndirectStorage(head: nil, tail: nil) + } + + // Create a new position in memory. + // Note that we are shallow copying the value. If it was reference type + // we just make a copy of the reference. + let copiedHead = SinglyLinkedListNode(value: storage.head!.value) + var previousCopied: SinglyLinkedListNode = copiedHead + + // Iterate through current list of nodes and copy them. + var current: SinglyLinkedListNode? = storage.head?.next + + while current != nil { + // Create a copy + let currentCopy = SinglyLinkedListNode(value: current!.value) + + // Create links + previousCopied.next = currentCopy + + // Update pointers + current = current?.next + previousCopied = currentCopy + } + + return IndirectStorage(head: copiedHead, tail: previousCopied) + } +} + + + +// MARK:- Extensions when comparable + +extension SinglyLinkedList where T: Comparable { + /// Deletes node containing a given value + /// + /// - Parameter v: value of the node to be deleted. + public mutating func deleteNode(withValue v: T) { + + guard storage.head != nil else { + return + } + + var previous: SinglyLinkedListNode? = nil + var current = storage.head + + while (current != nil) && (current?.value != v) { + previous = current + current = current?.next + } + + if let foundNode = current { + + if storage.head === foundNode { + storageForWritting.head = foundNode.next + } + + if storage.tail === foundNode { + storage.tail = previous + } + + previous?.next = foundNode.next + foundNode.next = nil + } + } + + + /// Deletes duplicates without using additional structures like a set to keep track the visited nodes. + /// - Complexity: O(N^2) + public mutating func deleteDuplicatesInPlace() { + // Copy on write: this updates storage if necessary. + var current = storageForWritting.head + + while current != nil { + var previous: SinglyLinkedListNode? = current + var next = current?.next + + while next != nil { + if current?.value == next?.value { + + if storage.head === next { + storage.head = next?.next + } + + if storage.tail === next { + storage.tail = previous + } + + // Delete next + previous?.next = next?.next + } + previous = next + next = next?.next + } + current = current?.next + } + } +} + + + +// MARK: - COLLECTION - + +extension SinglyLinkedList : Collection { + + public typealias Index = SinglyLinkedListIndex + + public var startIndex: Index { + get { + return SinglyLinkedListIndex(node: storage.head, tag: 0) + } + } + + public var endIndex: Index { + get { + if let h = storage.head { + let (_, numberOfElements) = findTail(in: h) + return SinglyLinkedListIndex(node: h, tag: numberOfElements) + } else { + return SinglyLinkedListIndex(node: nil, tag: startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return SinglyLinkedListIndex(node: idx.node?.next, tag: idx.tag+1) + } +} + + + +// MARK: - EXPRESSIBLE-BY-ARRAY-LITERAL - + +extension SinglyLinkedList : ExpressibleByArrayLiteral { + public typealias Element = T + + public init(arrayLiteral elements: Element...) { + var headSet = false + var current : SinglyLinkedListNode? + var numberOfElements = 0 + storage = IndirectStorage() + + for element in elements { + + numberOfElements += 1 + + if headSet == false { + storage.head = SinglyLinkedListNode(value: element) + current = storage.head + headSet = true + } else { + let newNode = SinglyLinkedListNode(value: element) + current?.next = newNode + current = newNode + } + } + storage.tail = current + } +} + + + +// MARK: - FORWARD-INDEX - + +public struct SinglyLinkedListIndex : Comparable { + fileprivate let node: SinglyLinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: SinglyLinkedListIndex, rhs: SinglyLinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} + + +extension SinglyLinkedList where T : KeyValuePair { + + public func find(elementWithKey key: T.K) -> T? { + let searchResults = filter { (keyValuePair) -> Bool in + return keyValuePair.key == key + } + + return searchResults.first + } +} + +// MARK: - HELPERS - + +func findTail(in node: SinglyLinkedListNode) -> (tail: SinglyLinkedListNode, count: Int) { + // Assign the tail + // Note that the passed node can already be linking to other nodes, + // so the tail needs to be calculated. + var current: SinglyLinkedListNode? = node + var count = 1 + + while current?.next != nil { + current = current?.next + count += 1 + } + + if current != nil { + return (tail: current!, count: count) + } else { + return (tail: node, count: 1) + } +} diff --git a/Singly Linked List/Tests/Tests.xcodeproj/project.pbxproj b/Singly Linked List/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..8dddf6498 --- /dev/null +++ b/Singly Linked List/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,280 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 006104711F361359007A6F50 /* SinglyLinkedListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006104701F361359007A6F50 /* SinglyLinkedListTests.swift */; }; + 006104791F36144E007A6F50 /* KeyValuePair.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006104761F36144E007A6F50 /* KeyValuePair.swift */; }; + 0061047B1F36144E007A6F50 /* SinglyLinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006104781F36144E007A6F50 /* SinglyLinkedList.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0061046D1F361359007A6F50 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 006104701F361359007A6F50 /* SinglyLinkedListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SinglyLinkedListTests.swift; sourceTree = ""; }; + 006104721F361359007A6F50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 006104761F36144E007A6F50 /* KeyValuePair.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = KeyValuePair.swift; path = ../../KeyValuePair.swift; sourceTree = ""; }; + 006104781F36144E007A6F50 /* SinglyLinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SinglyLinkedList.swift; path = ../../SinglyLinkedList.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0061046A1F361359007A6F50 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 006104621F36104C007A6F50 = { + isa = PBXGroup; + children = ( + 0061046F1F361359007A6F50 /* Tests */, + 0061046E1F361359007A6F50 /* Products */, + ); + sourceTree = ""; + }; + 0061046E1F361359007A6F50 /* Products */ = { + isa = PBXGroup; + children = ( + 0061046D1F361359007A6F50 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0061046F1F361359007A6F50 /* Tests */ = { + isa = PBXGroup; + children = ( + 006104701F361359007A6F50 /* SinglyLinkedListTests.swift */, + 006104761F36144E007A6F50 /* KeyValuePair.swift */, + 006104781F36144E007A6F50 /* SinglyLinkedList.swift */, + 006104721F361359007A6F50 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0061046C1F361359007A6F50 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 006104731F361359007A6F50 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 006104691F361359007A6F50 /* Sources */, + 0061046A1F361359007A6F50 /* Frameworks */, + 0061046B1F361359007A6F50 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 0061046D1F361359007A6F50 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 006104631F36104C007A6F50 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + TargetAttributes = { + 0061046C1F361359007A6F50 = { + CreatedOnToolsVersion = 8.3.3; + LastSwiftMigration = 0900; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 006104661F36104C007A6F50 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 006104621F36104C007A6F50; + productRefGroup = 0061046E1F361359007A6F50 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0061046C1F361359007A6F50 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0061046B1F361359007A6F50 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 006104691F361359007A6F50 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 006104711F361359007A6F50 /* SinglyLinkedListTests.swift in Sources */, + 0061047B1F36144E007A6F50 /* SinglyLinkedList.swift in Sources */, + 006104791F36144E007A6F50 /* KeyValuePair.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 006104671F36104C007A6F50 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 006104681F36104C007A6F50 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 006104741F361359007A6F50 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++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; + 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 = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 006104751F361359007A6F50 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++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"; + 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 = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 006104661F36104C007A6F50 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 006104671F36104C007A6F50 /* Debug */, + 006104681F36104C007A6F50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 006104731F361359007A6F50 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 006104741F361359007A6F50 /* Debug */, + 006104751F361359007A6F50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 006104631F36104C007A6F50 /* Project object */; +} diff --git a/Singly Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Singly Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Singly Linked List/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Singly Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Singly Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..a3659d5ab --- /dev/null +++ b/Singly Linked List/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Singly Linked List/Tests/Tests/Info.plist b/Singly Linked List/Tests/Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Singly Linked List/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/Singly Linked List/Tests/Tests/SinglyLinkedListTests.swift b/Singly Linked List/Tests/Tests/SinglyLinkedListTests.swift new file mode 100644 index 000000000..5ad8ffcc4 --- /dev/null +++ b/Singly Linked List/Tests/Tests/SinglyLinkedListTests.swift @@ -0,0 +1,249 @@ +import XCTest + + +class FindTailInNodeTests: XCTestCase { + + func testExample() { + let n1 = SinglyLinkedListNode(value: 34) + let n2 = SinglyLinkedListNode(value: 35) + let n3 = SinglyLinkedListNode(value: 36) + let n4 = SinglyLinkedListNode(value: 37) + + n1.next = n2 + n2.next = n3 + n3.next = n4 + + XCTAssertTrue(findTail(in: n1).tail === n4) + XCTAssertTrue(findTail(in: n2).tail === n4) + XCTAssertTrue(findTail(in: n4).tail === n4) + XCTAssertTrue(findTail(in: n4).tail === n4) + } +} + +class SinglyLinkedListTests: XCTestCase { + + func testAppendOneNodeFromEmptyList() { + var list = SinglyLinkedList() + list.append(value: 34) + XCTAssertTrue(list.first == 34) + XCTAssertTrue(list.count == 1, "Found \(list.count)") + } + + func testAppendMultipleNodesFromEmptyList() { + var list = SinglyLinkedList() + list.append(value: 34) + list.append(value: 35) + list.append(value: 36) + list.append(value: 34) + XCTAssertTrue(list.first == 34) + let second = list.index(list.startIndex, offsetBy: 1) + let third = list.index(list.startIndex, offsetBy: 2) + let fouth = list.index(list.startIndex, offsetBy: 3) + XCTAssertTrue(list[second] == 35) + XCTAssertTrue(list[third] == 36) + XCTAssertTrue(list[fouth] == 34) + XCTAssertTrue(list.count == 4, "Found \(list.count)") + } + + func testDelete() { + var list: SinglyLinkedList = [1] + list.append(value: 2) + list.append(value: 3) + list.append(value: 4) + list.append(value: 5) + + list.deleteNode(withValue: 1) + var second = list.index(list.startIndex, offsetBy: 1) + var third = list.index(list.startIndex, offsetBy: 2) + XCTAssertTrue(list.first == 2) + XCTAssertTrue(list[second] == 3) + XCTAssertTrue(list[third] == 4) + XCTAssertTrue(list.last == 5) + XCTAssertTrue(list.count == 4) + + list.deleteNode(withValue: 5) + second = list.index(list.startIndex, offsetBy: 1) + third = list.index(list.startIndex, offsetBy: 2) + XCTAssertTrue(list.first == 2) + XCTAssertTrue(list[second] == 3) + XCTAssertTrue(list.last == 4) + XCTAssertTrue(list.count == 3) + + list.deleteNode(withValue: 3) + XCTAssertTrue(list.first == 2) + XCTAssertTrue(list.last == 4) + XCTAssertTrue(list.count == 2) + + list.deleteNode(withValue: 2) + XCTAssertTrue(list.first == 4) + XCTAssertTrue(list.last == 4) + XCTAssertTrue(list.count == 1) + + list.deleteNode(withValue: 4) + XCTAssertTrue(list.first == nil) + XCTAssertTrue(list.last == nil) + XCTAssertTrue(list.count == 0) + } + + func testDeleteDuplicatesInPlace() { + var list: SinglyLinkedList = [1] + list.append(value: 2) + list.append(value: 2) + list.append(value: 3) + list.append(value: 5) + list.append(value: 2) + list.append(value: 4) + list.append(value: 2) + list.append(value: 5) + + list.deleteDuplicatesInPlace() + let second = list.index(list.startIndex, offsetBy: 1) + let third = list.index(list.startIndex, offsetBy: 2) + let fourth = list.index(list.startIndex, offsetBy: 3) + XCTAssertTrue(list.first == 1) + XCTAssertTrue(list[second] == 2) + XCTAssertTrue(list[third] == 3) + XCTAssertTrue(list[fourth] == 5) + XCTAssertTrue(list.last == 4) + XCTAssertTrue(list.count == 5) + } + + func testFindKthToLast() { + let list: SinglyLinkedList = [2,2,3,5,2,4,2,5] + XCTAssertTrue(list.find(kthToLast: 1)?.value == 5) + XCTAssertTrue(list.find(kthToLast: 2)?.value == 2) + XCTAssertTrue(list.find(kthToLast: 3)?.value == 4) + XCTAssertTrue(list.find(kthToLast: 4)?.value == 2) + XCTAssertTrue(list.find(kthToLast: 5)?.value == 5) + XCTAssertTrue(list.find(kthToLast: 6)?.value == 3) + XCTAssertTrue(list.find(kthToLast: 7)?.value == 2) + XCTAssertTrue(list.find(kthToLast: 8)?.value == 2) + XCTAssertTrue(list.find(kthToLast: 9)?.value == nil) + } + + func testConstructorFromArrayLiteralWhenEmpty() { + let list: SinglyLinkedList = [] + XCTAssertTrue(list.first == nil) + XCTAssertTrue(list.last == nil) + XCTAssertTrue(list.count == 0, "Found \(list.count)") + } + + func testConstructorFromArrayLiteralWithSingleElement() { + let list: SinglyLinkedList = [5] + XCTAssertTrue(list.first == 5) + XCTAssertTrue(list.last == 5) + XCTAssertTrue(list.count == 1, "Found \(list.count)") + } + + func testAppendValue() { + var list = SinglyLinkedList() + list.append(value: 1) + list.append(value: 1) + list.append(value: 2) + list.append(value: 2) + list.append(value: 4) + + let result = string(from: list) + XCTAssertTrue(result == "11224", "Found \(result)") + XCTAssertTrue(list.count == 5, "Found \(list.count)") + XCTAssertTrue(list.last == 4, "Found \(String(describing: list.last))") + } + + func testPrependValue() { + var list = SinglyLinkedList() + list.prepend(value: 1) + list.prepend(value: 2) + list.prepend(value: 3) + list.prepend(value: 4) + list.prepend(value: 5) + list.prepend(value: 6) + + let result = string(from: list) + XCTAssertTrue(result == "654321", "Found \(result)") + XCTAssertTrue(list.count == 6, "Found \(list.count)") + XCTAssertTrue(list.last == 1, "Found \(String(describing: list.last))") + } + + func testDeleteHeadInListWithMultipleItems() { + var list: SinglyLinkedList = [1,2,3,4,5,6,7,8] + + let _ = list.deleteItem(at: 0) + let result = string(from: list) + XCTAssertTrue(result == "2345678", "Found \(result)") + XCTAssertTrue(list.first == 2, "Found \(String(describing: list.first))") + XCTAssertTrue(list.count == 7, "Found \(list.count)") + } + + func testDeleteTailInListWithMultipleItems() { + var list: SinglyLinkedList = [1,2,3,4,5,6,7,8] + + let _ = list.deleteItem(at: 7) + let result = string(from: list) + XCTAssertTrue(result == "1234567", "Found \(result)") + XCTAssertTrue(list.last == 7, "Found \(String(describing: list.last))") + XCTAssertTrue(list.count == 7, "Found \(list.count)") + } + + func testDeleteItemInListWithMultipleItems() { + var list: SinglyLinkedList = [1,2,3,4,5,6,7,8] + + let _ = list.deleteItem(at: 4) + let result = string(from: list) + XCTAssertTrue(result == "1234678", "Found \(result)") + XCTAssertTrue(list.first == 1, "Found \(String(describing: list.first))") + XCTAssertTrue(list.last == 8, "Found \(String(describing: list.last))") + XCTAssertTrue(list.count == 7, "Found \(list.count)") + } + + func testDeleteHeadInListWithSingleElement() { + var list: SinglyLinkedList = [1] + + let _ = list.deleteItem(at: 0) + let result = string(from: list) + XCTAssertTrue(result == "", "Found \(result)") + XCTAssertTrue(list.first == nil, "Found \(String(describing: list.first))") + XCTAssertTrue(list.last == nil, "Found \(String(describing: list.last))") + XCTAssertTrue(list.count == 0, "Found \(list.count)") + } + + func testDirectIndexAccess() { + let list: SinglyLinkedList = [1,2,3,4,5,6,7,8] + let fifthElementIndex = list.index(list.startIndex, offsetBy: 5) + XCTAssertTrue(list[fifthElementIndex] == 6 , "Found \(list.count)") + } + + + func string(from list: SinglyLinkedList) -> String { + var result = "" + var iterator = list.makeIterator() + while let current = iterator.next() { + result += String(describing: current) + } + + return result + } + + func testCopyOnWriteUsingLiterals() { + var l1: SinglyLinkedList = [1,2,3,4,5,6,7,8] + l1.append(value: 0) + var l2 = l1 + + _ = l2.deleteItem(at: 3) + XCTAssertTrue(l1.count == 9) + XCTAssertTrue(l2.count == 8) + + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + _ = l1.deleteItem(at: 0) + + XCTAssertTrue(l1.count == 0) + XCTAssertTrue(l2.count == 8) + } + +} diff --git a/Skip-List/Images/Insert1.png b/Skip-List/Images/Insert1.png new file mode 100644 index 000000000..1e1a5959d Binary files /dev/null and b/Skip-List/Images/Insert1.png differ diff --git a/Skip-List/Images/Insert10.png b/Skip-List/Images/Insert10.png new file mode 100644 index 000000000..eaec313b3 Binary files /dev/null and b/Skip-List/Images/Insert10.png differ diff --git a/Skip-List/Images/Insert11.png b/Skip-List/Images/Insert11.png new file mode 100644 index 000000000..3c637093c Binary files /dev/null and b/Skip-List/Images/Insert11.png differ diff --git a/Skip-List/Images/Insert12.png b/Skip-List/Images/Insert12.png new file mode 100644 index 000000000..408356a6f Binary files /dev/null and b/Skip-List/Images/Insert12.png differ diff --git a/Skip-List/Images/Insert2.png b/Skip-List/Images/Insert2.png new file mode 100644 index 000000000..5fa094019 Binary files /dev/null and b/Skip-List/Images/Insert2.png differ diff --git a/Skip-List/Images/Insert3.png b/Skip-List/Images/Insert3.png new file mode 100644 index 000000000..08f1b78bb Binary files /dev/null and b/Skip-List/Images/Insert3.png differ diff --git a/Skip-List/Images/Insert4.png b/Skip-List/Images/Insert4.png new file mode 100644 index 000000000..779ad7dd8 Binary files /dev/null and b/Skip-List/Images/Insert4.png differ diff --git a/Skip-List/Images/Insert5.png b/Skip-List/Images/Insert5.png new file mode 100644 index 000000000..ebac3b33f Binary files /dev/null and b/Skip-List/Images/Insert5.png differ diff --git a/Skip-List/Images/Insert6.png b/Skip-List/Images/Insert6.png new file mode 100644 index 000000000..e2b44c3b0 Binary files /dev/null and b/Skip-List/Images/Insert6.png differ diff --git a/Skip-List/Images/Insert8.png b/Skip-List/Images/Insert8.png new file mode 100644 index 000000000..2eecd75e4 Binary files /dev/null and b/Skip-List/Images/Insert8.png differ diff --git a/Skip-List/Images/Insert9.png b/Skip-List/Images/Insert9.png new file mode 100644 index 000000000..f63345bdd Binary files /dev/null and b/Skip-List/Images/Insert9.png differ diff --git a/Skip-List/Images/Intro.png b/Skip-List/Images/Intro.png new file mode 100644 index 000000000..0bb64865d Binary files /dev/null and b/Skip-List/Images/Intro.png differ diff --git a/Skip-List/Images/Search1.png b/Skip-List/Images/Search1.png new file mode 100644 index 000000000..84399a621 Binary files /dev/null and b/Skip-List/Images/Search1.png differ diff --git a/Skip-List/Images/insert7.png b/Skip-List/Images/insert7.png new file mode 100644 index 000000000..d92f607f7 Binary files /dev/null and b/Skip-List/Images/insert7.png differ diff --git a/Skip-List/README.md b/Skip-List/README.md new file mode 100644 index 000000000..d3824952b --- /dev/null +++ b/Skip-List/README.md @@ -0,0 +1,118 @@ +# 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 and is relatively simpler to +implement compared to other map data structures. + +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/Search1.png) + +#Inserting + +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. + +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*. + +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. Stack is empty ( Level is *L0* /- *Ln* or at uninitialized stage) +2. Stack has items ( traversing upward is possible ) + +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. + +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. + + +###Example: + +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) + + + +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 + +#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) diff --git a/Skip-List/SkipList.playground/Contents.swift b/Skip-List/SkipList.playground/Contents.swift new file mode 100644 index 000000000..55b9d3a23 --- /dev/null +++ b/Skip-List/SkipList.playground/Contents.swift @@ -0,0 +1,20 @@ +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +// SkipList is ready for Swift 4. +// TODO: Add Test + +let k = SkipList() +k.insert(key: 10, data: "10") +k.insert(key: 12, data: "12") +k.insert(key: 13, data: "13") +k.insert(key: 20, data: "20") +k.insert(key: 24, data: "24") + +if let value = k.get(key: 20) { + print(value) +} else { + print("not found!") +} diff --git a/Skip-List/SkipList.playground/Sources/SkipList.swift b/Skip-List/SkipList.playground/Sources/SkipList.swift new file mode 100644 index 000000000..186286977 --- /dev/null +++ b/Skip-List/SkipList.playground/Sources/SkipList.swift @@ -0,0 +1,270 @@ +// 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 { + fileprivate 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: Sequence { + public func makeIterator() -> AnyIterator { + var curr = self + return AnyIterator { curr.pop() } + } +} + +private func coinFlip() -> Bool { + return arc4random_uniform(2) == 1 +} + +public class DataNode { + public typealias Node = DataNode + + 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() {} + +} + +// 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 + case .some(let value) where value.key != nil: + + if value.key == key { + isFound = true + break + } else { + if key < value.key! { + currentNode = node.down + } else { + currentNode = node.next + } + } + + default: + continue + } + + } else { + break + } + } + + if isFound { + return currentNode + } else { + return nil + } + + } + + func search(key: Key) -> Payload? { + guard let node = findNode(key: key) else { + return nil + } + + return node.next!.data + } + +} + +// 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) + var node = Node(key: key, data: data) + + 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 = head + head = newHead + currentTopNode = node + } + + } + + private func insertItem(key: Key, data: Payload) { + var stack = Stack() + var currentNode: Node? = head + + while currentNode != nil { + + if let nextNode = currentNode!.next { + if nextNode.key! > key { + stack.push(currentNode!) + currentNode = currentNode!.down + } else { + currentNode = nextNode + } + + } 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) + + node = Node(key: key, data: data) + node.down = currentTopNode + newHead.next = node + newHead.down = head + head = newHead + currentTopNode = node + + } else { + let nextNode = stack.pop() + + node = Node(key: key, data: data) + node.down = currentTopNode + node.next = nextNode!.next + nextNode!.next = node + currentTopNode = node + } + } + } + + public 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 { + insertItem(key: key, data: data) + } + + } else { + bootstrapBaseLayer(key: key, data: data) + } + } + +} + +// 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) { + 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/Skip-List/SkipList.playground/contents.xcplayground b/Skip-List/SkipList.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Skip-List/SkipList.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Skip-List/SkipList.playground/playground.xcworkspace/contents.xcworkspacedata b/Skip-List/SkipList.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Skip-List/SkipList.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift new file mode 100644 index 000000000..8a1959f70 --- /dev/null +++ b/Skip-List/SkipList.swift @@ -0,0 +1,271 @@ +// 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 { + fileprivate 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: Sequence { + public func makeIterator() -> AnyIterator { + var curr = self + return AnyIterator { curr.pop() } + } +} + +private func coinFlip() -> Bool { + return arc4random_uniform(2) == 1 +} + +public class DataNode { + public typealias Node = DataNode + + 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() {} + +} + +// 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 + case .some(let value) where value.key != nil: + + if value.key == key { + isFound = true + break + } else { + if key < value.key! { + currentNode = node.down + } else { + currentNode = node.next + } + } + + default: + continue + } + + } else { + break + } + } + + if isFound { + return currentNode + } else { + return nil + } + + } + + func search(key: Key) -> Payload? { + guard let node = findNode(key: key) else { + return nil + } + + return node.next!.data + } + +} + +// 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) + var node = Node(key: key, data: data) + + 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 = head + head = newHead + currentTopNode = node + } + + } + + private func insertItem(key: Key, data: Payload) { + var stack = Stack() + var currentNode: Node? = head + + while currentNode != nil { + + if let nextNode = currentNode!.next { + if nextNode.key! > key { + stack.push(currentNode!) + currentNode = currentNode!.down + } else { + currentNode = nextNode + } + + } 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) + + node = Node(key: key, data: data) + node.down = currentTopNode + newHead.next = node + newHead.down = head + head = newHead + currentTopNode = node + + } else { + let nextNode = stack.pop() + + node = Node(key: key, data: data) + node.down = currentTopNode + node.next = nextNode!.next + nextNode!.next = node + currentTopNode = node + } + } + } + + public 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 { + insertItem(key: key, data: data) + } + + } else { + bootstrapBaseLayer(key: key, data: data) + } + } + +} + +// 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) { + 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/Slow Sort/README.markdown b/Slow Sort/README.markdown new file mode 100644 index 000000000..f7742b6a3 --- /dev/null +++ b/Slow Sort/README.markdown @@ -0,0 +1,48 @@ +# 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 +func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) +} +``` + +## 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) diff --git a/Slow Sort/SlowSort.playground/Contents.swift b/Slow Sort/SlowSort.playground/Contents.swift new file mode 100644 index 000000000..54c1e61ea --- /dev/null +++ b/Slow Sort/SlowSort.playground/Contents.swift @@ -0,0 +1,4 @@ +var numberList = [1, 12, 9, 17, 13, 12] + +slowSort(0, numberList.count-1, &numberList) +print(numberList) diff --git a/Slow Sort/SlowSort.playground/Sources/SlowSort.swift b/Slow Sort/SlowSort.playground/Sources/SlowSort.swift new file mode 100644 index 000000000..cf09dcc5d --- /dev/null +++ b/Slow Sort/SlowSort.playground/Sources/SlowSort.swift @@ -0,0 +1,15 @@ +import Foundation + +public func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard i < j else { return } + + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) +} diff --git a/Slow Sort/SlowSort.playground/contents.xcplayground b/Slow Sort/SlowSort.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Slow Sort/SlowSort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Slow Sort/SlowSort.playground/playground.xcworkspace/contents.xcworkspacedata b/Slow Sort/SlowSort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Slow Sort/SlowSort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift new file mode 100644 index 000000000..968f6841b --- /dev/null +++ b/Slow Sort/SlowSort.swift @@ -0,0 +1,20 @@ +// +// SlowSort.swift +// +// +// Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. +// +// + +func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) +} diff --git a/Sorted Set/README.markdown b/Sorted Set/README.markdown new file mode 100644 index 000000000..a8b5ad1ea --- /dev/null +++ b/Sorted Set/README.markdown @@ -0,0 +1,334 @@ +# Sorted Set + +## Sorted Array Version + +An Sorted Set is a collection of unique items in sorted order. Items are usually sorted from least to greatest. + +The Sorted Set data type is a hybrid of: + +- a [Set](https://en.wikipedia.org/wiki/Set_%28mathematics%29), a collection of unique items where the order does not matter, and +- a [Sequence](https://en.wikipedia.org/wiki/Sequence), an sorted list of items where each item may appear more than once. + +It's important to keep in mind that two items can have the same *value* but still may not be equal. For example, we could define "a" and "z" to have the same value (their lengths), but clearly "a" != "z". + +## Why use an sorted set? + +Sorted Sets should be considered when you need to keep your collection sorted at all times, and you do lookups on the collection much more frequently than inserting or deleting items. Many of the lookup operations for an Sorted Set are **O(1)**. + +A good example would be keeping track of the rankings of players in a scoreboard (see example 2 below). + +#### These are sorted sets + +A set of integers: + + [1, 2, 3, 6, 8, 10, 1000] + +A set of strings: + + ["a", "is", "set", "this"] + +The "value" of these strings could be their text content, but also for example their length. + +#### These are not sorted sets + +This set violates the property of uniqueness: + + [1, 1, 2, 3, 5, 8] + +This set violates the sorted property: + + [1, 11, 2, 3] + +## The code + +We'll start by creating our internal representation for the Sorted Set. Since the idea of a set is similar to that of an array, we will use an array to represent our set. Furthermore, since we'll need to keep the set sorted, we need to be able to compare the individual elements. Thus, any type must conform to the [Comparable Protocol](https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_Comparable_Protocol/index.html). + +```swift +public struct SortedSet { + private var internalSet = [T]() + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + ... +``` + +Lets take a look at the `insert()` function first. This first checks if the item already exists in the collection. If so, it returns and does not insert the item. Otherwise, it will insert the item through straightforward iteration. + +```swift + public mutating func insert(_ item: T){ + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } +``` + +As we'll see later on, checking if the item is already in the set has an efficiency of **O(log(n) + k)** where **k** is the number of items with the same value as the item we are inserting. + +To insert the new item, the `for` loop starts from the beginning of the array, and checks to see if each item is larger than the item we want to insert. Once we find such an item, we insert the new one into its place. This shifts the rest of the array over to the right by 1 position. This loop is at worst **O(n)**. + +The total performance of the `insert()` function is therefore **O(n)**. + +Next up is the `remove()` function: + +```swift + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } +``` + +First this checks if the item exists and then removes it from the array. Because of the `removeAtIndex()` function, the efficiency for remove is **O(n)**. + +The next function is `indexOf()`, which takes in an object of type `T` and returns the index of the corresponding item if it is in the set, or `nil` if it is not. Since our set is sorted, we can use a binary search to quickly search for the item. + +```swift + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // see below + } + } + return nil + } +``` + +> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary%20Search). + +However, there is an important issue to deal with here. Recall that two objects can be unequal yet still have the same "value" for the purposes of comparing them. Since a set can contain multiple items with the same value, it is important to check that the binary search has landed on the correct item. + +For example, consider this sorted set of `Player` objects. Each `Player` has a name and a number of points: + + [ ("Bill", 50), ("Ada", 50), ("Jony", 50), ("Steve", 200), ("Jean-Louis", 500), ("Woz", 1000) ] + +We want the set to be sorted by points, from low to high. Multiple players can have the same number of points. The name of the player is not important for this ordering. However, the name *is* important for retrieving the correct item. + +Let's say we do `indexOf(bill)` where `bill` is player object `("Bill", 50)`. If we did a traditional binary search we'd land on index 2, which is the object `("Jony", 50)`. The value 50 matches, but it's not the object we're looking for! + +Therefore, we also need to check the items with the same value to the right and left of the midpoint. The code to check the left and right side looks like this: + +```swift + // Check to the right. + for j in mid.stride(to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in mid.stride(to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + + return nil +``` + +These loops start at the current `mid` value and then look at the neighboring values until we've found the correct object. + +The combined runtime for `indexOf()` is **O(log(n) + k)** where **n** is the length of the set, and **k** is the number of items with the same *value* as the one that is being searched for. + +Since the set is sorted, the following operations are all **O(1)**: + +```swift + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +``` + +## Examples + +Below are a few examples that can be found in the playground file. + +### Example 1 + +Here we create a set with random Integers. Printing the largest/smallest 5 numbers in the set is fairly easy. + +```swift +// Example 1 with type Int +var mySet = SortedSet() + +// Insert random numbers into the set +for _ in 0..<50 { + mySet.insert(randomNum(50, max: 500)) +} + +print(mySet) + +print(mySet.max()) +print(mySet.min()) + +// Print the 5 largest values +for k in 1...5 { + print(mySet.kLargest(k)) +} + +// Print the 5 lowest values +for k in 1...5 { + print(mySet.kSmallest(k)) +} +``` + +### Example 2 + +In this example we take a look at something a bit more interesting. We define a `Player` struct as follows: + +```swift +public struct Player: Comparable { + public var name: String + public var points: Int +} +``` + +The `Player` also gets its own `==` and `<` operators. The `<` operator is used to determine the sort order of the set, while `==` determines whether two objects are really equal. + +Note that `==` compares both the name and the points: + +```swifr +func ==(x: Player, y: Player) -> Bool { + return x.name == y.name && x.points == y.points +} +``` + +But `<` only compares the points: + +```swift +func <(x: Player, y: Player) -> Bool { + return x.points < y.points +} +``` + +Therefore, two `Player`s can each have the same value (the number of points), but are not guaranteed to be equal (they can have different names). + +We create a new set and insert 20 random players. The `Player()` constructor gives each player a random name and score: + +```swift +var playerSet = SortedSet() + +// Populate the set with random players. +for _ in 0..<20 { + playerSet.insert(Player()) +} +``` + +Insert another player: + +```swift +var anotherPlayer = Player() +playerSet.insert(anotherPlayer) +``` + +Now we use the `indexOf()` function to find out what rank `anotherPlayer` is. + +```swift +let level = playerSet.count - playerSet.indexOf(anotherPlayer)! +print("\(anotherPlayer.name) is ranked at level \(level) with \(anotherPlayer.points) points") +``` + +### Example 3 + +The final example demonstrates the need to look for the right item even after the binary search has completed. + +We insert 9 players into the set: + +```swift +var repeatedSet = SortedSet() + +repeatedSet.insert(Player(name: "Player 1", points: 100)) +repeatedSet.insert(Player(name: "Player 2", points: 100)) +repeatedSet.insert(Player(name: "Player 3", points: 100)) +repeatedSet.insert(Player(name: "Player 4", points: 100)) +repeatedSet.insert(Player(name: "Player 5", points: 100)) +repeatedSet.insert(Player(name: "Player 6", points: 50)) +repeatedSet.insert(Player(name: "Player 7", points: 200)) +repeatedSet.insert(Player(name: "Player 8", points: 250)) +repeatedSet.insert(Player(name: "Player 9", points: 25)) +``` + +Notice how several of these players have the same value of 100 points. + +The set looks something like this: + + [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] + +The next line looks for `Player 2`: + +```swift +print(repeatedSet.index(of: Player(name: "Player 2", points: 100))) +``` + +After the binary search finishes, the value of `mid` is at index 5: + + [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] + mid + +However, this is not `Player 2`. Both `Player 4` and `Player 2` have the same points, but a different name. The binary search only looked at the points, not the name. + +But we do know that `Player 2` must be either to the immediate left or the right of `Player 4`, so we check both sides of `mid`. We only need to look at the objects with the same value as `Player 4`. The others are replaced by `X`: + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + mid + +The code then first checks on the right of `mid` (where the `*` is): + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + mid * + +The right side did not contain the item, so we look at the left side: + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + * mid + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + * mid + +Finally, we've found `Player 2`, and return index 3. + +*Written By Zain Humayun* diff --git a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift new file mode 100644 index 000000000..c81f4d915 --- /dev/null +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift @@ -0,0 +1,30 @@ +//: # Example 1 with type Int + +var mySet = SortedSet() + +// Insert random numbers into the set +for _ in 0..<50 { + mySet.insert(random(min: 50, max: 500)) +} + +print(mySet) + +print("\nMaximum:") +print(mySet.max()) + +print("\nMinimum:") +print(mySet.min()) + +// Print the 5 largest values +print("\n5 Largest:") +for k in 1...5 { + print(mySet.kLargest(k)) +} + +// Print the 5 lowest values +print("\n5 Smallest:") +for k in 1...5 { + print(mySet.kSmallest(k)) +} + +//: [Next](@next) diff --git a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 000000000..dffc42643 --- /dev/null +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift new file mode 100644 index 000000000..2408d35d2 --- /dev/null +++ b/Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift @@ -0,0 +1,29 @@ +//: [Previous](@previous) + +//: # Example 2 with Player objects + +var playerSet = SortedSet() + +// Populate the set with random players. +for _ in 0..<20 { + playerSet.insert(Player()) +} + +// We'll look for this player later. +var anotherPlayer = Player() +playerSet.insert(anotherPlayer) + +// Print all players in order from highest points to lowest points. +// (Note: this is the reverse order of how they are stored in the set!) +print(playerSet) +//debugPrint(playerSet) + +// Highest and lowest players: +print(playerSet.max()) +print(playerSet.min()) + +// We'll find our player now: +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/Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift new file mode 100644 index 000000000..63edd11d2 --- /dev/null +++ b/Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift @@ -0,0 +1,22 @@ +//: [Previous](@previous) + +//: # Example 3: multiple entries with the same value + +var repeatedSet = SortedSet() + +repeatedSet.insert(Player(name: "Player 1", points: 100)) +repeatedSet.insert(Player(name: "Player 2", points: 100)) +repeatedSet.insert(Player(name: "Player 3", points: 100)) +repeatedSet.insert(Player(name: "Player 4", points: 100)) +repeatedSet.insert(Player(name: "Player 5", points: 100)) +repeatedSet.insert(Player(name: "Player 6", points: 50)) +repeatedSet.insert(Player(name: "Player 7", points: 200)) +repeatedSet.insert(Player(name: "Player 8", points: 250)) +repeatedSet.insert(Player(name: "Player 9", points: 25)) + +print(repeatedSet) +//debugPrint(repeatedSet) + +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/Sorted Set/SortedSet.playground/Sources/Player.swift b/Sorted Set/SortedSet.playground/Sources/Player.swift new file mode 100644 index 000000000..0960b2400 --- /dev/null +++ b/Sorted Set/SortedSet.playground/Sources/Player.swift @@ -0,0 +1,38 @@ +// The Player data type stores a random name, and a random number of +// points from 0 - 5000. +public struct Player: Comparable { + public var name: String + public var points: Int + + public init() { + self.name = String.random() + self.points = random(min: 0, max: 5000) + } + + public init(name: String, points: Int) { + self.name = name + self.points = points + } +} + +// Player x is equal to Player y if and only if both players have the +// same name and number of points. +public func == (x: Player, y: Player) -> Bool { + return x.name == y.name && x.points == y.points +} + +// Player x is less than Player y if x has less points than y. +public func < (x: Player, y: Player) -> Bool { + return x.points < y.points +} + +// Prints a Player formatted with their name and number of points. +public func print(player: Player) { + print("Player: \(player.name) | Points: \(player.points)") +} + +public func print(set: SortedSet) { + for i in 0.. Int { + return min + Int(arc4random_uniform(UInt32(max - min + 1))) +} + +// Generates a random alphanumeric string of a given length. +extension String { + public static func random(length: Int = 8) -> String { + let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + var randomString: String = "" + + for _ in 0.. { + private var internalSet = [T]() + + public init() { } + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + + // Inserts an item. Performance: O(n) + public mutating func insert(_ item: T) { + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } + + // Removes an item if it exists. Performance: O(n) + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } + + // Returns true if and only if the item exists somewhere in the set. + public func exists(_ item: T) -> Bool { + return index(of: item) != nil + } + + // Returns the index of an item if it exists, or -1 otherwise. + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // When we get here, we've landed on an item whose value is equal to the + // value of the item we're looking for, but the items themselves are not + // equal. We need to check the items with the same value to the right + // and to the left in order to find an exact match. + + // Check to the right. + for j in stride(from: mid, to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in stride(from: mid, to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + return nil + } + } + return nil + } + + // Returns the item at the given index. + // Assertion fails if the index is out of the range of [0, count). + public subscript(index: Int) -> T { + assert(index >= 0 && index < count) + return internalSet[index] + } + + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +} + diff --git a/Sorted Set/SortedSet.playground/contents.xcplayground b/Sorted Set/SortedSet.playground/contents.xcplayground new file mode 100644 index 000000000..18c02c912 --- /dev/null +++ b/Sorted Set/SortedSet.playground/contents.xcplayground @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Sorted Set/SortedSet.playground/playground.xcworkspace/contents.xcworkspacedata b/Sorted Set/SortedSet.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Sorted Set/SortedSet.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Sorted Set/SortedSet.swift b/Sorted Set/SortedSet.swift new file mode 100644 index 000000000..69546da0d --- /dev/null +++ b/Sorted Set/SortedSet.swift @@ -0,0 +1,118 @@ +/* + An Sorted Set is a collection where all items in the set follow an ordering, + usually sorted from 'least' to 'most'. The way you value and compare items + can be user-defined. + */ +public struct SortedSet { + private var internalSet = [T]() + + public init() { } + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + + // Inserts an item. Performance: O(n) + public mutating func insert(_ item: T) { + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } + + // Removes an item if it exists. Performance: O(n) + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } + + // Returns true if and only if the item exists somewhere in the set. + public func exists(_ item: T) -> Bool { + return index(of: item) != nil + } + + // Returns the index of an item if it exists, or -1 otherwise. + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // When we get here, we've landed on an item whose value is equal to the + // value of the item we're looking for, but the items themselves are not + // equal. We need to check the items with the same value to the right + // and to the left in order to find an exact match. + + // Check to the right. + for j in stride(from: mid, to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in stride(from: mid, to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + return nil + } + } + return nil + } + + // Returns the item at the given index. + // Assertion fails if the index is out of the range of [0, count). + public subscript(index: Int) -> T { + assert(index >= 0 && index < count) + return internalSet[index] + } + + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +} + diff --git a/Sparse Table/Images/idempotency.png b/Sparse Table/Images/idempotency.png new file mode 100644 index 000000000..88c8e7a8d Binary files /dev/null and b/Sparse Table/Images/idempotency.png differ diff --git a/Sparse Table/Images/query.png b/Sparse Table/Images/query.png new file mode 100644 index 000000000..fc1c42fb7 Binary files /dev/null and b/Sparse Table/Images/query.png differ diff --git a/Sparse Table/Images/query_example.png b/Sparse Table/Images/query_example.png new file mode 100644 index 000000000..c588828ee Binary files /dev/null and b/Sparse Table/Images/query_example.png differ diff --git a/Sparse Table/Images/recursion.png b/Sparse Table/Images/recursion.png new file mode 100644 index 000000000..6928e372c Binary files /dev/null and b/Sparse Table/Images/recursion.png differ diff --git a/Sparse Table/Images/recursion_examples.png b/Sparse Table/Images/recursion_examples.png new file mode 100644 index 000000000..737b95bf9 Binary files /dev/null and b/Sparse Table/Images/recursion_examples.png differ diff --git a/Sparse Table/Images/structure.png b/Sparse Table/Images/structure.png new file mode 100644 index 000000000..88902df0c Binary files /dev/null and b/Sparse Table/Images/structure.png differ diff --git a/Sparse Table/Images/structure_examples.png b/Sparse Table/Images/structure_examples.png new file mode 100644 index 000000000..69fd57218 Binary files /dev/null and b/Sparse Table/Images/structure_examples.png differ diff --git a/Sparse Table/README.markdown b/Sparse Table/README.markdown new file mode 100644 index 000000000..31bd5a781 --- /dev/null +++ b/Sparse Table/README.markdown @@ -0,0 +1,310 @@ +# Sparse Table + +I'm excited to present **Sparse Tables**. Despite being somewhat niche, Sparse Tables are simple to implement and extremely powerful. + +### The Problem + +Let's suppose: +- we have an array **a** of some type +- we have some associative binary function **f** [\*]. The function can be: min, max, [gcd](../GCD/), boolean AND, boolean OR ... + +*[\*] where **f** is also "idempotent". Don't worry, I'll explain this in a moment.* + +Our task is as follows: + +- Given two indices **l** and **r**, answer a **query** for the interval `[l, r)` by performing `f(a[l], a[l + 1], a[l + 2], ..., a[r - 1])`; taking all the elements in the range and applying **f** to them +- There will be a *huge* number **Q** of these queries to answer ... so we should be able to answer each query *quickly*! + +For example, if we have an array of numbers: + +```swift +var a = [ 20, 3, -1, 101, 14, 29, 5, 61, 99 ] +``` +and our function **f** is the *min* function. + +Then we may be given a query for interval `[3, 8)`. That means we look at the elements: + +``` +101, 14, 29, 5, 61 +``` + +because these are the elements of **a** with indices +that lie in our range `[3, 8)` – elements from index 3 up to, but not including, index 8. +We then we pass all of these numbers into the min function, +which takes the minimum. The answer to the query is `5`, because that's the result of `min(101, 14, 29, 5, 61)`. + +Imagine we have millions of these queries to process. +> - *Query 1*: Find minimum of all elements between 2 and 5 +> - *Query 2*: Find minimum of all elements between 3 and 9 +> - ... +> - *Query 1000000*: Find minimum of all elements between 1 and 4 + +And our array is very large. Here, let's say **Q** = 1000000 and **N** = 500000. Both numbers are *huge*. We want to make sure that we can answer each query really quickly, or else the number of queries will overwhelm us! + +*So that's the problem.* + +The naive solution to this problem is to perform a `for` loop +to compute the answer for each query. However, for very large **Q** and very large **N** this +will be too slow. We can speed up the time to compute the answer by using a data structure called +a **Sparse Table**. You'll notice that so far, our problem is exactly the same as that of the [Segment Tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree) +(assuming you're familiar). However! ... there's one crucial difference between Segment Trees +and Sparse Tables ... and it concerns our choice of **f**. + + +### A small gotcha ... Idempotency + +Suppose we wanted to find the answer to **`[A, D)`**. +And we already know the answer to two ranges **`[A, B)`** and **`[C, D)`**. +And importantly here, ... *these ranges overlap*!! We have **C** < **B**. + +![Overlapping ranges](Images/idempotency.png) + + +So what? Well, for **f** = minimum function, we can take our answers for **`[A, B)`** and **`[C, D)`** +and combine them! +We can just take the minimum of the two answers: `result = min(x1, x2)` ... *voilà!*, we have the minimum for **`[A, D)`**. +It didn't matter that the intervals overlap - we still found the correct minimum. +But now suppose **f** is the addition operation `+`. Ok, so now we're taking sums over ranges. +If we tried the same approach again, it wouldn't work. That is, +if we took our answers for **`[A, B)`** and **`[C, D)`** +and added them together we'd get a wrong answer for **`[A, D)`**. +*Why?* Well, we'd have counted some elements twice because of the overlap. + +Later, we'll see that in order to answer queries, Sparse Tables use this very technique. +They combine answers in the same way as shown above. Unfortunately this means +we have to exclude certain binary operators from being **f**, including `+`, `*`, XOR, ... +because they don't work with this technique. +In order to get the best speed of a Sparse Table, +we need to make sure that the **f** we're using is an **[idempotent](https://en.wikipedia.org/wiki/Idempotence)** binary operator. +Mathematically, these are operators that satisfy `f(x, x) = x` for all possible **x** that could be in **a**. +Practically speaking, these are the only operators that work; allowing us to combine answers from overlapping ranges. +Examples of idempotent **f**'s are min, max, gcd, boolean AND, boolean OR, bitwise AND and bitwise OR. +Note that for Segment Trees, **f** does not have to be idempotent. That's the crucial difference between +Segment Trees and Sparse Tables. + +*Phew!* Now that we've got that out of the way, let's dive in! + +## Structure of a Sparse Table + +Let's use **f** = min and use the array: + +```swift +var a = [ 10, 6, 5, -7, 9, -8, 2, 4, 20 ] +``` + +In this case, the Sparse Table looks like this: + +![Sparse Table](Images/structure.png) + +What's going on here? There seems to be loads of intervals. +*Correct!* Sparse tables are preloaded with the answers for lots of queries `[l, r)`. +Here's the idea. Before we process our **Q** queries, we'll pre-populate our Sparse Table `table` +with answers to loads of queries; +making it act a bit like a *cache*. When we come to answer one of our queries, we can break the query +down into smaller "sub-queries", each having an answer that's already in the cache. +We lookup the cached answers for the sub-queries in +`table` in constant time +and combine the answers together +to give the overall answer to the original query in speedy time. + +The problem is, we can't store the answers for every single possible query that we could ever have ... +or else our table would be too big! After all, our Sparse Table needs to be *sparse*. So what do we do? +We only pick the "best" intervals to store answers for. And as it turns out, the "best" intervals are those +that have a **width that is a power of two**! + +For example, the answer for the query `[10, 18)` is in our table +because the interval width: `18 - 10 = 8 = 2**3` is a power of two (`**` is the [exponentiation operator](https://en.wikipedia.org/wiki/Exponentiation)). +Also, the answer for `[15, 31)` is in our table because its width: `31 - 15 = 16 = 2**4` is again a power of two. +However, the answer for `[1, 6)` is *not* in there because the interval's width: `6 - 1 = 5` is *not* a power of two. +Consequently, we don't store answers for *all* possible intervals that fit inside **a** – +only the ones with a width that is a power of two. +This is true irrespective of where the interval starts within **a**. +We'll gradually see that this approach works and that relatively speaking, it uses very little space. + +A **Sparse Table** is a table where `table[w][l]` contains the answer for `[l, l + 2**w)`. +It has entries `table[w][l]` where: +- **w** tells us our **width** ... the number of elements or the *width* is `2**w` +- **l** tells us the **lower bound** ... it's the starting point of our interval + +Some examples: +- `table[3][0] = -8`: our width is `2**3`, we start at `l = 0` so our query is `[0, 0 + 2**3) = [0, 8)`. + The answer for this query is `min(10, 6, 5, -7, 9, -8, 2, 4, 20) = -8`. +- `table[2][1] = -7`: our width is `2**2`, we start at `l = 1` so our query is `[1, 1 + 2**2) = [1, 5)`. + The answer for this query is `min(6, 5, -7, 9) = -7`. +- `table[1][7] = 4`: our width is `2**1`, we start at `l = 7` so our query is `[7, 7 + 2**1) = [7, 9)`. + The answer for this query is `min(4, 20) = 4`. +- `table[0][8] = 20`: our width is `2**0`, we start at `l = 8` so our query is`[8, 8 + 2**0) = [8, 9)`. + The answer for this query is `min(20) = 20`. + + +![Sparse Table](Images/structure_examples.png) + + +A Sparse Table can be implemented using a [two-dimentional array](../2D%20Array). + +```swift +public class SparseTable { + private var table: [[T]] + + public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + } + // ... +} +``` + + +## Building a Sparse Table + +To build a Sparse Table, we compute each table entry starting from the bottom-left and moving up towards +the top-right (in accordance with the diagram). +First we'll compute all the intervals for **w** = 0, then compute all the intervals +and for **w** = 1 and so on. We'll continue up until **w** is big enough such that our intervals are can cover at least half the array. +For each **w**, we compute the interval for **l** = 0, 1, 2, 3, ... until we reach **N**. +This is all achieved using a double `for`-`in` loop: + +```swift +for w in 0.. 0)**: We need to find out the answer to `[l, l + 2**w)` for some **l**. +This interval, like all of our intervals in our table has a width that +is a power of two (e.g. 2, 4, 8, 16) ... so we can cut it into two equal halves. + - Our interval with width ``2**w`` is cut into two intervals, each of width ``2**(w - 1)``. + - Because each half has a width that is a power of two, we can look them up in our Sparse Table. + - We combine them together using **f**. + ``` + table[w][l] = f(table[w - 1][l], table[w - 1][l + 2 ** (w - 1)]) + ``` + + +![Sparse Table](Images/recursion.png) + +For example for `a = [ 10, 6, 5, -7, 9, -8, 2, 4, 20 ]` and **f** = *min*: + +- we compute `table[0][2] = 5`. We just had to look at `a[2]` because the range has a width of one. +- we compute `table[1][7] = 4`. We looked at `table[0][7]` and `table[0][8]` and apply **f** to them. +- we compute `table[3][1] = -8`. We looked at `table[2][1]` and `table[2][5]` and apply **f** to them. + + +![Sparse Table](Images/recursion_examples.png) + + + +```swift +public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + let N = array.count + let W = Int(ceil(log2(Double(N)))) + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + self.function = function + self.defaultT = defaultT + + for w in 0.. T { + let width = r - l + let W = Int(floor(log2(Double(width)))) + let lo = table[W][l] + let hi = table[W][r - (1 << W)] + return function(lo, hi) + } + ``` + +Finding answers to queries takes **O(1)** time. + +## Analysing Sparse Tables + +- **Query Time** - Both table lookups take constant time. All other operations inside `query` take constant time. +So answering a single query also takes constant time: **O(1)**. But instead of one query we're actually answering **Q** queries, +and we'll need time to built the table before-hand. +Overall time is: **O(NlgN + Q)** to build the table and answer all queries. +The naive approach is to do a for loop for each query. The overall time for the naive approach is: **O(NQ)**. +For very large **Q**, the naive approach will scale poorly. For example if `Q = O(N*N)` +then the naive approach is `O(N*N*N)` where a Sparse Table takes time `O(N*N)`. +- **Space**- The number of possible **w** is **lgN** and the number of possible **l** our table is **N**. So the table +has uses **O(NlgN)** additional space. + +### Comparison with Segment Trees + +- **Pre-processing** - Segment Trees take **O(N)** time to build and use **O(N)** space. Sparse Tables take **O(NlgN)** time to build and use **O(NlgN)** space. +- **Queries** - Segment Tree queries are **O(lgN)** time for any **f** (idempotent or not idempotent). Sparse Table queries are **O(1)** time if **f** is idempotent and are not supported if **f** is not idempotent. [†] +- **Replacing Items** - Segment Trees allow us to efficiently update an element in **a** and update the segment tree in **O(lgN)** time. Sparse Tables do not allow this to be done efficiently. If we were to update an element in **a**, we'd have to rebuild the Sparse Table all over again in **O(NlgN)** time. + + +[†] *Although technically, it's possible to rewrite the `query` method +to add support for non-idempotent functions. But in doing so, we'd bump up the time up from O(1) to O(lgn), +completely defeating the original purpose of Sparse Tables - supporting lightening quick queries. +In such a case, we'd be better off using a Segment Tree (or a Fenwick Tree)* + +## Summary + +That's it! See the playground for more examples involving Sparse Tables. +You'll see examples for: min, max, gcd, boolean operators and logical operators. + +### See also + +- [Segment Trees (Swift Algorithm Club)](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree) +- [How to write O(lgn) time query function to support non-idempontent functions (GeeksForGeeks)](https://www.geeksforgeeks.org/range-sum-query-using-sparse-table/) +- [Fenwick Trees / Binary Indexed Trees (TopCoder)](https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/) +- [Semilattice (Wikipedia)](https://en.wikipedia.org/wiki/Semilattice) + +*Written for Swift Algorithm Club by [James Lawson](https://github.com/jameslawson)* + diff --git a/Sparse Table/Sparse Table.playground/Contents.swift b/Sparse Table/Sparse Table.playground/Contents.swift new file mode 100644 index 000000000..ef83263b0 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/Contents.swift @@ -0,0 +1,144 @@ +// +// Swift Algorithm Club - Sparse Table +// Author: James Lawson (github.com/jameslawson) +// + +import Foundation + +// Last checked with Xcode Version 9.2 (9C40b) +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +public class SparseTable { + private var defaultT: T + private var table: [[T]] + private var function: (T, T) -> T + + public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + let N = array.count + let W = Int(ceil(log2(Double(N)))) + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + self.function = function + self.defaultT = defaultT + + for w in 0.. T { + let width = r - l + let N = table[0].count + if width <= 0 || l >= N { + return defaultT + } + let r = min(N, r) + let W = Int(floor(log2(Double(width)))) + let lo = table[W][l] + let hi = table[W][r - (1 << W)] + return function(lo, hi) + } +} + +print("---------------------------- EXAMPLE 1 -------------------------------------") +// Here we have an array of integers and we're repeatedly +// finding the minimum over various ranges + +let intArray = [1, -11, -7, 3, 2, 4] +let minIntTable = SparseTable(array: intArray, function: min, defaultT: Int.max) +print(minIntTable.query(from: 0, until: 6)) // min(1, 3, -11, 3, 2, 4) = -11 +print(minIntTable.query(from: 3, until: 5)) // min(3, 2) = 2 +print(minIntTable.query(from: 2, until: 6)) // min(-7, 3, 2, 4) = -7 +print(minIntTable.query(from: 0, until: 1)) // min(1) = 1 +print(minIntTable.query(from: 0, until: 0)) // min() = Int.max +print("----------------------------------------------------------------------------\n\n") + + +print("---------------------------- EXAMPLE 2 -------------------------------------") +// Now we have an array of doubles and we're repeatedly +// finding the maximum over various ranges + +let doubleArray = [1.5, 20.0, 3.5, 15.0, 18.0, -10.0, 5.5] +let maxDoubleTable = SparseTable(array: doubleArray, function: max, defaultT: -.infinity) +print(maxDoubleTable.query(from: 0, until: 4)) // max(1.5, 20.0, 3.5, 15.0) = 20.0 +print(maxDoubleTable.query(from: 3, until: 4)) // max(3.5, 15.0) = 15.0 +print(maxDoubleTable.query(from: 4, until: 6)) // max(18.0, -10.0, 5.5) = 18.0 +print(maxDoubleTable.query(from: 1, until: 2)) // max(20.0) = 20.0 +print(maxDoubleTable.query(from: 0, until: 0)) // max() = -inf +print("----------------------------------------------------------------------------\n\n") + + +print("---------------------------- EXAMPLE 3 -------------------------------------") +// An array of booleans and we're repeatedly +// finding the boolean AND over various ranges + +let boolArray = [true, false, true, true, true, false, false] +func and(_ x: Bool, _ y: Bool) -> Bool { return x && y } + +let maxBoolTable = SparseTable(array: boolArray, function: and, defaultT: false) +print(maxBoolTable.query(from: 0, until: 4)) // and(T, F, T, T) = F +print(maxBoolTable.query(from: 2, until: 5)) // and(T, T, T) = T +print(maxBoolTable.query(from: 2, until: 6)) // and(T, T, T, F) = F +print(maxBoolTable.query(from: 0, until: 1)) // and(T) = T +print(maxBoolTable.query(from: 1, until: 2)) // and(F) = F +print(maxBoolTable.query(from: 0, until: 0)) // and() = F +print("----------------------------------------------------------------------------\n\n") + +print("---------------------------- EXAMPLE 4 -------------------------------------") +// An array of positive integers and we're repeatedly finding +// the gcd (greatest common divisor) over various ranges. The gcd operator is +// associative and idempotent so we can use it with sparse tables + +let posIntArray = [7, 2, 3, 4, 6, 5, 25, 75, 100] +func gcd(_ m: Int, _ n: Int) -> Int { + var a = 0 + var b = max(m, n) + var r = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} + +let gcdTable = SparseTable(array: posIntArray, function: gcd, defaultT: 1) +print(gcdTable.query(from: 0, until: 4)) // gcd(7, 2, 3) = 1 +print(gcdTable.query(from: 3, until: 5)) // gcd(4, 6) = 2 +print(gcdTable.query(from: 5, until: 7)) // gcd(5, 25, 75) = 5 +print(gcdTable.query(from: 6, until: 9)) // gcd(25, 75, 100) = 25 +print(gcdTable.query(from: 3, until: 4)) // gcd(4) = 4 +print(gcdTable.query(from: 0, until: 0)) // gcd() = 1 +print("------------------------------------------------------------------------\n\n") + + + +print("---------------------------- EXAMPLE 5 -------------------------------------") +// An array of nonnegative integers where for each integer we consider its binary representation. +// We're repeatedly finding the binary OR (|) over various ranges. The binary operator is +// associative and idempotent so we can use it with sparse tables + +let binArray = [0b1001, 0b1100, 0b0000, 0b0001, 0b0010, 0b0100, 0b0000, 0b1111] + + +let orTable = SparseTable(array: binArray, function: |, defaultT: 0b0000) +print(String(orTable.query(from: 0, until: 2), radix: 2)) // binary_or(1001, 1100) = 1101 +print(String(orTable.query(from: 3, until: 5), radix: 2)) // binary_or(0001, 0010) = 0011 + +print(String(orTable.query(from: 3, until: 6), radix: 2)) // binary_or(0001, 0010, 0100) = 0111 +print(String(orTable.query(from: 6, until: 8), radix: 2)) // binary_or(0000, 1111) = 1111 +print(String(orTable.query(from: 1, until: 5), radix: 2)) // binary_or(1100, 0000, 0001, 0010) = 1111 +print(String(orTable.query(from: 0, until: 1), radix: 2)) // binary_or(1001) = 1001 +print(String(orTable.query(from: 0, until: 0), radix: 2)) // binary_or() = 0000 +print("----------------------------------------------------------------------------\n\n") diff --git a/Sparse Table/Sparse Table.playground/contents.xcplayground b/Sparse Table/Sparse Table.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata b/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 000000000..48a08c17c Binary files /dev/null and b/Splay Tree/Images/example-zigzig-1.png differ diff --git a/Splay Tree/Images/example-zigzig-2.png b/Splay Tree/Images/example-zigzig-2.png new file mode 100644 index 000000000..e10ed1f80 Binary files /dev/null and b/Splay Tree/Images/example-zigzig-2.png differ diff --git a/Splay Tree/Images/example-zigzig-3.png b/Splay Tree/Images/example-zigzig-3.png new file mode 100644 index 000000000..905b4d4bd Binary files /dev/null and b/Splay Tree/Images/example-zigzig-3.png differ diff --git a/Splay Tree/Images/example-zigzig-4.png b/Splay Tree/Images/example-zigzig-4.png new file mode 100644 index 000000000..1d46315cf Binary files /dev/null and b/Splay Tree/Images/example-zigzig-4.png differ diff --git a/Splay Tree/Images/example-zigzig-5.png b/Splay Tree/Images/example-zigzig-5.png new file mode 100644 index 000000000..002ca2833 Binary files /dev/null and b/Splay Tree/Images/example-zigzig-5.png differ diff --git a/Splay Tree/Images/example1-1.png b/Splay Tree/Images/example1-1.png new file mode 100644 index 000000000..1bd406248 Binary files /dev/null and b/Splay Tree/Images/example1-1.png differ diff --git a/Splay Tree/Images/example1-2.png b/Splay Tree/Images/example1-2.png new file mode 100644 index 000000000..46dd35bcd Binary files /dev/null and b/Splay Tree/Images/example1-2.png differ diff --git a/Splay Tree/Images/example1-3.png b/Splay Tree/Images/example1-3.png new file mode 100644 index 000000000..af2c6ee9d Binary files /dev/null and b/Splay Tree/Images/example1-3.png differ 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 000000000..dda9d6de9 Binary files /dev/null and b/Splay Tree/Images/examplezig1.png differ diff --git a/Splay Tree/Images/examplezig2.png b/Splay Tree/Images/examplezig2.png new file mode 100644 index 000000000..ba8a48867 Binary files /dev/null and b/Splay Tree/Images/examplezig2.png differ 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 000000000..11ec330f2 Binary files /dev/null and b/Splay Tree/Images/examplezigzig1.png differ diff --git a/Splay Tree/Images/examplezigzig2.png b/Splay Tree/Images/examplezigzig2.png new file mode 100644 index 000000000..0a9c64593 Binary files /dev/null and b/Splay Tree/Images/examplezigzig2.png differ diff --git a/Splay Tree/Images/examplezigzig3.png b/Splay Tree/Images/examplezigzig3.png new file mode 100644 index 000000000..dbc40a3ba Binary files /dev/null and b/Splay Tree/Images/examplezigzig3.png differ diff --git a/Splay Tree/Images/worst-case-1.png b/Splay Tree/Images/worst-case-1.png new file mode 100644 index 000000000..deda6d96f Binary files /dev/null and b/Splay Tree/Images/worst-case-1.png differ diff --git a/Splay Tree/Images/worst-case-2.png b/Splay Tree/Images/worst-case-2.png new file mode 100644 index 000000000..46870f229 Binary files /dev/null and b/Splay Tree/Images/worst-case-2.png differ diff --git a/Splay Tree/Images/worst-case-3.png b/Splay Tree/Images/worst-case-3.png new file mode 100644 index 000000000..65af205a8 Binary files /dev/null and b/Splay Tree/Images/worst-case-3.png differ diff --git a/Splay Tree/Images/worst-case-4.png b/Splay Tree/Images/worst-case-4.png new file mode 100644 index 000000000..ac007e7d8 Binary files /dev/null and b/Splay Tree/Images/worst-case-4.png differ diff --git a/Splay Tree/Images/worst-case-5.png b/Splay Tree/Images/worst-case-5.png new file mode 100644 index 000000000..4009a2592 Binary files /dev/null and b/Splay Tree/Images/worst-case-5.png differ diff --git a/Splay Tree/Images/worst-case-6.png b/Splay Tree/Images/worst-case-6.png new file mode 100644 index 000000000..b162346d3 Binary files /dev/null and b/Splay Tree/Images/worst-case-6.png differ diff --git a/Splay Tree/Images/zig.png b/Splay Tree/Images/zig.png new file mode 100644 index 000000000..e21522b6f Binary files /dev/null and b/Splay Tree/Images/zig.png differ diff --git a/Splay Tree/Images/zigzag1.png b/Splay Tree/Images/zigzag1.png new file mode 100644 index 000000000..1bd406248 Binary files /dev/null and b/Splay Tree/Images/zigzag1.png differ diff --git a/Splay Tree/Images/zigzag2.png b/Splay Tree/Images/zigzag2.png new file mode 100644 index 000000000..5f8e4c63f Binary files /dev/null and b/Splay Tree/Images/zigzag2.png differ diff --git a/Splay Tree/Images/zigzig-wrongrotated.png b/Splay Tree/Images/zigzig-wrongrotated.png new file mode 100644 index 000000000..fc9af14c2 Binary files /dev/null and b/Splay Tree/Images/zigzig-wrongrotated.png differ diff --git a/Splay Tree/Images/zigzig1.png b/Splay Tree/Images/zigzig1.png new file mode 100644 index 000000000..11ec330f2 Binary files /dev/null and b/Splay Tree/Images/zigzig1.png differ diff --git a/Splay Tree/Images/zigzig2.png b/Splay Tree/Images/zigzig2.png new file mode 100644 index 000000000..1e843c9af Binary files /dev/null and b/Splay Tree/Images/zigzig2.png differ diff --git a/Splay Tree/SplayTree.playground/Contents.swift b/Splay Tree/SplayTree.playground/Contents.swift new file mode 100644 index 000000000..28a201b37 --- /dev/null +++ b/Splay Tree/SplayTree.playground/Contents.swift @@ -0,0 +1,14 @@ +//: Playground - Splay Tree Implementation + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +var tree = SplayTree(value: 0) +tree.insert(value: 2) +tree.insert(value: 3) +tree.insert(value: 4) +tree.insert(value: 7) +_ = tree.search(value: 2) +tree.remove(value: 2) diff --git a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift new file mode 100644 index 000000000..f450eaced --- /dev/null +++ b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift @@ -0,0 +1,557 @@ +/* + * 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: Node) { + + 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 + */ + 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 + } + + /** + 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 + */ + 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!) + } + } + + /** + Performs a single rotation from a node to its parent + re-arranging the children properly + */ + 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: Node? + + if child.isLeftChild { + + 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 + + } + + + } +} + +public class Node { + + 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) { + self.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) + } +} + +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) { + 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 + } + + 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 Node { + + /* + 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) -> Node { + if let selfValue = self.value { + if value < selfValue { + if let left = left { + 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 { + 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 Node { + + /* + 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 + + */ + fileprivate func remove(value: T) -> Node? { + guard let target = search(value: value) else { return self } + + if let left = target.left, let right = target.right { + let largestOfLeftChild = left.maximum() + left.parent = nil + right.parent = nil + + SplayOperation.splay(node: largestOfLeftChild) + largestOfLeftChild.right = right + + return largestOfLeftChild + + } else if let left = target.left { + replace(node: target, with: left) + return left + + } else if let right = target.right { + replace(node: target, with: right) + return right + + } else { + return nil + } + } + + private func replace(node: Node, with newNode: Node?) { + guard let sourceParent = sourceNode.parent else { return } + + if sourceNode.isLeftChild { + sourceParent.left = newNode + } else { + sourceParent.right = newNode + } + + newNode?.parent = sourceParent + } +} + +// MARK: - Searching + +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) -> 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! { + node = n.right + if n.right != nil { nodeParent = n.right } + } else { + break + } + } + + if let node = node { + SplayOperation.splay(node: node) + return node + } else if let nodeParent = nodeParent { + SplayOperation.splay(node: nodeParent) + return nodeParent + } + + return nil + } + + public func contains(value: T) -> Bool { + return search(value: value) != nil + } + + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum(splayed: Bool = false) -> Node { + var node = self + while case let next? = node.left { + node = next + } + + if splayed == true { + SplayOperation.splay(node: node) + } + + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum(splayed: Bool = false) -> Node { + var node = self + while case let next? = node.right { + node = next + } + + if splayed == true { + 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() -> Node? { + 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() -> Node? { + 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 Node { + + 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 Node { + + 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 Node: CustomStringConvertible { + public var description: String { + var s = "" + if let left = left { + s += "left: (\(left.description)) <- " + } + if let v = value { + s += "\(v)" + } + if let right = right { + s += " -> (right: \(right.description))" + } + return s + } +} + +extension SplayTree: CustomStringConvertible { + public var description: String { + return root?.description ?? "Empty tree" + } +} + +extension Node: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "value: \(String(describing: value))" + if let parent = parent, let v = parent.value { + s += ", parent: \(v)" + } + 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 } + } +} + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root?.debugDescription ?? "Empty tree" + } +} 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..0f1fa48f0 --- /dev/null +++ b/Splay Tree/SplayTree.swift @@ -0,0 +1,557 @@ +/* + * 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: Node) { + + 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 + */ + 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 + } + + /** + 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 + */ + 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!) + } + } + + /** + Performs a single rotation from a node to its parent + re-arranging the children properly + */ + 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: Node? + + if child.isLeftChild { + + 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 + + } + + + } +} + +public class Node { + + 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) { + self.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) + } +} + +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) { + 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 + } + + 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 Node { + + /* + 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) -> Node { + if let selfValue = self.value { + if value < selfValue { + if let left = left { + 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 { + 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 Node { + + /* + 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 + + */ + fileprivate func remove(value: T) -> Node? { + guard let target = search(value: value) else { return self } + + if let left = target.left, let right = target.right { + let largestOfLeftChild = left.maximum() + left.parent = nil + right.parent = nil + + SplayOperation.splay(node: largestOfLeftChild) + largestOfLeftChild.right = right + + return largestOfLeftChild + + } else if let left = target.left { + replace(node: target, with: left) + return left + + } else if let right = target.right { + replace(node: target, with: right) + return right + + } else { + return nil + } + } + + private func replace(node: Node, with newNode: Node?) { + guard let sourceParent = sourceNode.parent else { return } + + if sourceNode.isLeftChild { + sourceParent.left = newNode + } else { + sourceParent.right = newNode + } + + newNode?.parent = sourceParent + } +} + +// MARK: - Searching + +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) -> 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! { + node = n.right + if n.right != nil { nodeParent = n.right } + } else { + break + } + } + + if let node = node { + SplayOperation.splay(node: node) + return node + } else if let nodeParent = nodeParent { + SplayOperation.splay(node: nodeParent) + return nodeParent + } + + return nil + } + + public func contains(value: T) -> Bool { + return search(value: value) != nil + } + + /* + Returns the leftmost descendent. O(h) time. + */ + public func minimum(splayed: Bool = false) -> Node { + var node = self + while case let next? = node.left { + node = next + } + + if splayed == true { + SplayOperation.splay(node: node) + } + + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum(splayed: Bool = false) -> Node { + var node = self + while case let next? = node.right { + node = next + } + + if splayed == true { + 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() -> Node? { + 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() -> Node? { + 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 Node { + + 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 Node { + + 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 Node: CustomStringConvertible { + public var description: String { + var s = "" + if let left = left { + s += "left: (\(left.description)) <- " + } + if let v = value { + s += "\(v)" + } + if let right = right { + s += " -> (right: \(right.description))" + } + return s + } +} + +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 { + s += ", parent: \(v)" + } + 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 } + } +} + +extension SplayTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root?.debugDescription ?? "Empty tree" + } +} 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..01201a108 --- /dev/null +++ b/Splay Tree/Tests/SplayTreeTests.swift @@ -0,0 +1,76 @@ +import XCTest + +class SplayTreeTests: XCTestCase { + + var tree1: SplayTree! + var tree2: SplayTree! + + override func setUp() { + super.setUp() + 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() { + tree1.insert(value: 10) + assert(tree1.value == 10) + + tree2.insert(value: 2) + assert(tree2.root?.value == 2) + } + + func testSearchNonExisting() { + 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 testDeleteRoot() { + tree2.remove(value: 44) + assert(tree2.value == 100) + } + + func testMinimum() { + let v = tree2.minimum() + assert(v?.value == 1) + } + + func testMaximum() { + let v = tree2.maximum() + 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) + } + +} 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md new file mode 100644 index 000000000..8a852c950 --- /dev/null +++ b/Splay Tree/readme.md @@ -0,0 +1,277 @@ +# 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 + +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 followed by an explanation about why ZigZig rotates first to the grandparent). + +### 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 opposite), 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. + +![ZigCase](Images/zig.png) + + +## Splaying + +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 + +To insert a value: + +- Insert it as in a binary search tree +- Splay the value to the root + +### Deletion + +To delete a value: + +- Perform search for the value, after performed search function if the tree contains the value, it'll be the root of the new tree. +- If the tree has only left child, change left child to the root of the tree, remove the old root node +- If the tree has only right child, change right child to the root of the tree, remove the old root node +- Else, the tree has both two children, set parent of two children to nil, so that they're two new trees (left-tree and right-tree). +- Splay the minimum node of right-tree (or minimum node of left-tree), then set left-tree as left child of new root of right-tree (or set right-tree as right child of new root of left-tree), return right-tree + +### Search + +To search a value: + +- Search for it as in a binary search tree +- Splay the node containing the value to the root +- If not found splay the node that would had been the parent of the searched value + +### Minimum and maximum + +- Search the tree for the required value +- Splay the node to the root + +## Examples + +### Example 1 + +Lets suppose a *find(20)* operation was performed and now the values **20** needs to be splayed to the root. +The sequence of steps will be the following: + + +1. Since we are in a *ZigZig* case, we need to rotate **9** to **4** + +![ZiggEx1](Images/examplezigzig1.png) + +2. We got the following tree after the first rotation: + +![ZiggEx2](Images/examplezigzig2.png) + +3. And finally the **20** is rotated to the **9** + +![ZiggEx3](Images/examplezigzig3.png) + + +### Example 2 + +Now suppose a *insert(7)* operation was performed and we're in a *ZigZag* case. + + +1. First **7** is rotated to **9** + +![ZigggEx21](Images/example1-1.png) + +2. And the result tree is: + +![ZigggEx22](Images/example1-2.png) + +3. Finally **7** is rotated to **4** + +![ZigggEx23](Images/example1-3.png) + + +## 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 example, caches or garbage collection algorithms, or in any other problem involving frequent access to a certain numbers of elements from a data set. + +## Disadvantages + +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. + +# An example of the Worst Case Performance + +Suppose the a sequence of consecutive values are inserted in an Splay Tree. +Let's take for example [1,2,3,4,5,6,7,8]. + +The tree construction will be like following: + + +1. Insert the number **1** + +2. Insert **2** + + +![WorstCase1](Images/worst-case-1.png) + + +3. Splay **2** to the root + + +![WorstCase2](Images/worst-case-2.png) + + +4. Insert **3** + + +![WorstCase3](Images/worst-case-3.png) + +5. Splay **3** to the root + + +![WorstCase4](Images/worst-case-4.png) + + +6. Insert **4** + + +![WorstCase5](Images/worst-case-5.png) + + +7. After inserting the rest of the values the tree will look like this: + + +![WorstCase6](Images/worst-case-6.png) + + + +If we keep insert number following the same sequence, that tree becomes inbalanced and have a height of **n** with **n** being the numbers of values inserted. +After getting this tree, a *find(1)* operation for example will take **O(n)** + +## ZigZig rotation order: first grandparent + +But thanks to the properties of the **Splay Tree** and the *ZigZig* rotations after the *find(1)* operation the tree becomes balanced again. This only happens if we respect the order of the *ZigZig* rotation, and the rotation to the grandparent happens first. + +The sequence of *ZigZigs* rotations will look like follows: + +1. Rotate **2** to **3** + +![ZigZig1](Images/example-zigzig-1.png) + +2. Rotate **1** to **2** + +![ZigZig2](Images/example-zigzig-2.png) + +3. Rotate **4** to **5** + +![ZigZig3](Images/example-zigzig-3.png) + +4. Rotate **1** to **4** + +![ZigZig4](Images/example-zigzig-4.png) + +5. Finally after splaying **1** to the root the tree will look like this: + +![ZigZig5](Images/example-zigzig-5.png) + + +Based on the example above, we can see why it's important to rotate first to the grandparent. We got a tree of height = 6, from an initial tree of height = 8. If the tree would had been taller, we would have achieved almost half of the initial height after the splaying operation. + +## ZigZig wrong rotation order + +If the rotations would had been taking first the parent and not the grandparent we would have finished with the following, yet unbalanced tree, just inverting the side of the elements. + +![ZigZigWrong](Images/zigzig-wrongrotated.png) + + +## 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=8Zs1lj_bUV0) + + +---------------- + +*Written for Swift Algorithm Club by Barbara Martina Rodeker* + +---------------- + diff --git a/Stack/README.markdown b/Stack/README.markdown index fbc2512e4..b84b585df 100644 --- a/Stack/README.markdown +++ b/Stack/README.markdown @@ -1,5 +1,7 @@ # Stack +> This topic has been tutorialized [here](https://www.raywenderlich.com/149213/swift-algorithm-club-swift-stack-data-structure) + A stack is like an array but with limited functionality. You can only *push* to add a new element to the top of the stack, *pop* to remove the element from the top, and *peek* at the top element without popping it off. Why would you want to do 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. @@ -38,11 +40,11 @@ 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 { - private var array = [T]() + fileprivate var array = [T]() public var isEmpty: Bool { return array.isEmpty @@ -52,19 +54,15 @@ public struct Stack { 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 } } @@ -72,6 +70,6 @@ public struct Stack { Notice that a push puts the new element at the end of the array, not the beginning. Inserting at the beginning of an array is expensive, an **O(n)** operation, because it requires all existing array elements to be shifted in memory. Adding at the end is **O(1)**; it always takes the same amount of time, regardless of the size of the array. -Fun fact about stacks: each time you call a function or a method, the return address is placed on a stack by the CPU. When the function ends, the CPU uses that return address to jump back to the caller. That's why if you call too many functions -- for example in a recursive function that never ends -- you get a so-called "stack overflow" as the CPU stack is out of space. +Fun fact about stacks: Each time you call a function or a method, the CPU places the return address on a stack. When the function ends, the CPU uses that return address to jump back to the caller. That's why if you call too many functions -- for example in a recursive function that never ends -- you get a so-called "stack overflow" as the CPU stack has run out of space. -*Written by Matthijs Hollemans* +*Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Stack/Stack Tests/Stack.xcodeproj/project.pbxproj b/Stack/Stack Tests/Stack.xcodeproj/project.pbxproj deleted file mode 100644 index bfa645c10..000000000 --- a/Stack/Stack Tests/Stack.xcodeproj/project.pbxproj +++ /dev/null @@ -1,394 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7B18E0431C5BF7F1005A2B8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0421C5BF7F1005A2B8E /* AppDelegate.swift */; }; - 7B18E0451C5BF7F1005A2B8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E0441C5BF7F1005A2B8E /* Assets.xcassets */; }; - 7B18E0481C5BF7F1005A2B8E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B18E0461C5BF7F1005A2B8E /* MainMenu.xib */; }; - 7B18E0531C5BF7F1005A2B8E /* StackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E0521C5BF7F1005A2B8E /* StackTests.swift */; }; - 7B18E05E1C5BF80C005A2B8E /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B18E05D1C5BF80C005A2B8E /* Stack.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 7B18E04F1C5BF7F1005A2B8E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B18E0371C5BF7F1005A2B8E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 7B18E03E1C5BF7F1005A2B8E; - remoteInfo = Stack; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 7B18E03F1C5BF7F1005A2B8E /* Stack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stack.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0421C5BF7F1005A2B8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7B18E0441C5BF7F1005A2B8E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7B18E0471C5BF7F1005A2B8E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 7B18E0491C5BF7F1005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E04E1C5BF7F1005A2B8E /* StackTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 7B18E0521C5BF7F1005A2B8E /* StackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackTests.swift; sourceTree = ""; }; - 7B18E0541C5BF7F1005A2B8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7B18E05D1C5BF80C005A2B8E /* Stack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Stack.swift; path = ../../Stack.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7B18E03C1C5BF7F1005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E04B1C5BF7F1005A2B8E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7B18E0361C5BF7F1005A2B8E = { - isa = PBXGroup; - children = ( - 7B18E0411C5BF7F1005A2B8E /* Stack */, - 7B18E0511C5BF7F1005A2B8E /* StackTests */, - 7B18E0401C5BF7F1005A2B8E /* Products */, - ); - sourceTree = ""; - }; - 7B18E0401C5BF7F1005A2B8E /* Products */ = { - isa = PBXGroup; - children = ( - 7B18E03F1C5BF7F1005A2B8E /* Stack.app */, - 7B18E04E1C5BF7F1005A2B8E /* StackTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 7B18E0411C5BF7F1005A2B8E /* Stack */ = { - isa = PBXGroup; - children = ( - 7B18E0421C5BF7F1005A2B8E /* AppDelegate.swift */, - 7B18E0441C5BF7F1005A2B8E /* Assets.xcassets */, - 7B18E0491C5BF7F1005A2B8E /* Info.plist */, - 7B18E0461C5BF7F1005A2B8E /* MainMenu.xib */, - 7B18E05D1C5BF80C005A2B8E /* Stack.swift */, - ); - path = Stack; - sourceTree = ""; - }; - 7B18E0511C5BF7F1005A2B8E /* StackTests */ = { - isa = PBXGroup; - children = ( - 7B18E0521C5BF7F1005A2B8E /* StackTests.swift */, - 7B18E0541C5BF7F1005A2B8E /* Info.plist */, - ); - path = StackTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7B18E03E1C5BF7F1005A2B8E /* Stack */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E0571C5BF7F1005A2B8E /* Build configuration list for PBXNativeTarget "Stack" */; - buildPhases = ( - 7B18E03B1C5BF7F1005A2B8E /* Sources */, - 7B18E03C1C5BF7F1005A2B8E /* Frameworks */, - 7B18E03D1C5BF7F1005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Stack; - productName = Stack; - productReference = 7B18E03F1C5BF7F1005A2B8E /* Stack.app */; - productType = "com.apple.product-type.application"; - }; - 7B18E04D1C5BF7F1005A2B8E /* StackTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7B18E05A1C5BF7F1005A2B8E /* Build configuration list for PBXNativeTarget "StackTests" */; - buildPhases = ( - 7B18E04A1C5BF7F1005A2B8E /* Sources */, - 7B18E04B1C5BF7F1005A2B8E /* Frameworks */, - 7B18E04C1C5BF7F1005A2B8E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 7B18E0501C5BF7F1005A2B8E /* PBXTargetDependency */, - ); - name = StackTests; - productName = StackTests; - productReference = 7B18E04E1C5BF7F1005A2B8E /* StackTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7B18E0371C5BF7F1005A2B8E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = "Swift Algorithm Club"; - TargetAttributes = { - 7B18E03E1C5BF7F1005A2B8E = { - CreatedOnToolsVersion = 7.2; - }; - 7B18E04D1C5BF7F1005A2B8E = { - CreatedOnToolsVersion = 7.2; - TestTargetID = 7B18E03E1C5BF7F1005A2B8E; - }; - }; - }; - buildConfigurationList = 7B18E03A1C5BF7F1005A2B8E /* Build configuration list for PBXProject "Stack" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7B18E0361C5BF7F1005A2B8E; - productRefGroup = 7B18E0401C5BF7F1005A2B8E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7B18E03E1C5BF7F1005A2B8E /* Stack */, - 7B18E04D1C5BF7F1005A2B8E /* StackTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7B18E03D1C5BF7F1005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0451C5BF7F1005A2B8E /* Assets.xcassets in Resources */, - 7B18E0481C5BF7F1005A2B8E /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E04C1C5BF7F1005A2B8E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7B18E03B1C5BF7F1005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E05E1C5BF80C005A2B8E /* Stack.swift in Sources */, - 7B18E0431C5BF7F1005A2B8E /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 7B18E04A1C5BF7F1005A2B8E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B18E0531C5BF7F1005A2B8E /* StackTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 7B18E0501C5BF7F1005A2B8E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 7B18E03E1C5BF7F1005A2B8E /* Stack */; - targetProxy = 7B18E04F1C5BF7F1005A2B8E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7B18E0461C5BF7F1005A2B8E /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 7B18E0471C5BF7F1005A2B8E /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7B18E0551C5BF7F1005A2B8E /* 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; - }; - 7B18E0561C5BF7F1005A2B8E /* 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; - }; - 7B18E0581C5BF7F1005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Stack/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Stack; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 7B18E0591C5BF7F1005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Stack/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Stack; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 7B18E05B1C5BF7F1005A2B8E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = StackTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.StackTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Stack.app/Contents/MacOS/Stack"; - }; - name = Debug; - }; - 7B18E05C1C5BF7F1005A2B8E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = StackTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.StackTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Stack.app/Contents/MacOS/Stack"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7B18E03A1C5BF7F1005A2B8E /* Build configuration list for PBXProject "Stack" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0551C5BF7F1005A2B8E /* Debug */, - 7B18E0561C5BF7F1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E0571C5BF7F1005A2B8E /* Build configuration list for PBXNativeTarget "Stack" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E0581C5BF7F1005A2B8E /* Debug */, - 7B18E0591C5BF7F1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7B18E05A1C5BF7F1005A2B8E /* Build configuration list for PBXNativeTarget "StackTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7B18E05B1C5BF7F1005A2B8E /* Debug */, - 7B18E05C1C5BF7F1005A2B8E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7B18E0371C5BF7F1005A2B8E /* Project object */; -} diff --git a/Stack/Stack Tests/Stack/AppDelegate.swift b/Stack/Stack Tests/Stack/AppDelegate.swift deleted file mode 100644 index 5daa0ee2d..000000000 --- a/Stack/Stack Tests/Stack/AppDelegate.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppDelegate.swift -// Stack -// -// Created by Matthijs Hollemans on 29-01-16. -// Copyright © 2016 Swift Algorithm Club. All rights reserved. -// - -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/Stack/Stack Tests/Stack/Assets.xcassets/AppIcon.appiconset/Contents.json b/Stack/Stack Tests/Stack/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/Stack/Stack Tests/Stack/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/Stack/Stack Tests/Stack/Base.lproj/MainMenu.xib b/Stack/Stack Tests/Stack/Base.lproj/MainMenu.xib deleted file mode 100644 index d2e0528b5..000000000 --- a/Stack/Stack Tests/Stack/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,680 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Stack/Stack Tests/Stack/Info.plist b/Stack/Stack Tests/Stack/Info.plist deleted file mode 100644 index 0dca3caa8..000000000 --- a/Stack/Stack Tests/Stack/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 51567669c..e0632f8b4 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -1,40 +1,60 @@ -/* +/** Stack - A stack is like an array but with limited functionality. You can only push + A stack is like an array but with limited functionality. You can only push to add a new element to the top of the stack, pop to remove the element from the top, and peek at the top element without popping it off. - A stack gives you a LIFO or last-in first-out order. The element you pushed + A stack gives you a LIFO or last-in first-out order. The element you pushed last is the first one to come off with the next pop. Push and pop are O(1) operations. + + ## Usage + ``` + var myStack = Stack(array: []) + myStack.push(10) + myStack.push(3) + myStack.push(57) + myStack.pop() // 57 + myStack.pop() // 3 + ``` */ - public struct Stack { - private var array = [T]() - + + /// Datastructure consisting of a generic item. + fileprivate var array = [T]() + + /// The number of items in the stack. public var count: Int { return array.count } - + + /// Verifies if the stack is empty. public var isEmpty: Bool { return array.isEmpty } - - public mutating func push(element: T) { + + /** + Pushes an item to the top of the stack. + + - Parameter element: The item being pushed. + */ + public mutating func push(_ element: T) { array.append(element) } - + + /** + Removes and returns the item at the top of the stack. + + - Returns: The item at the top of the stack. + */ public mutating func pop() -> T? { - if isEmpty { - return nil - } else { - return array.removeLast() - } + return array.popLast() } - - public func peek() -> T? { + + /// Returns the item at the top of the stack. + public var top: T? { return array.last } } @@ -53,7 +73,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. diff --git a/Stack/Stack.playground/contents.xcplayground b/Stack/Stack.playground/contents.xcplayground index 5da2641c9..a40c0f554 100644 --- a/Stack/Stack.playground/contents.xcplayground +++ b/Stack/Stack.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Stack/Stack.playground/playground.xcworkspace/contents.xcworkspacedata b/Stack/Stack.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Stack/Stack.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Stack/Stack.playground/timeline.xctimeline b/Stack/Stack.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Stack/Stack.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Stack/Stack.swift b/Stack/Stack.swift index 8186a70de..b12f713f5 100644 --- a/Stack/Stack.swift +++ b/Stack/Stack.swift @@ -1,32 +1,36 @@ /* - Last-in first-out stack (LIFO) - - Push and pop are O(1) operations. -*/ + Last-in first-out stack (LIFO) + 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 } - + 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: Sequence { + public func makeIterator() -> AnyIterator { + var curr = self + return AnyIterator { + return curr.pop() + } + } +} diff --git a/Stack/Tests/Info.plist b/Stack/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/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/Stack/Stack Tests/StackTests/StackTests.swift b/Stack/Tests/StackTests.swift similarity index 81% rename from Stack/Stack Tests/StackTests/StackTests.swift rename to Stack/Tests/StackTests.swift index 13aa77479..f4df09a67 100755 --- a/Stack/Stack Tests/StackTests/StackTests.swift +++ b/Stack/Tests/StackTests.swift @@ -1,13 +1,12 @@ import Foundation import XCTest -@testable import Stack class StackTest: XCTestCase { func testEmpty() { var stack = Stack() XCTAssertTrue(stack.isEmpty) XCTAssertEqual(stack.count, 0) - XCTAssertEqual(stack.peek(), nil) + XCTAssertEqual(stack.top, nil) XCTAssertNil(stack.pop()) } @@ -17,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()) } @@ -34,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()) } @@ -61,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()) } } diff --git a/Stack/Tests/Tests.xcodeproj/project.pbxproj b/Stack/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..8924fc935 --- /dev/null +++ b/Stack/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B80C4061C77A70A003CECC7 /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4051C77A70A003CECC7 /* Stack.swift */; }; + 7B80C4081C77A711003CECC7 /* StackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C4071C77A711003CECC7 /* StackTests.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; }; + 7B80C4051C77A70A003CECC7 /* Stack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Stack.swift; path = ../Stack.swift; sourceTree = SOURCE_ROOT; }; + 7B80C4071C77A711003CECC7 /* StackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackTests.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 = ( + 7B80C4051C77A70A003CECC7 /* Stack.swift */, + 7B80C4071C77A711003CECC7 /* StackTests.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 = ( + 7B80C4081C77A711003CECC7 /* StackTests.swift in Sources */, + 7B80C4061C77A70A003CECC7 /* Stack.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/Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Stack/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Stack/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Strassen Matrix Multiplication/README.markdown b/Strassen Matrix Multiplication/README.markdown new file mode 100644 index 000000000..07ce534b2 --- /dev/null +++ b/Strassen Matrix Multiplication/README.markdown @@ -0,0 +1,468 @@ +# 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|, matrix B = |5 6| + |3 4| |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 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. + +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/) + +*Written for Swift Algorithm Club by Richard Ash* \ No newline at end of file diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift new file mode 100644 index 000000000..6b9314557 --- /dev/null +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -0,0 +1,21 @@ +//: Playground - noun: a place where people can play + +import Foundation + +var A = Matrix(rows: 2, columns: 4, initialValue: 0) +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) +let F = B.strassenMatrixMultiply(by: A) +print(C) +print(D) +print(E) +print(F) diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift new file mode 100644 index 000000000..da4b95a78 --- /dev/null +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Sources/Matrix.swift @@ -0,0 +1,290 @@ +// +// Matrix.swift +// +// +// Created by Richard Ash on 10/28/16. +// +// + +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") + return grid[(row * columns) + column] + } set { + assert(indexIsValid(row: row, column: column), "Index out of range") + grid[(row * columns) + column] = newValue + } + } + + public subscript(type: Matrix.Index, 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") + let column = (0.. T in + let currentColumnIndex = currentRow * columns + value + return grid[currentColumnIndex] + } + return column + } + } set { + switch type { + case .row: + assert(newValue.count == columns) + for (column, element) in newValue.enumerated() { + grid[(value * columns) + column] = element + } + case .column: + assert(newValue.count == rows) + for (row, element) in newValue.enumerated() { + grid[(row * columns) + value] = element + } + } + } + } + + // 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) + 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))))) + } +} + +// Term-by-term Matrix Math + +extension Matrix: Addable { + public static func +(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 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.. Self + static func - (lhs: Self, rhs: Self) -> Self +} + +public protocol Multipliable { + static func * (lhs: Self, rhs: Self) -> Self +} + +extension Int: Number { + public static var zero: Int { return 0 } +} + +extension Double: Number { + public static var zero: Double { return 0.0 } +} + +extension Float: Number { + public static var zero: Float { return 0.0 } +} + +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 }) + } +} diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/contents.xcplayground b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/contents.xcplayground new file mode 100644 index 000000000..9f5f2f40c --- /dev/null +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ 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 @@ + + + + + diff --git a/Ternary Search Tree/README.markdown b/Ternary Search Tree/README.markdown new file mode 100644 index 000000000..fee2874cf --- /dev/null +++ b/Ternary Search Tree/README.markdown @@ -0,0 +1,4 @@ +# Ternary Search Tree + +Data structure and simple test in playground has been implemented. +Documentation and examples coming soon!! :) diff --git a/Ternary Search Tree/TST.playground/Contents.swift b/Ternary Search Tree/TST.playground/Contents.swift new file mode 100644 index 000000000..0f576835b --- /dev/null +++ b/Ternary Search Tree/TST.playground/Contents.swift @@ -0,0 +1,59 @@ +//: Playground - noun: a place where people can play + +import Cocoa +import Foundation + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +let treeOfStrings = TernarySearchTree() + +var testStrings: [(key: String, data: String)] = [] +let testCount = 30 +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) + + if data == nil { + print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)") + } + if data != aTest.data { + print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)") + } +} + +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) + if data == nil { + print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)") + } + if data != aTest.data { + print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)") + } +} diff --git a/Ternary Search Tree/TST.playground/Sources/TSTNode.swift b/Ternary Search Tree/TST.playground/Sources/TSTNode.swift new file mode 100644 index 000000000..7fea88d1d --- /dev/null +++ b/Ternary Search Tree/TST.playground/Sources/TSTNode.swift @@ -0,0 +1,32 @@ +// +// TSTNode.swift +// +// +// Created by Siddharth Atre on 3/15/16. +// +// + +import Foundation + +class TSTNode { + //Member properties of a particular node. + var key: Character + var data: Element? + var hasData: Bool + + //Children + var left: TSTNode?, right: TSTNode?, middle: TSTNode? + + init(key: Character, data: Element?) { + self.key = key + self.data = data + self.hasData = (data != nil) + } + + init(key: Character) { + self.key = key + self.data = nil + self.hasData = false + } + +} diff --git a/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift new file mode 100644 index 000000000..9c4c860d8 --- /dev/null +++ b/Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift @@ -0,0 +1,91 @@ +// +// TernarySearchTree.swift +// +// +// Created by Siddharth Atre on 3/15/16. +// +// + +import Foundation + +public class TernarySearchTree { + + var root: TSTNode? + + public init() {} + + // MARK: - Insertion + + public func insert(data: Element, withKey key: String) -> Bool { + return insert(node: &root, withData: data, andKey: key, atIndex: 0) + } + + private func insert(node: inout TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { + + //sanity check. + if key.characters.count == 0 { + return false + } + + //create a new node if necessary. + 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.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] > 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 insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1) + } + //otherwise, all done. + else { + node!.data = data + node?.hasData = true + return true + } + } + } + + // MARK: - Finding + + public func find(key: String) -> Element? { + return find(node: root, withKey: key, atIndex: 0) + } + + private func find(node: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { + + //Given key does not exist in tree. + if node == nil { + return nil + } + + let index = key.index(key.startIndex, offsetBy: charIndex) + //go left + if key[index] < node!.key { + return find(node: node!.left, withKey: key, atIndex: charIndex) + } + //go right + 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 find(node: node!.middle, withKey: key, atIndex: charIndex + 1) + } else { + 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..97f09fdd2 --- /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/TST.playground/playground.xcworkspace/contents.xcworkspacedata b/Ternary Search Tree/TST.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Ternary Search Tree/TST.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Ternary Search Tree/TSTNode.swift b/Ternary Search Tree/TSTNode.swift new file mode 100644 index 000000000..16f1ba2cf --- /dev/null +++ b/Ternary Search Tree/TSTNode.swift @@ -0,0 +1,53 @@ +// +// TSTNode.swift +// +// +// Created by Siddharth Atre on 3/15/16. +// +// + +import Foundation + +/** + This class represents a node in the Ternary Search Tree. + A node has two main data members, the key and the data. + All nodes in a TST must have keys, but only some will have data. + This can be seen in the way the data variable is of Optional type. +*/ +class TSTNode { + //Member properties of a particular node. + + /// The key that identifies this node. + var key: Character + /// The data stored in this node. May be `nil` + var data: Element? + /// Boolean flag to depict whether this node holds data or not. + var hasData: Bool + + /// The children of this node + var left: TSTNode?, right: TSTNode?, middle: TSTNode? + + /** + Initializer for key and/or data + + - parameter key: The key to set for this node. + - parameter data: The optional data to set in this node. + */ + init(key: Character, data: Element?) { + self.key = key + self.data = data + self.hasData = (data != nil) + } + + /** + Make a node that only has a key + + - parameter key: The key to ascribe to this node. + */ + init(key: Character) { + self.key = key + self.data = nil + self.hasData = false + } + +} diff --git a/Ternary Search Tree/TernarySearchTree.swift b/Ternary Search Tree/TernarySearchTree.swift new file mode 100644 index 000000000..761c75b6f --- /dev/null +++ b/Ternary Search Tree/TernarySearchTree.swift @@ -0,0 +1,134 @@ +// +// TernarySearchTree.swift +// +// +// Created by Siddharth Atre on 3/15/16. +// +// + +import Foundation + +/** +The Ternary Search Tree (TST) Data structure. +Data structure uses key-value mappings. Keys are strings used to map to any data element. +See README for more information. +*/ +public class TernarySearchTree { + + /// A reference to the root node of this TST + var root: TSTNode? + + /** + Standard initializer + */ + public init() {} + + // MARK: - Insertion + + /** + Public insertion method. + + - parameter data: The value to store in this TST. + - parameter key: The key to associate with this value. + + - returns: Value indicating insertion success/failure. + */ + @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 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 insert(node: inout TSTNode?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool { + + //sanity check. + guard key.characters.count > 0 else { + return false + } + + //create a new node if necessary. + 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.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] > 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 insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1) + } + //otherwise, all done. + else { + node!.data = data + node?.hasData = true + return true + } + } + } + + // MARK: - Finding + + /** + Public find method. + + - parameter key: Search for an object associated with this key. + + - returns: The element, if found. Otherwise, nil. + */ + public func find(key: String) -> Element? { + return find(node: root, withKey: key, atIndex: 0) + } + + /** + Helper method that performs actual legwork of find operation. Implemented recursively. + + - 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 find(node: TSTNode?, withKey key: String, atIndex charIndex: Int) -> Element? { + + //Given key does not exist in tree. + guard let node = node else { + return nil + } + + let index = key.index(key.startIndex, offsetBy: charIndex) + //go left + if key[index] < node.key { + return find(node: node.left, withKey: key, atIndex: charIndex) + } + //go right + 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 find(node: node.middle, withKey: key, atIndex: charIndex + 1) + } else { + 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..a595e40a3 --- /dev/null +++ b/Ternary Search Tree/Tests/TernarySearchTreeTests.swift @@ -0,0 +1,77 @@ +// +// 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 testCount = 30 + + func testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + func testCanFindStringInTree() { + var testStrings: [(key: String, data: String)] = [] + let treeOfStrings = TernarySearchTree() + + 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)) + 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)) + 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)) + 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..1d48e705a --- /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 = 4.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 = 4.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/project.xcworkspace/contents.xcworkspacedata b/Ternary Search Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Ternary Search Tree/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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..97f09fdd2 --- /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.. For more information about in-order traversals [see here](../Binary%20Tree/). + + +## Predecessors and successors + +An in-order traversal of a tree yields a linear ordering of the nodes. Thus +each node has both a **predecessor** and a **successor** (except for the first +and last nodes, which only have a successor or a predecessor respectively). In +a threaded binary tree, each left child that would normally be `nil` instead +stores the node's predecessor (if it exists), and each right child that would +normally be `nil` instead stores the node's successor (if it exists). This is +what separates threaded binary trees from standard binary trees. + +There are two types of threaded binary trees: **single threaded** and **double +threaded**: +- A single threaded tree keeps track of **either** the in-order predecessor + **or** successor (left **or** right). +- A double threaded tree keeps track of **both** the in-order predecessor + **and** successor (left **and** right). + +Using a single or double threaded tree depends on what we want to accomplish. +If we only need to traverse the tree in one direction (either forward or +backward), then we use a single threaded tree. If we want to traverse in both +directions, then we use a double threaded tree. + +It is important to note that each node stores either its predecessor or its +left child, and either its successor or its right child. The nodes do not +need to keep track of both. For example, in a double threaded tree, if a node +has a right child but no left child, it will track its predecessor in place of +its left child. + +Here is an example valid "full" threaded binary tree: + +![Full](Images/Full.png) + +While the following threaded binary tree is not "full," it is still valid. The +structure of the tree does not matter as long as it follows the definition of a +binary search tree: + +![Partial](Images/Partial.png) + +The solid lines denote the links between parents and children, while the dotted +lines denote the "threads." It is important to note how the children and +thread edges interact with each other. Every node besides the root has one +entering edge (from its parent), and two leaving edges: one to the left and one +to the right. The left leaving edge goes to the node's left child if it +exists, and to its in-order predecessor if it does not. The right leaving edge +goes to the node's right child if it exists, and to its in-order successor if +it does not. The exceptions are the left-most node and the right-most node, +which do not have a predecessor or successor, respectively. + + +## Representation + +Before we go into detail about the methods of a threaded binary tree, we should +first explain how the tree itself is represented. The core of this data +structure is the `ThreadedBinaryTree` class. Each instance of +this class represents a node with six member variables: `value`, `parent`, +`left`, `right`, `leftThread`, and `rightThread`. Of all of these, only +`value` is required. The other five are Swift *optionals* (they may be `nil`). +- `value: T` is the value of this node (e.g. 1, 2, A, B, etc.) +- `parent: ThreadedBinaryTree?` is the parent of this node +- `left: ThreadedBinaryTree?` is the left child of this node +- `right: ThreadedBinaryTree?` is the right child of this node +- `leftThread: ThreadedBinaryTree?` is the in-order predecessor of this node +- `rightThread: ThreadedBinaryTree?` is the in-order successor of this node + +As we are storing both `leftThread` and `rightThread`, this is a double +threaded tree. Now we are ready to go over some of the member functions in our +`ThreadedBinaryTree` class. + + +## Traversal algorithm + +Let's start with the main reason we're using a threaded binary tree. It is now +very easy to find the in-order predecessor and the in-order successor of any +node in the tree. If the node has no `left`/`right` child, we can simply +return the node's `leftThread`/`rightThread`. Otherwise, it is trivial to move +down the tree and find the correct node. + +```swift + func predecessor() -> ThreadedBinaryTree? { + if let left = left { + return left.maximum() + } else { + return leftThread + } + } + + func successor() -> ThreadedBinaryTree? { + if let right = right { + return right.minimum() + } else { + return rightThread + } + } +``` +> Note: `maximum()` and `minimum()` are methods of `ThreadedBinaryTree` which +return the largest/smallest node in a given sub-tree. See +[the implementation](ThreadedBinaryTree.swift) for more detail. + +Because these are `ThreadedBinaryTree` methods, we can call +`node.predecessor()` or `node.successor()` to obtain the predecessor or +successor of any `node`, provided that `node` is a `ThreadedBinaryTree` object. + +Because predecessors and/or successors are tracked, an in-order traversal of a +threaded binary tree is much more efficient than the recursive algorithm +outlined above. We use these predecessor/successor attributes to great effect +in this new algorithm for both forward and backward traversals: + +```swift + 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 + } + } + } +``` +Again, this a method of `ThreadedBinaryTree`, so we'd call it via +`node.traverseInorderForward(visitFunction)`. Note that we are able to specify +a function that executes on each node as they are visited. This function can +be anything you want, as long as it accepts `T` (the type of the values of the +nodes of the tree) and has no return value. + +Let's walk through a forward traversal of a tree by hand to get a better idea +of how a computer would do it. For example, take this simple threaded tree: + +![Base](Images/Base.png) + +We start at the root of the tree, **9**. Note that we don't `visit(9)` yet. +From there we want to go to the `minimum()` node in the tree, which is **2** in +this case. We then `visit(2)` and see that it has a `rightThread`, and thus +we immediately know what its `successor()` is. We follow the thread to **5**, +which does not have any leaving threads. Therefore, after we `visit(5)`, we go +to the `minimum()` node in its `right` subtree, which is **7**. We then +`visit(7)` and see that it has a `rightThread`, which we follow to get back to +**9**. *Now* we `visit(9)`, and after noticing that it has no `rightThread`, +we go to the `minimum()` node in its `right` subtree, which is **12**. This +node has a `rightThread` that leads to `nil`, which signals that we have +completed the traversal! We visited the nodes in order **2, 5, 7, 9, 12**, +which intuitively makes sense, as that is their natural increasing order. + +A backward traversal would be very similar, but you would replace `right`, +`rightThread`, `minimum()`, and `successor()` with `left`, `leftThread`, +`maximum()`, and `predecessor()`. + + +## Insertion and deletion + +The quick in-order traversal that a threaded binary trees gives us comes at a +small cost. Inserting/deleting nodes becomes more complicated, as we have to +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 +[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. + +Let's start with the same tree that we used for the above traversal example: + +![Base](Images/Base.png) + +Suppose we insert **10** into this tree. The resulting graph would look like +this, with the changes highlighted in red: + +![Insert1](Images/Insert1.png) + +If you've done your homework and are familiar with binary search trees, the +placement of this node should not surprise you. What's new is how we maintain +the threads between nodes. So we know that we want to insert **10** as +**12**'s `left` child. The first thing we do is set **12**'s `left` child to +**10**, and set **10**'s `parent` to **12**. Because **10** is being inserted +on the `left`, and **10** has no children of its own, we can safely set +**10**'s `rightThread` to its `parent` **12**. What about **10**'s +`leftThread`? Because we know that **10** < **12**, and **10** is the only +`left` child of **12**, we can safely set **10**'s `leftThread` to **12**'s +(now outdated) `leftThread`. Finally we set **12**'s `leftThread = nil`, as it +now has a `left` child. + +Let's now insert another node, **4**, into the tree: + +![Insert2](Images/Insert2.png) + +While we are inserting **4** as a `right` child, it follows the exact same +process as above, but mirrored (swap `left` and `right`). For the sake of +completeness, we'll insert one final node, **15**: + +![Insert3](Images/Insert3.png) + +Now that we have a fairly crowded tree, let's try removing some nodes. +Compared to insertion, deletion is a little more complicated. Let's start with +something simple, like removing **7**, which has no children: + +![Remove1](Images/Remove1.png) + +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`, +`right`, `leftThread`, and `rightThread` to `nil`, effectively removing it from +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: + +![Remove2](Images/Remove2.png) + +This is a little trickier, as **5** has some children that we have to deal +with. The core idea is to replace **5** with its first child, **2**. To +accomplish this, we of course set **2**'s `parent` to **9** and set **9**'s +`left` child to **2**. Note that **4**'s `rightThread` used to be **5**, but +we are removing **5**, so it needs to change. It is now important to +understand two important properties of threaded binary trees: + +1. For the rightmost node **m** in the `left` subtree of any node **n**, +**m**'s `rightThread` is **n**. +2. For the leftmost node **m** in the `right` subtree of any node **n**, +**m**'s `leftThread` is **n**. + +Note how these properties held true before the removal of **5**, as **4** was +the rightmost node in **5**'s `left` subtree. In order to maintain this +property, we must set **4**'s `rightThread` to **9**, as **4** is now the +rightmost node in **9**'s `left` subtree. To completely remove **5**, all we +now have to do is set **5**'s `parent`, `left`, `right`, `leftThread`, and +`rightThread` to `nil`. + +How about we do something crazy? What would happen if we tried to remove +**9**, the root node? This is the resulting tree: + +![Remove3](Images/Remove3.png) + +Whenever we want to remove a node that has two children, we take a slightly +different approach than the above examples. The basic idea is to replace the +node that we want to remove with the leftmost node in its `right` subtree, +which we call the replacement node. + +> Note: we could also replace the node with the rightmost node in its `left` +> subtree. Choosing left or right is mostly an arbitrary decision. + +Once we find the replacement node, **10** in this case, we remove it from the +tree using the algorithms outlined above. This ensures that the edges in the +`right` subtree remain correct. From there it is easy to replace **9** with +**10**, as we just have to update the edges leaving **10**. Now all we have to +do is fiddle with the threads in order to maintain the two properties outlined +above. In this case, **12**'s `leftThread` is now **10**. Node **9** is no +longer needed, so we can finish the removal process by setting all of its +variables to `nil`. + +In order to illustrate how to remove a node that has only a `right` child, +we'll remove one final node, **12** from the tree: + +![Remove4](Images/Remove4.png) + +The process to remove **12** is identical to the process we used to remove +**5**, but mirrored. **5** had a `left` child, while **12** has a `right` +child, but the core algorithm is the same. + +And that's it! This was just a quick overview of how insertion and deletion +work in threaded binary trees, but if you understood these examples, you should +be able to insert or remove any node from any tree you want. More detail can +of course be found in +[the implementation](ThreadedBinaryTree.swift). + + +## Miscellaneous methods + +There are many other smaller operations that a threaded binary tree can do, +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%20Search%20Tree/). + + +## 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/ThreadedBinaryTree.playground/Contents.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift new file mode 100644 index 000000000..ece1966e0 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift @@ -0,0 +1,80 @@ +//: 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.") + } else { + print("This is an INVALID threaded binary tree.") + } + } else { + print("This tree is nil.") + } +} + +print("\nTree with Single Node") +let emptyTree = ThreadedBinaryTree(value: 1) +check(emptyTree) + +print("\nFull Balanced Binary Tree with 7 Nodes") +let fullTree = ThreadedBinaryTree(value: 4) +fullTree.insert(2) +fullTree.insert(1) +fullTree.insert(6) +fullTree.insert(5) +fullTree.insert(3) +fullTree.insert(7) +check(fullTree) + +print("\n\nBase Binary Tree with 5 Nodes") +let tree = ThreadedBinaryTree(array: [9, 5, 12, 2, 7]) +check(tree) + +print("\nInsert 10") +tree.insert(10) +check(tree) + +print("\nInsert 4") +tree.insert(4) +check(tree) + +print("\nInsert 15") +tree.insert(15) +check(tree) + +print("\nRemove 13 (Not in the Tree)") +tree.remove(13) +check(tree) + +print("\nRemove 7") +tree.remove(7) +check(tree) + +print("\nRemove 5") +tree.remove(5) +check(tree) + +print("\nRemove 9 (root)") +let newRoot = tree.remove(9) +check(newRoot) + +print("\nRemove 12") +newRoot?.remove(12) +check(newRoot) + +print("\n\nDone with Tests!\n") 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..5c7671688 --- /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. + */ + @discardableResult 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 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 let next = node.left { + node = next + } + return node + } + + /* + Returns the rightmost descendent. O(h) time. + */ + public func maximum() -> ThreadedBinaryTree { + var node = self + while 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 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.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Topological Sort/Graph.swift b/Topological Sort/Graph.swift new file mode 100644 index 000000000..5032ba1d1 --- /dev/null +++ b/Topological Sort/Graph.swift @@ -0,0 +1,51 @@ +public class Graph: CustomStringConvertible { + public typealias Node = String + + private(set) public var adjacencyLists: [Node : [Node]] + + public init() { + adjacencyLists = [Node: [Node]]() + } + + public func addNode(_ value: Node) -> Node { + adjacencyLists[value] = [] + return value + } + + public func addEdge(fromNode from: Node, toNode to: Node) -> Bool { + adjacencyLists[from]?.append(to) + return adjacencyLists[from] != nil ? true : false + } + + public var description: String { + return adjacencyLists.description + } + + public func adjacencyList(forNode node: Node) -> [Node]? { + for (key, adjacencyList) in adjacencyLists { + if key == node { + return adjacencyList + } + } + return nil + } +} + +extension Graph { + typealias InDegree = Int + + func calculateInDegreeOfNodes() -> [Node : InDegree] { + var inDegrees = [Node: InDegree]() + + for (node, _) in adjacencyLists { + inDegrees[node] = 0 + } + + for (_, adjacencyList) in adjacencyLists { + for nodeInList in adjacencyList { + inDegrees[nodeInList] = (inDegrees[nodeInList] ?? 0) + 1 + } + } + return inDegrees + } +} diff --git a/Topological Sort/Images/Algorithms.graffle b/Topological Sort/Images/Algorithms.graffle new file mode 100644 index 000000000..a31b0469a Binary files /dev/null and b/Topological Sort/Images/Algorithms.graffle differ diff --git a/Topological Sort/Images/Algorithms.png b/Topological Sort/Images/Algorithms.png new file mode 100644 index 000000000..e693a1023 Binary files /dev/null and b/Topological Sort/Images/Algorithms.png differ diff --git a/Topological Sort/Images/Example.graffle b/Topological Sort/Images/Example.graffle new file mode 100644 index 000000000..41233407c Binary files /dev/null and b/Topological Sort/Images/Example.graffle differ diff --git a/Topological Sort/Images/Example.png b/Topological Sort/Images/Example.png new file mode 100644 index 000000000..d16c6aa50 Binary files /dev/null and b/Topological Sort/Images/Example.png differ diff --git a/Topological Sort/Images/Graph.graffle b/Topological Sort/Images/Graph.graffle new file mode 100644 index 000000000..7f0ef98ed Binary files /dev/null and b/Topological Sort/Images/Graph.graffle differ diff --git a/Topological Sort/Images/Graph.png b/Topological Sort/Images/Graph.png new file mode 100644 index 000000000..3d152592b Binary files /dev/null and b/Topological Sort/Images/Graph.png differ diff --git a/Topological Sort/Images/GraphResult.graffle b/Topological Sort/Images/GraphResult.graffle new file mode 100644 index 000000000..b76974130 Binary files /dev/null and b/Topological Sort/Images/GraphResult.graffle differ diff --git a/Topological Sort/Images/GraphResult.png b/Topological Sort/Images/GraphResult.png new file mode 100644 index 000000000..a70aab50e Binary files /dev/null and b/Topological Sort/Images/GraphResult.png differ diff --git a/Topological Sort/Images/InvalidSort.graffle b/Topological Sort/Images/InvalidSort.graffle new file mode 100644 index 000000000..b6dd91518 Binary files /dev/null and b/Topological Sort/Images/InvalidSort.graffle differ diff --git a/Topological Sort/Images/InvalidSort.png b/Topological Sort/Images/InvalidSort.png new file mode 100644 index 000000000..e9c052762 Binary files /dev/null and b/Topological Sort/Images/InvalidSort.png differ diff --git a/Topological Sort/Images/TopologicalSort.graffle b/Topological Sort/Images/TopologicalSort.graffle new file mode 100644 index 000000000..fb5ff5749 Binary files /dev/null and b/Topological Sort/Images/TopologicalSort.graffle differ diff --git a/Topological Sort/Images/TopologicalSort.png b/Topological Sort/Images/TopologicalSort.png new file mode 100644 index 000000000..7e6516191 Binary files /dev/null and b/Topological Sort/Images/TopologicalSort.png differ diff --git a/Topological Sort/README.markdown b/Topological Sort/README.markdown new file mode 100644 index 000000000..5659dc3fd --- /dev/null +++ b/Topological Sort/README.markdown @@ -0,0 +1,145 @@ +# Topological Sort + +Topological sort is an algorithm that orders a directed graph such that for each directed edge *u→v*, vertex *u* comes before vertex *v*. + +In other words, a topological sort places the vertices of a [directed acyclic graph](../Graph/) on a line so that all directed edges go from left to right. + +Consider the graph in the following example: + +![Example](Images/Graph.png) + +This graph has two possible topological sorts: + +![Example](Images/TopologicalSort.png) + +The topological orderings are **S, V, W, T, X** and **S, W, V, T, X**. Notice how the arrows all go from left to right. + +The following is not a valid topological sort for this graph, since **X** and **T** cannot happen before **V**: + +![Example](Images/InvalidSort.png) + +## Where is this used? + +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%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: + +![Example](Images/Algorithms.png) + +If we consider each algorithm to be a vertex in the graph you can clearly see the dependencies between them. To learn something you might have to know something else first. This is exactly what topological sort is used for -- it will sort things out so that you know what to do first. + +## How does it work? + +**Step 1: Find all vertices that have in-degree of 0** + +The *in-degree* of a vertex is the number of edges pointing at that vertex. Vertices with no incoming edges have an in-degree of 0. These vertices are the starting points for the topological sort. + +In the context of the previous example, these starting vertices represent algorithms and data structures that don't have any prerequisites; you don't need to learn anything else first, hence the sort starts with them. + +**Step 2: Traverse the graph with depth-first search** + +Depth-first search is an algorithm that starts traversing the graph from a certain vertex and explores as far as possible along each branch before backtracking. To find out more about depth-first search, please take a look at the [detailed explanation](../Depth-First%20Search/). + +We perform a depth-first search on each vertex with in-degree 0. This tells us which vertices are connected to each of these starting vertices. + +**Step 3: Remember all visited vertices** + +As we perform the depth-first search, we maintain a list of all the vertices that have been visited. This is to avoid visiting the same vertex twice. + +**Step 4: Put it all together** + +The last step of the sort is to combine the results of the different depth-first searches and put the vertices in a sorted list. + +## Example + +Consider the following graph: + +![Graph Example](Images/Example.png) + +**Step 1:** The vertices with 0 in-degree are: **3, 7, 5**. These are our starting vertices. + +**Step 2:** Perform depth-first search for each starting vertex, without remembering vertices that have already been visited: + +``` +Vertex 3: 3, 10, 8, 9 +Vertex 7: 7, 11, 2, 8, 9 +Vertex 5: 5, 11, 2, 9, 10 +``` + +**Step 3:** Filter out the vertices already visited in each previous search: + +``` +Vertex 3: 3, 10, 8, 9 +Vertex 7: 7, 11, 2 +Vertex 5: 5 +``` + +**Step 4:** Combine the results of these three depth-first searches. The final sorted order is **5, 7, 11, 2, 3, 10, 8, 9**. (Important: we need to add the results of each subsequent search to the *front* of the sorted list.) + +The result of the topological sort looks like this: + +![Result of the sort](Images/GraphResult.png) + +> **Note:** This is not the only possible topological sort for this graph. For example, other valid solutions are **3, 7, 5, 10, 8, 11, 9, 2** and **3, 7, 5, 8, 11, 2, 9, 10**. Any order where all the arrows are going from left to right will do. + +## The code + +Here is how you could implement topological sort in Swift (see also [TopologicalSort1.swift](TopologicalSort1.swift)): + +```swift +extension Graph { + public func topologicalSort() -> [Node] { + // 1 + let startNodes = calculateInDegreeOfNodes().filter({ _, indegree in + return indegree == 0 + }).map({ node, indegree in + return node + }) + + // 2 + var visited = [Node : Bool]() + for (node, _) in adjacencyLists { + visited[node] = false + } + + // 3 + var result = [Node]() + for startNode in startNodes { + result = depthFirstSearch(startNode, visited: &visited) + result + } + + // 4 + return result + } +} +``` + +Some remarks: + +1. Find the in-degree of each vertex and put all the vertices with in-degree 0 in the `startNodes` array. In this graph implementation, vertices are called "nodes". Both terms are used interchangeably by people who write graph code. + +2. The `visited` array keeps track of whether we've already seen a vertex during the depth-first search. Initially, we set all elements to `false`. + +3. For each of the vertices in the `startNodes` array, perform a depth-first search. This returns an array of sorted `Node` objects. We prepend that array to our own `result` array. + +4. The `result` array contains all the vertices in topologically sorted order. + +> **Note:** For a slightly different implementation of topological sort using depth-first search, see [TopologicalSort3.swift](TopologicalSort3.swift). This uses a stack and does not require you to find all vertices with in-degree 0 first. + +## Kahn's algorithm + +Even though depth-first search is the typical way to perform a topological sort, there is another algorithm that also does the job. + +1. Find out what the in-degree is of every vertex. +2. Put all the vertices that have no predecessors in a new array called `leaders`. These vertices have in-degree 0 and therefore do not depend on any other vertices. +3. Go through this list of leaders and remove them one-by-one from the graph. We don't actually modify the graph, we just decrement the in-degree of the vertices they point to. That has the same effect. +4. Look at the (former) immediate neighbor vertices of each leader. If any of them now have an in-degree of 0, then they no longer have any predecessors themselves. We'll add those vertices to the `leaders` array too. +5. This repeats until there are no more vertices left to look at. At this point, the `leaders` array contains all the vertices in sorted order. + +This is an **O(n + m)** algorithm where **n** is the number of vertices and **m** is the number of edges. You can see the implementation in [TopologicalSort2.swift](TopologicalSort2.swift). + +Source: I first read about this alternative algorithm in the Algorithm Alley column in Dr. Dobb's Magazine from May 1993. + +*Written for Swift Algorithm Club by Ali Hafizji and Matthijs Hollemans* diff --git a/Topological Sort/Tests/Info.plist b/Topological Sort/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Topological Sort/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/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj b/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..f97ffdc69 --- /dev/null +++ b/Topological Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,281 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7B3471BB1C8F50CF008381CD /* TopologicalSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3471BA1C8F50CF008381CD /* TopologicalSortTests.swift */; }; + 7B3471BF1C8F50DD008381CD /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3471BC1C8F50DD008381CD /* Graph.swift */; }; + 7B3471C11C8F50DD008381CD /* TopologicalSort1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3471BE1C8F50DD008381CD /* TopologicalSort1.swift */; }; + 7B3471C31C8F5348008381CD /* TopologicalSort2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3471C21C8F5348008381CD /* TopologicalSort2.swift */; }; + 7BE143491C9C6A93001BC747 /* TopologicalSort3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE143481C9C6A93001BC747 /* TopologicalSort3.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; }; + 7B3471BA1C8F50CF008381CD /* TopologicalSortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopologicalSortTests.swift; sourceTree = SOURCE_ROOT; }; + 7B3471BC1C8F50DD008381CD /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graph.swift; path = ../Graph.swift; sourceTree = SOURCE_ROOT; }; + 7B3471BE1C8F50DD008381CD /* TopologicalSort1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TopologicalSort1.swift; path = ../TopologicalSort1.swift; sourceTree = SOURCE_ROOT; }; + 7B3471C21C8F5348008381CD /* TopologicalSort2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TopologicalSort2.swift; path = ../TopologicalSort2.swift; sourceTree = SOURCE_ROOT; }; + 7BE143481C9C6A93001BC747 /* TopologicalSort3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TopologicalSort3.swift; path = ../TopologicalSort3.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 = ( + 7B3471BC1C8F50DD008381CD /* Graph.swift */, + 7B3471BE1C8F50DD008381CD /* TopologicalSort1.swift */, + 7B3471C21C8F5348008381CD /* TopologicalSort2.swift */, + 7BE143481C9C6A93001BC747 /* TopologicalSort3.swift */, + 7B3471BA1C8F50CF008381CD /* TopologicalSortTests.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 = ( + 7B3471C31C8F5348008381CD /* TopologicalSort2.swift in Sources */, + 7B3471BF1C8F50DD008381CD /* Graph.swift in Sources */, + 7B3471BB1C8F50CF008381CD /* TopologicalSortTests.swift in Sources */, + 7B3471C11C8F50DD008381CD /* TopologicalSort1.swift in Sources */, + 7BE143491C9C6A93001BC747 /* TopologicalSort3.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/Topological Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Topological Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/Topological Sort/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..14f27f777 --- /dev/null +++ b/Topological Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Topological Sort/Tests/TopologicalSortTests.swift b/Topological Sort/Tests/TopologicalSortTests.swift new file mode 100644 index 000000000..939f15fae --- /dev/null +++ b/Topological Sort/Tests/TopologicalSortTests.swift @@ -0,0 +1,82 @@ +import Foundation +import XCTest + +extension Graph { + public func loadEdgeList(_ lines: [String]) { + for line in lines { + let items = line.components(separatedBy: " ").filter { s in !s.isEmpty } + if adjacencyList(forNode: items[0]) == nil { + addNode(items[0]) + } + if adjacencyList(forNode: items[1]) == nil { + addNode(items[1]) + } + addEdge(fromNode: items[0], toNode: items[1]) + } + } +} + +class TopologicalSort: XCTestCase { + + // The topological sort is valid if a node does not have any of its + // predecessors in its adjacency list. + func checkIsValidTopologicalSort(_ graph: Graph, _ a: [Graph.Node]) { + for i in stride(from: (a.count - 1), to: 0, by: -1) { + if let neighbors = graph.adjacencyList(forNode: a[i]) { + for j in stride(from: (i - 1), through: 0, by: -1) { + XCTAssertFalse(neighbors.contains(a[j]), "\(a) is not a valid topological sort") + } + } + } + } + + func testTopologicalSort() { + let graph = Graph() + + let node5 = graph.addNode("5") + let node7 = graph.addNode("7") + let node3 = graph.addNode("3") + let node11 = graph.addNode("11") + let node8 = graph.addNode("8") + let node2 = graph.addNode("2") + let node9 = graph.addNode("9") + let node10 = graph.addNode("10") + + graph.addEdge(fromNode: node5, toNode: node11) + graph.addEdge(fromNode: node7, toNode: node11) + graph.addEdge(fromNode: node7, toNode: node8) + graph.addEdge(fromNode: node3, toNode: node8) + graph.addEdge(fromNode: node3, toNode: node10) + graph.addEdge(fromNode: node11, toNode: node2) + graph.addEdge(fromNode: node11, toNode: node9) + graph.addEdge(fromNode: node11, toNode: node10) + graph.addEdge(fromNode: node8, toNode: node9) + + XCTAssertEqual(graph.topologicalSort(), ["5", "7", "11", "2", "3", "10", "8", "9"]) + XCTAssertEqual(graph.topologicalSortKahn(), ["3", "7", "5", "8", "11", "2", "9", "10"]) + XCTAssertEqual(graph.topologicalSortAlternative(), ["5", "7", "3", "8", "11", "10", "9", "2"]) + } + + func testTopologicalSortEdgeLists() { + let p1 = ["A B", "A C", "B C", "B D", "C E", "C F", "E D", "F E", "G A", "G F"] + let p2 = ["B C", "C D", "C G", "B F", "D G", "G E", "F G", "F G"] + let p3 = ["S V", "S W", "V T", "W T"] + let p4 = ["5 11", "7 11", "7 8", "3 8", "3 10", "11 2", "11 9", "11 10", "8 9"] + + let data = [ p1, p2, p3, p4 ] + + for d in data { + let graph = Graph() + graph.loadEdgeList(d) + + let sorted1 = graph.topologicalSort() + checkIsValidTopologicalSort(graph, sorted1) + + let sorted2 = graph.topologicalSortKahn() + checkIsValidTopologicalSort(graph, sorted2) + + let sorted3 = graph.topologicalSortAlternative() + checkIsValidTopologicalSort(graph, sorted3) + } + } +} diff --git a/Topological Sort/Topological Sort.playground/Contents.swift b/Topological Sort/Topological Sort.playground/Contents.swift new file mode 100644 index 000000000..3921d37fc --- /dev/null +++ b/Topological Sort/Topological Sort.playground/Contents.swift @@ -0,0 +1,38 @@ +//: Playground - noun: a place where people can play + +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +import UIKit + +let graph = Graph() + +let node5 = graph.addNode("5") +let node7 = graph.addNode("7") +let node3 = graph.addNode("3") +let node11 = graph.addNode("11") +let node8 = graph.addNode("8") +let node2 = graph.addNode("2") +let node9 = graph.addNode("9") +let node10 = graph.addNode("10") + +graph.addEdge(fromNode: node5, toNode: node11) +graph.addEdge(fromNode: node7, toNode: node11) +graph.addEdge(fromNode: node7, toNode: node8) +graph.addEdge(fromNode: node3, toNode: node8) +graph.addEdge(fromNode: node3, toNode: node10) +graph.addEdge(fromNode: node11, toNode: node2) +graph.addEdge(fromNode: node11, toNode: node9) +graph.addEdge(fromNode: node11, toNode: node10) +graph.addEdge(fromNode: node8, toNode: node9) + +// using depth-first search +graph.topologicalSort() + +// also using depth-first search +graph.topologicalSortAlternative() + +// Kahn's algorithm +graph.topologicalSortKahn() diff --git a/Topological Sort/Topological Sort.playground/Sources/Graph.swift b/Topological Sort/Topological Sort.playground/Sources/Graph.swift new file mode 100644 index 000000000..5032ba1d1 --- /dev/null +++ b/Topological Sort/Topological Sort.playground/Sources/Graph.swift @@ -0,0 +1,51 @@ +public class Graph: CustomStringConvertible { + public typealias Node = String + + private(set) public var adjacencyLists: [Node : [Node]] + + public init() { + adjacencyLists = [Node: [Node]]() + } + + public func addNode(_ value: Node) -> Node { + adjacencyLists[value] = [] + return value + } + + public func addEdge(fromNode from: Node, toNode to: Node) -> Bool { + adjacencyLists[from]?.append(to) + return adjacencyLists[from] != nil ? true : false + } + + public var description: String { + return adjacencyLists.description + } + + public func adjacencyList(forNode node: Node) -> [Node]? { + for (key, adjacencyList) in adjacencyLists { + if key == node { + return adjacencyList + } + } + return nil + } +} + +extension Graph { + typealias InDegree = Int + + func calculateInDegreeOfNodes() -> [Node : InDegree] { + var inDegrees = [Node: InDegree]() + + for (node, _) in adjacencyLists { + inDegrees[node] = 0 + } + + for (_, adjacencyList) in adjacencyLists { + for nodeInList in adjacencyList { + inDegrees[nodeInList] = (inDegrees[nodeInList] ?? 0) + 1 + } + } + return inDegrees + } +} diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift new file mode 100644 index 000000000..2ad9b51a0 --- /dev/null +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort1.swift @@ -0,0 +1,38 @@ +extension Graph { + 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], !seen { + result = depthFirstSearch(nodeInAdjacencyList, visited: &visited) + result + } + } + } + + visited[source] = true + return [source] + result + } + + /* Topological sort using depth-first search. */ + public func topologicalSort() -> [Node] { + + let startNodes = calculateInDegreeOfNodes().filter({ _, indegree in + return indegree == 0 + }).map({ node, _ in + return node + }) + + var visited = [Node: Bool]() + for (node, _) in adjacencyLists { + visited[node] = false + } + + var result = [Node]() + for startNode in startNodes { + result = depthFirstSearch(startNode, visited: &visited) + result + } + + return result + } +} diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift new file mode 100644 index 000000000..589801d33 --- /dev/null +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort2.swift @@ -0,0 +1,41 @@ +extension Graph { + /* Topological sort using Kahn's algorithm. */ + public func topologicalSortKahn() -> [Node] { + var nodes = calculateInDegreeOfNodes() + + // Find vertices with no predecessors and puts them into a new list. + // These are the "leaders". The leaders array eventually becomes the + // topologically sorted list. + var leaders = nodes.filter({ _, indegree in + return indegree == 0 + }).map({ node, _ in + return node + }) + + // "Remove" each of the leaders. We do this by decrementing the in-degree + // of the nodes they point to. As soon as such a node has itself no more + // predecessors, it is added to the leaders array. This repeats until there + // are no more vertices left. + var l = 0 + while l < leaders.count { + if let edges = adjacencyList(forNode: leaders[l]) { + for neighbor in edges { + if let count = nodes[neighbor] { + nodes[neighbor] = count - 1 + if count == 1 { // this leader was the last predecessor + leaders.append(neighbor) // so neighbor is now a leader itself + } + } + } + } + l += 1 + } + + // Was there a cycle in the graph? + if leaders.count != nodes.count { + print("Error: graphs with cycles are not allowed") + } + + return leaders + } +} diff --git a/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift new file mode 100644 index 000000000..3d4a2bbbc --- /dev/null +++ b/Topological Sort/Topological Sort.playground/Sources/TopologicalSort3.swift @@ -0,0 +1,35 @@ +/* + An alternative implementation of topological sort using depth-first search. + This does not start at vertices with in-degree 0 but simply at the first one + it finds. It uses a stack to build up the sorted list, but in reverse order. +*/ +extension Graph { + public func topologicalSortAlternative() -> [Node] { + var stack = [Node]() + + var visited = [Node: Bool]() + for (node, _) in adjacencyLists { + visited[node] = false + } + + func depthFirstSearch(_ source: Node) { + if let adjacencyList = adjacencyList(forNode: source) { + for neighbor in adjacencyList { + if let seen = visited[neighbor], !seen { + depthFirstSearch(neighbor) + } + } + } + stack.append(source) + visited[source] = true + } + + for (node, _) in visited { + if let seen = visited[node], !seen { + depthFirstSearch(node) + } + } + + return stack.reversed() + } +} diff --git a/Topological Sort/Topological Sort.playground/contents.xcplayground b/Topological Sort/Topological Sort.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Topological Sort/Topological Sort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Topological Sort/Topological Sort.playground/playground.xcworkspace/contents.xcworkspacedata b/Topological Sort/Topological Sort.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Topological Sort/Topological Sort.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift new file mode 100644 index 000000000..05f1ab887 --- /dev/null +++ b/Topological Sort/TopologicalSort1.swift @@ -0,0 +1,38 @@ +extension Graph { + private func depthFirstSearch(_ source: Node, visited: inout [Node : Bool]) -> [Node] { + var result = [Node]() + visited[source] = true + + if let adjacencyList = adjacencyList(forNode: source) { + for nodeInAdjacencyList in adjacencyList { + if let seen = visited[nodeInAdjacencyList], !seen { + result = depthFirstSearch(nodeInAdjacencyList, visited: &visited) + result + } + } + } + + return [source] + result + } + + /* Topological sort using depth-first search. */ + public func topologicalSort() -> [Node] { + + let startNodes = calculateInDegreeOfNodes().filter({ _, indegree in + return indegree == 0 + }).map({ node, _ in + return node + }) + + var visited = [Node: Bool]() + for (node, _) in adjacencyLists { + visited[node] = false + } + + var result = [Node]() + for startNode in startNodes { + result = depthFirstSearch(startNode, visited: &visited) + result + } + + return result + } +} diff --git a/Topological Sort/TopologicalSort2.swift b/Topological Sort/TopologicalSort2.swift new file mode 100644 index 000000000..589801d33 --- /dev/null +++ b/Topological Sort/TopologicalSort2.swift @@ -0,0 +1,41 @@ +extension Graph { + /* Topological sort using Kahn's algorithm. */ + public func topologicalSortKahn() -> [Node] { + var nodes = calculateInDegreeOfNodes() + + // Find vertices with no predecessors and puts them into a new list. + // These are the "leaders". The leaders array eventually becomes the + // topologically sorted list. + var leaders = nodes.filter({ _, indegree in + return indegree == 0 + }).map({ node, _ in + return node + }) + + // "Remove" each of the leaders. We do this by decrementing the in-degree + // of the nodes they point to. As soon as such a node has itself no more + // predecessors, it is added to the leaders array. This repeats until there + // are no more vertices left. + var l = 0 + while l < leaders.count { + if let edges = adjacencyList(forNode: leaders[l]) { + for neighbor in edges { + if let count = nodes[neighbor] { + nodes[neighbor] = count - 1 + if count == 1 { // this leader was the last predecessor + leaders.append(neighbor) // so neighbor is now a leader itself + } + } + } + } + l += 1 + } + + // Was there a cycle in the graph? + if leaders.count != nodes.count { + print("Error: graphs with cycles are not allowed") + } + + return leaders + } +} diff --git a/Topological Sort/TopologicalSort3.swift b/Topological Sort/TopologicalSort3.swift new file mode 100644 index 000000000..3d4a2bbbc --- /dev/null +++ b/Topological Sort/TopologicalSort3.swift @@ -0,0 +1,35 @@ +/* + An alternative implementation of topological sort using depth-first search. + This does not start at vertices with in-degree 0 but simply at the first one + it finds. It uses a stack to build up the sorted list, but in reverse order. +*/ +extension Graph { + public func topologicalSortAlternative() -> [Node] { + var stack = [Node]() + + var visited = [Node: Bool]() + for (node, _) in adjacencyLists { + visited[node] = false + } + + func depthFirstSearch(_ source: Node) { + if let adjacencyList = adjacencyList(forNode: source) { + for neighbor in adjacencyList { + if let seen = visited[neighbor], !seen { + depthFirstSearch(neighbor) + } + } + } + stack.append(source) + visited[source] = true + } + + for (node, _) in visited { + if let seen = visited[node], !seen { + depthFirstSearch(node) + } + } + + return stack.reversed() + } +} diff --git a/Treap/Treap.swift b/Treap/Treap.swift new file mode 100644 index 000000000..d6cee2e70 --- /dev/null +++ b/Treap/Treap.swift @@ -0,0 +1,164 @@ +// +// Treap.swift +// TreapExample +// +// Created by Robert Thompson on 7/27/15. +// 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 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 + } + } + + 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 { + 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 { + 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 + } +} + +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 + } +} + +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 + } + } + + 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 + } + + 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 new file mode 100644 index 000000000..d8393e1c5 --- /dev/null +++ b/Treap/Treap/Treap.xcodeproj/project.pbxproj @@ -0,0 +1,286 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + E1E34DCD1C7670240023AF4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 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 = ""; }; + E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TreapMergeSplit.swift; path = ../../TreapMergeSplit.swift; sourceTree = ""; }; + E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TreapCollectionType.swift; path = ../../TreapCollectionType.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E1E34DCF1C7670250023AF4D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E1E34DBA1C7670240023AF4D = { + isa = PBXGroup; + children = ( + E1E34DC51C7670240023AF4D /* Treap */, + E1E34DD51C7670250023AF4D /* TreapTests */, + E1E34DC41C7670240023AF4D /* Products */, + ); + sourceTree = ""; + }; + E1E34DC41C7670240023AF4D /* Products */ = { + isa = PBXGroup; + children = ( + E1E34DD21C7670250023AF4D /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + E1E34DC51C7670240023AF4D /* Treap */ = { + isa = PBXGroup; + children = ( + E1E34DE11C7670350023AF4D /* Treap.swift */, + E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */, + E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */, + E1E34DCD1C7670240023AF4D /* Info.plist */, + ); + path = Treap; + sourceTree = ""; + }; + E1E34DD51C7670250023AF4D /* TreapTests */ = { + isa = PBXGroup; + children = ( + E1E34DD61C7670250023AF4D /* TreapTests.swift */, + E1E34DD81C7670250023AF4D /* Info.plist */, + ); + path = TreapTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E1E34DD11C7670250023AF4D /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + E1E34DCE1C7670250023AF4D /* Sources */, + E1E34DCF1C7670250023AF4D /* Frameworks */, + E1E34DD01C7670250023AF4D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = TreapTests; + productReference = E1E34DD21C7670250023AF4D /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E1E34DBB1C7670240023AF4D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0800; + ORGANIZATIONNAME = "WillowTree, Inc."; + TargetAttributes = { + E1E34DD11C7670250023AF4D = { + CreatedOnToolsVersion = 7.2.1; + LastSwiftMigration = 0800; + }; + }; + }; + buildConfigurationList = E1E34DBE1C7670240023AF4D /* Build configuration list for PBXProject "Treap" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E1E34DBA1C7670240023AF4D; + productRefGroup = E1E34DC41C7670240023AF4D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E1E34DD11C7670250023AF4D /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E1E34DD01C7670250023AF4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 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 XCBuildConfiguration section */ + E1E34DD91C7670250023AF4D /* 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; + }; + E1E34DDA1C7670250023AF4D /* 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; + }; + E1E34DDF1C7670250023AF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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)"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + E1E34DE01C7670250023AF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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)"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E1E34DBE1C7670240023AF4D /* Build configuration list for PBXProject "Treap" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E1E34DD91C7670250023AF4D /* Debug */, + E1E34DDA1C7670250023AF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E1E34DDF1C7670250023AF4D /* Debug */, + E1E34DE01C7670250023AF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E1E34DBB1C7670240023AF4D /* Project object */; +} diff --git a/Treap/Treap/Treap.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Treap/Treap/Treap.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Treap/Treap/Treap.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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 new file mode 100644 index 000000000..fa2508008 --- /dev/null +++ b/Treap/Treap/Treap.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Info.plist b/Treap/Treap/Treap/Info.plist similarity index 92% rename from Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Info.plist rename to Treap/Treap/Treap/Info.plist index 0dca3caa8..63294f2da 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Info.plist +++ b/Treap/Treap/Treap/Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. + Copyright © 2016 WillowTree, Inc. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass diff --git a/Treap/Treap/TreapTests/Info.plist b/Treap/Treap/TreapTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Treap/Treap/TreapTests/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/Treap/Treap/TreapTests/TreapTests.swift b/Treap/Treap/TreapTests/TreapTests.swift new file mode 100644 index 000000000..a5d156ec9 --- /dev/null +++ b/Treap/Treap/TreapTests/TreapTests.swift @@ -0,0 +1,80 @@ +// +// TreapTests.swift +// TreapTests +// +// 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.*/ + +// swiftlint:disable force_try + +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 testSwift4() { + // last checked with Xcode 9.0b4 + #if swift(>=4.0) + print("Hello, Swift 4!") + #endif + } + + 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) + } + 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) + } + +} diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift new file mode 100644 index 000000000..eeee065fe --- /dev/null +++ b/Treap/TreapCollectionType.swift @@ -0,0 +1,111 @@ +// +// TreapCollectionType.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 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 { + results.append(contentsOf: left.keys) + 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 + } +} + +public func ==(lhs: TreapIndex, rhs: TreapIndex) -> Bool { + return lhs.keys == rhs.keys && lhs.keyIndex == rhs.keyIndex +} diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift new file mode 100644 index 000000000..62d18d16f --- /dev/null +++ b/Treap/TreapMergeSplit.swift @@ -0,0 +1,114 @@ +// +// TreapMergeSplit.swift +// TreapExample +// +// Created by Robert Thompson on 7/27/15. +// 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 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: 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: key, val: val, p: -1) { + return (left: left, right: right) + } else { + return (left: .empty, right: .empty) + } + default: + return (left: .empty, right: .empty) + } + } + + 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 + } + return .empty +} + +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/Tree/Images/Tree.png b/Tree/Images/Tree.png index 751dac2e3..59ef800cb 100644 Binary files a/Tree/Images/Tree.png and b/Tree/Images/Tree.png differ diff --git a/Tree/README.markdown b/Tree/README.markdown index 98d1bec12..40129cab5 100644 --- a/Tree/README.markdown +++ b/Tree/README.markdown @@ -1,22 +1,25 @@ -# Tree +# Trees + +> This topic has been tutorialized [here](https://www.raywenderlich.com/138190/swift-algorithm-club-swift-tree-data-structure) + A tree represents hierarchical relationships between objects. This is a tree: ![A tree](Images/Tree.png) -A tree consists of nodes. +A tree consists of nodes, and these nodes are linked to one another. Nodes have links to their children and usually to their parent as well. The children are the nodes below a given node; the parent is the node above. A node always has just one parent but can have multiple children. ![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: ![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. @@ -25,15 +28,15 @@ Here's a basic implementation in Swift: ```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) { self.value = value } - - func addChild(node: TreeNode) { + + public func addChild(_ node: TreeNode) { children.append(node) node.parent = self } @@ -49,7 +52,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 } @@ -119,7 +122,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. @@ -129,7 +132,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 } @@ -153,7 +156,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 @@ -165,4 +168,6 @@ Then we can describe the tree with the following array: Each entry in the array is a pointer to its parent node. The item at index 3, `tea`, has the value 1 because its parent is `hot`. The root node points to `-1` because it has no parent. You can only traverse such trees from a node back to the root but not the other way around. +By the way, sometimes you see algorithms using the term *forest*. Unsurprisingly, that is the name given to a collection of separate tree objects. For an example of this, see [union-find](../Union-Find/). + *Written for Swift Algorithm Club by Matthijs Hollemans* diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index c4e8959f5..1fad157a0 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -1,31 +1,5 @@ //: Playground - noun: a place where people can play -public class TreeNode { - public var value: T - - public var parent: TreeNode? - public var children = [TreeNode]() - - public init(value: T) { - self.value = value - } - - func addChild(node: TreeNode) { - children.append(node) - node.parent = self - } -} - -extension TreeNode: CustomStringConvertible { - public var description: String { - var s = "\(value)" - if !children.isEmpty { - s += " {" + children.map { $0.description }.joinWithSeparator(", ") + "}" - } - return s - } -} - let tree = TreeNode(value: "beverages") let hotNode = TreeNode(value: "hot") @@ -68,7 +42,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.playground/Sources/Tree.swift b/Tree/Tree.playground/Sources/Tree.swift new file mode 100644 index 000000000..fa49f25e9 --- /dev/null +++ b/Tree/Tree.playground/Sources/Tree.swift @@ -0,0 +1,39 @@ +public class TreeNode { + public var value: T + + public weak var parent: TreeNode? + public var children = [TreeNode]() + + public init(value: T) { + self.value = value + } + + public func addChild(_ node: TreeNode) { + children.append(node) + node.parent = self + } +} + +extension TreeNode: CustomStringConvertible { + public var description: String { + var s = "\(value)" + if !children.isEmpty { + s += " {" + children.map { $0.description }.joined(separator: ", ") + "}" + } + return s + } +} + +extension TreeNode where T: Equatable { + public func search(_ value: T) -> TreeNode? { + if value == self.value { + return self + } + for child in children { + if let found = child.search(value) { + return found + } + } + return nil + } +} diff --git a/Tree/Tree.playground/contents.xcplayground b/Tree/Tree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Tree/Tree.playground/contents.xcplayground +++ b/Tree/Tree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Tree/Tree.playground/playground.xcworkspace/contents.xcworkspacedata b/Tree/Tree.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Tree/Tree.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Tree/Tree.playground/timeline.xctimeline b/Tree/Tree.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Tree/Tree.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Tree/Tree.swift b/Tree/Tree.swift index e77045339..08cb61eb5 100644 --- a/Tree/Tree.swift +++ b/Tree/Tree.swift @@ -1,39 +1,40 @@ public class TreeNode { - public var value: T - - public var parent: TreeNode? - public var children = [TreeNode]() + public var value: T - public init(value: T) { - self.value = value - } - - func addChild(node: TreeNode) { - children.append(node) - node.parent = self - } + public weak var parent: TreeNode? + public var children = [TreeNode]() + + public init(value: T) { + self.value = value + } + + public func addChild(_ node: TreeNode) { + children.append(node) + node.parent = self + } } extension TreeNode: CustomStringConvertible { - public var description: String { - var s = "\(value)" - if !children.isEmpty { - s += " {" + children.map { $0.description }.joinWithSeparator(", ") + "}" + public var description: String { + var s = "\(value)" + if !children.isEmpty { + s += " {" + children.map { $0.description }.joined(separator: ", ") + "}" + } + return s } - return s - } } extension TreeNode where T: Equatable { - func search(value: T) -> TreeNode? { - if value == self.value { - return self - } - for child in children { - if let found = child.search(value) { - return found - } + public func search(_ value: T) -> TreeNode? { + if value == self.value { + return self + } + for child in children { + if let found = child.search(value) { + return found + } + } + return nil } - return nil - } } + diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md new file mode 100644 index 000000000..8d0c45c8a --- /dev/null +++ b/Trie/ReadMe.md @@ -0,0 +1,158 @@ +# Trie + +> This topic has been tutorialized [here](https://www.raywenderlich.com/139410/swift-algorithm-club-swift-trie-data-structure) + +## What is a Trie? + +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) + +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? + +Tries are very useful for certain situations. Here are some of the advantages: + +* 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. + +## Common Algorithms + +### Contains (or any general lookup method) + +`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: + +```swift +func contains(word: String) -> Bool { + guard !word.isEmpty else { return false } + + // 1 + var currentNode = root + + // 2 + var characters = Array(word.lowercased()) + var currentIndex = 0 + + // 3 + while currentIndex < characters.count, + let child = currentNode.children[characters[currentIndex]] { + + currentNode = child + currentIndex += 1 + } + + // 4 + if currentIndex == characters.count && currentNode.isTerminating { + return true + } else { + return false + } +} +``` + +The `contains` method is fairly straightforward: + +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`. + +### Insertion + +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. + +```swift +func insert(word: String) { + guard !word.isEmpty else { + return + } + + // 1 + var currentNode = root + + // 2 + for character in word.lowercased() { + // 3 + 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 + } + + // 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. 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 + +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". + +If you'd like to remove "Apple", you'll need to take care to leave the "App" chain in tact. + +```swift +func remove(word: String) { + guard !word.isEmpty else { + return + } + + // 1 + guard let terminalNode = findTerminalNodeOf(word: word) else { + return + } + + // 2 + if terminalNode.isLeaf { + deleteNodesForWordEndingWith(terminalNode: terminalNode) + } else { + terminalNode.isTerminating = false + } + wordCount -= 1 +} +``` + +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 + +Let n be the length of some value in the `Trie`. + +* `contains` - Worst case O(n) +* `insert` - O(n) +* `remove` - O(n) + +### Other Notable Operations + +* `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. 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..6b7cc9b61 --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -0,0 +1,559 @@ +// !$*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 = ""; }; + EB8369AC1E15C5710003A7F8 /* ReadMe.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; 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 */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + EB798DFB1DFEF79900F0628D /* Products */ = { + isa = PBXGroup; + children = ( + EB798DFA1DFEF79900F0628D /* Trie.app */, + EB798E0B1DFEF79900F0628D /* TrieTests.xctest */, + EB798E161DFEF79900F0628D /* TrieUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + EB798DFC1DFEF79900F0628D /* Trie */ = { + isa = PBXGroup; + children = ( + EB8369AC1E15C5710003A7F8 /* ReadMe.md */, + 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 = 1000; + ORGANIZATIONNAME = "Rick Zaccone"; + TargetAttributes = { + EB798DF91DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; + ProvisioningStyle = Automatic; + }; + EB798E0A1DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; + ProvisioningStyle = Automatic; + TestTargetID = EB798DF91DFEF79900F0628D; + }; + EB798E151DFEF79900F0628D = { + CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; + ProvisioningStyle = Automatic; + TestTargetID = EB798DF91DFEF79900F0628D; + }; + }; + }; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + 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_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + 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 = 4.2; + }; + 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 = 4.2; + }; + 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 = 4.2; + 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 = 4.2; + 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 = 4.2; + 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 = 4.2; + 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; + defaultConfigurationName = Release; + }; + EB798E221DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E231DFEF79900F0628D /* Debug */, + EB798E241DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB798E251DFEF79900F0628D /* Build configuration list for PBXNativeTarget "TrieUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB798E261DFEF79900F0628D /* Debug */, + EB798E271DFEF79900F0628D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* 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.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Trie/Trie/Trie.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..d8e350129 --- /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.407 + 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/AppDelegate.swift b/Trie/Trie/Trie/AppDelegate.swift new file mode 100644 index 000000000..48dc24673 --- /dev/null +++ b/Trie/Trie/Trie/AppDelegate.swift @@ -0,0 +1,22 @@ +// +// 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/Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Assets.xcassets/AppIcon.appiconset/Contents.json b/Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Binary Search Tree/Solution 1/BinarySearchTree Tests/BinarySearchTree/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Trie/Trie/Trie/Assets.xcassets/AppIcon.appiconset/Contents.json 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/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/Info.plist b/Trie/Trie/Trie/Info.plist similarity index 87% rename from Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/Info.plist rename to Trie/Trie/Trie/Info.plist index ec6d36e96..ed3668788 100644 --- a/Select Minimum Maximum/SelectMinimumMaximum Tests/SelectMinimumMaximum/Info.plist +++ b/Trie/Trie/Trie/Info.plist @@ -18,14 +18,14 @@ APPL CFBundleShortVersionString 1.0 - CFBundleSignature - ???? CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2016 Swift Algorithm Club. All rights reserved. + Copyright © 2016 Rick Zaccone. All rights reserved. + NSMainStoryboardFile + Main NSPrincipalClass NSApplication 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. diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift new file mode 100644 index 000000000..3d5031cf3 --- /dev/null +++ b/Trie/Trie/Trie/Trie.swift @@ -0,0 +1,254 @@ +// +// 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 { + 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: NSObject, NSCoding { + typealias Node = TrieNode + /// The number of words in the trie + public var count: Int { + return wordCount + } + /// Is the trie empty? + public var isEmpty: Bool { + return wordCount == 0 + } + /// All words currently in the trie + public var words: [String] { + return wordsInSubtrie(rootNode: root, partialWord: "") + } + fileprivate let root: Node + fileprivate var wordCount: Int + + /// Creates an empty trie. + override init() { + root = Node() + wordCount = 0 + super.init() + } + + // 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 +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() { + 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 + } + + /// Determines whether a word is in the trie. + /// + /// - Parameters: + /// - word: the word to check for + /// - matchPrefix: whether the search word should match + /// if it is only a prefix of other nodes in the trie + /// - Returns: true if the word is present, false otherwise. + func contains(word: String, matchPrefix: Bool = false) -> Bool { + guard !word.isEmpty else { + return false + } + var currentNode = root + for character in word.lowercased() { + guard let childNode = currentNode.children[character] else { + return false + } + currentNode = childNode + } + return matchPrefix || 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() { + 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. + /// + /// - Parameter word: the word in question + /// - Returns: the node where the search ended, nil if the + /// search failed. + private func findTerminalNodeOf(word: String) -> Node? { + if let lastNode = findLastNodeOf(word: word) { + return lastNode.isTerminating ? lastNode : nil + } + 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. + /// + /// - 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 + fileprivate 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 + } + + /// 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]() + let prefixLowerCased = prefix.lowercased() + if let lastNode = findLastNodeOf(word: prefixLowerCased) { + if lastNode.isTerminating { + words.append(prefixLowerCased) + } + for childNode in lastNode.children.values { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) + words += childWords + } + } + return words + } +} diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift new file mode 100644 index 000000000..8ce34f6c7 --- /dev/null +++ b/Trie/Trie/Trie/ViewController.swift @@ -0,0 +1,25 @@ +// +// 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..59da2cd9b --- /dev/null +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -0,0 +1,218 @@ +// +// 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 wordArray and trie should + /// stay around. + override func tearDown() { + super.tearDown() + } + + /// Reads words from the dictionary file and inserts them into an array. If + /// the word array already has words, do nothing. This allows running all + /// tests without repeatedly filling the array with the same values. + func createWordArray() { + guard wordArray == nil else { + return + } + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary.txt" + let filePath = resourcePath.appendingPathComponent(fileName) + + var data: String? + do { + data = try String(contentsOfFile: filePath, encoding: String.Encoding.utf8) + } catch let error as NSError { + XCTAssertNil(error) + } + XCTAssertNotNil(data) + let dictionarySize = 162825 + wordArray = data!.components(separatedBy: "\n") + XCTAssertEqual(wordArray!.count, dictionarySize) + } + + /// Inserts words into a trie. If the trie is non-empty, don't do anything. + func insertWordsIntoTrie() { + guard let wordArray = wordArray, trie.count == 0 else { return } + for word in wordArray { + trie.insert(word: word) + } + } + + /// Tests that a newly created trie has zero words. + func testCreate() { + let trie = Trie() + XCTAssertEqual(trie.count, 0) + } + + /// Tests the insert method + func testInsert() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cutie") + trie.insert(word: "fred") + XCTAssertTrue(trie.contains(word: "cute")) + XCTAssertFalse(trie.contains(word: "cut")) + trie.insert(word: "cut") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertEqual(trie.count, 4) + } + + /// Tests the remove method + func testRemove() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cut") + XCTAssertEqual(trie.count, 2) + trie.remove(word: "cute") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertFalse(trie.contains(word: "cute")) + XCTAssertEqual(trie.count, 1) + } + + /// Tests the words property + func testWords() { + let trie = Trie() + var words = trie.words + XCTAssertEqual(words.count, 0) + trie.insert(word: "foobar") + words = trie.words + XCTAssertEqual(words[0], "foobar") + XCTAssertEqual(words.count, 1) + } + + /// Tests the performance of the insert method. + func testInsertPerformance() { + self.measure { + let trie = Trie() + for word in self.wordArray! { + trie.insert(word: word) + } + } + XCTAssertGreaterThan(trie.count, 0) + XCTAssertEqual(trie.count, wordArray?.count) + } + + /// Tests the performance of the insert method when the words are already + /// present. + func testInsertAgainPerformance() { + self.measure { + for word in self.wordArray! { + self.trie.insert(word: word) + } + } + } + + /// Tests the performance of the contains method. + func testContainsPerformance() { + self.measure { + for word in self.wordArray! { + XCTAssertTrue(self.trie.contains(word: word)) + } + } + } + + /// Tests the performance of the remove method. Since setup has already put + /// words into the trie, remove them before measuring performance. + func testRemovePerformance() { + for word in self.wordArray! { + self.trie.remove(word: word) + } + self.measure { + self.insertWordsIntoTrie() + for word in self.wordArray! { + self.trie.remove(word: word) + } + } + XCTAssertEqual(trie.count, 0) + } + + /// Tests the performance of the words computed property. Also tests to see + /// if it worked properly. + func testWordsPerformance() { + var words: [String]? + self.measure { + words = self.trie.words + } + XCTAssertEqual(words?.count, trie.count) + for word in words! { + XCTAssertTrue(self.trie.contains(word: word)) + } + } + + /// Tests the archiving and unarchiving of the trie. + func testArchiveAndUnarchive() { + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary-archive" + let filePath = resourcePath.appendingPathComponent(fileName) + NSKeyedArchiver.archiveRootObject(trie, toFile: filePath) + let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie + XCTAssertEqual(trieCopy?.count, trie.count) + } + + /// Tests whether word prefixes are properly found and returned. + func testFindWordsWithPrefix() { + let trie = Trie() + trie.insert(word: "test") + trie.insert(word: "another") + trie.insert(word: "exam") + let wordsAll = trie.findWordsWithPrefix(prefix: "") + XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) + let words = trie.findWordsWithPrefix(prefix: "ex") + XCTAssertEqual(words, ["exam"]) + trie.insert(word: "examination") + let words2 = trie.findWordsWithPrefix(prefix: "exam") + XCTAssertEqual(words2, ["exam", "examination"]) + let noWords = trie.findWordsWithPrefix(prefix: "tee") + XCTAssertEqual(noWords, []) + let unicodeWord = "😬😎" + trie.insert(word: unicodeWord) + let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") + XCTAssertEqual(wordsUnicode, [unicodeWord]) + trie.insert(word: "Team") + let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") + XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) + } + + /// Tests whether word prefixes are properly detected on a boolean contains() check. + func testContainsWordMatchPrefix() { + let trie = Trie() + trie.insert(word: "test") + trie.insert(word: "another") + trie.insert(word: "exam") + let wordsAll = trie.contains(word: "", matchPrefix: true) + XCTAssertEqual(wordsAll, true) + let words = trie.contains(word: "ex", matchPrefix: true) + XCTAssertEqual(words, true) + trie.insert(word: "examination") + let words2 = trie.contains(word: "exam", matchPrefix: true) + XCTAssertEqual(words2, true) + let noWords = trie.contains(word: "tee", matchPrefix: true) + XCTAssertEqual(noWords, false) + let unicodeWord = "😬😎" + trie.insert(word: unicodeWord) + let wordsUnicode = trie.contains(word: "😬", matchPrefix: true) + XCTAssertEqual(wordsUnicode, true) + trie.insert(word: "Team") + let wordsUpperCase = trie.contains(word: "Te", matchPrefix: true) + XCTAssertEqual(wordsUpperCase, true) + } +} diff --git a/Trie/Trie/TrieUITests/Info.plist b/Trie/Trie/TrieUITests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Trie/Trie/TrieUITests/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/TrieUITests/TrieUITests.swift b/Trie/Trie/TrieUITests/TrieUITests.swift new file mode 100644 index 000000000..380bf3092 --- /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. + } + +} diff --git a/Trie/images/trie.png b/Trie/images/trie.png new file mode 100644 index 000000000..00dacc008 Binary files /dev/null and b/Trie/images/trie.png differ diff --git a/Two-Sum Problem/README.markdown b/Two-Sum Problem/README.markdown index 0c010954a..bbd033343 100644 --- a/Two-Sum Problem/README.markdown +++ b/Two-Sum Problem/README.markdown @@ -1,66 +1,82 @@ # Two-Sum Problem -You're given an array `a` with numbers. Write an algorithm that checks if there are any two entries in the array that add up to a given number `k`. In other words, is there any `a[i] + a[j] == k`? +Given an array of integers and an integer target, return the indices of two numbers that add up to the target. There are a variety of solutions to this problem (some better than others). The following solutions both run in **O(n)** time. # Solution 1 -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. +This solution looks at one number at a time, storing each number in the dictionary. It uses the number as the key and the number's index in the array as the value. -With this approach, each key in the dictionary corresponds to a new target value. If one of the following numbers from the array is equal to one of the dictionary's keys, then we know there exist two numbers that sum to `k`. +For each number n, we know the complementing number to sum up to the target is `target - n`. By looking up the complement in the dictionary, we'd know whether we've seen the complement before and what its index is. ```swift -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { - var dict = [Int: Int]() - - for i in 0 ..< a.count { - if let newK = dict[a[i]] { - return (newK, i) - } else { - dict[k - a[i]] = i +func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? { + var dict = [Int: Int]() + + // For every number n, + for (currentIndex, n) in nums.enumerated() { + // Find the complement to n that would sum up to the target. + let complement = target - n + + // Check if the complement is in the dictionary. + if let complementIndex = dict[complement] { + return (complementIndex, currentIndex) + } + + // Store n and its index into the dictionary. + dict[n] = currentIndex } - } - - return nil // if empty array or no entries sum to target k + + return nil } ``` -The `twoSumProblem()` function takes two parameters: the array `a` with the numbers, and `k`, the sum we're looking for. It returns the first set of indices `(i, j)` where `a[i] + a[j] == k`, or `nil` if no two numbers add up to `k`. +The `twoSum` function takes two parameters: the `numbers` array and the target sum. It returns the two indicies of the pair of elements that sums up to the target, or `nil` if they can't be found. -Let's take a look at an example and run through the algorithm to see how it works. Given is the array: +Let's run through the algorithm to see how it works. Given the array: ```swift -[ 7, 2, 23, 8, -1, 0, 11, 6 ] +[3, 2, 9, 8] ``` -Let's find out if there exist two entries whose sum is equal to 10. +Let's find out if there exist two entries whose sum is 10. Initially, our dictionary is empty. We begin looping through each element: -- **i = 0**: Is `0` in the dictionary? No. We add the difference between the target `k` and the current number to the dictionary. The difference is `10 - 7 = 3`, so the dictionary key is `3`. The value for that key is the current index, `0`. The dictionary now looks like this: +- **currentIndex = 0** | n = nums[0] = 3 | complement = 10 - 3 = 7 + +Is the complement `7` in the dictionary? No, so we add `3` and its index `0` to the dictionary. ```swift -[ 3: 0 ] +[3: 0] ``` -- **i = 1:** Is `2` in the dictionary? No. Let's do as above and add the difference (`10 - 2 = 8`) and the array index (`1`). The dictionary is: +- **currentIndex = 1** | n = 2 | complement = 10 - 2 = 8 + +Is the complement `8` in the dictionary? No, so we add `2` and its index `1` to the dictionary. ```swift -[ 3: 0, 8: 1 ] +[3: 0, 2: 1] ``` -- **i = 2:** Is `23` in the dictionary? No. Again, we add it to the dictionary. The difference is `10 - 23 = -13` and the index is `2`: +- **currentIndex = 2** | n = 9 | complement = 10 - 9 = 1 + +Is the complement `1` in the dictionary? No, so we add `9` and its index `2` to the dictionary.: ```swift -[ 3: 0, 8: 1, -13: 2 ] +[3: 0, 2: 1, 9: 2] ``` -- **i = 3:** Is `8` in the dictionary? Yes! That means that we have found a pair of entries that sum to our target. Namely the current number `8` and `array[dict[8]]` because `dict[8] = 1`, `array[1] = 2`, and `8 + 2 = 10`. Therefore, we return the corresponding indices of these numbers. For `8` that is the current loop index, `3`. For `2` that is `dict[8]` or `1`. The tuple we return is `(1, 3)`. +- **currentIndex = 3** | n = 8 | complement = 10 - 8 = 2 + +Is the complement `2` in the dictionary? Yes! That means that we have found a pair of entries that sum to the target! + +Therefore, the `complementIndex = dict[2] = 1` and the `currentIndex = 3`. The tuple we return is `(1, 3)`. -The given array actually has multiple solutions: `(1, 3)` and `(4, 6)`. However, only the first solution is returned. +If the given array has multiple solutions, only the first solution is returned. -The running time of this algorithm is **O(n)** because it potentially may need to look at all array elements. It also requires **O(n)** additional storage space for the dictionary. +The running time of this algorithm is **O(n)** because it may look at every element in the array. It also requires **O(n)** additional storage space for the dictionary. # Solution 2 @@ -69,7 +85,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 +94,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 @@ -148,4 +164,8 @@ It's possible, of course, that there are no values for `a[i] + a[j]` that sum to I'm quite enamored by this little algorithm. It shows that with some basic preprocessing on the input data -- sorting it from low to high -- you can turn a tricky problem into a very simple and beautiful algorithm. -*Written by Matthijs Hollemans and Daniel Speiser* +## Additional Reading + +* [3Sum / 4Sum](https://github.com/raywenderlich/swift-algorithm-club/tree/master/3Sum%20and%204Sum) + +*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser updated to swift 4.2 by Farrukh Askari* diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift index 5fee2deb4..00a39b04a 100644 --- a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift @@ -1,25 +1,20 @@ -//: Playground - noun: a place where people can play +//: Two Sum +// Last checked with: Version 10.0 (10A255) -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 +func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? { + var dict = [Int: Int]() + + for (currentIndex, n) in nums.enumerated() { + let complement = target - n + + if let complementIndex = dict[complement] { + return (complementIndex, currentIndex) + } + + dict[n] = currentIndex } - } - return nil + + return nil } -let a = [7, 100, 2, 21, 12, 10, 22, 14, 3, 4, 8, 4, 9] -if let (i, j) = twoSumProblem(a, k: 33) { - i // 3 - a[i] // 21 - j // 4 - a[j] // 12 - a[i] + a[j] // 33 -} - -twoSumProblem(a, k: 37) // nil +twoSum([3, 2, 9, 8], target: 10) // expected output: indices 1 and 3 diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/contents.xcplayground b/Two-Sum Problem/Solution 1/2Sum.playground/contents.xcplayground index 06828af92..3de2b51ba 100644 --- a/Two-Sum Problem/Solution 1/2Sum.playground/contents.xcplayground +++ b/Two-Sum Problem/Solution 1/2Sum.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Two-Sum Problem/Solution 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 1/2Sum.swift b/Two-Sum Problem/Solution 1/2Sum.swift deleted file mode 100644 index 0f438c11d..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.playground/Contents.swift b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift index 07883e251..469c15b5f 100644 --- a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift @@ -1,17 +1,18 @@ //: Playground - noun: a place where people can play +// Last checked with: Version 10.0 (10A255) -func twoSumProblem(a: [Int], k: Int) -> ((Int, Int))? { +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 + i += 1 } else { - --j + j -= 1 } } return nil diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/timeline.xctimeline b/Two-Sum Problem/Solution 2/2Sum.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Two-Sum Problem/Solution 2/2Sum.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - 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 -} diff --git a/Under Construction.markdown b/Under Construction.markdown new file mode 100644 index 000000000..be53e01b0 --- /dev/null +++ b/Under Construction.markdown @@ -0,0 +1,31 @@ +# Under Construction :construction: + +Here you'll find algorithms that are currently under construction. Suggestions and feedback is welcome! + +### Sorting + +Special-purpose sorts: + - [Radix Sort](Radix%20Sort/) + +### Special-purpose sorts: + +- [Bucket Sort](Bucket%20Sort/) + +### Queues + +- [Bounded Priority Queue](Bounded%20Priority%20Queue). A queue that is bounded to have a limited number of elements. + +### Trees + +- [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%20Tree/) + +### Miscellaneous + +- [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%20Cover%20(Unweighted)/) diff --git a/Union-Find/Images/AfterFind.png b/Union-Find/Images/AfterFind.png new file mode 100644 index 000000000..6405f8e6d Binary files /dev/null and b/Union-Find/Images/AfterFind.png differ diff --git a/Union-Find/Images/AfterUnion.png b/Union-Find/Images/AfterUnion.png new file mode 100644 index 000000000..10c1f2d7e Binary files /dev/null and b/Union-Find/Images/AfterUnion.png differ diff --git a/Union-Find/Images/BeforeFind.png b/Union-Find/Images/BeforeFind.png new file mode 100644 index 000000000..e0cdd224f Binary files /dev/null and b/Union-Find/Images/BeforeFind.png differ diff --git a/Union-Find/Images/BeforeUnion.png b/Union-Find/Images/BeforeUnion.png new file mode 100644 index 000000000..13890ccb0 Binary files /dev/null and b/Union-Find/Images/BeforeUnion.png differ diff --git a/Union-Find/README.markdown b/Union-Find/README.markdown new file mode 100644 index 000000000..a268f1d70 --- /dev/null +++ b/Union-Find/README.markdown @@ -0,0 +1,225 @@ +# Union-Find + +Union-Find is a data structure that can keep track of a set of elements partitioned into a number of disjoint (non-overlapping) subsets. It is also known as disjoint-set data structure. + +What do we mean by this? For example, the Union-Find data structure could be keeping track of the following sets: + + [ a, b, f, k ] + [ e ] + [ g, d, c ] + [ i, j ] + +These sets are **disjoint** because they have no members in common. + +Union-Find supports three basic operations: + +1. **Find(A)**: Determine which subset an element **A** is in. For example, `find(d)` would return the subset `[ g, d, c ]`. + +2. **Union(A, B)**: Join two subsets that contain **A** and **B** into a single subset. For example, `union(d, j)` would combine `[ g, d, c ]` and `[ i, j ]` into the larger set `[ g, d, c, i, j ]`. + +3. **AddSet(A)**: Add a new subset containing just that element **A**. For example, `addSet(h)` would add a new set `[ h ]`. + +The most common application of this data structure is keeping track of the connected components of an undirected [graph](../Graph/). It is also used for implementing an efficient version of Kruskal's algorithm to find the minimum spanning tree of a graph. + +## 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: Multiple implementations of Union-Find has been included in playground.__ + +```swift +public struct UnionFind { + private var index = [T: Int]() + private var parent = [Int]() + private var size = [Int]() +} +``` + +Our Union-Find data structure is actually a forest where each subset is represented by a [tree](../Tree/). + +For our purposes we only need to keep track of the parent of each tree node, not the node's children. To do this we use the array `parent` so that `parent[i]` is the index of node `i`'s parent. + +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 + / \ / + 3 5 4 + +There are two trees in this forest, each of which corresponds to one set of elements. (Note: due to the limitations of ASCII art the trees are shown here as binary trees but that is not necessarily the case.) + +We give each subset a unique number to identify it. That number is the index of the root node of that subset's tree. In the example, node `1` is the root of the first tree and `6` is the root of the second tree. + +So in this example we have two subsets, the first with the label `1` and the second with the label `6`. The **Find** operation actually returns the set's label, not its contents. + +Note that the `parent[]` of a root node points to itself. So `parent[1] = 1` and `parent[6] = 6`. That's how we can tell something is a root node. + +## Add set + +Let's look at the implementation of these basic operations, starting with adding a new set. + +```swift +public mutating func addSetWith(_ element: T) { + index[element] = parent.count // 1 + parent.append(parent.count) // 2 + size.append(1) // 3 +} +``` + +When you add a new element, this actually adds a new subset containing just that element. + +1. We save the index of the new element in the `index` dictionary. That lets us look up the element quickly later on. + +2. Then we add that index to the `parent` array to build a new tree for this set. Here, `parent[i]` is pointing to itself because the tree that represents the new set contains only one node, which of course is the root of that tree. + +3. `size[i]` is the count of nodes in the tree whose root is at index `i`. For the new set this is 1 because it only contains the one element. We'll be using the `size` array in the Union operation. + +## Find + +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? { + if let indexOfElement = index[element] { + return setByIndex(indexOfElement) + } else { + return nil + } +} +``` + +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 { + if parent[index] == index { // 1 + return index + } else { + parent[index] = setByIndex(parent[index]) // 2 + return parent[index] // 3 + } +} +``` + +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. + +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)**. + +3. We return the index of the root node as the result. + +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 indices of the elements are marked in red.) + +During the call to `setOf(4)`, the tree is reorganized to look like this: + +![AfterFind](Images/AfterFind.png) + +Now if we need to call `setOf(4)` again, we no longer have to go through node `2` to get to the root. So as you use the Union-Find data structure, it optimizes itself. Pretty cool! + +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), let secondSet = setOf(secondElement) { + return firstSet == secondSet + } else { + return false + } +} +``` + +Since this calls `setOf()` it also optimizes the tree. + +## 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] + } + } + } + } +``` + +Here is how it works: + +1. We find the sets that each element belongs to. Remember that this gives us two integers: the indices of the root nodes in the `parent` array. + +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 (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. + +5. Update the size of larger tree because it just had a bunch of nodes added to it. + +An illustration may help to better understand this. Let's say we have these two sets, each with its own tree: + +![BeforeUnion](Images/BeforeUnion.png) + +Now we call `unionSetsContaining(4, and: 3)`. The smaller tree is attached to the larger one: + +![AfterUnion](Images/AfterUnion.png) + +Note that, because we call `setOf()` at the start of the method, the larger tree was also optimized in the process -- node `3` now hangs directly off the root. + +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 + +##### 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)*, *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 new file mode 100644 index 000000000..b1f7fb4e1 --- /dev/null +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -0,0 +1,58 @@ +//: Playground - noun: a place where people can play + +var dsu = UnionFindQuickUnion() + +for i in 1...10 { + 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) + } +} + +// check our division +print(dsu.inSameSet(2, and: 4)) +print(dsu.inSameSet(4, and: 6)) +print(dsu.inSameSet(6, and: 8)) +print(dsu.inSameSet(8, and: 10)) + +print(dsu.inSameSet(1, and: 3)) +print(dsu.inSameSet(3, and: 5)) +print(dsu.inSameSet(5, and: 7)) +print(dsu.inSameSet(7, and: 9)) + +print(dsu.inSameSet(7, and: 4)) +print(dsu.inSameSet(3, and: 6)) + +var dsuForStrings = UnionFindQuickUnion() +let words = ["all", "border", "boy", "afternoon", "amazing", "awesome", "best"] + +dsuForStrings.addSetWith("a") +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) + } +} + +print(dsuForStrings.inSameSet("a", and: "all")) +print(dsuForStrings.inSameSet("all", and: "awesome")) +print(dsuForStrings.inSameSet("amazing", and: "afternoon")) + +print(dsuForStrings.inSameSet("b", and: "boy")) +print(dsuForStrings.inSameSet("best", and: "boy")) +print(dsuForStrings.inSameSet("border", and: "best")) + +print(dsuForStrings.inSameSet("amazing", and: "boy")) +print(dsuForStrings.inSameSet("all", and: "border")) diff --git a/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift b/Union-Find/UnionFind.playground/Sources/UnionFindQuickFind.swift new file mode 100644 index 000000000..2cd048de6 --- /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..2be8875eb --- /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..49a526fe3 --- /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..70217422f --- /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..1c0bacd82 --- /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/contents.xcplayground b/Union-Find/UnionFind.playground/contents.xcplayground new file mode 100644 index 000000000..06828af92 --- /dev/null +++ b/Union-Find/UnionFind.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Union-Find/UnionFind.playground/playground.xcworkspace/contents.xcworkspacedata b/Union-Find/UnionFind.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Union-Find/UnionFind.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown new file mode 100644 index 000000000..a6423be03 --- /dev/null +++ b/Z-Algorithm/README.markdown @@ -0,0 +1,174 @@ +# 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) + 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 = “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 + 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.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"](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/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift new file mode 100644 index 000000000..65acaabd1 --- /dev/null +++ b/Z-Algorithm/ZAlgorithm.swift @@ -0,0 +1,65 @@ +/* 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) + 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 +} diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..56aa92170 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -0,0 +1,92 @@ +//: Playground - noun: a place where people can play + +func ZetaAlgorithm(ptrn: String) -> [Int]? { + let pattern = Array(ptrn) + 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 +} + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength = pattern.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 */ + +let str = "Hello, playground!" +str.indexesOf(pattern: "ground") // [11] + +let traffic = "🚗🚙🚌🚕🚑🚐🚗🚒🚚🚎🚛🚐🏎🚜🚗🏍🚒🚲🚕🚓🚌🚑" +traffic.indexesOf(pattern: "🚑") // [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.swift b/Z-Algorithm/ZetaAlgorithm.swift new file mode 100644 index 000000000..f2c453364 --- /dev/null +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -0,0 +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 + */ + +import Foundation + +extension String { + + func indexesOf(pattern: String) -> [Int]? { + let patternLength = pattern.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 + } +} diff --git a/gfm-render.sh b/gfm-render.sh new file mode 100755 index 000000000..4e18c8560 --- /dev/null +++ b/gfm-render.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash + +set -e + +# $1 - readme file name +function render_markdown_to_html { + # escape escaping characters on Darwin only + content=$( + cat "$1" \ + | sed 's/\\/\\\\/g' \ + | sed 's/"/\\"/g' \ + | sed $'s/\t/\\\\t/g' \ + | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\\n/g' \ + ) + + # network call to GitHub API + json="{\"text\":\"$content\",\"mode\":\"gfm\",\"context\":\"$USERNAME/swift-algorithm-club\"}" + echo -e "$(curl -s --data "$json" -u $USERNAME:$TOKEN https://api.github.com/markdown)" +} + +# download github systax highlight stylesheet +echo "> Downloading github-light.css..." +curl -s -O https://raw.githubusercontent.com/primer/github-syntax-light/master/lib/github-light.css + +# slightly modify the main stylesheet +echo "> Modifying github-light.css..." +cat >> github-light.css << EOF +#container { + margin: 0 auto; + width: 75%; + min-width: 768px; + max-width: 896px; + position: relative; +} + +body { + font-size: 18px; +} + +code { + padding: 0.2em; + margin: 0; + font-size: 85%; + background-color: #f6f8fa; + line-height: 1.45; + border-radius: 3px +} + +pre code { + padding: 0px; + background-color: transparent; +} + +.highlight { + margin: 0px; + padding: 0px 16px; + font-size: 85%; + line-height: 1.45; + overflow: auto; + background-color: #f6f8fa; + border-radius: 3px; +} + +@media (max-width: 768px) { + #container { + position: absolute; + margin: 0; + width: 100%; + height: 100%; + min-width: 100%; + } +} +EOF + +# other markdown articles +for title in "What are Algorithms" "Big-O Notation" "Algorithm Design" "Why Algorithms"; do + echo "> Generating $title.html..." + + cat > "$title.html" << EOF + + + $title + + + +
$(render_markdown_to_html "$title.markdown")
+ + +EOF +done + +# if index.html does not exist, create one; +# otherwise, empty its content. +echo "> Generating index.html..." +cat > index.html << EOF + + + Swift Algorithm Club + + + +
$(render_markdown_to_html README.markdown | sed 's/.markdown/.html/g')
+ + +EOF + +# iterate immediate directories +find . -maxdepth 1 -type d | while read folder; do + readme='' + + # get the right extension for the README file if there is one + if [[ -f $folder/README.md ]]; then readme="$folder/README.md"; fi + if [[ -f $folder/README.markdown ]]; then readme="$folder/README.markdown"; fi + + # skip if there is no README or it it the README of the repository + if [[ (-z $readme) || $readme == "./README.markdown" ]]; then continue; fi + + # render README to HTML + name=$(basename "$folder") + echo "> Generating $name/index.html..." + + cat > "$folder/index.html" << EOF + + + $name + + + +
$(render_markdown_to_html "$readme")
+ + +EOF +done + +# push to gh-pages +if [[ $CI = true ]]; then + git checkout -b gh-pages + git add . + git commit -m "$Generated by TravisCI on $(date +%D)" + git push -f https://$TOKEN@github.com/$USERNAME/swift-algorithm-club.git gh-pages +fi diff --git a/install_swiftlint.sh b/install_swiftlint.sh new file mode 100755 index 000000000..b33d83de2 --- /dev/null +++ b/install_swiftlint.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Installs the SwiftLint package. +# Tries to get the precompiled .pkg file from Github, but if that +# fails just recompiles from source. + +set -e + +SWIFTLINT_PKG_PATH="/tmp/SwiftLint.pkg" +SWIFTLINT_PKG_URL="https://github.com/realm/SwiftLint/releases/download/0.10.0/SwiftLint.pkg" + +wget --output-document=$SWIFTLINT_PKG_PATH $SWIFTLINT_PKG_URL + +if [ -f $SWIFTLINT_PKG_PATH ]; then + echo "SwiftLint package exists! Installing it..." + sudo installer -pkg $SWIFTLINT_PKG_PATH -target / +else + echo "SwiftLint package doesn't exist. Compiling from source..." && + git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint && + cd /tmp/SwiftLint && + git submodule update --init --recursive && + sudo make install +fi