German University in Cairo Media Engineering and Technology Prof. Dr. Slim Abdennadher Dr. Wael Abouelsaadat

Data Structures and , Winter term 2018 Practice Assignment 2

Exercise 2-1 Sorting Algorithms Given the following array of integers:

11 5 14 10 2

Apply each of the following methods to sort this array:

In each step, you are required to:

• clearly describe the current step being performed • show the resulting contents of the array

Please note that you are not required to write a program.

Exercise 2-2 Recursive Bubble Sort Re-implement bubble sort such that you compensate for the outer loop with recursion.

Solution: import java.util.Arrays; public class BubbleSort{

public static void bubbleSort( int[] data, int i) { if(i==data.length - 1) return; for ( int j = 0; j < data.length-i-1; ++j) if ( data[j] > data[j+1] ) { int temp= data[j]; data[j]=data[j+1]; data[j+1]=temp; } bubbleSort( data, i+1); }

//alternative answer public static void bubbleSort2( int[] data, int N) {

1 for ( int j = 0; j < N-1; ++j) if ( data[j] > data[j+1] ) { int temp= data[j]; data[j]=data[j+1]; data[j+1]=temp; } if ( N > 2 ) bubbleSort2( data, N-1); }

public static void main(String[] args) { int[] array={4,7,1,9,3,6,0}; bubbleSort(array,0); //alternative answer //bubbleSort2(array, array.length); System.out.println(Arrays.toString(array)); } }

Exercise 2-3 Modified Selection Sort In the lecture you were introduced to the Selection Sort algorithm. For this exercise, you need to implement a modified version of the Selection Sort algorithm, where:

• instead of finding the smallest element in the array and changing its position with an element at the beginning of the array, • you need to find both the smallest and the largest elements and change their positions with elements at the beginning and end of the array respectively.

You are required to select the smallest and largest numbers in one pass; in other words, your implementation should only include a single loop for finding both of the smallest and largest numbers. Remark: There are some special cases that you need to figure out and handle in your implementation. Make sure that your solution works for the arrays:

{6, 4, 5} and {2, 6, 8, 1, 7, 9, 4, 3, 5}

What is the invariant of this ?

Solution: import java.util.Arrays; public class ModifiedSelectionSort {

public static void modifiedSelectionSort(int [] a) { for(int i = 0; i < a.length / 2; i++) { int minIndex = i; int maxIndex = i; int min = a[minIndex]; int max = a[maxIndex];

for(int j = i+1; j < a.length - i; j++) { if(a[j] < min) { minIndex = j; min = a[minIndex]; } if(a[j] >= max) { maxIndex = j;

2 max = a[maxIndex]; } } a[minIndex] = a[i]; a[i] = min; if(maxIndex == i) maxIndex = minIndex; a[maxIndex] = a[a.length-1-i]; a[a.length-1-i] = max; } }

public static void main(String[] args) { int[] a = {9,8,7,3,2,5,1,2,4,3,0}; //[0, 1, 2, 2, 3, 3, 4, 5, 7, 8, 9] modifiedSelectionSort(a); System.out.println(Arrays.toString(a));

a= new int[]{6,4,5}; modifiedSelectionSort(a); System.out.println(Arrays.toString(a));

a= new int[]{2,6,8,1,7,9,4,3,5}; modifiedSelectionSort(a); System.out.println(Arrays.toString(a)); } }

The invariant of this sorting algorithm is that the data items with indices less than or equal to i and data items with indices greater than or equal to end - i, where end is the index of the last element, are sorted.

3 Exercise 2-4 Index Sort

a) Write a method indexSort that uses the following algorithm to sort an array x of integers. Loop through the integers in x. For each integer, calculate what index it will be stored at in the output array y of the same length as x. For example, for the following array:

4 3 8 2

by comparing 4 with the rest of the array, we can deduce that 4 should be stored at index 2. Thus, after the first pass the resulting array should be of the following form:

4

Make sure that your algorithm handles arrays with duplicate keys. Solution: import java.util.Arrays;

public class IndexSort {

public static int[] indexSort(int[] x) { int[] y = new int[x.length]; for (int i = 0; i < x.length; i++) { int index = 0; for (int j = 0; j < x.length; j++) { if ((x[j] < x[i]) || ((x[j] == x[i]) && (j < i))) { index++; } } y[index] = x[i]; } return y; }

public static void main(String[] args) { int[] a = {9,8,7,3,2,5,1,2,4,3,0}; //[0, 1, 2, 2, 3, 3, 4, 5, 7, 8, 9] int[] b = indexSort(a); System.out.println(Arrays.toString(b)); } }

b) What is the of your algorithm? Solution: The time complexity of the indexSort is O(n2), where n is the number of elements in the array; since to find the position of any element in the array it has to be compared with all other elements. c) What is the invariant of your algorithm? Solution: After the ith pass, the first i elements of the original array are in their correct positions in the result array.

Exercise 2-5 Shaker Sort Shaker Sort is a simple optimisation of the Bubble Sort, that performs passes in both directions (simultaneous- ly), allowing out-of-place items to move fast across the whole array.

4 Shaker Sort performs the following steps:

1. Examines pairs of items, starting from the beginning of the array and performs swapping if necessary. 2. Examines pairs of items, starting from the end of the array and performs swapping if necessary. 3. Repeats the previous two steps until the array is sorted.

Consider the following array:

7 5 11 10 8

Example:

a) From the beginning: • Examine a[0] and a[1]. • Compare the contents of this pair (7 and 5): swap contents. Resulting array: 5 7 11 10 8 • Examine a[1] and a[2], compare the contents of this pair (7 and 11): do not swap contents. • Examine a[2] and a[3], compare the contents of this pair (11 and 10): swap contents. Resulting array: 5 7 10 11 8 • Examine a[3] and a[4], compare the contents of this pair (11 and 8): swap contents. Resulting array: 5 7 10 8 11 b) From the end: • Examine a[4] and a[3], compare the contents of this pair (11 and 8): do not swap contents. • Examine a[3] and a[2], compare the contents of this pair (8 and 10): swap contents. Repeat until array is sorted.

Write a method shakerSort to implement this algorithm.

Solution: import java.util.Arrays; public class ShakerSort {

public static void shakerSort(int[] x) { int temp;

// We divided by two because we already have two passes running on // our array, this means it is sufficient to pass on half of the array for(int i =0; i < (x.length/2); i++) { //The second check condition is to ensure we do not pass the range //of the array so we check j and j+1, same applies to the next loop

for(int j = i; jx[j+1]) { temp = x[j]; x[j] = x[j+1]; x[j+1] = temp; } } for(int k = x.length-2-i; k>i; k--)

5 { if(x[k] < x[k-1]) { temp = x[k]; x[k] = x[k-1]; x[k-1] = temp; } } } }

public static void main(String[] args) { int[] array = {10,11,3,2,5,8,1}; shakerSort(array); System.out.println(Arrays.toString(array)); } }

6 Exercise 2-6 Counting Sort

a) Write a method booleanSort that uses the following algorithm to sort an array x of positive integers. It should use another boolean flag array of as many elements as the maximum value in array x plus 1. This boolean array will be used to denote the presence of the elements of array x if found. Thus the algorithm, should loop through the integers in x. For each integer i of the array, the flag of index i of the boolean array should be set to true. Then the algorithm should reconstruct the from the true values of flag depending on their locations.

Solution: public static int[] booleanSort(int[] x) { int max = max(x); boolean[] flag = new boolean[max+1]; // filling the boolean flag array for(int i=0;i

int [] result = new int[x.length]; // getting which values are present in the flag array // and inserting them into the result array int index = 0; for(int i=0; i

public static int max(int[] x) { int max = x[0]; for(int i=1; imax) max = x[i]; } return max; }

b) How can you modify your algorithm to handle arrays with duplicate values? (Hint: Call it countingSort!)

Solution: Instead of the previous boolean flag array, we could use an int flag array. public static int[] countingSort(int[] x) {

int max = max(x); int[] flag = new int[max+1]; // filling the int flag array to handle duplicates for(int i=0;i

int [] result = new int[x.length]; // getting which values are present in the flag array and inserting them // into the result array as many times as indicated by the integer int index = 0; for(int i=0; i

7 { while(flag[i] > 0) { result[index] = i; index++; flag[i]--; } } return result; }

c) What is the time complexity of your algorithm?

Solution: The time complexity of the Boolean Sort is O(n + m) where n is the number of items in the list and m is the maximum value of the array.

d) What are the drawbacks of the algorithm described above?

Solution: The main drawback of the algorithm is the space complexity. If we are to sort an algorithm consisting of a large element of value e then we have to have a large flag array of size e+1 to hold a single element. Therefore, if m is much greater than n, then it becomes very inefficient. e) What is the invariant of your algorithm?

Solution: At the ith pass, the information of the occurrences of the first ith elements of array x will be stored in array flag.

Exercise 2-7 Student Records You are required to implement a sorting algorithm and use it to sort some student records. Each record is composed of:

• Name

• Student ID • GPA

Your program should sort a list of students, according to their names.

Solution: import java.util.Arrays; class Student { String name; int studentID; double gpa;

public Student(String n, int ID, double g) { name = n; studentID = ID; gpa = g; }

public String toString(){

8 return "ID: " + studentID + " "+name + " "+gpa; }

public static void swap(Student[] s, int i) { Student temp = s[i]; s[i] = s[i+1]; s[i+1] = temp; }

public static void sortByID(Student[] s) { for (int i = 0; i < (s.length - 1); i++) { for (int j = 0; j < (s.length - 1 - i); j++) { if(s[j] == null || s[j+1] == null) break; else { if ( (s[j].studentID) > (s[j+1].studentID)) swap(s, j); } } } }

public static void sortByName(Student[] s) { for (int i = 0; i < (s.length - 1); i++) { for (int j = 0; j < (s.length - 1 - i); j++) { if(s[j] == null || s[j+1] == null) break; else { if ((s[j].name.compareToIgnoreCase(s[j+1].name)) > 0) swap(s, j); } } } }

public static void main(String[] args) throws Exception { Student[] records = new Student[3]; records[0] = new Student("Mohamed",9181, 2.1); records[1] = new Student("Amira", 2241, 1.2); records[2] = new Student("Yasmine",1902,0.9); sortByID(records); System.out.println("After sorting by ID:"); System.out.println(Arrays.toString(records)); System.out.println("------"); sortByName(records); System.out.println("After sorting by Name:"); System.out.println(Arrays.toString(records)); System.out.println("------"); } }

Exercise 2-8 Midterm Exam 2013 Suppose that while your computer is sorting an array of objects, its memory is struck by a cosmic ray that changes exactly one of the keys to something completely different. For each of the sorting algorithms discussed in the lectures, what is the worst-case possibility in terms of the ordering of the final array? For each sorting algorithm the final array could

9 x) not even close to sorted, y) have just one or two keys out of place, or z) consist of two separate sorted subsets, one following the other, plus perhaps one or two additional keys out of place.

Choose x), y), or z) for the following algorithms. Justify your answers by examples.

a) Insertion sort b) Selection sort c) Bubble sort

Solution:

a) For insertion sort: z). consider the case where, half-way through the sort, the last key in the „sorted“ list is changed to a very low number.

1 3 5 7 9|8 4 2 6 10 zap! 1 3 5 7 0|8 4 2 6 10

Using an in-place insertion sort implementation that searches from the end of the sorted array, the remaining keys will never get past the zero.

1 3 5 7 0 2 4 6 8 10

Note that if a key in the „unsorted list“ is zapped, no harm is done at all. b) For selection sort: y). If an item in the „sorted list“ is zapped, only that one item is affected. If an item in the „unsorted list“ is zapped to a value lower than the last item in the sorted list, that item will be out-of-place, but other items are still sorted. c) For bubble sort: y). Similar to the selection sort, while the bubble sort is running, there is a „sorted part“. Namely, the last i items are sorted after i iterations. If an item in the „sorted list“ is zapped, only that one item is affected. If an item in the „unsorted list“ is zapped to a value bigger than the last item in the sorted list, that item will be out-of-place, but other items are still sorted.

Exercise 2-9 Midterm Exam 2015 Suppose we have an array a containing n integers. Initially the integers are not sorted. We would like to rearrange the array in ascending order using the following algorithm. Bogosort simply shuffles elements of the array randomly until it is sorted. The Bogosort is only a theoretical concept, which has no use in practical applications. The Bogosort is also know as the Slow Sort or Stupid Sort. Algorithm in Pseudocode: bogoSort(array) while !isSorted(array) shuffle(array)

a) Write a Java method void bogoSort(int[] a) that takes an array a and sorts the array based on the above described algorithm. Please note that the shuffling operation should be done in every pass for all numbers of the array randomly. You are requested to implement the shuffle and the isSorted methods.

10 Solution: import java.util.Arrays; import java.util.Random; public class Ex11 {

/** * This method shuffles every element in the array by following the steps: * 1- Loop on all the array elements 2- generate a random position in the * range from (0 to a.length-1) 3- swap the current element with the element * at the random position * */ public static void shuffle(int[] a) {

for (int i = 0; i < a.length; i++) { Random randGen = new Random(); int newPos = randGen.nextInt(a.length); // OR we can user Math.random() method // int newPos =(int) (Math.random()*a.length) ; int temp = a[i]; a[i] = a[newPos]; a[newPos] = temp; } }

/** * This method shuffles every element in the array by following the steps: * 1- Create a new array to shuffle the numbers in it 2- generate a random * position in the range from (0 to a.length-1) 3- Insert the current * element at the random position in the new array only if it empty (no * number was inserted at this cell before) * */ public static void shuffle1(int[] a) { int[] b = new int[a.length]; boolean[] c = new boolean[a.length]; for (int i = 0; i < a.length; i++) { int newPos = (int) (Math.random() * a.length); while (c[newPos]) newPos = (int) (Math.random() * a.length); c[newPos] = true; b[newPos] = a[i]; } for (int i = 0; i < a.length; i++) a[i] = b[i];

}

static boolean isOrdered(int[] a) { for (int i = 0; i < a.length - 1; i++) if (a[i] > a[i + 1]) return false; return true; }

static void bogoSort(int[] a) { while (!isOrdered(a)) shuffle(a); System.out.println("The array is sorted");

}

public static void main(String[] args) { int[] a = { 4, 7, 1, 9, 3 }; bogoSort(a);

}

}

11 b) Given an intially unordered array

1. What is the best case complexity of the algorithm. Justify your answer. 4cm Solution: The Best case complexity is O(n). The array will get sorted after the first shuffle. 2. What is the worst case complexity of the algorithm. Justify your answer. 4cm Solution: The worst case complexity is unbounded. The number of comparisons and swaps are both unbounded as the array is randomly shuffled. 3. What is the invariant of the algorithm? Justify your answer. Solution: The algorithm has no invariant. We can not guarantee any condition to be true at the beginning and end of every execution of a loop due to the random shuffling.

12