Skip to content

Commit 8bdfcae

Browse files
committedJan 30, 2016
Add permutations and combinations
1 parent 516f9ec commit 8bdfcae

File tree

6 files changed

+649
-1
lines changed

6 files changed

+649
-1
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//: Playground - noun: a place where people can play
2+
3+
/* Calculates n! */
4+
func factorial(n: Int) -> Int {
5+
var n = n
6+
var result = 1
7+
while n > 1 {
8+
result *= n
9+
n -= 1
10+
}
11+
return result
12+
}
13+
14+
factorial(5)
15+
factorial(20)
16+
17+
18+
19+
/*
20+
Calculates P(n, k), the number of permutations of n distinct symbols
21+
in groups of size k.
22+
*/
23+
func permutations(n: Int, _ k: Int) -> Int {
24+
var n = n
25+
var answer = n
26+
for _ in 1..<k {
27+
n -= 1
28+
answer *= n
29+
}
30+
return answer
31+
}
32+
33+
permutations(5, 3)
34+
permutations(50, 6)
35+
permutations(9, 4)
36+
37+
38+
39+
/*
40+
Prints out all the permutations of the given array.
41+
Original algorithm by Niklaus Wirth.
42+
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
43+
*/
44+
func permuteWirth<T>(a: [T], _ n: Int) {
45+
if n == 0 {
46+
print(a) // display the current permutation
47+
} else {
48+
var a = a
49+
permuteWirth(a, n - 1)
50+
for i in 0..<n {
51+
swap(&a[i], &a[n])
52+
permuteWirth(a, n - 1)
53+
swap(&a[i], &a[n])
54+
}
55+
}
56+
}
57+
58+
let letters = ["a", "b", "c", "d", "e"]
59+
print("Permutations of \(letters):")
60+
permuteWirth(letters, letters.count - 1)
61+
62+
let xyz = [ "x", "y", "z" ]
63+
print("\nPermutations of \(xyz):")
64+
permuteWirth(xyz, 2)
65+
66+
67+
68+
/*
69+
Prints out all the permutations of an n-element collection.
70+
71+
The initial array must be initialized with all zeros. The algorithm
72+
uses 0 as a flag that indicates more work to be done on each level
73+
of the recursion.
74+
75+
Original algorithm by Robert Sedgewick.
76+
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
77+
*/
78+
func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) {
79+
var a = a
80+
pos += 1
81+
a[n] = pos
82+
if pos == a.count - 1 {
83+
print(a) // display the current permutation
84+
} else {
85+
for i in 0..<a.count {
86+
if a[i] == 0 {
87+
permuteSedgewick(a, i, &pos)
88+
}
89+
}
90+
}
91+
pos -= 1
92+
a[n] = 0
93+
}
94+
95+
print("\nSedgewick permutations:")
96+
let numbers = [0, 0, 0, 0] // must be all zeros
97+
var pos = -1
98+
permuteSedgewick(numbers, 0, &pos)
99+
100+
101+
102+
/*
103+
Calculates C(n, k), or "n-choose-k", i.e. how many different selections
104+
of size k out of a total number of distinct elements (n) you can make.
105+
*/
106+
func combinations(n: Int, _ k: Int) -> Int {
107+
return permutations(n, k) / factorial(k)
108+
}
109+
110+
combinations(3, 2)
111+
combinations(28, 5)
112+
113+
print("\nCombinations:")
114+
for i in 1...20 {
115+
print("\(20)-choose-\(i) = \(combinations(20, i))")
116+
}
117+
118+
119+
120+
121+
/* Supporting code because Swift doesn't have a built-in 2D array. */
122+
struct Array2D<T> {
123+
let columns: Int
124+
let rows: Int
125+
private var array: [T]
126+
127+
init(columns: Int, rows: Int, initialValue: T) {
128+
self.columns = columns
129+
self.rows = rows
130+
array = .init(count: rows*columns, repeatedValue: initialValue)
131+
}
132+
133+
subscript(column: Int, row: Int) -> T {
134+
get { return array[row*columns + column] }
135+
set { array[row*columns + column] = newValue }
136+
}
137+
}
138+
139+
/*
140+
Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose
141+
k things out of n possibilities.
142+
143+
Thanks to the dynamic programming, this algorithm from Skiena allows for
144+
the calculation of much larger numbers, at the cost of temporary storage
145+
space for the cached values.
146+
*/
147+
func binomialCoefficient(n: Int, _ k: Int) -> Int {
148+
var bc = Array2D(columns: n + 1, rows: n + 1, initialValue: 0)
149+
150+
for i in 0...n {
151+
bc[i, 0] = 1
152+
bc[i, i] = 1
153+
}
154+
155+
if n > 0 {
156+
for i in 1...n {
157+
for j in 1..<i {
158+
bc[i, j] = bc[i - 1, j - 1] + bc[i - 1, j]
159+
}
160+
}
161+
}
162+
163+
return bc[n, k]
164+
}
165+
166+
binomialCoefficient(30, 15)
167+
binomialCoefficient(66, 33)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='osx'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>

‎Combinatorics/Combinatorics.swift

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* Calculates n! */
2+
func factorial(n: Int) -> Int {
3+
var n = n
4+
var result = 1
5+
while n > 1 {
6+
result *= n
7+
n -= 1
8+
}
9+
return result
10+
}
11+
12+
/*
13+
Calculates P(n, k), the number of permutations of n distinct symbols
14+
in groups of size k.
15+
*/
16+
func permutations(n: Int, _ k: Int) -> Int {
17+
var n = n
18+
var answer = n
19+
for _ in 1..<k {
20+
n -= 1
21+
answer *= n
22+
}
23+
return answer
24+
}
25+
26+
/*
27+
Prints out all the permutations of the given array.
28+
Original algorithm by Niklaus Wirth.
29+
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
30+
*/
31+
func permuteWirth<T>(a: [T], _ n: Int) {
32+
if n == 0 {
33+
print(a) // display the current permutation
34+
} else {
35+
var a = a
36+
permuteWirth(a, n - 1)
37+
for i in 0..<n {
38+
swap(&a[i], &a[n])
39+
permuteWirth(a, n - 1)
40+
swap(&a[i], &a[n])
41+
}
42+
}
43+
}
44+
45+
/*
46+
Prints out all the permutations of an n-element collection.
47+
48+
The initial array must be initialized with all zeros. The algorithm
49+
uses 0 as a flag that indicates more work to be done on each level
50+
of the recursion.
51+
52+
Original algorithm by Robert Sedgewick.
53+
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
54+
*/
55+
func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) {
56+
var a = a
57+
pos += 1
58+
a[n] = pos
59+
if pos == a.count - 1 {
60+
print(a) // display the current permutation
61+
} else {
62+
for i in 0..<a.count {
63+
if a[i] == 0 {
64+
permuteSedgewick(a, i, &pos)
65+
}
66+
}
67+
}
68+
pos -= 1
69+
a[n] = 0
70+
}
71+
72+
/*
73+
Calculates C(n, k), or "n-choose-k", i.e. how many different selections
74+
of size k out of a total number of distinct elements (n) you can make.
75+
Doesn't work very well for large numbers.
76+
*/
77+
func combinations(n: Int, _ k: Int) -> Int {
78+
return permutations(n, k) / factorial(k)
79+
}
80+
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+
Thanks to the dynamic programming, this algorithm from Skiena allows for
86+
the calculation of much larger numbers, at the cost of temporary storage
87+
space for the cached values.
88+
*/
89+
func binomialCoefficient(n: Int, _ k: Int) -> Int {
90+
var bc = Array2D(columns: n + 1, rows: n + 1, initialValue: 0)
91+
92+
for i in 0...n {
93+
bc[i, 0] = 1
94+
bc[i, i] = 1
95+
}
96+
97+
if n > 0 {
98+
for i in 1...n {
99+
for j in 1..<i {
100+
bc[i, j] = bc[i - 1, j - 1] + bc[i - 1, j]
101+
}
102+
}
103+
}
104+
105+
return bc[n, k]
106+
}

0 commit comments

Comments
 (0)