Class 24: Slides [PPTX], Notes [PDF], Code [RKT]
Here is the page with instructions on using ElevenLearning: http://www.cs.virginia.edu/cs1120/on-line-version-of-course-book. Please post your comments/suggestions on it there.
If you have comments/solutions/questions on the book exercises, you can post them directly as comments to this post.
For Exercise 9.4:
The value of (mlist-length pair) will be indeterminable. I say that the value will be indeterminable because the program will never end, or keep on going until the computer runs out of memory. The procedure will keep on evaluating pair until it gets to null. The only problem is, pair will never get to null because it is circular, with the cdr being itself. So the program will just keep on adding one for each recursive call, and it will keep on doing recursive calls because pair will never get to null.
Yes, that is correct.
I was just looking over the Orders of Growth in the textbook, and in Example 7.1, the end of the first example reads “This is true, since n-7>n+12 for all values n.” I was wondering if this was a mistake or if I misunderstood something?
Opps…this is a mistake. It should say, “This is true, since n-7 <= n + 12 for all values n.” Sorry for the confusion, its fixed now (in my development version).
Would the answer to exercise 9.6 look something like this?
(define (mlist-inc! p)
(if (null? p) null
(begin (+ mcar 1)
(mlist-inc! mcdr))))
Its on the right track, but won’t actually change anything about the input list. Instead of
(+ mcar 1)
, you want to modify the value of the mcar of p by usingset-mcar!
. Here’s a full definition:(define (mlist-inc! p)
(if (null? p)
(void)
(begin
(set-mcar! p (+ 1 (mcar p)))
(mlist-inc! (mcdr p)))))
The other change is to use
(void)
as the result for the base case to make it somlist-inc!
does not produce any value when it is evaluated.Although this is related to Question 1 from the problem set, I also believe it pertains to Exercise 7.9 from the book.
If we prove for functions g = (2^n) and f = (3^n) that g is not in Θf, then Θ(2^n) is not equivalent to Θ(3^n). So we must prove that g is in O(f) but not in Ω(f), which implies that g is not in Θf:
Choose c = 1, and n_0 = 1
(2^n) g is a member of the set O(f)
But no matter what values are chosen for c and n_0, we can find an n > n_0 such that the inequality (2^n) >= c(3^n) does not hold.
Given that (2^n) <= (3^n) for all n if c = 1 (stated above), then we must choose c = c(3^n). However, since c 1, such that c*(3^n) = (1/d)(3^n), which we can re-write as (1/d)(2^n)((3/2)^n). So if ((3/2)^n) = d, then the original inequality gives (2^n) >= (2^n), which is true. But, if we solve for n, then n = log_3/2 (d) = ln(d)/ln(3/2), so that any n we choose greater than ln(d)/ln(3/2) = ln(1/c)/ln(3/2) – where c and d are constants – invalidates the original inequality.
=> g is not a member of Ω(f)
Together => g is not a member of Θ(f), so Θ(g) is not equivalent to Θ(f)
The second paragraph should read
Choose c = 1, and n_0 = 1
(2^n) g is a member of the set O(f)
Choose c = 1, and n_0 = 1
“(2^n) g is a member of the set O(f)”
Choose c = 1, and n_0 = 1
(2^n) is less than or equal to (3^n) for all n
So g is a member of the set O(f)
Yes, this is the right overall strategy and it is correct that Θ(2n) is not equivalent to Θ(3n).
To prove two sets are not equal, all we have to do is find one element that is in one of the sets but not in the other set. Choosing f = 2n works. It is in Θ(2n). (We could prove this using the definition, but it follows obviously since it is clear that any function grows as fast as itself!) But, 2n is not in Θ(3n), as you proved above. I can’t quite follow the proof, though, but I think this is mostly because of the difficult in writing math in the limited HTML subset WordPress allows in comments.
Since 2n is in O(3n), to prove 2n is not in Θ(3n), we need to show that 2n is not in Ω(3n). To prove this, we need to show that no matter that values are selected for c and n0, we can select a value of n that invalidates the inequality required by the definition of Ω: for all n ≥ n0, 2n ≥ c × 3n. This is what you need to prove for Question 1c of PS5, so I’ll hold off on providing a full proof.
Possible solution to Exercise 9.1:
> (define x 2)
> ( * x (+ (nextx) x))
> 10 | 12 | 15 | 18 ;; four possible solutions
Yes, this works!
The possible evaluations are:
(nextx), xsecond, xfirst → 18
xsecond, (nextx), xfirst → 15
xfirst, (nextx), xsecond → 12
xfirst, xsecond, (nextx) → 10
Also, a question from today’s lecture – how does the make-list procedure we defined differ from the “insto” procedure back in chapter 5? In other words, would (make-list 5) evaluate to (list 1 2 3 4 5)?
The are, indeed, very similar. The way we defined
make-list
:(define (make-list n)
(if (= n 0) null
(cons 0 (make-list (- n 1)))))
it produces a list of n zeros. The only difference to make revintsto is the first input to cons:
(define (revintsto n)
(if (= n 0) null
(cons n (make-list (- n 1)))))
Making
intsto
(where the numbers are in order) is a bit more complicated, as explained in Example 5.8.When you post solutions, it would be helpful to have it in an alonzo-botesque format. That way I don’t have to see every solution before I input it, I can just see right or wrong on my answer with a little “give up” tab that will give me the answer to the exercise if I can’t get it after too many attempts.
Yes, this would definitely be useful, but not simple to produce. Perhaps an enterprising cs1120 student will want to work on this after the course!
Some questions about the proposed extension for the problem set: Do we need to submit attempted answers for ALL of the exercises in Chapter 9 including the gold starred ones? Or should we simply submit answers for the ones we’ve been having trouble with?
I would submit comments on the online version of the book, but I have never utilized it. I already have the downloaded pdf version and the physical copy and have assumed those two sufficient.
All you need to do is submit a useful comment. It can be about just one of the exercises, and can be either a proposed solution, or a question/attempt at a solution. (All of the other comments posted here appear to satisfy the intent of this.)
Exercise 8.1
list-sort-best-first best case input would be null, because at the beginning this would satisfy the if procedure base case, making it not need to run through the rest of the cases. This running time would be Θ(n) with n being the number of elements in the list, in this case being null so barely any time.
Its true that the input for which
list-sort-best-first
runs fastest would benull
, but this isn’t what is meant by best case input. (For nearly all procedures, the fastest-case input would always be the smallest input, so this isn’t usually an interesting question.)What we mean by best case input is the input of size N for which the procedure runs fastest. There are many different lists of length N, and the running time for
list-sort-best-first
will be different depending on properties of the input list. To answer the question, what you need to do is think about how the actual values in the input list impact the running time, and figure out what properties of the input elements will produce the fastest running time for a give input size.Thank you so much for allowing us to do this and bump the Problem Set! I’m extremely grateful for the extra few days~
For exercise 9.5
(define (mpair-circular? p)
(if (null? p) false
(if (eq? p (mcdr p))
true
(mpair-circular? (mcdr p))))
This works for some inputs…but not for all of them. It only detects the circularity when it is a one-element loop (that is, a mcons in the list has a mcdr that points to itself). But, there are lots of other ways an mlist could be circular. For example,
(define m1 (mlist 1 2 3))
(set-mcdr! (mcdr (mcdr m1)) m1)
Evaluating
(mpair-circular? m1)
should outputtrue
for this, but with your definition it will never finish evaluating!(Actually implementing
mpair-circular?
correctly is quite tricky, hence the gold star for this one.)exercise 9.6 possible solution:
(define (mlist-inc! lst)
(if (null? lst)
(error “Oops! That’s not a list”)
(set! lst (+ 1 (mcar lst))
(mlist-inc! (mcdr lst))))
could you also do this using a map/list-map procedure?
(define (mlist-inc! lst)(
if (null? lst)
(error “Opps! That’s not a list”)
(map (lambda (x) (+ 1 x)) lst))
would you run into any problems doing a recursive call doing it the other way because you are running it through with a changed list?
if that doesn’t actually mutate the elements of the original list, where does the new list get stored memory wise?
Yes, this is a good way to do it…except that
list-map
(and the built-inmap
) procedure only work on regular lists, they don’t work on mlists. You would need to use themlist-map!
procedure (defined in Example 9.2) for this. Then, you could do:(define (mlist-inc! p)
(mlist-map! (lambda (e) (+ e 1)) p))
Do you mean the definition I provided in the earlier comment? That doesn’t create any new mcons cells. It is just replacing the values in the elements of the mcons cells in the input list.
For exercise 9.7.
Assuming that we have a function mlist-reverse! that reverses a given list (I don’t know if I’m allowed to assume that) you can then (maybe) define mlist-truncate! as…
(define (mlist-truncate!)
(if (= 0 (car (mlist-reverse! p)))
(mlist-reverse!
(cdr (mlist-reverse! p)))
(error “list is circular”)))
it’s actually (if (null? (car (mlist-reverse p)))
I don’t really understand what you are trying to do here. Reversing the list might help since it makes it easier to find the next-to-last mcons, but this is a pretty awkward way to do this. Instead, I would suggest doing something more like what we did in class today with
find-last-mcons
, except here we need to find the next-to-last mcons (that is, the base case is when(null? (mcdr (mcdr p)))
, and remove the last element by doing,(set-mcdr! p null)
.I’m not sure if I totally understand the “while” procedure, but in the interest of providing a new problem that has not been submitted before, here is my attempt at problem 9.11
(define ( mlist-map! F p)
(while (lambda ()(> p null))
(begin (set-mcar! P (f (mcar p )))
(mlist-map! F (mcdr p)))))
This is on the right track, but the stopping test doesn’t quite make sense. I think you just mean
(lambda () (not (null? p)))
for this. Then, the body procedure would be similar to what you have, except there is no recursive call because of thewhile
. Instead, we update the value ofp
usingset!
:(define (mlist-map! f p)
(while
(lambda ()
(not (null? p))
(lambda ()
(set-mcar! p (f (mcar p)))
(set! p (mcdr p)))))