Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Algorithms: CLRS in Ruby

listrophy
November 19, 2019

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
Tweet

More Decks by listrophy

Other Decks in Programming

Transcript

  1. rubyconf 2019 BRAD GRZESIAK ‣ 2002 ICPC WORLD FINALS: 11TH

    PLACE ‣ FORMER AEROSPACE ENGINEER ‣ FOUNDER/CEO OF BENDYWORKS ‣ PORTED matrix TO ruby @LISTROPHY
  2. rubyconf 2019 SYLLABUS ‣ COMPLEXITY ‣ INSERTION SORT ‣ QUICK

    SORT ‣ BUCKET SORT ‣ LONGEST COMMON SUBSEQUENCE ‣ MINIMUM SPANNING TREE ‣ SHORTEST PATH ‣ MAX FLOW
  3. 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
  4. rubyconf 2019 COMPLEXITY O(1) O(log n) O(n) O(n log n)

    O(n²) great! ok hmmm uffda oh no
  5. 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
  6. 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
  7. 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
  8. 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 github.com/CoralineAda/alice
  9. 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)
  10. 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
  11. 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
  12. 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)
  13. 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 adj[u.name].each_pair do |v, w| 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)
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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 *|)
  19. 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/