Skip to content
Snippets Groups Projects
Part2.scala 1.61 KiB
Newer Older
Matt Bovel's avatar
Matt Bovel committed
package midterm22

import scala.annotation.nowarn

// Questions 4-7

// See tests in midterm22.Part2Test.
// Run with `sbt testOnly midterm22.Part2Test`.

/*
Answers to the exam questions:
  When called with a Vector:
    The total amount of work is O(n), as it is dominated by the time needed to
    read the array. More precisely W(n) = c + 2*W(n/2) = O(n).

    The depth is O(log(n)), because every recursion takes constant time
    and we divide the size of the input by 2 every time, i.e. D(n) = c + D(n/2) = O(log(n)).

    Note however that in practice it is often still faster to manipulate
    start and end indices rather than using take and drop.

  When called with a List:
    Every recursion takes up to time O(n) rather than constant time.

    The total amount of work is O(n) times the number of recursion, because
    take and drop takes time O(n) on lists. Precisely, W(n) = n + 2*W(n/2) = O(log(n)*n)

    The depth is computed similarly: D(n) = n + D(n/2) = O(n), i.e.

Note: these are theoretical results. In practice, you should always double-check
that kind of conclusions with benchmarks. We did so in
`midterm-code/src/main/scala/bench`. Results are available in `bench-results`.
From these results, we can conclude that
1. Vectors are indeed faster in this case, and
2. parallelization of `contains` yields a 2x speedup.
 */
@nowarn
def contains[A](l: Iterable[A], elem: A): Boolean =
  val n = l.size
  if n <= 5 then
    for i <- l do
      if i == elem then
        return true
    false
  else
    val (p0, p1) = parallel(
      contains(l.take(n / 2), elem),
      contains(l.drop(n / 2), elem)
    )
    p0 || p1