Professional Documents
Culture Documents
07 Week
07 Week
Introduction to bluej
We want to write the TextContainer class that stores text broken into lines
On the text container, we want to carry out the operations below:
●
Insert a new line as last line of the text (appends a line to the exixting text)
●
Remove the first line
●
Replace one word with another word in the text
●
Check if the text container is empty
public class TextContainer
{ public TextContainer() {…}
public void add(String aLine){…}
public String removeFirst() {…}
public boolean isEmpty() {…}
public int replace(String find, String replace) {…}
4 } Foundations of Computer Science – A. Luchetta 2021-2022
Class TextContainer
}
Note: check vSize <= 0 is more robust than the
check vSize == 0
11 Foundations of Computer Science – A. Luchetta 2021-2022
/**
Removes the first line of the container
@return if the container is not empty, removes the first
line of the container, throws the exception
otherwise
@throws NoSuchElementException //javadoc for exceptions
*/
public String removeFirst()
{
// check of precondition
if (isEmpty())
throw new NoSuchElementException();
// temporary storage of line to remove (index 0)
String tmpString = v[0];
// removal of first line – SEQUENCE IS IMPORTANT!
for (int i = 0; i < vSize - 1; i++)
v[i] = v[i+1];
v[vSize – 1] = null; // cleaning
vSize--; // counter decrement
return tmpString;
12
}
Foundations of Computer Science – A. Luchetta 2021-2022
Replace method
The method must traverse all stored lines to search for the word find (the
TextContainer class stores lines, not single words)
The method must be able to split the individual lines into words and identify the
presence of the specified word find
If we find the specified word find, we must replace it with the specified word
replace, increase the replacement counter and insert the modified line into the array
in the correct sequence
if (token.equals(find))
{
container
token = replace;
count++; // replacement counter increment
found = true;
}
tmpLine = tmpLine + token + " ";
}
if (found) // substitution of line
v[i] = tmpLine;
st.close();
}
return count;
} // end of method
15} // end of class
Foundations of Computer Science – A. Luchetta 2021-2022
Test class - TextContainerTester
n = text.replace(args[0], args[1]);
}
To understand how to use recursion correctly, let's first see how it works
When a recursive method invokes itself, the Java virtual machine performs the same
actions that are performed when any method is invoked
suspends the execution of the invoking method
executes the invoked method until it is terminated
the execution of the invoking method resumes from the point at which it was
suspended
This method is clearly inefficient and serves only to illustrate the binary recursion
39 Foundations of Computer Science – A. Luchetta 2021-2022
Double ricursion
Below you can see the diagram of recursive calls with values of the from and to
arguments equal to 0 and 7, respectively
0, 7
0, 3 4, 7
0, 1 2, 3 4, 5 6, 7
0, 0 1, 1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7
Multiple recursion should be used very carefully, as it can lead to very inefficient
programs
By calculating the Fibonacci numbers of ascending order ...
… We notice that the processing time glines VERY rapidly… almost 3 million
invocations to calculate fibBad (31) !
we will quantify this problem later
fib(1) fib(0)
47 Foundations of Computer Science – A. Luchetta 2021-2022
Fibonacci numbers - fibGood
**/ returns an array that contains
fib(n) and fib(n-1) */
public static long[] fibGood(int n)
{
The fibGood if (n < 0) // preconditions
method shown on throw new IllegalArgumentException();
the right performs if (n < 2) // base cases
linear recursion: {
long[] ret = {n, 0};
The algorithm is return ret;
now efficient }
// recursive step
long[] tmp = fibGood(n - 1); //F(n-1), F(n-2)
long[] ret = {tmp[0] + tmp[1], tmp[0]};
return ret;
48 } Foundations of Computer Science – A. Luchetta 2021-2022
fibGood(5) 5, 3
fibGood(4) 3, 2
fibGood(3) 2, 1
Fibonacci n 0 1 2 3 4 5 6 7 ...
fibGood(1) 1, 0
numbers Fn 0 1 1 2 3 5 8 13 ...
49 Foundations of Computer Science – A. Luchetta 2021-2022
Example: recursively reverse a string
We want to reverse the sequence of a string with a recursive algorithm
Example: "One" is reversed in "enO"
Recursive algorithm:
preconditions: if the string s to be inverted is not a string, but the null reference, null is
returned
base case: if the number of characters in the string s is less than 2, the string is returned
because there is no need to reverse
recursive step: extract the first character of the string s[0]. Recursively invert the substring
with indexes from 1 to s.length() - 1. Return the concatenation of the revesed substring with
the first character.
Example: s = "One"; returns "en" + "O" think recursively!
50 Foundations of Computer Science – A. Luchetta 2021-2022
Example: recursively reverse a string
/**
Reverses the specified string
@param s the specified string
@return the reversed string
*/
private static String reverseString(String s)
{
// preconditions
if (s == null)
return null;
// base case
if (s.length() < 2)
return s;
// recursive step
String r = reverseString(s.substring(1));
return r + s.charAt(0);
51 } Foundations of Computer Science – A. Luchetta 2021-2022
Recursive calculation of the greatest common divisor
Calculate the greatest common divisor (GCD) between two positive integers m and n
with the Euclidean algorithm below:
preconditions: if m or n are not positive throw the IllegalArgumentException
base case: if n divides m, then the GCD is equal to n
recursive step: the GCD between m and n is equal to the GCD between n and m% n
think recursively!
move 1 move 5
move 2 move 6
It can be shown that the number of moves required to solve the puzzle with the
proposed algorithm is
2 1 n
private static void solveHanoi(int from, int to, int temp, int size)
{
if (size > 0)
{
solveHanoi(from, temp, to, size - 1);
System.out.println("move from T" + from + " to T" + to);
solveHanoi(temp, to, from, size - 1);
}
}
}
62 Foundations of Computer Science – A. Luchetta 2021-2022
main() calls solveHanoi(1,3,2,2)
A legend tells that some Buddhist monks in a temple in the Far East have been
involved since long in solving the game, physically moving their 64 disks from one
tower to another, aware that when they have finished the world will end
It takes 264 - 1 moves, which is about 18 billion trillion moves… that's about 18x1018
Assuming that the monks make a move every minute, they make about 525,000
moves a year: so the world will end in more than 30 trillion years!
A 1GHz processor making one move at each clock interval (one billion moves per
second) takes 18 billion seconds, which is about 584 years!
A very frequent problem in data processing is the sorting of the data, according to a
predefined criterion
names in alphabetical order, numbers in ascending order ...
We will study different algorithms for sorting, also introducing an analytical tool to
evaluate their performance
On ordered data, it is then possible to search very efficiently, and we will study
suitable algorithms
The algorithms we will study are recursive and efficient, but not all recursive
algorithms are efficient!
For simplicity, we will first focus on sorting a set of integers stored in an array
we will then see how we can simply extend to the case in which we sort objects
rather than numbers
Let us sort an array a ascending order, as in the example below
11 9 17 5 12 5 9 11 12 17
a[0] a[1] a[2] a[3] a[4] a[0] a[1] a[2] a[3] a[4]
unsorted sorted
11 9 17 5 12 5 9 17 11 12
a[0] a[1] a[2] a[3] a[4]
First, we need to find the smallest element in the array, using the search algorithm
we already know,
in our example the smallest number 5 at index 3
Being a[3] the smallest element, its correct position in the ordered array is at a[0]
the number 11 is stored in a[0], so we have to move it
we don't know what the correct position of 11 is
we temporarily move it to a[3], the position where the minimum is
therefore, we exchange a[3] with a[0]
69 Foundations of Computer Science – A. Luchetta 2021-2022
Selection sort
5 9 17 11 12 The colored side of the array
is already sorted
a[0] a[1] a[2] a[3] a[4]
The left side of the array is already sorted and will no longer be considered, we have
to sort the right side
We sort the right side with the same algorithm
we look for the minimum, which is 9 in position a[1]
since it is already in the first position a[1] of the side to be ordered, there is no need
to move it
5 9 17 11 12
a[0] a[1] a[2] a[3] a[4]
70 Foundations of Computer Science – A. Luchetta 2021-2022
Selection sort
5 9 17 11 12
a[0] a[1] a[2] a[3] a[4]
We go on and sort the side of the array that contains the elements a[2], a[3] and a[4]
the minimum is number 11 in position a[3]
we exchange a [3] with a [2]
5 9 11 17 12 5 9 11 17 12
a[0] a[1] a[2] a[3] a[4] a[0] a[1] a[2] a[3] a[4]
71 Foundations of Computer Science – A. Luchetta 2021-2022
Selection sort
5 9 11 17 12
a[0] a[1] a[2] a[3] a[4]
Now the array to be sorted contains a[3] and a[4]
the minimum is number 12 in position a[4]
we exchange a[4] with a[3]
5 9 11 12 17 5 9 11 12 17
a[0] a[1] a[2] a[3] a[4] a[0] a[1] a[2] a[3] a[4]
At this point the side to be sorted contains only one element, so it is obviously
sorted
72 Foundations of Computer Science – A. Luchetta 2021-2022
public class ArrayAlgorithms // class containing algorithms for arrays
{
public static void selectionSort(int[] a)
{ for (int i = 0; i < a.length - 1; i++)
{ int minPos = findMinPos(a, i);
if (minPos != i) swap(a, minPos, i);
}
}
private static void swap(int[] a, int i, int j)
{ int temp = a[i];
a[i] = a[j];
a[j] = temp; Selection sort
} Selection sort
private static int findMinPos(int[] a, int from)
{ int pos = from;
int min = a[from];
for (int i = from + 1; i < a.length; i++)
{ int temp = a[i]; // complex method
if (temp < min) // to simplify the
{ pos = i; // performance evaluation
min = temp; // see ahead
}
}
return pos;
}
} 73 Foundations of Computer Science – A. Luchetta 2021-2022
Selection sort
The selection sort algorithm is correct and can sort any array of integers
so why are we going to study other sorting algorithms?
what is the need to study different algorithms to solve the same problem?
We will see that there are sorting algorithms that sort faster with the same array size
The performance of the selection sort algorithm therefore has a quadratic trend as a
function of the size of the array
The next questions we ask ourselves are
Is it possible to evaluate the performance of an algorithm from a theoretical point of
view?
without writing a program and without running it many times, to detect its
execution times and observe ithe time trend?
is there a more efficient algorithm for sorting?
The execution time of an algorithm depends on the number and type of machine
instructions that the processor executes
To do a theoretical analysis
without writing a code for the algorithm, compile it and translate it into machine
language
we have to make drastic simplifications
What we will do is to count the number of read or write accesses to array elements
neglecting the other instructions
BIG OMEGA: we will say that T(n) is W(F(n) if there exist two positive constants c > 0
and n0 > 0 such that T(n) ≥ cF (n) for n > n0
- in informal terms T (n) glines more than F(n) for large n
BIG THETA: we will say that T(n) is (F (n)) if T(n) is O(F (n)) and also (F (n)
- in informal terms T (n) glines as F(n) for large n
The number of memory accesses (time complexity) T(n) to sort an array of n integers
by means of the selection sort selection algorithm is equal to:
We will therefore say that the asymptotic trend of the time complexity of the sorting
by selection algorithm is equal to
O (n2)
We can express the same concept by saying that T(n) ∈ O(n2)
Geometrical proof
Arithmetic proof
89 Foundations of Computer Science – A. Luchetta 2021-2022
Linear search
Linear search
We have already seen an algorithm to identify the position of an element that has a
particular value within an array whose elements are not sorted
Since in the worst case all the elements have to be examined, it is called sequential
or linear search
public class ArrayAlgorithms // usual class
{
public static int linearSearch(int[] a, int v)
{
for (int i = 0; i < a.length; i++)
if (a[i] == v)
return i; // FOUND
The number of memory accesses (time complexity) T(n) to sort an array of n integers
by means of the selection sort selection algorithm is equal to:
We will therefore say that the asymptotic trend of the time complexity of the sorting
by selection algorithm is equal to
O (n2)
We can express the same concept by saying that T(n) ∈ O(n2)
The number of memory accesses (time complexity) T(n) to sort an array of n integers
by means of the selection sort selection algorithm is equal to:
We will therefore say that the asymptotic trend of the time complexity of the sorting
by selection algorithm is equal to
O (n2)
We can express the same concept by saying that T(n) ∈ O(n2)
Finding the position of an element that has a particular value within an array can be
tackled more efficiently if the array is sorted
Let’s find the element with value 12
We compare 12 with the element located (approximately) in the center of the array,
a[2], which is 11
The element we are looking for is greater than 11
if it is present in the array, it will be to the right of 11
5 9 11 12 17 21
a[0] a[1] a[2] a[3] a[4] a[5]
96 Foundations of Computer Science – A. Luchetta 2021-2022
Binary search
Now we have to look for element 12 in the only sub-array that is to the right of a[2]
We use the same algorithm, that is comparing 12 with the element found in the center,
a[4], which is 17
The element we are looking for is less than 17
if it is present in the array, it will be to the left of 17
5 9 11 12 17 21
a[0] a[1] a[2] a[3] a[4] a[5]
At this point, we must search for element 12 in the sub-array consisting of only
element a[3]
We use the same algorithm, comparing 12 with the element found in the center, a[3],
which is 12
The element we are looking for is equal to 12
the element we are looking for is present in the array and is in position 3
5 9 11 12 17 21
a[0] a[1] a[2] a[3] a[4] a[5]
If the comparison between the element to be searched and the element a[3] had given
a negative result, we would have searched in the empty sub-array on the left or right,
concluding that the searched element is not present in the array
This algorithm is called binary search, because at each step the array is divided into
two parts, and it only works if the array is sorted
5 9 11 12 17 21
a[0] a[1] a[2] a[3] a[4] a[5]
if (middle == t)
return mid; // FOUND → base case 2
else if (middle < t)
// SEARCH ON THE RIGHT
return binSearch(a, mid + 1, to, t);
else
// SEARCH ON THE LEFT
return binSearch(a, from, mid - 1, t);
}
... 2021-2022
100 } Foundations of Computer Science – A. Luchetta
Evaluation of performance of binary search
T(n) = T(n/2) + 1
The solution of this functional equation (equation between functions) to obtain T(n) as a function of n is not
simple and goes beyond the scope of this course
However, it can easily be verified, by substitution, that the solution is
T (n) = 1 + log2n O(log n)
The performance of the algorithm is therefore better than that of linear search
This applies in worst cases. i.e. when the element we look for is in the last position of the array or is not
present
We could also prove that the result holds also for the average case
We should compute the number of accesses in n + 1 cases (when the element looked for is in position 0, 1, … n-1, and not present)
and then divide for the number of cases
Note: the base of the algorithm can be omitted as the change from one base to another requires to multiply
by a constant log10 x = log10 2 * log2 x where log10 2 is a constant
We have analyzed the time complexity of linear search and found that we have to
perform
1 access in the best case when we find the element we are looking for in the first
position
n accesses in the worst cases when we find the element in the last position or we do not
find the element
(n + 1) /2 accesses in the average case (the element we are looking for is present and is
in any of the possible positions with the same probability)
We have to do two comparisons on each loop iteration, one to check if we have found
the element, the other to check if we have reached the end of the data
return -1;
We can cut the number of comparisons in half by using a sentinel (also useful in other
circumstances)
Assuming that the array v[] is only partially filled and has at least one free position, we
insert the value to look for at the vSize index
At this point we are sure that the searched element appears in the array at least once;
we can therefore interrupt the search cycle when the data is found without checking if
the vector has run out
At the end of the cycle, if the found element occupies the vSize position, the search
has failed
if (i != vSize)
two comparisons ... // found
sentinel else
size n ... // not found
binary Serach