Sunteți pe pagina 1din 45

Object-Oriented Design Running Time Recursion

- Ed. 2 and 3.: Chapter 2, 3 - Ed. 4: Chapter 2, 3, 4

Object-Oriented Design
In an object-oriented programming language, we are dealing with class and objects. Here we review briefly some major concepts of object-oriented programming.
Inheritance Polymorphism method overriding method overloading Keyword: this Exception Interface, Abstract Classes Casting

Inheritance Inheritance allows classes (subclasses) to use the members of another class (superclass) as their own members. We use the keyword extends to make a class a subclass of a superclass. Example:
public class SalaryEmployee extends NewEmployee { // class body }

Inheritance Inheritance allows classes (subclasses) to use the members of another class (superclass) as their own members. We use the keyword extends to make a class a subclass of a superclass. Example:
public class SalaryEmployee extends NewEmployee { // class body }

Polymorphism Polymorphism adds flexibility to the programming. Java provides two kinds of polymorphism: method overriding and overloading. override: A method of a superclass is re-defined in the subclass. Example:
class S { //. . . public void a() { // . . . } } class T extends S { //. . . public void a() { // . . . } }

overloading: A method name is used by more than one method in the same class. Example:
class T { // . . . public int a() { // . . . } public void a( int x ) { // . . . } }

The Keyword this In Java, the keywork this is a reference to the current object. We may see code like the example below.
class T { private double x; public T() { this( 0.0 ); } public T( double y ) { x = y; } }
class S { int x, y;

public void a(int x, int y){ this.x = x; this.y = y; }


}

Exceptions In Java, exceptions are objects that can be thrown and then caught. Example: void a() throws myException { //. . . if( . . . ) { throw new myException( "Error" ); } } class B { // . . . public int b() { try { // . . . a(); } catch( myException e ) { // do something } } }

Because an exception is a class, we need also a file that contains this class. Example:
class myException extends RuntimeException { public myException() {} public myException( String s ) { super( s ); } }

An example:
import java.lang.*; //Here we define some exception types of our own. //Exception classes generally have constructors but no data //or other methods. All these do is call their superclass //constructors. class MyException extends Exception { public MyException() {super();} public MyException(String s) { super(s); } } class MyOtherException extends Exception { public MyOtherException() { super();} public MyOtherException(String s) { super(s); } }

class MySubException extends MyException { public MySubException() { super(); } public MySubException(String s) { super(s); } } public class Throwtest { //This is the main() method. Note that it uses two //catch clauses to handle two standard Java exceptions. public static void main(String argv[]) { int i = 2;

//First, covert our argument to an integer. //Make sure we have an argument and that it is convertible. try { i = Integer.parseInt(argv[0]); } catch (ArrayIndexOutOfBoundsException e) {//argv is empty System.out.println("Must specify an argument"); return; } catch (NumberFormatException e) {//argv[0] is not an integer System.out.println("Must specify an integer argument"); }

//Now, pass that integer to method a(). a(i); }


//This method invokes b(), which is declared to throw //one type of exception. We handle that one exception. public static void a(int i) { try { b(i); }

catch (MyException e) { //Point 1 //Here we handle MyException and its subclass MySubException if (e instanceof MySubException) System.out.print("MySubException: "); else System.out.print("MyException: "); System.out.println(e.getMessage()); System.out.println("Handle at point 1"); } }

public static void b(int i) throws MyException { int result; try { System.out.print("i = " + i); result = c(i); System.out.print(" c(i) = " + result); } catch (MyOtherException e) { //Point 2 //Handle MyOtherException: System.out.println("MyOtherException: " + e.getMessage()); System.out.println("Handle at point 2"); } finally { //Terminate the output we printed above with a newline. System.out.print("\n"); } }

public static int c(int i) throws MyException, MyOtherException { switch (i) { case 0: //processing resumes at point 1 above throw new MyException("input too low"); case 1: //processing resumes at point 1 above throw new MyException("input still too low"); case 99: //processing resumes at point 2 above throw new MyOtherException("input too high"); default: return i*i;}}}

If you use JCreator to compile and run your program, the above program Should be changed as follows: import javax.swing.JOptionPane; public static void main(String argv[]) { int i = 2; try {i = (int) new Integer(JOptionPane.showInputDialog("Enter an integer"));}

try { i = Integer.parseInt(argv[0]); }

Interfaces Java provides a structure called interface for the implementation of application programming interface (API). An interface defines the methods that a class must implement. If a class implements a given interface, it must have all the methods defined in the interface. Example:
public interface CarDriver { public static final int speed = 100; public Reading panel(); public void shiftGear( int n ); public void brake( int n ); public void fuel( int n ); }

public class pickupTruck implements CarDriver { // . . . public Reading panel() { // . . . return rd; } public void shiftGear( int n ) { // . . . } public void brake( int n ) { // . . . } public void fuel( int n ) { // . . . } }

An example:
import java.util.*; import java.lang.*;

interface CanFight { void fight ( );} interface CanSwim { void swim ( );} interface CanFly {void fly ( );}
class ActionCharacter { public void fight( ) { }} class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void fight ( ) {System.out.println(Can fight!);} public void swim ( ) {System.out.println(Can swim!); } public void fly ( ) {System.out.println(Can fly!);} }

public class Adventure { static void t(CanFight x) { x.fight();} static void u(CanSwim x) { x.swim();} static void v(CanFly x) { x.fly();} static void w(ActionCharacter x) { x.fight();} public static void main (String[ ] args) { Hero h = new Hero( ); t(h); //Treat it as a CanFight u(h); //Treat it as a CanSwim v(h); //Treat it as a CanFly w(h); //Treat it as an ActionCharacter } }

ActionCharacter subclass Hero

CanFight implementation

CanSwim

CanFly

instantiation h

static void t(CanFight x) { x.fight();} static void u(CanSwim x) { x.swim();} static void v(CanFly x) { x.fly();} static void w(ActionCharacter x) { x.fight();} Hero h = new Hero( ) t(h); //Treat it as a CanFight u(h); //Treat it as a CanSwim v(h); //Treat it as a CanFly w(h); //Treat it as an ActionCharacter

Abstract Classes Weve reviewed this before. An abstract class contains both abstract methods and normal methods. The abstract methods must be overridden in subclasses. Because of the abstract methods, an abstract class cannot be instantiated.

Casting Recall that casting can be used to convert data types. Now let us see how it works with objects. If class T extends class S, then we can do the following reference:
T o = new T(); S so = o; S so1 = new T();

S
extends

so
assign

type casting (T) so

or
S so = new T(); T o = ( T )so;

Interfaces can be treated similar to superclasses. If class T implements interface I, we can do the following:
T I I T o = new T(); io = o; io1 = new T(); o1 = ( T )io1;

I
Impl.

io
assign

type casting
(T) io

o
8 bits
... 1 0 0 ... 1 0

A possible error by basic data type casting: int i = 258; byte b = (byte) i;

16 bits

Data Structure Exercises 2.1

Running Time and Recursion


Suppose we have the following two pieces of code. Fragment 1:
i = 0; z = x + y; n = i * i;

Fragment 2:
for( int i = 0; i < n; i++ ) { a[ i ] = i * i; }

Which one takes shorter time to run?

Running Time In this course, we want to compare algorithms. We want to know which algorithm is more efficient. By efficiency, we mean that an algorithm either takes less time to run or uses less memory than the other. Let us look at the running time here. Running time depends on many factors. Since we will be dealing with a collection of objects most of the time, what interests us is the relationship between running time and the number of objects.

Lets say we have n objects. We want to find out the function

T f (n)
Here T represents running time. In fact, we are interested in the situation when the number of objects becomes very large.

Some simple relationships are listed below.


Relationship Running time does not change (constant time) Running time is proportional to logn Running time is proportional to n Running time is proportional to the square of n Running time is proportional to n3

f (n)
O(1) O(logn) O(n) O(n2) O(n3)

Remember that these relationships hold only when n is very large.

Now let us compare these relationships.


constant n n2 n3 c 1 1 1 c 2 4 8 c 3 9 27 c 4 16 64 c 5 25 125

Therefore, if running time is proportional to n3, the code will take very long time to run. Next is proportional to n2 and so on. If running time is a constant, it is fast. In fact, it is the fastest type.

Suppose that we have a task that can be done by one of the two algorithms, A and B. The running time of algorithm A is proportional to the number of objects, n while the running time of algorithm B is proportional to the square of n. Which algorithm we should use?

A Simple Rule to determine Running Time There is a simple rule to estimate running time (or the relationship, so to speek) If we have a loop like this:
for( int i = 0; i < n; i++ ) { a[ i ] = i * i; }

The running time is proportional to n.

If we have nested loops like this:


for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { a[ j ] = a[ i ] * j; } }

The running time is proportional to the square of n (when n is very large). Now we see a pattern here.

Mathematicians have a fancy symbol for running-time relationships when n is large. They call it big-Oh. Relationship constant On the order of logn on the order of n on the order of n2 on the order of n3 big-Oh Symbol

O(1)
O(logn)

O ( n)
O(n 2 )
O(n 3 )

In fact, O stands for order. These relationships belong to different orders.

Recursion In Java course, we have learned recursion. recursion: A method calls itself. Example: Factorial function can be expressed as 0! = 1, 1! = 1, n! = n * (n 1)!, n > 1. We can use this relationship to calculate factorial function.

Here is the method factorial().


public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

Let us consider a case n = 4.


public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=3

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); } public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=3

n=2

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

Return 24

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); } public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

Return 6
n=3

Return 2
n=2

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

Return 1
n=1

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); } public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=3

2*1=2

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n=4

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

3*2=6

public static long factorial( long n ) { if( n <= 1 ) return 1; else return n * factorial( n - 1 ); }

n = 4 * 6 = 24

Therefore, the function returns 24, namely, 4 3 2 1.

Running Time of a Recursion Let us take the factorial method as an example. n 1 2 3 4 Number of Function Calls 1 2 3 4

Therefore, the running time of a recursion is proposional to the number of function calls. In this case, it is propotional to n, the size of the problem.

Data Structure Exercises 2.2

S-ar putea să vă placă și