Logo
  • Home
  • Classes
  • Conveying Computing
  • Exams
  • Fractal Gallery
  • Guides
  • Problem Sets
  • Syllabus

PS5 Comments

Question 1: For each g and f pair below, argue convincingly whether or not g is (1) in O(f), (2) in Ω(f), and (3) in Θ(f) as explained above. For all questions, assume n is a non-negative integer.
  1. g: n + 3, f: n
    Answer:
    1. n + 3 is in O (n).

      Choose c = 2 and n0 = 3. Then, we have (n + 3) ≤ 2n which simplifies to 3 ≤ n which is true for all n ≥ 3.

    2. n + 3 is in Ω (n).

      Choose c = 1 and n0 = 0. Then, we have n + 3 ≥ n which is true for all n.

    3. n + 3 is in Θ(n) since we showed it was in O(n) and in Ω(n).
  2. g: n2 + n, f: n2
    Answer:
    1. n2 + n is in O(n2).

      Choose c = 2 and n0 = 1. Then, we have (n2 + n) ≤ 2n2 which simplifies to n ≤ n2 and 1 ≤ n, which is true for all n > 1.

    2. n2 + n is in Ω(n2).

      Choose c = 1 and n0 = 0. Then we have (n2 + n) > n2 which is true for all n > 0.

    3. n2 + n is in Θ(n2) since we showed it was in O(n2) and in Ω(n2).
  3. g: 2n, f: 3n
    Answer:
    1. 2n is in O(3 n).

      Choose c = 1 and n0 = 0. Then we have 2n ≤ 3n which is true for all n > 0.

    2. 2n is not in Ω (3n).

      Since 3n grows faster than 2n for any choice of c, we can always find a value m such that 2n < c * 3n for all n > m.

      Recall that 2n is 2 * 2 * 2 * ... (n times) and 3n is 3 * 3 * 3 ... (n times). So, we need to choose n such that c * 3 * 3 * 3 ... (n times) is greater than 2 * 2 * ... (n times). Each time we increase the value of n by one, the value of c3n / 2n is multiplied by 1.5. After some number of multiplications, it must be greater than 1.

    3. 2n is not in Θ (3 n) since in (2) we argued it is not in Ω (3 n).
  4. g: 2n, f: nn
    Answer:
    1. 2n is in O (nn).

      Choose c = 1 and n0 = 2. Then, we have 2n ≤ nn for all n ≥ 2.

    2. 2n is not in Ω (n n).

      Since nn grows faster than 2n for any choice of c, we can always find a value m such that 2n < cnn for all n > m. For example, we can choose n = 1/c + 1.

      Then, cnn = c1/c1/c + 1 = 1/c1/c. Since c must be less than 1/2 (otherwise n = 3 would work), we know 1/c > 2, and 1/c1/c ≥ 21/c.

    3. 2n is not in Θ (n n) since in (2) we argued it is not in Ω (3 n).
  5. g: the federal debt n years from today, f: the US population n years from today (this one requires a more informal argument)
    Answer: This one merits a longer discussion that will be in a future lecture (after you have read Tyson's Science's Endless Golden Age).
Question 2:

a. Draw the global environment after the following expressions are evaluated:

   (define t1 (mcons 'name 'email))
   (set-mcar! t1 'nom)
   (set-mcdr! t1 'courriel)
   (set-mcdr! t1 t1)
Answer: The global environment contains all the Scheme primitives, but we only show the new definitions. The only important one for this question is t1 which is defined as (mcons 'name 'email). The value of t1 is an mcons cell where, at first, the mcar is 'name and the mcdr is 'email. The (set-mcar! t1 'nom) expression replaces the value of the mcar part of t1 with 'nom. Next,(set-mcdr! t1 'courriel) replaces the value in the mcdr part of t1 with the value of 'courriel. Finally,(set-mcdr! t1 t1) replaces the value in the mcdr part of t1 with the value of t1. The value of t1 is the mcons cell t1 points to.

Hence, the global environment looks like:

b. Suppose we then evaluate (mlist-length t1) where mlist-length is defined as in Section 9.3. Explain why the evaluation of (mlist-length t1) never terminates.
Answer: Looking at the diagram, we see that the mcdr of t1 is t1. So, every time we evaluate (mcdr t1) we get t1. We can keep evaluating mcdr forever, but never get to null.
Question 3:

a. Define post-item! as a procedure that takes two parameters (name, description) and adds an entry with the given name and description to the items table.

Answer:
(define (post-item! name description)
  (table-insert! items (list name description)))
b. Describe the running time of your post-item! procedure. Your answer should use Θ notation, clearly explain what all variables you use mean, and include a convincing explanation of why your answer is correct.
Answer: The running time of post-item! as defined above is in Θ (Nitems) where Nitems is the number of entries in the items table.

The body of post-item! is (table-insert! items (list name description)). The (list name description) evaluation is constant time since the time it takes to make a cons cell does not depend on the sizes of its inputs. The table-insert! procedure is defined as:

(define (table-insert! table entry)
  ;;; The entry must have the right number of values --- one for each field in the table
  (assert (= (length entry) (length (table-fields table))))
  (if (null? (table-entries table))
      (set-mcdr! (tlist-get-data 'table table) (mlist entry))
      (mlist-append! (table-entries table) (mlist entry)))
  (void)) ;;; don't evaluate to a value
The assert involves two applications of length, which (at least as we defined list-length) has running time in Θ(N) where N is the length of the input list. Here, the inputs are both fixed sizes, so the running time is constant. The evaluations of (table-entries table), (set-mcdr! (tlist-get-data 'table table) (mlist entry)), and (mlist entry) are also all constant time. They do not depend on anything whose size varies. So, we only need to consider the evaluation of (mlist-append! (table-entries table) (mlist entry))). The running time of mlist-append! is linear in the length of its first input (as analyzed in class, we need to mcdr down the first input list until we find the last mcons cell). In this case, that is the number of entries in the table. The table passed into table-insert! is items, so the total running time is in Θ (Nitems) where Nitems is the number of entries in the items table.
Question 4:

a. Define insert-bid! as a procedure that takes three parameters (bidder, item and amount) and adds a corresponding entry to the bids table.

Answer:
(define (insert-bid! bidder item amount)
  (table-insert! bids (list bidder item amount)))
b. Describe the running time of your insert-bid! procedure. Your answer should use Θ notation, clearly explain what all variables you use mean, and include a convincing explanation of why your answer is correct.
Answer: The analysis is similar to that for post-item! in the previous question.

Our insert-bid! procedure applies table-insert! to the bids table and the new bid. Creating the new bid using list and the three operands is in Θ(1). The table-insert! procedure includes (mlist-append! (table-entries table) (mlist entry))). The mlist-append! procedure, defined in Example 9.4, has a running time in Θ(N) where N is the number of elements in the first input list. Hence, insert-bid! has running time in Θ(Nbids) where Nbids is the number of entries in the bids table.

Question 5:

a. Define the table-select procedure.

Answer:
(define (table-select table field predicate)
   (let ((fieldno (table-field-number table field)))
      (if (= fieldno 0) (error "No matching field" field)
          (make-table (table-fields table)
                      (mlist-filter
                          (lambda (entry) (predicate (list-get-element entry fieldno)))
                          (table-entries table)))))
b. Describe the asymptotic running time of your table-select procedure using Θ notation. Be careful to specify carefully what any variables you use in your answer mean.
Answer: If the number of fields in the table is constant, the table-select procedure we defined has running time in Θ(Ntable) where Ntable is the number of entries in the table argument.

The make-table, table-fields and table-entries are constant time. The mlist-filter procedure needs to look at every element in its input list, so its running time is in Θ(N) where N is the number of elements in the input list. This assumes the filter input procedure is constant time. If the number of fields in the table is constant, then that is the case. Thus, the total work is in Θ(Ntable) where Ntable is the number of entires in the input table.

If the number of fields is not constant, then we need to consider how the work required by table-field-number and list-get-element scales with the selected field. Both procedures need to cdr down a list until the matching entry is found. Hence, they have running times in Θ(M) where M is the number of elements in the input list.

As it is used in table-select it is the number of fields in the table in both cases. Hence, the total work is in Θ(NtableFtable) where Ntable is the number of entries in the table argument and Ftable is the number of fields in the table argument. In most cases, though, it would be reasonable to assume the number of fields is bounded (since we don't usually add more fields to a table), hence the running time is in in Θ(Ntable).

Question 6:

a. Define a get-highest-bid procedure that takes an item name as a parameter and evaluates to the bid entry that is the highest bid on that item. If there is no bid, return null. You shouldn't assume that the last entry that is a bid on this item is the highest bid for that item.

Answer:
(define (get-highest-bid item)
  (let ((fieldno (table-field-number bids 'amount))
        (entries (table-entries (table-select bids 'item-name (make-string-selector item)))))
    (if (null? entries) null
        (mlist-find-best 
         (lambda (bid1 bid2)
           (> (list-get-element bid1 fieldno) (list-get-element bid2 fieldno)))
         entries))))

b. Describe the asymptotic running time of your get-highest-bid procedure using Θ notation. Be careful to specify carefully what any variables you use in your answer mean.

Answer:

The get-highest-bid evaluates (get-bids item). This selects matching bids from the bids table. Since table-select has running time in Θ(Ntable) where Ntable is the number of entries in the table (question 5b), this has running time in Θ(Nbids) where Nbids is the number of entries in the bids table.

The length of the resulting list is on average (/ Nbids Nitems) since all bids are for items in the table. Since the length of the list is Nbids/Nitems, the work required by the get-highest-bid procedure is in Θ(Nbids/Nitems).

But, get-highest-bid has to do both the work of get-bids and then get-highest-bid, so its total work is in Θ(Nbids + Nbids/Nitems ). Since Nitems is positive, the first term will dominate in the asympotitic operator, so the running time is in Θ(Nbids).

Question 7: Define a place-bid! procedure that satisfies the description above. Don't attempt to do everything at once! Start by satisfying one of the properties first and testing your procedure before trying to satisfy the other property.

Answer:
(define (place-bid! bidder item amount)
  (let ((bidder-entry (table-entries 
                       (table-select bidders 'name 
                                     (make-string-selector bidder))))
        (item-entry (table-entries 
                     (table-select items 'item-name 
                                   (make-string-selector item))))
        (highest-bid (get-highest-bid item)))
    (if (= (mlength bidder-entry) 0)
        (error bidder " is not a legitimate bidder!")
        (if (> (mlength bidder-entry) 1)
            (error "Multiple matching bidders named: " bidder)
            (if (= (mlength item-entry) 0)
                (error item " is not for sale!")
                (if (> (mlength item-entry) 1)
                    (error "Multiple matching items: " item)
                    (if (or (null? highest-bid) 
                            (> amount (list-get-element highest-bid (table-field-number bids 'amount))))
                         (begin (insert-bid! bidder item amount) true)
                         (error "Bid amount does not exceed previous highest bid: " highest-bid))))))))
Question 8:

a. Define a procedure end-auction! that reports the final auction results. You may assume that the auction has been conducted fairly (i.e., using place-bid! and not by randomly mutating the tables). For each item in the auction, your procedure should print out a message indicating who won the item and for what price, or that there were no bits on the item.

Answer: We use the built-in mmap which is like map for mutable lists (or mlist-map! defined in Example 9.2).

(define (end-auction!)
  (mlist-sum
   (mmap
    (lambda (item-entry)
      (let ((item-name (list-get-element item-entry (table-field-number items 'item-name))))
        (let ((high-bid (get-highest-bid item-name)))
          (if (null? high-bid)
              (begin
                (printf "No bids on ~a.~n" 
                        (list-get-element item-entry 
                                          (table-field-number items 'item-name)))
                0)
              (begin
                (printf "Congratulations ~a!  You have won the ~a for $~a.~n"
                        (list-get-element high-bid (table-field-number bids 'bidder-name))
                        item-name
                        (list-get-element high-bid (table-field-number bids 'amount)))
                (list-get-element high-bid (table-field-number bids
		'amount)))))))
    (table-entries items))))

b. Describe the running time of your end-auction! procedure. (You answer should use Θ notation, should clearly define the meaning of all variables you use in your answer, and should include a convincing explanation of why it is correct.)

Answer: The work required by end-auction! depends on both the number of items and the number of bids. We define these as Nitems and Nbids.

Our end-auction! procedure uses mmap with the input list (table-entries items). The mmap procedure has running time in Θ(N) where N is the number of elements in the input list. But, this assumes the amount of work done for each item is constant. In end-auction! it is not constant though! For each item, the mapping procedure evaluates (get-highest-bid item-name), as well as list-get-element twice. The list-get-element procedure has running time in Θ(V) where V is the value of its second parameter, since it needs to cdr down the list V times to find the Vth element. In both cases, V is constant though, since it is the result of (table-field-number bids 'bidder-name) or (table-field-number bids 'amount). Hence, we only need to worry about how much work (get-highest-bid item-name) requires.

As analyzed in question 6b, the running time of get-highest-bid is in Θ(Nbids).

Evaluating end-auction! evaluates get-highest-bid once for each item, so we need to multiply the number of items times the time for each item. Thus, the total running time is in Θ(Nitems × Nbids). Note that this should make us believe there is a more efficient way to implement end-auction!. It is doing some redundant work, since it looks through the entire bids table for each item (hence, looking at each bid Nitems times, instead of just once). It should be possible to implement end-auction! with running time in Θ(Nitems + Nbids), but this would be more complicated (and worth a gold star bonus!).

Print Friendly Print Get a PDF version of this webpage PDF

Leave a Reply Cancel reply

You must be logged in to post a comment.

cs1120 | RSS | Comments RSS | Book | Using These Materials | Login | Admin | Powered by Wordpress