Skip to content

Commit ef593e0

Browse files
committed
Merge pull request #1 from hollance/master
update
2 parents 90eb49b + 8364813 commit ef593e0

File tree

19 files changed

+846
-30
lines changed

19 files changed

+846
-30
lines changed

Boyer-Moore/README.markdown

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,51 @@ The closer a character is to the end of the pattern, the smaller the skip amount
137137
138138
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.
139139

140+
See also: [a detailed analysis](http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/bmen.htm) of the algorithm.
141+
142+
## Boyer-Moore-Horspool algorithm
143+
144+
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).
145+
146+
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, it 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.
147+
148+
Here's an implementation of the Boyer-Moore-Horspool algorithm:
149+
150+
```swift
151+
extension String {
152+
public func indexOf(pattern: String) -> String.Index? {
153+
let patternLength = pattern.characters.count
154+
assert(patternLength > 0)
155+
assert(patternLength <= self.characters.count)
156+
157+
var skipTable = [Character: Int]()
158+
for (i, c) in pattern.characters.dropLast().enumerate() {
159+
skipTable[c] = patternLength - i - 1
160+
}
161+
162+
var index = self.startIndex.advancedBy(patternLength - 1)
163+
164+
while index < self.endIndex {
165+
var i = index
166+
var p = pattern.endIndex.predecessor()
167+
168+
while self[i] == pattern[p] {
169+
if p == pattern.startIndex { return i }
170+
i = i.predecessor()
171+
p = p.predecessor()
172+
}
173+
174+
let advance = skipTable[self[index]] ?? patternLength
175+
index = index.advancedBy(advance)
176+
}
177+
178+
return nil
179+
}
180+
}
181+
```
182+
183+
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.
184+
185+
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)
186+
140187
*Written for Swift Algorithm Club by Matthijs Hollemans*

Combinatorics/Combinatorics.playground/Contents.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,24 @@ for i in 1...20 {
117117

118118

119119

120+
/*
121+
Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose
122+
k things out of n possibilities.
123+
*/
124+
func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
125+
var result = 1
126+
127+
for i in 0..<k {
128+
result *= (n - i)
129+
result /= (i + 1)
130+
}
131+
return result
132+
}
133+
134+
quickBinomialCoefficient(8, 2)
135+
quickBinomialCoefficient(30, 15)
136+
137+
120138

121139
/* Supporting code because Swift doesn't have a built-in 2D array. */
122140
struct Array2D<T> {
@@ -165,3 +183,4 @@ func binomialCoefficient(n: Int, _ k: Int) -> Int {
165183

166184
binomialCoefficient(30, 15)
167185
binomialCoefficient(66, 33)
186+

Combinatorics/Combinatorics.playground/timeline.xctimeline

Lines changed: 0 additions & 6 deletions
This file was deleted.

Combinatorics/Combinatorics.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ func combinations(n: Int, _ k: Int) -> Int {
7878
return permutations(n, k) / factorial(k)
7979
}
8080

81+
/*
82+
Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose
83+
k things out of n possibilities.
84+
*/
85+
func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
86+
var result = 1
87+
88+
for i in 0..<k {
89+
result *= (n - i)
90+
result /= (i + 1)
91+
}
92+
return result
93+
}
94+
8195
/*
8296
Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose
8397
k things out of n possibilities.

Combinatorics/README.markdown

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,43 @@ combinations(28, 5) // prints 98280
304304

305305
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.
306306

307-
Here is an algorithm that uses dynamic programming to overcome the need for calculating factorials. It is based on Pascal's triangle:
307+
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:
308+
309+
n! n * (n - 1) * ... * 1
310+
C(n, k) = ------------- = ------------------------------------------
311+
(n - k)! * k! (n - k) * (n - k - 1) * ... * 1 * k!
312+
313+
After the reduction of fractions, we get the following formula:
314+
315+
n * (n - 1) * ... * (n - k + 1) (n - 0) * (n - 1) * ... * (n - k + 1)
316+
C(n, k) = --------------------------------------- = -----------------------------------------
317+
k! (0 + 1) * (1 + 1) * ... * (k - 1 + 1)
318+
319+
We can implement this formula as follows:
320+
321+
```swift
322+
func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
323+
var result = 1
324+
for i in 0..<k {
325+
result *= (n - i)
326+
result /= (i + 1)
327+
}
328+
return result
329+
}
330+
```
331+
332+
This algorithm can create larger numbers than the previous method. Instead of calculating the entire numerator (a potentially huge number) and then dividing it by the factorial (also a very large number), here we already divide in each step. That causes the temporary results to grow much less quickly.
333+
334+
Here's how you can use this improved algorithm:
335+
336+
```swift
337+
quickBinomialCoefficient(8, 2) // prints 28
338+
quickBinomialCoefficient(30, 15) // prints 155117520
339+
```
340+
341+
This new method is quite fast but you're still limited in how large the numbers can get. You can calculate `C(30, 15)` without any problems, but something like `C(66, 33)` will still cause integer overflow in the numerator.
342+
343+
Here is an algorithm that uses dynamic programming to overcome the need for calculating factorials and doing divisions. It is based on Pascal's triangle:
308344

309345
0: 1
310346
1: 1 1
@@ -351,10 +387,9 @@ func binomialCoefficient(n: Int, _ k: Int) -> Int {
351387

352388
This uses [Array2D](../Array2D/) as helper code because Swift doesn't have a built-in two-dimensional array. The algorithm itself is quite simple: the first loop fills in the 1s at the outer edges of the triangle. The other loops calculate each number in the triangle by adding up the two numbers from the previous row.
353389

354-
Now you can calculate `C(30, 15)` without any problems:
390+
Now you can calculate `C(66, 33)` without any problems:
355391

356392
```swift
357-
binomialCoefficient(30, 15) // prints 155117520
358393
binomialCoefficient(66, 33) // prints a very large number
359394
```
360395

@@ -364,4 +399,4 @@ You may wonder what the point is in calculating these permutations and combinati
364399

365400
Wirth's and Sedgewick's permutation algorithms and the code for counting permutations and combinations are based on the Algorithm Alley column from Dr.Dobb's Magazine, June 1993. The dynamic programming binomial coefficient algorithm is from The Algorithm Design Manual by Skiena.
366401

367-
*Written for Swift Algorithm Club by Matthijs Hollemans*
402+
*Written for Swift Algorithm Club by Matthijs Hollemans and [Kanstantsin Linou](https://github.com/nuts23)*

Linked List/LinkedList.playground/Contents.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public class LinkedListNode<T> {
44
var value: T
55
var next: LinkedListNode?
6-
var previous: LinkedListNode?
6+
weak var previous: LinkedListNode?
77

88
public init(value: T) {
99
self.value = value
@@ -155,10 +155,10 @@ extension LinkedList: CustomStringConvertible {
155155
extension LinkedList {
156156
public func reverse() {
157157
var node = head
158-
while node != nil {
159-
swap(&node!.next, &node!.previous)
160-
head = node
161-
node = node!.previous
158+
while let currentNode = node {
159+
node = currentNode.next
160+
swap(&currentNode.next, &currentNode.previous)
161+
head = currentNode
162162
}
163163
}
164164
}

Linked List/LinkedList.playground/timeline.xctimeline

Lines changed: 0 additions & 6 deletions
This file was deleted.

Linked List/LinkedList.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
public class LinkedListNode<T> {
77
var value: T
88
var next: LinkedListNode?
9-
var previous: LinkedListNode?
9+
weak var previous: LinkedListNode?
1010

1111
public init(value: T) {
1212
self.value = value
@@ -159,9 +159,9 @@ extension LinkedList {
159159
public func reverse() {
160160
var node = head
161161
while let currentNode = node {
162-
swap(&currentNode.next, &currentNode.previous)
163-
head = currentNode
164-
node = currentNode.previous
162+
node = currentNode.next
163+
swap(&currentNode.next, &currentNode.previous)
164+
head = currentNode
165165
}
166166
}
167167
}

Linked List/README.markdown

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ We'll start by defining a type to describe the nodes:
5858
public class LinkedListNode<T> {
5959
var value: T
6060
var next: LinkedListNode?
61-
var previous: LinkedListNode?
61+
weak var previous: LinkedListNode?
6262

6363
public init(value: T) {
6464
self.value = value
@@ -70,6 +70,8 @@ This is a generic type, so `T` can be any kind of data that you'd like to store
7070

7171
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.)
7272

73+
> **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.
74+
7375
Let's start building `LinkedList`. Here's the first bit:
7476

7577
```swift
@@ -450,9 +452,9 @@ How about reversing a list, so that the head becomes the tail and vice versa? Th
450452
public func reverse() {
451453
var node = head
452454
while let currentNode = node {
455+
node = currentNode.next
453456
swap(&currentNode.next, &currentNode.previous)
454457
head = currentNode
455-
node = currentNode.previous
456458
}
457459
}
458460
```
@@ -465,8 +467,6 @@ This loops through the entire list and simply swaps the `next` and `previous` po
465467
nil <---| |--->| |--->| |--->| |<--- head
466468
+--------+ +--------+ +--------+ +--------+
467469

468-
You may be wondering why the last statement says `node = currentNode.previous` to go to the next node instead of `currentNode.next` like you'd expect, but remember that we just swapped those pointers!
469-
470470
Arrays have `map()` and `filter()` functions, and there's no reason why linked lists shouldn't either.
471471

472472
```swift
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//: # Example 1 with type Int
2+
3+
var mySet = OrderedSet<Int>()
4+
5+
// Insert random numbers into the set
6+
for _ in 0..<50 {
7+
mySet.insert(random(50, max: 500))
8+
}
9+
10+
print(mySet)
11+
12+
print("\nMaximum:")
13+
print(mySet.max())
14+
15+
print("\nMinimum:")
16+
print(mySet.min())
17+
18+
// Print the 5 largest values
19+
print("\n5 Largest:")
20+
for k in 1...5 {
21+
print(mySet.kLargest(k))
22+
}
23+
24+
// Print the 5 lowest values
25+
print("\n5 Smallest:")
26+
for k in 1...5 {
27+
print(mySet.kSmallest(k))
28+
}
29+
30+
//: [Next](@next)

0 commit comments

Comments
 (0)