Sorting arrays (Bubble Sort) - java

I have a small doubt while sorting arrays and yeah I am new to programming. Take a look at this code for example:
public void bubbleSort(int[] array) {
boolean swapped = true;
int j = 0;
int tmp;
while (swapped) {
swapped = false;
j++;
for (int i = 0; i < array.length - j; i++) {
if (array[i] > array[i + 1]) {
tmp = array[i];
array[i] = array[i + 1];
array[i + 1] = tmp;
swapped = true;
}
}
}
In the above code, why do we have to use j++ and i < (array.length-j) as the test expression? We could have rather used i < (array.length) as the test expression while omitting the variable j. Any answers?

"Why do we have to use j++ and i < (array.length-j) as the test expression?"
The reason behind is at any time elements array[ array.length -j ] to array[array.length - 1] are already sorted.
Example: Say you have array of length n.
So after the first iteration the biggest element will be placed at array[n - 1].
So because the largest element is already sorted on the next iteration we will only sort array of length n - 1.
After the second iteration the second biggest element will be placed at array[ n - 2].
So because the 1st largest and 2nd largest elements are already sorted on the next iteration we will only sort array of length n - 2, and so on...
The running time of the algorithm will be which is
As you said it we could have used i < (array.length - 1) but we will be just doing a lot of work for nothing. If we do this the running time will be (nn) which is O(nn). But though the running time is still O(n*n) but it is obvious that is smaller than , hence the first one is efficient.

Related

Why does Bubble Sort outer loop end at n-1?

I found this bubble sort (first sort I'm ever studying), I understand it almost fully but I'm stuck on one spot.
public static int[] bubbleSort(int[] tempArray) {
int i, j, temp, n = tempArray.length;
boolean swapped;
for (i = 0; i < n - 1; i++) {
swapped = false;
for (j = 0; j < n - i - 1; j++) {
if (tempArray[j] > tempArray[j + 1]) {
temp = tempArray[j];
tempArray[j] = tempArray[j + 1];
tempArray[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
break;
}
return tempArray;
}
what is the point of "n - 1" in outer loop besides helping to make inner loop (n - i - 1) shorter? I tried removing the "n -1" and having count++ to work in the inner loop and the result was the same, so what is the reason for it then? Thanks!
It is because the largest element is already sorted in the first iteration.
A picture is worth a thousand words
Image is from https://en.wikipedia.org/wiki/Bubble_sort
Additional there is no need for the last element because bubble sort is all about swapping adjacent element and the last element doesn't have adjacent element.
It is because bubble sorting works on swapping of adjacent element.
If outer loop goes till n then in the inner loop you cannot pick another element.
temp = tempArray[j];
tempArray[j] = tempArray[j + 1];
tempArray[j + 1] = temp;
This is because the size of array is till n and inner loop swap between j and j+1.
Feel free to ask further doubts.

Find the pair (i,j) such that i<j and and (a[i] + a[j]) is maximum

Given an unsorted array – arr find a pair arr[i] and arr[j] such that
arr[i] < arr[j] & i<j and (arr[i] + arr[j]) is maximum.
Expected time complexity – O(n)
For array a = {4, 1, 3, 2, 5, 3}
pair is (4, 5).
Here is the code I've tried..
void findPair(int[] a){
int n = a.length;
int max = a[0];
int secondMax = Integer.MIN_VALUE;
for(int i=1; i<n; i++){
if(a[i]>max){
secondMax = max;
max = a[i];
}
}
if(secondMax == Integer.MIN_VALUE){
System.out.println("-1 -1");
}
else{
System.out.println(secondMax+" "+max);
}
}
Here's a solution using a stack. The idea is that the stack always contains a descending sequence, such that for each number you look at, it can be paired with the largest number in the stack lower than it.
It's safe to pop the numbers off as you use them, because e.g. if you have a 6 and the top of the stack is 3, there is no need to keep the 3 around in case it can be paired with a bigger number; if there's a 7 later, you would wait to pair it with the 6 instead of the 3.
public void solution(int[] arr) {
Stack<Integer> stack = new Stack<>();
int bestX = -1, bestY = -1, bestSum = -1;
for(int y : arr) {
while(!stack.isEmpty() && stack.peek() < y) {
int x = stack.pop();
if(x + y > bestSum) { bestX = x; bestY = y; bestSum = x + y; }
}
stack.push(y);
}
System.out.println(bestX + " " + bestY);
}
The time complexity is O(n) despite the nested loop, because the inner loop always pops from the stack, and each element is only pushed once so it can only be popped once.
I thought about your question a lot and I think I found an acceptable solution.
You should split the array into subarrays starting from the end of the array (right side). Building the sub arrays is in iterative manner. You start with the right-most number and you add to the subarray all the numbers before him that are lower than him. The iteration goes to the next subarray when you reach a number which is bigger/equal to the right-most number in the subarray.
Example:
Your array is: {1,7,3,4,5,4,6,2}
Output should be: (5,6)
The splitting should be:
{{1, 7}, {3, 4, 5, 4, 6}, {2}}
<--(3) <--(2) <--(1)
You start from the last index with the value of 2. The number before him is 6 so that's the end of the first subarray. Next you start with 6, all the numbers before him until 7 are lower than 6 so you add them to that subarray. The last subarray starts with 7 and adds 1. See arrows for clarification.
Next, check within each subarray which number from left to the right-most number is max and mark it for possible pair with the right-most number.
In our example it would be: (1,7), (5,6).
There are only two options because {2} has only 1 variable. In the subarray with 6 as right-most the max number is 5 and in the subarray with 7 as right-most 1 is the only other number so it is also the max.
If no pair is found, return "no possible pair found".
Finally, check sum and return biggest pair: (5,6)
1+7 = 8 < 5+6 = 11
Why is this O(n) ?
You scan the array once for splitting: O(n)
Each subarray of size d you scan for max value: O(d)
Sum of all subarrays scanning: O(n)
Total: O(n)
I'm not strong in Java so my code can be written in Python and the conversion should be easy (because Python is easy!). If you wish for Python code, let me know and I'll write some for you. Also, I can explain more why this algorithm works (If not fully understood).
DISCLAIMER: Solution is O(n^2), not O(n) as required by the OP
What about using 2 nested loops:
i from 0 to a.length
j from i+1 to a.length
This ensures that i<j
Then have an if to ensure that a[i]<a[j] and find the max
int currentMax = -1;
int foundI = -1;
int foundJ = -1;
for(int i=0; i<a.length; i++) {
for(int j=i+1; j<a.length; j++) {
if(a[i] < a[j] && a[i] + a[j] > currentMax) {
currentMax = a[i] + a[j];
foundI = i;
foundJ = j;
}
}
}
Output:
System.out.println("i:" + foundI);
System.out.println("j:" + foundJ);
System.out.println("a[i]:" + a[foundI]);
System.out.println("a[j]:" + a[foundJ]);
System.out.println("sum:" + currentMax);
i:0
j:4
a[i]:4
a[j]:5
sum:9

selection sort loop questions in Java

I have a basic question about the inner loop length in Java selection sort. Here is the commonly used code for selection sort:
package com.java2novice.algos;
public class MySelectionSort {
public static int[] doSelectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int index = i;
for (int j = i + 1; j < arr.length; j++)
/* why not the length is not arr.length-1? I think the length is
exactly the same as what it is, the array's length is a
static number as array.length-1, but when it comes to the inner
loop why it plus 1 to the array length? */
if (arr[j] < arr[index])
index = j;
int smallerNumber = arr[index];
arr[index] = arr[i];
arr[i] = smallerNumber;
}
return arr;
}
}
Imagine you're trying to sort five items. The array length is 5, which means the indexes are 0 through 4.
In the first iteration of the inner loop, you have i=0 and j=1. You need j to index to the end of the array. That's why the expression in the inner loop is j < array.Length.
i, of course, only goes from 0 to 3, which is why the outer loop has i < array.Length - 1.
If you lay five playing cards on a table and walk through the steps of the selection sort, you'll get a better idea of what's happening here.
the first loop does not need to check the last index, therefore, it goes to arr.length - 1. on the second loop, of course, the last index of the array must be checked so the loop goes to the last index (arr.length).
imagine if the first loop goes to the last index. then this line for (int j = i + 1; j < arr.length; j++) will never execute.
check out this Pseudo code of selection sort for a better understanding of the algorithm

Are the following two recursive sorting methods the same?

I've been working on selection sort and bubble sort using recursion. I've finally come up with two methods, and they worked perfectly fine. But as I took a final look at those, they look like just one one method which is selectionSortRecursive. Could you tell me the difference (or are they the same)?
public static void selectionSortRecursive(Comparable[] list, int n)
{
Comparable temp;
if ( n > 1 ){
for ( int i = 0; i < n - 1; i++ )
{
if(list[i].compareTo(list[i + 1]) > 0){
temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
}
}
selectionSortRecursive(list, n - 1);
}
}
public static void bubbleSortRecursive( Comparable[] list, int n)
{
Comparable tmp;
if (n >1) {
for (int i = 0; i < n - 1; i++)
{
if(list[i+1].compareTo(list[i]) < 0)
{
tmp = list[i];
list[i] = list[i+1];
list[i+1] = tmp;
}
}
bubbleSortRecursive( list, n - 1);
}
}
The only line which is different is
if(list[i].compareTo(list[i + 1]) > 0){
and
if(list[i+1].compareTo(list[i]) < 0)
and provided compareTo is implemented correctly this will do the same thing.
BTW the if(n > 1) check is redundant. And I would move tmp to the most inner scope you can.
Both sorts are bubble sorts. A bubble sort "bubbles" values to the top/right position.
A selection sort selects the lowest/highest value repeatedly, swap in the selected with the position it needs to place it. i.e. the swap would be outside the loop to find the lowest/highest.
It's both bubble sort, one bubbles the element from the top to the bottom, the other one does it the way round. Selection sort is different: it searches the smallest elements of all remaining (unsorted) elements and places it in the next slot, it does not change any other elements. Bubble sort, instead, always compares tow elements and swaps them is the first one is bigger (or smaller) than the second one - which is what you are doing.

How does this bubblesort variation effectively carry out a sort?

// A strange variation on a bubblesort I created inadvertently. I omitted the usual if a[j] >a[j+1] by mistake yet the code was still able to function perfectly. Would there be any advantage to using a bubblesort of this kind over a normal bubblesort.
public int[] bubbleSort(int[] a)
{
for (int i = 0; i < a.length - 1; i++)
{
for (int j = i + 1; j < a.length - 1; j++)
{
if (a[i] > a[j])
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
return a;
}
Notice that at the end of the first iteration of the outer loop, the first value in the array will necessarily be the minimum value in the array (do you see why?) After the second iteration, the second value will be the second-smallest value, and after the third iteration the third value will be the third-smallest value, etc.
(That said, I think there's a bug in your logic. The upper bound on j should be a.length rather than a.length - 1, since otherwise the last value in the array is never compared to anything else or moved.)
You might want to look into selection sort, which works by moving the smallest value in the array to the front, then the second-smallest, etc. The algorithm you've come up with is (essentially) a modified version of selection sort rather than a modified bubble sort.
Hope this helps!

Categories

Resources