MODULE 2 MODULE TITLE: BASIC ARRAY OPERATIONS OVERVIEW This module discusses the basic operations that can be performed in an array. Various algorithms and techniques, and their time complexity to accomplish such operations are also covered. MODULE OBJECTIVES: At the end of this module, the students should be able to: Create programs using arrays and loop statements Implement simple algorithms to manipulate the values of an array Explain the advantages and disadvantages of an algorithm 14 | P a g e PRE-TEST Name: Score: Section: Instructor: Date: Directions: Encircle ‘T’ if the statement is correct. Otherwise, encircle ‘F’. (10 points) T | F 1. The length of an array can be determined using the length property. T | F 2. Time complexity describes the amount of time it takes to code an algorithm. T | F 3. An array is a container object that holds a fixed number of values of a single type. T | F 4. The length of an array is established when the array is created. T | F 5. The time complexity of traversing an array is O(1) because each element is accessed only once. T | F 6. Each item in an array is called an element, and each element is accessed by its numerical index. T | F 7. You can create an array by using the new operator. T | F 8. Array indices are 0-based; that is, they start from 0 to array.length-1. T | F 9. The time complexity of the linear search is O(1) because each element in the array is compared only once. T | F 10. Linear search sequentially checks each element of the list until a match is found or the whole list has been searched. 15 | P a g e CONTENTS Time Complexity and the Big O Notation Time complexity describes the amount of time it takes to run an algorithm. Time complexity is commonly estimated by counting the number of elementary operations performed by the algorithm, supposing that each elementary operation takes a fixed amount of time to perform. Big O notation is used in Computer Science to describe the performance or complexity of an algorithm. Big O specifically describes the worst-case scenario, and can be used to describe the execution time required or the space used (e.g. in memory or on disk) by an algorithm. Below are some common orders of growth along with descriptions. O(1) describes an algorithm that will always execute in the same time (or space) regardless of the size of the input data set. O(n) describes an algorithm whose performance will grow linearly and in direct proportion to the size of the input data set. O(n2) represents an algorithm whose performance is directly proportional to the square of the size of the input data set. This is common with algorithms that involve nested iterations over the data set. Deeper nested iterations will result in O(n3), O(n4) etc. O(2n) denotes an algorithm whose growth doubles with each additon to the input data set. The growth curve of an O(2n) function is exponential - starting off very shallow, then rising meteorically. An example of an O(2n) function is the recursive calculation of Fibonacci numbers. Logarithms are slightly trickier to explain so I'll use a common example. Binary search is a technique used to search sorted data sets. It works by selecting the middle element of the data set, essentially the median, and compares it against a target value. If the values match it will return success. If the target value is higher than the value of the probe element it will take the upper half of the data set and perform the same operation against it. Likewise, if the target value is lower than the value of the probe element it will perform the operation against the lower half. It will continue to halve the data set with each iteration until the value has been found or until it can no longer split the data set. This type of algorithm is described as O(log n). The iterative halving of data sets described in the binary search example produces a growth curve that peaks at the beginning and slowly flattens out as the size of the data sets increase e.g. an input data set containing 10 items takes one second to complete, a data set containing 100 items takes two seconds, and a data set containing 1000 items will take three seconds. Doubling the size of the input data set has little effect on its growth as after a single iteration of the algorithm the data set will be halved and therefore on a par with an input data set half the 16 | P a g e size. This makes algorithms like binary search extremely efficient when dealing with large data sets. Traversing Through an Array As discussed in the previous module, you can traverse through an array using a for loop. Instead of printing element by element, you can iterate the index using for loop starting from 0 to length of the array -1 and access elements at each index. import java.io.*; public class Array { public static void main (String args[]) throws IOException { // the size of the array int size; BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // sets the size of the array System.out.print("\nEnter the size of the array: "); size = Integer.parseInt(reader.readLine()); // creates the array int[] array = new int[size]; // assign values to the array for(int i=0; i<size; i++) { System.out.print("\nEnter a number: "); array[i] = Integer.parseInt(reader.readLine()); } // display the values to the screen for(int i=0; i<size; i++) { System.out.print("\nArray["+ i + "] = " + array[i]); } } } Below is a sample output of the program: 17 | P a g e You can also use the length property of an array to determine its length. In this example, we can replace i<size with i<array.length as loop condition. The time complexity of traversing an array is O(n) because each element is accessed only once. Searching a Value Our next example is a program that will check if a certain value exists in the array. The program will use linear search algorithm to find the value. A linear search or sequential search is a method for finding an element within a list. It sequentially checks each element of the list until a match is found or the whole list has been searched. The time complexity of the linear search is O(n) because each element in the array is compared only once. import java.io.*; public class Array { public static void main (String args[]) throws IOException { // the size of the array int size; // the number to be searched int numToSearch; // if true, it means that numToSearch has been found boolean found = false; BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // sets the size of the array System.out.print("\nEnter the size of the array: "); size = Integer.parseInt(reader.readLine()); // creates the array int[] array = new int[size]; // assign values to the array for(int i=0; i<size; i++) { System.out.print("\nEnter a number: "); array[i] = Integer.parseInt(reader.readLine()); } // sets the value of numToSearch System.out.print("\nEnter the number to be searched: "); numToSearch = Integer.parseInt(reader.readLine()); // applies linear search algorithm to check if numToSearch exists in the array for(int i=0; i<size; i++) { if(numToSearch==array[i]) { 18 | P a g e found = true; break; } } // displays the output if(found==true) System.out.print("\nThe number is present in the array."); else System.out.print("\nThe number is not present in the array."); } } Below is a sample output of the program: Finding the Highest Value The next program will find the highest value in an array of integers. The algorithm to find the highest value is: Assume that the highest value is present at the beginning of the array and store that value in a variable. Then compare it with other array elements one by one, if any element is greater than our assumed highest value, then the highest value is updated. The time complexity of this algorithm is O(n) because each element in the array is compared only once. import java.io.*; public class Array { public static void main(String[ ] args) throws IOException { 19 | P a g e // the highest value in the array int highest; // the size of the array int size; BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // sets the size of the array System.out.print("\nEnter the size of the array: "); size = Integer.parseInt(reader.readLine()); // creates the array int[] array = new int[size]; // assign values to the array for(int i=0; i<size; i++) { System.out.print("\nEnter a number: "); array[i] = Integer.parseInt(reader.readLine()); } // assumes that the first element is the highest number highest = array[0]; // traverses the array to find the highest number for(int i=1; i<size; i++) { if(highest<array[i]) highest = array[i]; } // displays the output System.out.print("\nThe highest number is " + highest); } } Below is a sample output of the program: Counting Odd and Even Numbers The next program will count and display the number of odd and even numbers in an array. 20 | P a g e The algorithm we used for this example works like this: Step 1. Initialize the counters for odd and even numbers. Set the initial value to 0. Step 2. Traverse through the array. Increment the counter for even numbers if the array element is divisible by 2. Else, increment the counter for odd numbers. Step 3. Display the value of the counters for odd and even numbers. The time complexity of this algorithm is O(n) because each element in the array is accessed only once. Let’s see the actual program. import java.io.*; public class Array { public static void main (String args[]) throws IOException { // the size of the array int size; // the counter for odd numbers int oddctr; // the counter for even numbers int evenctr; BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // sets the size of the array System.out.print("\nEnter the size of the array: "); size = Integer.parseInt(reader.readLine()); // creates the array int[] array = new int[size]; // assign values to the array for(int i=0; i<size; i++) { System.out.print("\nEnter a number: "); array[i] = Integer.parseInt(reader.readLine()); } // sets the initial value of the counters to 0 oddctr = 0; evenctr = 0; // traverse through the array to count number of odd and even numbers for(int i=0; i<size; i++) { if(array[i]%2==0) evenctr++; else 21 | P a g e oddctr++; } // displays the result System.out.print("\nThere are " + evenctr + " even numbers "); System.out.print("\nThere are " + oddctr + " odd numbers "); } } Below is a sample output of the program: 22 | P a g e POST-TEST Name: Score: Section: Instructor: Date: I. True or False. Encircle ‘T’ if the statement is correct. Otherwise, encircle ‘F’. (10 points) T | F 1. Displaying the tenth element of an array will result to O(n) time complexity. T | F 2. The time complexity of the linear search is O(1) because each element in the array is compared only once. T | F 3. The time complexity of sequential search is O(n). T | F 4. Displaying the first element of an array will result to O(1) time complexity. T | F 5. Linear search sequentially checks each element of the list until a match is found or the whole list has been searched. T | F 6. Time complexity describes the amount of time it takes to run an algorithm. T | F 7. The length of an array is established when the array is declared. T | F 8. Array indices are 0-based; that is, they start from 0 to array.length-1. T | F 9. The time complexity of traversing an array is O(1) because each element is accessed only once. T | F 10. An array is a container object that holds a fixed number of values of a single type. II. Output Tracing. Trace and write the output of the following Java statements. If the statements will result to a compile-time or runtime error, do not write anything except ERROR as your answer. Write your answers in the space provided. (2 points each) Java Statements 1. int[] numbers = {-6,3,-4,1,-5}; for(int i=0; i<numbers.length-1; i++) { numbers[i] -= numbers[i+1]; System.out.print(numbers[i]+" "); } 2. int[] numbers = {7,3,8,-11,3}; for(int i=0; i<numbers.length-1; i++) { numbers[i+1] = ++numbers[i] + numbers[i+1]; System.out.print(numbers[i]+" "); } 3. int[] numbers = {-5,4,2,-4,6,7}; for(int i=0; i<numbers.length-1; i++){ if(!(numbers[i]>numbers[i+1])) Output 23 | P a g e System.out.print(++numbers[i] + " "); else System.out.print(++numbers[i+1] + " "); } 4. int[] numbers = {-8,2,3,-5,-6,1}; for(int i=0; i<numbers.length-1; i++){ if(numbers[i]>0 && numbers[i+1]<2) System.out.print(++numbers[i] + " "); else System.out.print(++numbers[i+1] + " "); } 5. int[] numbers = {10,-6,-5,7,6,2}; for(int i=0, j=numbers.length-1; i<numbers.length-1; i++, j--){ if(numbers[i]>0 || numbers[i+1]<5) System.out.print(++numbers[i] + " "); else System.out.print(++numbers[i+1] + " "); } 24 | P a g e MODULE TEST Name: Section: Instructor: Score: Date: I. True or False. Encircle ‘T’ if the statement is correct. Otherwise, encircle ‘F’. (10 points) T | F 1. The time complexity of sequential search is O(n). T | F T | F T | F 2. 3. 9. Displaying the first element of an array will result to O(1) time complexity. Time complexity describes the amount of time it takes to run an algorithm. The time complexity of traversing an array is O(1) because each element is accessed only once. T | F 5. The time complexity of the linear search is O(1) because each element in the array is compared only once. T | F 6. Linear search sequentially checks each element of the list until a match is found or the whole list has been searched. T | F T | F 7. 8. T | F 9. The length of an array is established when the array is declared. Running a loop in an array with 5 elements has the same time complexity with running a loop in an array with 50 elements. Displaying the fifth element of an array will result to O(1) time complexity. T | F 10. Array indices are 0-based; that is, they start from 0 to array.length-1. II. Programming Problem Create a program that will read N numbers. Find and display the second highest number. (32 points) Sample Output How many numbers? 4 Enter a number: 5 Enter a number: 3 Enter a number: 6 Enter a number: 2 The second highest number is 5. 25 | P a g e Grading Rubric 26 | P a g e REFERENCES Textbook: [1] Malik D. S. 2019. C++ Programming including Data Structures. Cengage Learning. Online Resources: [2] Hackerearth. 2020. Data Structures. Retrieved May 10, 2020 from https://www.hackerearth.com/practice/data-structures/arrays/1-d/tutorial/ [3] TutorialsPoint. 2020. Data Structures - Algorithms Basics. Retrieved May 10, 2020 https://www.tutorialspoint.com/data_structures_algorithms/algorithms_basics.htm [4] Friesen J. 2017. Data Structures and Algorithms in Java, Part 1: Overview. Retrieved May 10, 2020 from https://www.javaworld.com/article/3215112/java-101-datastructures-andalgorithms-in-java-part-1.html [5] Bell R. 2020. A Beginner's Guide to Big O Notation. Retrieved May 10, 2020 from https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/ 27 | P a g e