0% found this document useful (0 votes)
65 views48 pages

COMP171 Data Structures and Algorithm: Tutorial 2 TA: M.Y.Chan

The document outlines the agenda for a tutorial on data structures and algorithms, including a short revision on pointers, a discussion of classes and how to implement them, examples of dynamically allocating and manipulating arrays, an introduction to recursion as a problem solving technique, and tips on coding conventions. Breaks are scheduled throughout the 2 hour tutorial for questions and discussion.

Uploaded by

Bhavik Mody
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views48 pages

COMP171 Data Structures and Algorithm: Tutorial 2 TA: M.Y.Chan

The document outlines the agenda for a tutorial on data structures and algorithms, including a short revision on pointers, a discussion of classes and how to implement them, examples of dynamically allocating and manipulating arrays, an introduction to recursion as a problem solving technique, and tips on coding conventions. Breaks are scheduled throughout the 2 hour tutorial for questions and discussion.

Uploaded by

Bhavik Mody
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 48

COMP171 Data Structures

and Algorithm
Tutorial 2
TA: M.Y.Chan
A few words…
• Materials will be posted on the course
homepage before the tutorials
• Please have a glance before the tutorials
• Please interrupt me if I’ve gone too fast
• Please don’t hesitate to ask questions in
the tutorials
Today’s Outline
• A short revision (10 minutes)
• More on Class (15 minutes)
• Simple dynamic list (15 minutes)
• Recursion (40 minutes)
• Break (10 minutes)
• Template (10 minutes)
• Coding conventions (10 minutes)
A Short Revision
• Question on Pointer:
• What is printed by the following program?
• void PrintEquality(bool isEqual) {
• if (isEqual) cout << "Yes" << endl;
• else cout << "No" << endl;
• }
• int main(){
• int * * p = new int * (new int(4));
• int * q = *p;
• *q = 5;
Easy question – you should be
• PrintEquality(p == &q);
• PrintEquality(*p == q); able to answer this within 2min
• PrintEquality(**p == *q);
• }
A Short Revision
• The answer is:
• 1) No 2) Yes 3) Yes
• But why?
More on Class
• From requirement to Implementation
• Example: a Dice class
• State & behavior
• State: depends on the physical properties
• Behavior: what the class does
More on Class
This header file is an interface to the class. It describe the behavior
of the class, but not on how it is implemented
• Class Dice{
• Public: Behavior = public member function
• Dice(int sides); // constructor
• int Roll(); // return the random roll
• int NumSides() const // how many sides this dies has
• Private: State = private data
• int myRollCount; // time die rolled
• int mySides; // sides on die
• }
More on Class
• Header file provide information that
programmers need to know to call a
function & compiler can verify the
correctness of the function call
• Implementation file (.cpp files) contains the
details about implementation (function
bodies)
More on Class
• #include “dice.h”
• #include “randgen.h”
• // implementation of dice class
• Dice::Dice(int sides)
• // postcondition: all private fields initialized
• {
• myRollCount = 0;
• mySide = sides;
• }
• Int Dice::Roll()
• // postcondition: number of rolls updated
• // random ‘die’ roll returned
• {
• RandGen gen; // random number generator
• myRollCount = myRollCount + 1; // update # of times die rolled
• return gen.RandInt(1,mySides); // in range [1.. mySide]
• }
More on Class
• Int Dice::NumSides() const
• // postcondition: return # of sides of die
• {
• return mySides;
• }

• Int Dice:: NumRolls() const


• // postcondition: return # of times die has been rolled
• {
• return myRollCount;
• }
More on Class
• Create object by constructor
• Eg. Dice cube(6), Dice Dodeca(12)

Dice (int sides) Dice (int sides)

Behavior
Behavior
Int Roll() Int Roll()

Public
Public

Int NumSides() const Int NumSides() const


Int NumRolls() const Int NumRolls() const
________________ ________________
myRollCount myRollCount
Private
Private

State
0
State

mySides mySides
6 12

Cube(6) Dodeca(12)
More on Class
• Accessor functions – access the states but
do not alter the state Tips: All state or instance variables in a class
should be private
• E.g. NumSides(), NumRolls()
• Always come with the keyword “const”
• Mutator functions – alter the state
• E.g. Roll()
More on Class
• Inherit from other classes (base classes &
derived classes)
• Allow easy software reuse (instead of re-
inventing the wheels)
• Eg. extending the features of string such that it
supports the "tokenizing“ feature (chop the string
into words).
• Additional features:
• void Tokenize(); −−− chop the string into words
• int argSize(); −−−−− returns no. of words
• string arg(int k); −−−− returns the kth words
More on Class
• Expected behaviors:
myString input;
getline(cin, input);
input.Tokenize();
for (int i = 0; i < input.argSize(); ++i)
cout << input.arg(i) << endl;
More on Class
Base Class Derived Class
• class myString : public string {
• public: Inherits from string class and
• void Tokenize(); behaves like a string
• int argSize();
• string arg(int k);
• private: Additional member functions
• vector<string> arglist;
• }
• void myString::Tokenize() { Additional data member
• istrstream s ( c_str() );
• string temp;
• while (s >> temp) c_str() is a member function
• arglist.push_back(temp); of string that returns a "string
• } literal“ version of itself.
• int myString::argSize() {
• return arglist.size(); Note that myString inherits
• }
all the features of string; i.e., it
• string myString::arg(int k) {
• return arglist[k]; can be used just like an ordinary
• } string
A Simple Dynamic List
Example
cout << "Enter list size: ";
int n;
cin >> n;
int *A = new int[n];
if(n<=0){
cout << "bad size" << endl;
return 0;
}
initialize(A, n, 0); // initialize the array A with value 0
print(A, n);
A = addElement(A,n,5); //add an element of value 5 at the
end of A
print(A, n);
A = deleteFirst(A,n); // delete the first element from A
print(A, n);
selectionSort(A, n); // sort the array (not shown)
print(A, n);
delete [] A;
Initialize

void initialize(int list[], int size, int


value){
for(int i=0; i<size; i++)
list[i] = value;

}
print()

void print(int list[], int size) {


cout << "[ ";
for(int i=0; i<size; i++)
cout << list[i] << " ";
cout << "]" << endl;
}
Adding Elements
// for adding a new element to end of array
int* addElement(int list[], int& size, int value){
int* newList = new int [size+1]; // make new array
if(newList==0){
cout << "Memory allocation error for addElement!" << endl;
exit(-1);
}
for(int i=0; i<size; i++)
newList[i] = list[i];
if(size) delete [] list;
newList[size] = value;
size++;
return newList;
}
Delete the first element
// for deleting the first element of the array
int* deleteFirst(int list[], int& size){
if(size <= 1){
if( size) delete list;
size = 0;
return NULL;
}
int* newList = new int [size-1]; // make new array
if(newList==0){
cout << "Memory allocation error for deleteFirst!" <<
endl;
exit(-1);
}
for(int i=0; i<size-1; i++) // copy and delete old
array
newList[i] = list[i+1];
delete [] list;
size--;
Adding Element (version 2)
// for adding a new element to end of array
void addElement( int * & list, int & size, const int value ){

int * newList = new int [size + 1];

if( newList == NULL ){


cout << "Memory allocation error for addElement!" << endl;
exit(-1);
}

for( int i = 0; i < size; i++ )


newList[ i ] = list[ i ];

if( size ) delete [] list;

newList[ size ] = value;


size++;
list = newList;
return;
Deleting Element (version 2)
void deleteFirst( int * & list, int & size ){

if( size <= 1 ){


if( size )
delete list;
list = NULL;
size = 0;
return;
}

delete list; // delete the first element


list++;
size--;
return;
}
Another Main program
int main(){

int * A = NULL;
int size = 0;
int i;

for( i = 0; i < 10; i++ )


addElement( A, size, i );

for( i = 0; i < 10; i++ )


cout << A[i] << " ";
cout << endl;

for( i = 0; i < 4; i++ )


deleteFirst( A, size );

for( i = 0; i < 6; i++ )


cout << A[i] << " ";
cout << endl;
0123456789
return 0; 456789
}
Recursion
• Recursion is an indispensable tool in
programmer’s toolkit
• It allow many complex problems to be
solved simply
• Elegance and understanding in code often
leads to better programs: easy to modify,
extend and verify
Recursion
• Idea: to get help solving a problem from
“coworkers” (clones) who work and act like
you do
• Ask clone to solve a simpler (smaller) but
similar problem
• Use clone’s result to put together your
answer
• Need both concepts: call on the clone and
use the result
Recursive function design
principle
• Recursive functions have two key attributes
• There is a base case, which does not make a
recursive call
• All other cases make a recursive call, with some
parameter or other measure that decreases or
moves towards the base case
• Ensure that sequence of calls eventually
reaches the base case (converge)
• "Measure" can be tricky, but usually it’s
straightforward
Recursive function design
principle
int recur_fn(parameters){
if(stopping condition)
return stopping value;
// other stopping conditions if needed
return function of recur_fn(revised
parameters)

Note: you can have more than one stopping


condition and additional task can be done
before or after the invocation of clone
Recursion
• Theoretically speaking, you can replace all
the for- and while- loops by recursions
• However, it may not be the most efficient
solution
Recursion
• Example 1: How to print words entered,
but in reverse order?
• Possible solution: we can use a array to
store all the words and print in reverse
order.
• The array is probably the best approach,
but recursion works too…
Recursion
• Explanation: Deploy
the task to the
coworker. Ask the
clone to deliver the
result first and we
print the current
word later.
Recursion
• Sometime recursion is not appropriate,
when it is bad, it can be very bad – every
tool requires knowledge and experience in
how to use it
• Example: Fibonacci numbers
Recursion
• Example 2: Fibonacci
numbers (discussed
in the lecture)
• How many clone/calls
to compute Fib(5)?
Recursion
• Answer: 15
• A Huge number of function invocations
result in overhead and memory usage
• Iterative approach is preferred
Break

• 10 minutes break
• Remember to come back !!
Don’t escape from this
tutorials !! Thanks
Recursion
• Recursion is not that bad !!!!!
• Can you still remember the example of
Exponential fun ?
int exp(int numb, int power){
if(power ==0)
return 1;
return numb * exp(numb, power -1);
}
Recursion
• Is it the best? …
• How about this
Recursion
• Much faster than the previous solution
• How about iterative method?
• The power of recursion !!!
• It is different from our conventional way of
calculation (ie. Iterative approach)
• Later, you will learn more about algorithm
analysis -> how “good” the method is.
• The most efficient way to do recursion is to
break down the task evenly and distribute to the
coworkers and significantly “decrease” the size
of the task in each recursion
Recursion
• Another example from your textbook (P.38
Ex.1.5)
• Question: Write a recursive function that
returns the number of 1’s in the binary
representation of N. Use the fact that this
is equal to the number of 1’s in the
representation of N/2, plus 1, if N is odd.
Recursion
• Consider:
1. Long Division
2. Binary representation
 You will get some idea of the hint and
know more about how to change the
iterative approach to recursions
Recursion
• Straight-forward
• How to print the
binary representation
of a given integer?
Recursion
• void print(int n)
• {
• // base case
• if ( n==1 )
• {
• cout << 1;
• return;
• }

• print(n/2);

• if ( n%2 == 1 )
• cout << 1;
• else
• cout << 0;
• }
Recursion
• You can try out the questions in your
textbook
• Get enough practices
Recursion
• Sometimes you may be asked to tell the
meaning of a given recursive function
What is the output of the function call f(3429)?
void f(int x)
{
if (x < 10)
cout << x;
else
{
cout << x % 10;
f( x / 10 );
}
}
Recursion
• Another Question:

What is the value of the function call g(29039)?


int g(int x)
{
if ( x < 10 )
return 1;
else
return g( x / 10 ) + 1;
}

The question can be more complicated if it involves two different recursive


function which invoke each other recursively. Hope you will find this interesting
questions in the future, but not in the exam.
Template
• Problem: We wrote a function for adding
two integer values. However, if we want
other functions for adding two values of
other types, do we need to write a function
for each of them?
• Of course, Reinventing your source code
every time doesn’t seem like a very
intelligent approach with a language that
touts reusability
Template
• no longer holds a generic base class, but
instead it holds an unspecified parameter.
• When you use a template, the parameter
is substituted by the compiler
Template
• Template syntax
• The template keyword
tells the compiler that the
class definition that
follows will manipulate
one or more unspecified
types
Coding Convention
• Programming style
• Useful link:
http://www.possibility.com/Cpp/CppCoding
Standard.html

You might also like