Gucs Sample Chapter2
Gucs Sample Chapter2
Computer Science
Chapter 2
Yin Wang
B: Right.
A: It seems that you have learned the concept set. Yes, you may think
of a data type as a set.
B: But I didn't learn much about sets. Actually I forgot most of it.
A: Don't worry. Think about the concept "clothing", which includes all
kinds of clothes. You may think of clothing as a set. Similarly, when we
talk about "humans", we mean the set containing you, me and all
other people. Human is also a set.
B: A set feels like a bag of things.
A: Yes, but this "bag" is not physical. It does not physically contain
things. It is something abstract. It lives in our head.
B: Now I have a better understanding of the word abstract.
2 > 3
B: I noticed that 2 > 3 and 2 < 3 look very much like 2 * 3. There are
2 and 3, and an operator (>, < or *) in the middle.
var y = 2 * 3;
y < 8 // y is less than 8
B: What are those double slashes // ?
A: Yes. You may read the comments, but you don't need to type them
into console. Now try them and let me know what are the values of
those comparison expressions.
B: They are either true or false.
A: Here true and false are called boolean values. They are values of
the boolean data type. We call true, false, 2 < 3, 3 == 3 etc. boolean
typed expressions.
B: Why do we write == for equality? Why not just =?
A: This is because the single equal sign = has already been used for
variable de nitions, for example var x = 2 * 3, so we have to use
some other symbol for equality. JavaScript chose to use ==, so did
many other languages.
B: I see. = and == look quite similar.
A: Yes, so you must be very careful. Never write = when you mean ==,
otherwise you may cause dangerous bugs (computer term for
mistakes).
B: What bugs can this cause?
A: There are no other values in the boolean data type, except true and
false.
A: Actually we can say "boolean type" for short of boolean data type.
Can you draw a picture of the boolean type, similar to the picture of
the number type?
B: Here it is, a bag containing just true and false.
fi
A: Very good. Boolean is essential for conditional branches. That is
why I introduce them rst.
B: What is a conditional branch?
function abs(x)
{
if (x < 0)
{
return -x;
}
else
{
return x;
}
}
A: You may think of the orange part in English: "If (x is less than 0),
then {the value of abs(x) is -x}, otherwise {the value of abs(x) is x}."
B: That makes more sense now. It is not very different from English.
if (condition)
{
fi
// code to be executed when condition is true
}
else
{
// code to be executed when condition is false
}
A: We use the value of the condition to decide which way to go, so the
condition must be evaluated before we take one of the branches.
B: There seems to be an order of evaluation. Some expressions must be
evaluated before others.
A: You can create functions that return boolean values too. For
example, you can de ne a function which will return true if the input
temperature (temp) is over 30 celsius.
function hot(temp)
{
return temp > 30;
}
A: Exactly the same idea, very clever! Now we go on. We will write a
bigger function with three branches in it. This function sign will
return the sign of its input number. For example:
fi
fi
fi
sign(-4) returns -1
sign(4) returns 1
sign(19) returns 1
sign(-28) returns -1
sign(0) returns 0
function sign(x)
{
if (x < 0)
{
return -1;
}
else
{
// ...
}
}
The conditional branch statement can have only two branches, but
here we have three cases: negative, zero and positive.
B: Nice. A branch of a river can have branches too. This means I can
write this?
function sign(x)
{
if (x < 0)
{
return -1;
}
else
{
if (x == 0)
{
return 0;
}
else
{
return 1
}
}
}
A: There is a special syntax rule which we may use here. The rule is
that whenever you have an if immediately inside the else branch, you
may omit the braces for the else branch.
For example, in the above code you may delete these braces (marked).
if (x < 0)
{
return -1;
}
else
{
if (x == 0) // branch immediately inside else
{
return 0;
}
else
{
return 1
}
}
After that, you may put the second if next to the else, so it looks like
"else if".
if (x < 0)
{
return -1;
}
else if (x == 0)
{
return 0;
}
else
{
return 1
}
A: But remember that this simpli cation requires that no other code
goes between else and if, otherwise you have to write the braces.
B: Got it.
fi
A: So we have nished learning conditional branches.
B: There are four basic building blocks now. Variable, function, call and
conditional branch.
A: Yes. Just four of them. Now we proceed and use them to write
programs that were not possible before.
B: Exciting!
The factorial of 5 is 5 * 4 * 3 * 2 * 1.
The factorial of 4 is 4 * 3 * 2 * 1.
The factorial of 3 is 3 * 2 * 1.
And so on...
function fact(n)
{
// TODO
}
Is it true that 5! = 5 * 4! ?
B: Yes.
A: Is it true that 4! = 4 * 3! ?
B: Yes.
A: Right. Can you translate the above math de nition of factorial into
JavaScript?
B: Here it is
fi
fi
fi
fi
fi
function fact(n)
{
if (n == 0)
{
return 1;
}
else
{
return n! = n * (n - 1)!;
}
}
A: That is not right. "We have n! = n * (n - 1)!" doesn't mean that you
just write return n! = n * (n - 1)!. Do you see the problem?
B: Oh, I forgot. n! is math's language. In JavaScript we write fact(n)
for n!, so (n - 1)! should be written as fact(n - 1). The last line should
be
A: This is still not correct. Remember that after the return, you should
write an expression that is the output value of the function, but fact(n)
= fact(n - 1) is not even a valid expression in our language. It is a
syntax error.
function fact(n)
{
if (n == 0)
{
return 1;
}
else
{
return n * fact(n - 1);
}
}
A: Correct.
A: The branch without recursive call is called a base case. Here fact has
one base case (n == 0), but other functions may have more than one
base cases.
B: What do you call the branches with recursive calls?
A: Yes. A base case is where the function stops calling itself, so you
must have at least one base case, otherwise the function will keep
calling itself and go into in nite loops.
B: Can we demonstrate how this could happen?
A: Yes, you can. Try deleting the base case of fact, leaving only the
recursive case. Then do substitutions repeatedly on fact(5).
B: The erroneous fact function looks like this:
function fact(n)
{
return n * fact(n - 1);
}
(Write your substitution of fact(5) using the erroneous de nition, and send
it to the teacher.)
A: Now you can clearly see that you must have a base case.
B: Yes.
A: You may use our old friend substitution for this. First do a
substitution of fact(3). Of course this time we use the correct
de nition of fact.
B: Like this?
if (3 == 0)
{
return 1;
}
else
{
return 3 * fact(3 - 1);
}
A: For our purpose, you may further reduce this. For example, here 3
== 0 must be false, so you can just go to the else branch and have 3 *
fact(3 - 1). Because you know 3 - 1 is 2, you can reduce the whole
thing to
3 * fact(2)
fact(3)
3 * fact(2)
3 * 2 * fact(1)
3 * 2 * 1 * fact(0)
3 * 2 * 1 * 1
6
B: 3 * 2 ?
fact(3)
(3 * fact(2))
fi
fi
(3 * (2 * fact(1)))
(3 * (2 * (1 * fact(0))))
(3 * (2 * (1 * 1)))
b(0) is 0
b(1) is 1
b(2) = b(0) + b(1), which is 1
b(3) = b(1) + b(2), which is 2
b(4) = b(2) + b(3), which is 3
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
b(5) is b(3) + b(4), which is 5
b(6) is b(4) + b(5), which is 8
b(7) is b(5) + b(6), which is 13
b(8) is b(6) + b(7), which is 21
... ...
B: Here it is.
function fib(n)
{
if (n == 0)
{
return 0;
}
else if (n == 1)
{
return 1;
}
else
{
return fib(n - 2) + fib(n - 1);
}
}
A: Perfect. Can you tell me how many base cases and recursive calls are
there?
B: Two bases. Two recursive calls.
A: Think about this. We need to compute the other numbers from the
previous two numbers. The recursion will end up needing the values
of fib(0) and fib(1), so you can't have just one base case.
B: Is there a systematic way in which I can know how many base cases
to write?
A: The trick is to look at the recursive calls. See how the recursive
call's input parameters are different from the function's parameters,
and then gure out the values in which they end up.
B: I don't understand this.
A: Can you see that our way of writing the fib function has a big
problem?
B: Does it also take a lot of storage space, like fact?
A: Not exactly the same problem. You can use fib(4) as an example,
try drawing a graph showing the substitutions of the recursive calls.
Draw an arrow connecting each recursive call to its substitution.
B: I can draw it like this. Because there are two recursive calls, the
graph seems to be "branching" into a tree.
A: Right. Try expanding this graph into a graph for fib(5), and again
see how many times fib(2) is evaluated.
B: Three times. The number of times we evaluate fib(2) seems to be
growing with bigger fib(n).
A: Now that we see the examples of fib(4) and fib(5), try to gure
out a general formula in which the number of repeated evaluation of
fib(2) grows with n. For example, is it 2n, n2, or 2n ? If you have no
clue, try extending our previous examples. Draw a graph of fib(6),
fib(7), and so on.
A: Try redraw a picture for fact(3), in the style you just did for
fib(4).
B: Here it is. I can see that the graph for fact(3) has no branching. It is
more like a chain, not a tree.
A: Tree recursion may not always be costly, and it is often the only
way to write certain programs.
B: Some teachers told me that recursion is slow and should be avoided
or converted to other ways, for example loops.
A: Okay. That's all for today's class. Here are the exercises.
B: Thank you. Have a good night!