listrophy
November 19, 2019
310

# Algorithms: CLRS in Ruby

One of the most celebrated books in Computer Science academia is "Introduction to Algorithms," also known as "CLRS" after its 4 authors. It's the go-to (pun!) textbook for many intermediate college courses, and this talk will introduce some of its many wonderful algorithms in Ruby form, including: various sorting techniques, dynamic programming, and some fun graph techniques. If you want a theory-heavy lecture, this talk is NOT for you!

## listrophy

November 19, 2019

## Transcript

1. ALGORITHMS
CLRS IN RUBY

2. rubyconf 2019
‣ 2002 ICPC WORLD FINALS:
11TH PLACE
‣ FORMER AEROSPACE
ENGINEER
‣ FOUNDER/CEO OF
BENDYWORKS
‣ PORTED matrix TO ruby
@LISTROPHY

3. rubyconf 2019
SYLLABUS
‣ COMPLEXITY
‣ INSERTION SORT
‣ QUICK SORT
‣ BUCKET SORT
‣ LONGEST COMMON SUBSEQUENCE
‣ MINIMUM SPANNING TREE
‣ SHORTEST PATH
‣ MAX FLOW

4. rubyconf 2019
INTRODUCTION TO
ALGORITHMS
‣ CORMEN
‣ LEISERSON
‣ RIVEST
‣ STEIN

5. rubyconf 2019
COMPLEXITY

6. rubyconf 2019
COMPLEXITY
hNoHereComes
( _ )
O
thing(s)!

7. rubyconf 2019
COMPLEXITY
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
O(1)
a[4]
O(n)
a.map
O(log n)
a.bsearch
V
D T X
B F N R U W Y
P
H
L
J
A C E G I K M O Q S U V W X Y Z

8. rubyconf 2019
COMPLEXITY
O(1)
O(log n)
O(n)
O(n log n)
O(n²)
great!
ok
hmmm
uffda
oh no

9. rubyconf 2019
SORTING

10. rubyconf 2019
INSERTION SORT

11. rubyconf 2019
SORTING
INSERTION SORT
(1...length).each do |right|
subject = self[right]
left = right - 1
while left > -1 && self[left] > self[right]
self[left + 1] = self[left]
left += 1
end
self[left + 1] = subject
end

12. rubyconf 2019
INSERTION SORT DEMO

13. rubyconf 2019
INSERTION SORT
COMPLEXITY
O(n²)

14. rubyconf 2019
QUICK SORT

15. rubyconf 2019
SORTING
QUICK SORT
def quicksort
qsort_help(0, self.length - 1)
end
def qsort_help(p, r)
return unless p < r
q = partition(p, r)
qsort_help(p, q - 1)
qsort_help( q + 1, r)
end
def partition(p, r)
x = self[r]
i = p - 1
(p...r).each do |j|
if self[j] <= x
i += 1
swap(i, j)
end
end
swap(i + 1, r)
i + 1
end

16. rubyconf 2019
QUICK SORT DEMO

17. rubyconf 2019
QUICK SORT
COMPLEXITY
O(n log n)

18. rubyconf 2019
SORTING

19. rubyconf 2019
BUCKET SORT

20. rubyconf 2019
SORTING
BUCKET SORT
def bucket_sort
b = Array.new(length)
each_with_index do |val, idx|
b[val] = val
end
replace(b)
end
def bucket_sort
b = Array.new(length)
mx = max
(0...length).each do |i|
idx = length * (self[i] / mx)
b[idx] ||= []
b[idx] << self[i]
end
b.each(&:insertion_sort!)
replace(b.flatten.compact)
end

21. rubyconf 2019
BUCKET SORT DEMO

22. rubyconf 2019
BUCKET SORT
COMPLEXITY
O(n) ?

23. rubyconf 2019
DYNAMIC
PROGRAMMING

24. rubyconf 2019
LONGEST COMMON
SUBSEQUENCE

25. rubyconf 2019
DYNAMIC PROGRAMMING
LONGEST COMMON SUBSEQUENCE
ATCGG G
C TTTGC
ACCAC G
C TAACA

26. rubyconf 2019
DYNAMIC PROGRAMMING
LONGEST COMMON SUBSEQUENCE
def command
return @command if @command
@command = Message::Command...
@command ||= Message::Command...
...
end
def subject
@subject ||= sentence
.nouns
.reject...
end
def command
@command = Message::Command...
@command ||= Message::Command...
...
end
def subject
@subject ||= sentence.nouns.reject...
end

27. rubyconf 2019
DYNAMIC PROGRAMMING
LONGEST COMMON SUBSEQUENCE ( ABCDEF 㱻 BDF )
A B C D E F
B
D
F
0 1 1 1 1 1
0 1 1 2 2 2
0 1 1 2 2 3
if match?(top, left)
1 + ⬉
else
[‐, ‏].max
end
O(n∙m)

28. rubyconf 2019
LONGEST COMMON SUBSEQUENCE
def lcs
setup
compute_matrix
@matrix.last.last
end
def setup
@matrix = Array.new(@a.length + 1) do
Array.new(@b.length + 1, 0)
end
end
def compute_matrix
(1..(@a.length)).each do |i|
(1..(@b.length)).each do |j|
compute_cell(i, j)
end
end
end
def compute_cell(i, j)
@matrix[i][j] =
if @a[i - 1] == @b[j - 1]
matches(i, j)
else
does_not_match(i, j)
end
end
def matches(i, j)
@matrix[i - 1][j - 1] + 1
end
def does_not_match(i, j)
[ @matrix[i - 1][j],
@matrix[i][j - 1]
].max
end

29. rubyconf 2019
GRAPHS

30. rubyconf 2019
MINIMUM SPANNING
TREE

31. rubyconf 2019
GRAPHS
MINIMUM SPANNING TREE
A
H G F
E
I
B C D
8
4
11
7
1
2
4
8 7
14
10
9
2

32. rubyconf 2019
GRAPHS
MINIMUM SPANNING TREE (PRIM'S ALGORITHM)
A
H G F
E
I
B C D
8
4
11
7
1
2
4
8 7
14
10
9
2
vertices.map { |u| u.key = ∞ }
queue = PQueue.new(vertices)
until queue.empty?
u = queue.extract
u.neighbors.each do |v, w|
if queue.has?(v) && w < v.key
v.parent = u
v.key = w
end
end
end
A B H G F C I D E
O(E+V log V)

33. rubyconf 2019
SHORTEST PATH

34. rubyconf 2019
GRAPHS
SHORTEST PATH (DIJKSTRA'S ALGORITHM)
A
H G F
E
I
B C D
8
4
11
7
1
2
4
8 7
14
10
9
2
queue = PQueue.new(nodes)
until queue.empty?
u = queue.extract_first
u.relax(v, w)
end
end
class Node
# ...
def relax(other, w)
if other.d > (d + w)
other.d = d + w
other.parent = self
end
end
end
A B H G F C I D E
0
8
4
12
15
9 11
25
21
14
19
O(E+V log V)

35. rubyconf 2019
MAX FLOW

36. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
loop do
# find any path from s to t
p = find_path(s, t,
edges.reject {|_names, e| e.capacity == 0 })
break if p.empty?
# find the segement with least remaining capacity
segs = segments(p)
residual_capacity_p = segs.map do |uv|
edges[uv].residual_capacity
end.min
segs.each do |(u, v)|
# add that capacity to each edge
edges[[u, v]].flow += residual_capacity_p
# if we need to reverse the flow in the future:
edges[[v, u]].flow = -edges[[u, v]].flow
end
end

37. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4

38. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4
4
4
4

39. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4
12
4
4
12
4
12

40. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4
12
4
4
12
7
4
12

41. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4
12
11
11
12
7
4
19

42. rubyconf 2019
GRAPHS
MAX FLOW (FORD-FULKERSON ALGORITHM)
S
D
C
B
A
T
16
13
4
10
12
9
14
7
20
4
12
0
0
11
11
0
12
7
4
19
O(E |f *|)

43. rubyconf 2019
THANK YOU
@listrophy
@bendyworks
COMPLEXITY
INSERTION SORT
QUICK SORT
BUCKET SORT
LONGEST COMMON SUBSEQUENCE
MINIMUM SPANNING TREE
SHORTEST PATH
MAX FLOW
gitlab.com/listrophy/clrs-algorithms/