INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM
ICS102, SECTIONS 52, 54 & 55
(001 Semester)
INTRODUCTION TO COMPUTING
LAB #08 More on Methods with Parameters and Recursion
Instructor: Bashir M. Ghandi
To gain experience with:
All the methods we saw in the last lab involved only
primitive types as parameters. However,
objects can be passed as parameters to a method. In fact, we have been passing object as parameters in our programs. For example, each time the draw
or fill method of the Graphics/Grapics2D class is called,
a graphic shape object is passed as a parameter.
Rectangle square = new
Rectangle(10,10,50,50);
g2.fill(square).
This means the fill method of the Graphics
class must have been declared similar to:
public void fill (Rectangle rect)
However, there is one fundamental difference between
passing an object as parameter and passing a primitive type as parameter. Before we examine this difference, let us
first understand what exactly happened when a primitive type variable is
declared and when an object variable is created.
We recall that if a variable of primitive type is
declared, memory is allocated for the variable depending on its type.
E.g. int age; à
if we now assign a value to the variable, the value
is stored in the memory:
E.g. age=30; à
On the other hand, when an
object variable is declared, the memory that is allocated is only enough to
hold the address (some times called reference) of the object. The memory for the actual object, which will
contain its fields and method is not allocated until the object is created.
E.g. Rectangle square; à
Now, if an object is created using: new
Rectangle(10, 10, 50, 50);
Then memory is created for the object to hold all
the fields and methods of the object.
The address of the first byte of that memory (say location 1000) is
stored in the reference variable square.
It is important to note that the variable square
is not the object. It is only a
reference (the address) of the object.
Now the difference between passing primitive types
and objects as parameters is that primitive types are passed by value,
while object are passed by reference.
Thus, in case of primitive types, the value of the actual
parameter is copied to the formal parameter and any change to the formal parameter
will not affect the actual parameter.
In case of objects however, it is the address
of the actual object that is copied to the formal parameter. Now since the called method has access to
the address of the actual objects, it can use that to access and modify the
state (fields) of the actual object if it so wish.
Example 1: The
following program passes two integer values to a method swap so that the
two values are interchanged. At first
glance it appeared as if it will work, but actually it doesn’t since the
changes in the method do not affect the actual parameters.
import java.io.*; import TextIO; class SwapPrimitives { static
TextIO inputStream = new TextIO(System.in); static
void swap(int first, int second) { int temp; temp=first; first=second; second=temp; } public
static void main (String[] args) throws IOException { int num1, num2; System.out.print("Enter
two integer numbers:"); num1 =
inputStream.readInt(); num2 =
inputStream.readInt(); System.out.println("\nValues
before swapping are: "+num1+" and "+num2); swap(num1,
num2); System.out.println("Values
before swapping are: "+num1+" and "+num2); } } |
To solve this problem, we
can create objects containing the integer numbers and pass them to the swap
method instead. Before we do this, we
briefly introduce how to create classes that can be use to create objects.
The classes we have
written so far are all static classes.
That is, they contain only static methods, thus, they cannot be used to
create objects. While we cannot
completely avoid the use of static classes, their use is in fact bad as far as
object-oriented approach to problem solving is concerned. This approach, is primarily about working
with objects, thus, we should as much as possible try to create classes that
can be used to create objects rather than static classes. We shall learn more about this in Lab # 11,
for now let us introduce the things we need to know to create these types of
classes.
Variables and
Methods should be non-static:
When creating object
classes, we must declare the variables and methods that we wish to belong to
objects as non-static. That is,
they should not have the word static in their
definition. Such variables and methods
are usually called instant variables and instant methods, as they
only exist when an object of the class is created.
Constructors:
When an object is
created, the instant variables of the object are automatically initialized to
some default values (e.g. 0 for numeric variables). If we want to initialize these variables with different values,
then we have to declare what is called a constructor. Constructors are similar to methods except
for the following:
·
They do not have any
return type (not even void)
·
Thy must have the same
name as the class
There can be any number
of constructors for a class provided each has a different signature (different
formal parameters).
Example 2: The following example solves the swapping problem
by first defining a class containing an integer variable and passing objects of
this class to the swap method.
import TextIO; class MyInteger { int n; public
MyInteger(int number) { n=number; } } public class SwapObjects { static TextIO inputStream = new
TextIO(System.in); static void swap(MyInteger first,
MyInteger second) { int temp; temp=first.n; first.n=second.n; second.n=temp; } public
static void main (String[] args) throws IOException { int num1, num2; System.out.print("Enter
two integer numbers:"); num1
= inputStream.readInt(); num2
= inputStream.readInt(); MyInteger
intObject1 = new MyInteger(num1); MyInteger
intObject2 = new MyInteger(num2); System.out.println("\nValues
Before swapping are: "+num1+" and "+num2); swap(intObject1,
intObject2); System.out.println("Values
After swapping are: "+intObject1.n+" and "+intObject2.n); } } |
So far, we have seen that the execution of an application begin
with the main method, which may call other methods, which may call other
methods, etc.
Now Java also allows a method to call itself. This is called recursion and such
methods are called recursive methods.
Recursion is essentially another way of performing iteration and
it is a very powerful tool for simplifying algorithms and coding of methods
that involve repetitions.
A well-defined recursive method has:
·
a base case.
·
a recursive
step, which must always get “closer” to the base case from one invocation to
another.
Each call to a recursive method sets up a new execution
environment, with new parameters and local variables.
When the method completes, control returns to the method that
invoked it (which may be an earlier invocation of itself).
Example 3: The following is a recursive method that computes the factorial of an integer n. Notice that the method looks very similar to the mathematical definition. This elegance is one of the beauty of recursion.
.import
java.io.IOException; import TextIO; class Factorial
{ static TextIO inputStream = new
TextIO(System.in); public static int factorial(int n) { if
(n == 0) return 1; else
return n*factorial(n-1); } public static void main (String[] args)
throws IOException { int n, answer; System.out.print("Enter
an integer:"); n
= inputStream.readInt(); answer
= factorial(n); System.out.println("The
factorial of "+ n + " is " + answer); } } |
Factorial: A Sample Trace
factorial (6) = (6*factorial(5))
= (6*(5*factorial(4)))
=
(6*(5*(4*factorial(3))))
=
(6*(5*(4*(3*factorial(2)))))
=
(6*(5*(4*(3*(2*factorial(1))))))
= (6*(5*(4*(3*(2*1)))))
= (6*(5*(4*(3*2))))
= (6*(5*(4*6)))
= 6*(5*24))
= (6*120)
= 720
Example 4: The following is a recursive method that computes the nth fibonacci number which is defined as follows:
|
1 for n=0 |
|
|
|
fibonacci(n) = |
1 for n=1 |
|
|
fibonacci(n-1)+fibonacci(n-2) for n>1 |
|
|
|
|||
import
java.io.IOException; import TextIO; class Fibonacci
{ static
TextIO inputStream = new TextIO(System.in); static
int fibonacci (int num) { if (num == 0 || num == 1) return 1; else
return
(fibonacci(num-1) + fibonacci(num-2)); } public static void main (String[] args)
throws IOException { int
n, answer; System.out.print("Enter an
integer:"); n = inputStream.readInt(); answer = fibonacci(n); System.out.println("The
"+n+ "th Fibonacci number is: "+ answer); } } |
|||
The next example
requires the knowledge of some methods of the standard class String. We shall study String in detail in the next
lab, but for now, here are some of its basic methods.
length() |
returns the
number of characters in the string |
charAt(n) |
returns the
character at position n assuming the first character is at position 0. |
substring(n) |
returns a
string starting from position n to the end of the string (again counting is
assumed to begin from 0) |
substring(n1,n2) |
returns a tring
starting from n1 to n2-1. |
equals(stringvar) |
returns true if
this string is eqaul to the string in stringvar. (Note:All objects are
compared using this method) |
Example 3: The following example is a recursive method that checks whether a character is contained in a string
.import
java.io.IOException; import
java.io.*; import TextIO; class Member { static
TextIO stdin = new TextIO(System.in); static
boolean isMember(char ch, String str) { if (str.length()==0) return false; else
if (ch == str.charAt(0)) return true; else
return isMember(ch,
str.substring(1)); } public static void main (String[] args)
throws IOException { char
ch; String
str; System.out.print("Enter your
string (one word!): "); str = stdin.readString(); System.out.print("Now enter
the character you wish to search for: "); ch = stdin.readChar(); if (isMember(ch, str)) System.out.println(ch
+" Is a member of "+str); else System.out.println(ch
+" Is NOT a member of "+str); } } |
1. Write a recursive method sum(int n) that
receives a parameter n as a parameter and returns the sum of the
following series:
1 + 2 + 3 + 4 + . . .+ n
Write a main method
that reads an integer from the user and calls your method to compute the sum
and print the result.
2.
Write a recursive method
power(double x, int n) that returns xn (Note:
do mot use Math.pow method. Write a main
method that reads input from the user and calls your method to get the power and
prints the result.
3.
The greatest common
divisor (gcd) of a number can be defined recursively as follows:
|
m if m<=n
and m divides n |
gcd(n, m) = |
gcd(m, n) if
m>n |
|
gcd(m, n%m) if n>m and m does not divides n |
|
|
Write a
recursive method gcd(int n, int m) that returns the gcd of two
numbers. Write a main
method that reads two integer numbers and calls your method to compute the gcd
and print the result.
4.
A palindrome is a string
that reads the same way both backwards and forwards. Example is madam.
Write a boolean method isPalindrome(String s) that
receives a string and returns true if the string is a palindrome and false
otherwise. Write a main method
that reads a word from the user and prints a message stating whether or not the
word is a palindrome.
|
|