difference between these two bubble sort implementations [duplicate] - java

This question already has answers here:
bubble sort with a boolean to determine whether array is already sorted
(3 answers)
Closed 8 years ago.
I have two implementations of bubble sort, but one of them works fine and other one does not can anybody explain me what is the difference in these two
first one this works fine
private static int[] sortBuble(int[] a) {
boolean swapped = true;
for (int i = 0; i < a.length && swapped; i++) {
swapped = false;
System.out.println("number of iteration" + i);
for (int j = 1; j < a.length; j++) {
if (a[j - 1] > a[j]) {
int temp = a[j - 1];
a[j - 1] = a[j];
a[j] = temp;
swapped = true;
}
}
}
return a;
}
Second one this does not work, but they look more or less same
private static int[] sortBuble1(int[] a) {
boolean swapped = true;
for (int i = 0; i < a.length && swapped; i++) {
swapped = false;
System.out.println("number of iteration" + i);
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
swapped = true;
}
}
}
return a;
}

They are not the same. You are holding i constant for each iteration of the inner-for loop in the second example, and using a[i] for comparison, which is just incorrect. As I said in my other answer, the first is also inefficient. The following is an optimized version of the first one:
private static int[] bubblesort(int[] nums)
{
boolean done = false;
for (int i = 0; i < nums.length && !done; i++)
{
done = true;
for (int j = nums.length-1; j > i; j--)
{
if (nums[j] < nums[j-1])
{
int temp = nums[j];
nums[j] = nums[j-1];
nums[j-1] = temp;
done = false;
}
}
}
return nums;
}
At the end of the ith iteration, we know that the first i elements are sorted, so we don't need to look at them anymore. We need the boolean to determine if we need to continue or not. If no swaps are made, then we are done. We can remove the boolean and it will still work, but will be less efficient.

The difference lies in the indexes used for the arrays.
In the first case, your inner for loop with j is independent of i. Also, you use adjacent values of j while swapping, so that you are always swapping adjacent values in the array.
In the second case, your inner for loop starts j from i + 1. And you're using both i and j to index your array. So you're actually not comparing adjacent elements, but elements that may be far apart (e.g., when i=1 and j=4). That is not bubble sort, and this algorithm will not work that way.

Related

what is the difference between j=i+1 and j=1 if i=0 (in a nested for loop)?

I don't understand the reason why the first for loop gives only one result, while the second gives me two results. Can someone explain to me how it works?
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] array = {5,5,11,15};
int target = 10;
System.out.print("First Solution: ");
twoSum(array,target);
System.out.println();
System.out.print("Second Solution: ");
twoSum2(array,target);
}
public static void twoSum(int[] array, int target){
for(int i = 0; i < array.length; i++){
for(int j = i+1; j < array.length; j++){
if(array[i] + array[j] == target){
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
// if i want all the possible solutions
public static void twoSum2(int[] array, int target){
for(int i = 0; i < array.length; i++){
for(int j = 1; j < array.length; j++){
if(array[i] + array[j] == target){
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
}
first output: [0, 1]
second output: [0, 1][1, 1]
Assumption
Your use case is to find pairs of elements in array that sum up to a target value
What's happening in twoSum() method or j = i + 1 case
As the inner loop starts with the immediately next index of the outer loop you are distinct pairs which are adding up to the desired value
What's happening in twoSum2() method or j = 1 case
As the inner loop starts with the index 1 every time regardless of the outer index value you are getting duplicate pairs which are adding up to the desired value along with an erroneous situation of a single element getting counted twice(I believe it's a bug and should be handled by an if condition check). Moreover, since it's starting from index 1 instead of 0 even all duplicates are not guaranteed. This approach should be avoided if my assumption of your use case is correct
Recommendation
Try exploring the Hashset based approach for this problem here. You can utilize the code or tweak it to match your use case. It's time complexity will be linear i.e. O(n) better than the current algorithm used in your code which is quadratic i.e. O(n^2)
The first finds all (i, j) such that j > i in approx. n*n/2 steps.
The second loop is probably long. If meant for (i, j) such that i ≠ j
public static void twoSum2(int[] array, int target) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++){
if (j != i) {
if (array[i] + array[j] == target) {
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
}
This excludes (0, 0), (1, 1), (2, 2), ...
However this takes approx. n² steps.
One could also take extend the first solution.
public static void twoSum2(int[] array, int target) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++){
if (array[i] + array[j] == target) {
System.out.print(Arrays.toString(new int[]{i, j}));
System.out.print(Arrays.toString(new int[]{j, i}));
}
}
}
}
Tip: Arrays.sort may be used so you may start with largest fitting number. And Arrays.binarySearch to find target - array[i].

Explanation of best case of Bubble Sort being O(n) and not O(n^2)?

Given a Bubble Sort algorithm
for (int i = 0; i < A.length - 1; i++)
for (int j = 0; j < A.length - i - 1; j++)
if (A[j] > A[j + 1]) {
int temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
}
In the case that the array given is already sorted, the if statement in the inner-loop will always be false breaking the inner for loop and incrementing j until A.length-i-1 is reached. When A.length-i-1 is reached, i is incremented. This process cycles until i reaches A.length-1.
My confusion:
If both nested loops iterate to their respective upper-bounds, although there are no swaps being made, wouldn't the time complexity still be O(n^2) for best-case? Can anyone explain simply to me why it would be O(n)
If the program is as is, yes it will still take O(n^2) for the best-case scenario. But you can enhance this program.
During your first pass, you will see that no exchange has taken place. You can keep a flag which checks that if during a pass no exchange has taken place, you don't need to further passes.
In that case, you will only do one pass and time complexity will be O(n)
Sample Program (Could be better structured):
boolean previousIterationSwap = false;
final int[] A = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = 0; i < A.length - 1; i++) {
// After the first iteration check if previous iteration had any
// swap
if (i > 0 && !previousIterationSwap) {
break;
}
for (int j = 0; j < A.length - i - 1; j++) {
if (A[j] > A[j + 1]) {
previousIterationSwap = true;
final int temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
} else {
previousIterationSwap = false;
}
}
}
Consider the following code:
int[] bubbleSort(int[] arrayToBeSorted){
int n = arrayToBeSorted.length; // length of array
int temp = 0; // to store value temporarily
int flag =0; // to check if given array already sorted or not
for (int i=0;i<n-1;i++){
for (int j=0;j<n-i-1;j++){
if(arrayToBeSorted[j] > arrayToBeSorted[j+1]){
flag = 1;
temp = arrayToBeSorted[j];
arrayToBeSorted[j] = arrayToBeSorted[j+1];
arrayToBeSorted[j+1] = temp;
}
}
//checking if array is sorted already or not
if (flag ==0){
System.out.println("Already sorted so time complexity is only O(N)");
break;
}
}
return arrayToBeSorted;
}
If you have an unsorted array in the above code, then the nested for loop will be executed until the given array is sorted completely. Thus it will take n*n -> O(n*n) time complexity.
But if you provide an already sorted array, you can see in the above code, when i=0, then the nested j loop will be executed n-i-1 times but the code inside if block won't be executing.
for (int j=0;j<n-i-1;j++){
if(arrayToBeSorted[j] > arrayToBeSorted[j+1]){
flag = 1;
temp = arrayToBeSorted[j];
arrayToBeSorted[j] = arrayToBeSorted[j+1];
arrayToBeSorted[j+1] = temp;
}
}
This means your array is already sorted. so the flag will remains 0 as it is.
Thus before going to the second increment i.e i=1,
your loop will stop so you save another n iteration.
Thus, the loop executes only n times not n*n times.
This will break your loop for further execution if array is already sorted
if (flag ==0){
System.out.println("Already sorted so time complexity is only O(N)");
break;
}

Find number of duplicate that occurs in array - Java

I can't wrap my head around this. Need to find duplicates and I did. All now that is left is to print how many times a duplicate appears in the array. I just started with Java,so this needs to be hard coded for me to understand. Spend last two days trying to figure it out but with no luck.. Any help will be great! Talk is cheap,here is the code..
import java.util.Arrays;
public class LoopTest {
public static void main(String[] args) {
int[] array = {12,23,-22,0,43,545,-4,-55,43,12,0,-999,-87};
int positive_counter = 0;
int negative_counter = 0;
for (int i = 0; i < array.length; i++) {
if(array[i] > 0) {
positive_counter++;
} else if(array[i] < 0) {
negative_counter++;
}
}
int[] positive_array = new int[positive_counter];
int[] negative_array = new int[negative_counter];
positive_counter = 0;
negative_counter = 0;
for (int i = 0; i < array.length; i++) {
if(array[i] > 0) {
positive_array[positive_counter++] = array[i];
} else if(array[i] < 0) {
negative_array[negative_counter++] = array[i];
}
}
System.out.println("Positive array: " + (Arrays.toString(positive_array)));
System.out.println("Negative array: " + (Arrays.toString(negative_array)));
Arrays.sort(array);
System.out.println("Array duplicates: ");
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if(array[i] == array[j]) {
System.out.println(array[j]);
}
}
}
}
}
Since you are already sorting the array you can find the duplicates with just one loop (they will be next to each other right?). So you can do something like:
Arrays.sort(array);
System.out.println("Array duplicates: ");
int lastValueCount=1; //How many times we met the current value (at least 1 - this time)
for (int i = 1; i < array.length; i++){
if(array[i] == array[i-1])
lastValueCount++; //If it is the same as the previous increase the count
else {
if(lastValueCount>1) //If it is duplicate print it
System.out.println(array[i-1]+" was found "+lastValueCount+" times");
lastValueCount=1; //reset the counter
}
}
Result for your array is:
Array duplicates:
0 was found 2 times
12 was found 2 times
43 was found 2 times
Also you can use some of the Java bells and whistles like inserting the values into Map or something like that but I guess you are looking from an algorithmic point of view so the above is the simple answer with just one loop
Just go through your solution, first you separate positive and negative numbers in two different arrays, then you never use them, so what's the purpose of this separation ?
I am giving you just an idea related to your problem, it's better to solve it by your self so that you can get hands on Java.
Solution: you can use Dictionary-key value pair. Go through your array, put element in dictionary as a key and value as zero, on every iteration check if that key already exist in Dictionary, just increment its value. In the end, all of the values are duplicates that occurs in your array.
Hope it helps you.
From the algorithmic point of view, Veselin Davidov's answer is good (the most efficient).
In a production code, you would rather write it like this :
Map<Integer, Long> result =
Arrays.stream(array)
.boxed() //converts IntStream to Stream<Int>
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));
The result is this Map :
System.out.println(result);
{0=2, 545=1, -4=1, -22=1, -87=1, -999=1, -55=1, 23=1, 43=2, 12=2}
An easy way would be using Maps. Without changing code too much:
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = i + 1; j < array.length; j++) {
if(array[i] == array[j]) {
System.out.println(array[j]);
count++;
}
}
map.put(array[i], count);
}
Docs:
https://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Edit: As a recommendation, after you are done with the example, you should analize your code and find what isn´t neccesary, what could be done better, etc.
Are all your auxiliary arrays neccesary? Are all loops necessary?
You can do it by creating an array list for duplicate values:-
Arrays.sort(array);
System.out.println("Array duplicates: ");
ArrayList<Integer> duplicates = new ArrayList<Integer>();
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if(j != i && array[i] == array[j] && !duplicates.contains(array[i])){
duplicates.add(array[i]);
System.Out.println(duplicates[duplicates.size()-1]);
}
}
}
public static void findDuplicate(String s){
char[] charArray=s.toCharArray();
ArrayList<Character> duplicateList = new ArrayList<>();
System.out.println(Arrays.toString(charArray));
for(int i=0 ; i<=charArray.length-1; i++){
if(duplicateList.contains(charArray[i]))
continue;
for(int j=0 ; j<=charArray.length-1; j++){
if(i==j)
continue;
if(charArray[i] == charArray[j]){
duplicateList.add(charArray[j]);
System.out.println("Dupliate at "+i+" and "+j);
}
}
}
}

Is my Bubble Sort implementation correct?

public class MyBubbleSort {
public static void bubbleSort(int[] a, int n) {
int i, j, temp;
for (i = 0; i <= (n-2); i++) {
for (j = i + 1; j <= (n-1); j++) {
if (a[j] < a[i]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
}
It gives me a sorted array when I do a debug but I just wanted to be 100% sure.
You could tidy the code a bit:
Make it extend an interface Sort with a single method sort(int[] a, int n).
MyBubbleSort method should implement said interface and not be static.
int i and j should be declared inside the corresponding fordeclaration.
temp should be declared inside the inner if.
It is questionable if you need to pass in the length of the array as this is a property on the Java array type. The only time to pass the length would be if you intended to sort sub arrays.
You are doing a correct bubble sort ! In your "if" statement, you are correctly swapping two adjacent values if they are not well sorted. And this is the principle of the bubble sort: you repeat this process until your array is correctly sorted. https://www.youtube.com/watch?v=lyZQPjUT5B4
However you are doing strange things in your code ! As zapl said in the comments you don't need this "n" parameter as you can simply get you array's size in your method.
Also prefer using " < length ", " < length - 1 " instead of your <= which are, if you think well, more intuitive
public static void bubbleSort(int[] tab) {
int n = tab.length ;
for (int i = 0; i < n-1; i++) {
for (int j = i + 1; j < n ; j++) {
if (tab[j] < tab[i]) {
int temp = tab[i];
tab[i] = tab[j];
tab[j] = temp;
}
}
}
}

No duplicates in an array [duplicate]

This question already has answers here:
How to get unique values from array
(13 answers)
Closed 8 years ago.
void RemoveDups(){
int f=0;
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i;k<nelems;k++)
{
arr[k]=arr[k+1];
}
nelems--;
}
if(i==(nelems+1)){
f++;
i=f+1; //increment again
}
}
}
This is the logic i have written to remove duplicate elements from an array ,but this is not working at all ?what changes i should make to make it work? or you people have better logic for doing the same considering time complexity.and i don't want to use built-in methods to achieve this.
int end = input.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (input[i] == input[j]) {
int shiftLeft = j;
for (int k = j + 1; k < end; k++, shiftLeft++) {
input[shiftLeft] = input[k];
}
end--;
j--;
}
}
}
I think you can use Set Collection
copy all the values to an HashSet and then using Iterator access the Values
Set<Integer> hashset= new HashSet<Integer>();
You have two options, C# has the Distinct() Linq expression that will do this for you (Missed the Java tag), however if you need to remove items, have you thought about sorting the list first, then comparing the current item to the previous item and if they're the same, remove them. It would mean your diplicate detection is only ever running through the array once.
If you're worried about sort you could easily implement an efficient bubble sort or somthing to that effect
You never decrease i after You compared for examlpe arr[0] to arr[5], You never will test arr[1] == arr[2]
You need to start a new loop (i) after You've incremented f.
try
for(int f=0;f<nelems-1;f++)
{
for(int i=f+1;i<nelems;i++)
{
...
}
}
with this nested for loop you can compare every two element of the array.
a good start is to eliminate duplicate elements without shrinking the array which is done lastly:
public class run2 extends Thread {
public static void main(String[] args) {
int arr[] = { 1, 2, 2, 3, 5, 6, 5, 5, 6, 7 };
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] == -1)
j++;
if (arr[i] == arr[j])
arr[j] = -1;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == -1) {
for (int j = i; j < arr.length; j++) {
if (arr[j] != -1) {
arr[i] = arr[j];
arr[j] = -1;
break;
}
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
Adapt this code :
public static int[] removeDuplicates(int[] numbersWithDuplicates) {
// Sorting array to bring duplicates together
Arrays.sort(numbersWithDuplicates);
int[] result = new int[numbersWithDuplicates.length];
int previous = numbersWithDuplicates[0];
result[0] = previous;
for (int i = 1; i < numbersWithDuplicates.length; i++) {
int ch = numbersWithDuplicates[i];
if (previous != ch) {
result[i] = ch;
}
previous = ch;
}
return result;
}
As far as I understood from your code,you are comparing each value starting from index 0 to the rest of the element and when you see the element which is located at index f your are trying to shift the entire array and decrementing the size of array(nelems).Look at line no. 11
if(i==(nelems+1)){
f++;
i=f+1;
The problem is when i is set to f+1,i will again be incremented in the for loop for the next iteration.So basically i starts comparing from f+2.And also you are comparing i with (nelems+1) considering the case when nelems decremented but you are not considering the case when i reaches the end without decreasing nelems in that case i will never be equale to (nelems+1).Now considering your logic you could do 2 things.
1.Here is your working code.
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i+1;k<nelems;k++)
{
arr[k-1]=arr[k];
}
if(i==(nelems-1)){
f++;
i=f;
}
nelems--;
}
if(i==(nelems-1)){//end of the loop
f++;
i=f; //increment again
}
}
2.You could use an outer for loop alternatively that will increment the f value once the inner for is completed.
void RemoveDups(){
for(int f=0;f<nelems;++f){
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i;k<nelems;k++)
arr[k]=arr[k+1];
nelems--;
}
}
}
}
Now your problem is solved but the time complexity of your code will be(O(N^3)).
Now instead of shifting the entire array at line 4,you could just swap the arr[f] with last element.
if(arr[f]==arr[i]){
swap(arr[f],arr[nelems-1]);
nelems--;
}
it will reduce the time complexity from O(N^3) to O(N^2).
Now I'll suggest you my method
1.just sort the array.It will be done in O(NlogN).
2.now using one for loop you can get what do you wanted.
void RemoveDups(){
int k=0,i;
for(i=1;i<nelems;++i){
while(arr[i]==arr[i-1])
++i;
arr[k++]=arr[i-1];
}
arr[k++]=arr[i-1];
}
Now basically you got an array of size k,which contains non repeated element in sorted order and the time complexity of my solution is O(NlogN).

Categories

Resources