Ok I'm trying to write an algorithm for sorting an array, in this case an array of random integers. I know QuickSort or similar would obviously more efficient, but for this assignment I have to basically make a modified version of the inefficient Bubble Sort algorithm.
The idea is to compare integers across a gap. After each pass, the gap is supposed to be cut in half. If value on left is greater than value on right, they are swapped. Execution is supposed to continue until no swaps occurs or gap is 1. I'm usually pretty descent at this sort of thing but it seems that I'm missing something. For some reason the algorithm isn't sorting my arrays.
Here is my code. Maybe someone can see what I'm missing:
public class ShellArray
{
private int capacity;
private int [] randArray;
private static final int RANGE = 200; //Range set to 200 for possible integers.
public ShellArray(int capacity)
{
this.capacity = capacity;
randArray = new int[capacity];
populate(randArray, RANGE, capacity);
}
/**************************************************************************************************************************************************
//
//Populates array with random integers within given range.
//
***************************************************************************************************************************************************/
private static void populate(int [] myArray, int numRange, int extent)
{
Random r = new Random();
for (int i = 0; i < extent; i++)
myArray[i] = (r.nextInt(numRange)+1);
}
/**************************************************************************************************************************************************
//
//The first version of shellSort calls the second version with min value as 0 and max as length of randArray-1. Takes no parameters.
//
***************************************************************************************************************************************************/
public void shellSort()
{
shellSort(0, randArray.length-1);
}
/**************************************************************************************************************************************************
//
// shellSort which takes min and max parameters. Calculates gap at center, across which values are compared. Passes continue until gap size is 1
// and array is sorted.
// Uses boolean sorted to indicate when array is sorted so passes don't continue needelessly after array is sorted. Essentially, if no values
// are swapped after a pass, we know array is sorted and sorted is not set to false.
//
// Outer for loop controls position of final value. Since largest value is bubbled to end, position decreases by 1 after each pass.
// After each pass, size of gap is cut in half, as long as gap is 2 or greater. Otherwise gap would become too small.
// Inner for loop controls the index values to be compared.
// Uses swap method to swap values which are not in the correct order.
// Array is printed after each pass.
//
***************************************************************************************************************************************************/
public void shellSort(int min, int max)
{
String result;
int gap;
int j = 0;
int size = randArray.length-1;
boolean swapped;
for(gap = size/2; gap <= 0; gap = gap/2)
{
swapped = true;
while (swapped)
{
swapped = false;
int comp;
for(comp = 0; comp+gap <= size; comp++)
{
if (randArray[comp] > randArray[comp+gap])
{
swap(comp, comp+gap);
swapped = true; //swapped set to true if any element is swapped with another.
}
else
swapped = false;
}
}
result = "";
for(int y = 0; y < randArray.length; y++)
{
result += randArray[y] + " ";
j++;
}
System.out.println("Pass " +j+": " +result+"\n");
}
}
/**************************************************************************************************************************************************
//
// Swaps two values in the array.
//
***************************************************************************************************************************************************/
private void swap(int index1, int index2)
{
int temp = randArray[index1];
randArray[index1] = randArray[index2];
randArray[index2] = temp;
}
public String toString()
{
String result = "";
for(int y = 0; y < randArray.length; y++)
result += randArray[y] +" ";
return result;
}
}
You haven't provided the details of your assignment, but the idea of a sort along these lines is that the final stage (i.e. with gap == 1) is a bona fide standard sort all on its own -- in this case, I guess a bubble sort -- and the prior stages pre-treat the input so that the efficiency of that final sort is much better than for random input. At least for gap == 1, then, you must repeat the sort loop until there are no swaps.
There are two main variations possible here, and you haven't given us the information to know which you want:
The first variation shrinks the gap after each iteration of the sort loop until it reaches 1, then repeats with that gap until there are no more swaps.
The second variation repeats the sort loop with the same gap until there are no swaps, then shrinks the gap and repeats.
My guess would be that you want the second, as that's the one that is actually a shell sort (of an unusual flavor). Even though it might sound like it would be less efficient than the other, there's a good chance that it's more efficient, because devoting a small amount of additional effort when the gap is large accomplishes larger element movements in fewer steps.
Related
I was going through the below sample program and was trying to understand how the below recursion works, I couldn't understand how the left and the right array elements are sorted, finally merging the two subarrays as below. Any pictorial explanation of the below method would be of great help, as I try to understand the below recursive code.
public static int[] mergeSort(int[] arrayToSort) {
// BASE CASE: arrays with fewer than 2 elements are sorted
if (arrayToSort.length < 2) {
return arrayToSort;
}
// STEP 1: divide the array in half
// we use integer division, so we'll never get a "half index"
int midIndex = arrayToSort.length / 2;
int[] left = Arrays.copyOfRange(arrayToSort, 0, midIndex);
int[] right = Arrays.copyOfRange(arrayToSort, midIndex, arrayToSort.length);
// STEP 2: sort each half
int[] sortedLeft = mergeSort(left);
int[] sortedRight = mergeSort(right);
// STEP 3: merge the sorted halves
int[] sortedArray = new int[arrayToSort.length];
int currentLeftIndex = 0;
int currentRightIndex = 0;
for (int currentSortedIndex = 0; currentSortedIndex < arrayToSort.length;
currentSortedIndex++) {
// sortedLeft's first element comes next
// if it's less than sortedRight's first
// element or if sortedRight is exhausted
if (currentLeftIndex < sortedLeft.length
&& (currentRightIndex >= sortedRight.length
|| sortedLeft[currentLeftIndex] < sortedRight[currentRightIndex])) {
sortedArray[currentSortedIndex] = sortedLeft[currentLeftIndex];
currentLeftIndex++;
} else {
sortedArray[currentSortedIndex] = sortedRight[currentRightIndex];
currentRightIndex++;
}
}
return sortedArray;
}
The sorting is performed in the merging loop:
if the array is very small (0 or 1 element), mergeSort() returns it immediately.
otherwise, it splits the array into 2 subarrays of approximately the same size, left and right, which are sorted by calling the same method recursively:
// STEP 2: sort each half
int[] sortedLeft = mergeSort(left);
int[] sortedRight = mergeSort(right);
the final step iterates over the sorted halves to produce a new sorted array.
The recursive calls complete because they are only performed with sub arrays strictly smaller than the argument array.
I am trying to calculate the Big-O time complexity for these 3 algorithms, but seems like I have a lack of knowledge on this topic.
1st:
private void firstAlgorithm(int size) {
int[] array = new int[size];
int i=0; int flag=0;
while(i<size) {
int num=(int)(Math.random()*(size));
if (num==0 && flag==0) {
flag=1;
array[i]=0;
i++;
} else if(num==0 && flag==1) {
continue;
} else if(!checkVal(num, array)) {
array[i]=num;
i++;
}
}
}
private static boolean checkVal(int val, int[] arr) {
int i = 0;
for (int num:arr) {
if (num==val) {
return true;
}
}
return false;
}
2nd:
private void secondAlgorithm(int size) {
int i = 0;
int[] array = new int[size];
boolean[] booleanArray = new boolean[size];
while (i < array.length) {
int num = (int) (Math.random() * array.length);
if (!booleanArray[num]) {
booleanArray[num] = true;
array[i] = num;
i++;
}
}
}
3rd:
private void thirdAlgorithm(int size) {
int[] array = new int[size];
for (int i = 0; i < array.length; i++) {
int num = (int) (Math.random() * (i - 1));
if (i > 0) {
array = swap(array, i, num);
}
}
}
private static int[] swap(int[] arr, int a, int b) {
int i = arr[a];
arr[a] = arr[b];
arr[b] = i;
return arr;
}
Would be nice, if you could explain your results.
In my opinion, 1st - O(n^2) because of two loops, 2nd don't know, 3rd O(n)
THank you
I assume that in all your algorithms, where you are generating a random number, you meant to take the remainder of the generated number, not multiplying it with another value (example for the first algorithm: Math.random() % size). If this is not the case, then any of the above algorithms have a small chance of not finishing in a reasonable amount of time.
The first algorithm generates and fills an array of size integers. The rule is that the array must contain only one value of 0 and only distinct values. Checking if the array already contains a newly generated value is done in O(m) where m is the number of elements already inserted in the array. You might do this check for each of the size elements which are to be inserted and m can get as large as size, so an upper bound of the running-time is O(size^2).
The second algorithm also generates and fills an array with random numbers, but this time the numbers need not be distinct, so no need to run an additional O(m) check each iteration. The overall complexity is given by the size of the array: O(size).
The third algorithm generates and fills an array with random numbers and at each iteration it swaps some elements based on the given index, which is a constant time operation. Also, reassigning the reference of the array to itself is a constant time operation (O(1)). It results that the running-time is bounded by O(size).
I'm learning algorithms and data structures and I'm now on the part of time and space complexity.
I have to solve a problem and them tell (based on my code) the time and spatial complexity.
This is the code:
public class B {
public static int minSum = -1;
public static void main(String[] args) {
int objects, sumA = 0, sumB = 0;
Scanner readInput = new Scanner(System.in);
objects = readInput.nextInt();
int[] trunk = new int[objects];
if (objects == 0) {
System.out.print(0 + "\n");
} else if (objects == 1) {
trunk[0] = readInput.nextInt();
System.out.print(trunk[0] + "\n");
} else {
for (int i = 0; i < objects; i++) {
trunk[i] = readInput.nextInt();
}
bruteforce(trunk, sumA, sumB, 0);
System.out.println(minSum);
}
}
public static void bruteforce(int[] trunk, int sumA, int sumB, int index) {
int partialDiff;
if (minSum == 0) {
System.out.println(minSum);
System.exit(0);
} else if (index == trunk.length) {
partialDiff = Math.abs(sumA - sumB);
if (partialDiff < minSum || minSum == -1) {
minSum = partialDiff;
}
} else {
bruteforce(trunk, sumA + trunk[index], sumB, index + 1);
bruteforce(trunk, sumA, sumB + trunk[index], index + 1);
}
}
}
Basically the user first inputs a number of objects and then inputs, for each object, its value. The algorithm will distribute the objects by two bags and must calculate the min difference that can be calculated when distributing the objects by the two bags.
I believe that it takes exponential time but I'm struggling with an estimative for the spatial complexity. Can you point me In some direction?
The space complexity is linear - O(n).
You calculate this by multiplying the amount of memory used in each function call by the max recursion depth.
There is a constant amount of memory being used in each function call - just partialDiff and stack information.
To determine the max recursion depth, you can basically just look at index (since this is the variable that decides when it stops recursing deeper).
You call the function with index = 0.
At each recursive call, index increases by one.
As soon as index reaches the size of the array, it stops.
Note that function calls are depth-first, meaning it will completely evaluate the first call to bruteforce before the second call, thus only one will take up memory at a time.
So, for an array of length 2, it goes something like this: (Call 1 is the first function call, Call 2 the second)
Call with index 0
Call 1 with index 1
Call 1 with index 2
Call 2 with index 2
Call 2 with index 1
Call 1 with index 2
Call 2 with index 2
So the max depth (and thus space complexity) is 3, one more than the number of items in the array.
So it's memory used in each function call * max depth = constant * linear = linear.
Consider two sum,X=x1+x2+...+xn, and Y=y1+y2+...+ym.
Give an algorithm that finds indices i and j such that swapping xi with yj makes the two sums
equal,that is , X-xi+yj = Y-yj+xi ,if they exist.
Hi guys!
so up there you can see the description. So firstly i am getting two unsorted arrays. then i sort them. then I have to subtract them from each other in order to find the difference between them then in two for loops i compare array's elements difference.
so here is my code
Timport java.util.ArrayList;
public class algorithm {
int j;
int i;
int key;
public algorithm() {
super();
// TODO Auto-generated constructor stub
}
public ArrayList<Integer> sortingFunction(ArrayList<Integer> array){
for(j=1;j<array.size();j++){
key = array.get(j);
i = j - 1;
while (i>=0 && array.get(i)>key){
array.set(i+1, array.get(i));
i = i - 1;
}
array.set(i+1, key);
}
return array;
}
public int calculationFunction(ArrayList<Integer> array){
int sum = 0;
for(int x = 0; x<array.size(); x++){
sum += array.get(x);
}
return sum;
}
public void writingFunction(ArrayList<Integer> array){
for(int x = 0; x<array.size(); x++){
System.out.print(array.get(x)+" ");
}
System.out.println();
}
public void twoSumsEqualAlgorithm (int x, int y, ArrayList<Integer> array1, ArrayList<Integer> array2 ){
int x_copy = x;
int y_copy = y;
//System.out.println(x);
//System.out.println(y);
for(int i = 0; i<array2.size(); i++){
x_copy = x + (array2.get(i) * 2);
//System.out.print("x;"+ x_copy);
//System.out.println(" y;"+ y);
if(x_copy >= y){
for(int j = 0; j<array1.size(); j++){
y_copy = y + (array1.get(j) * 2);
if(x_copy == y_copy){
System.out.print("we have found the true values; ");
System.out.print("'"+array1.get(j)+"'"+" from myArray1("+j+ ") and ");
System.out.println("'"+array2.get(i)+"'"+" from myArray2("+i+")");
//return;
}
else if(x_copy < y_copy){
//System.out.println("x is lower than y");
break;
}
}
}
}
}
private void exit(int k) {
// TODO Auto-generated method stub
}
}
and this is the test part
import java.util.ArrayList;
public class test {
/**
* #param args
*/
public static void main(String[] args) {
ArrayList<Integer> myArr1 = new ArrayList<Integer>();
ArrayList<Integer> myArr2 = new ArrayList<Integer>();
algorithm alg = new algorithm();
myArr1.add(8);
myArr1.add(4);
myArr1.add(2);
myArr1.add(15);
myArr1.add(10);
myArr1.add(16);
myArr1.add(1);
myArr1.add(11);
myArr2.add(5);
myArr2.add(3);
myArr2.add(7);
myArr2.add(6);
myArr2.add(19);
myArr2.add(2);
myArr2.add(12);
myArr2.add(1);
myArr2.add(0);
myArr1 = alg.sortingFunction(myArr1);
myArr2 = alg.sortingFunction(myArr2);
System.out.print("myArray1; ");
alg.writingFunction(myArr1);
System.out.print("myArray2; ");
alg.writingFunction(myArr2);
System.out.print("sum of myarray1; ");
System.out.println(alg.calculationFunction(myArr1));
System.out.print("sum of myarray2; ");
System.out.println(alg.calculationFunction(myArr2));
alg.twoSumsEqualAlgorithm(alg.calculationFunction(myArr1), alg.calculationFunction(myArr2), myArr1, myArr2);
}
}
so i think when i calculate the complexity of my algorithm it is O(n^2).
I read some posts and it says i can do the same job with O(nlgn) complexity.
comparing two array list can done in a way which will lead to a a lower big-O But with >sorting.
You can sort each arraylist using mergesort or quicksort O(nlg(n)) then compare the two >sorted lists in O(n). the result is O(nlgn).
But another algorithm (without sorting) would iterate over each element in one array (n). And >then checks whether the element is another array (n) (and marks it to handle duplicates >properly). This latter algorithm is O(n^2).
Comparing two sorted int arrays
so i just couldn't a way to implement. Any ideas?
So you need to solve xi-yj == (X-Y)/2
Sort the y array and loop over the x array. For each x_i do a binary search in the y array for (X-Y)/2-xi. If you find something stop, otherwise continue. The complexity for the sort is O(n log n). The complexity for each lookup in O(log n) and you need at most n lookups --> total complexity is O(n log n)
What you want to do is NOT a comparison of two arrays. It's similar in design but a completely different task that I would solve like this:
1) Mergesort or quicksort both collections. This is O(nlgn) when well designed.
2) Add up the numbers in collection x and collection y, and calculate X-Y as the difference D. O(n).
3) (Assuming D is negative) Do a scan of x from smallest to largest, and a scan of y from largest to smallest. For each element in the scan of x, check each element in the scan of y until swapping x and y would make D go PAST zero. If this happens, advance x and continue checking elements in the scan of y (e.g. don't reset the scan of y each time you advance the scan of x).
If you get D to exactly hit zero, then you've found your swap. This is at worst O(n), because you read x's elements exactly once, and read y's elements at most x.length+y.length times.
4) (assuming D is positive) Do similar logic to the above but scan x from largest to smallest and y from smallest to largest.
In an array first we have to find whether a desired number exists in that or not?
If not then how will I find nearer number to the given desired number in Java?
An idea:
int nearest = -1;
int bestDistanceFoundYet = Integer.MAX_INTEGER;
// We iterate on the array...
for (int i = 0; i < array.length; i++) {
// if we found the desired number, we return it.
if (array[i] == desiredNumber) {
return array[i];
} else {
// else, we consider the difference between the desired number and the current number in the array.
int d = Math.abs(desiredNumber - array[i]);
if (d < bestDistanceFoundYet) {
// For the moment, this value is the nearest to the desired number...
bestDistanceFoundYet = d; // Assign new best distance...
nearest = array[i];
}
}
}
return nearest;
Another common definition of "closer" is based on the square of the difference. The outline is similar to that provided by romaintaz, except that you'd compute
long d = ((long)desiredNumber - array[i]);
and then compare (d * d) to the nearest distance.
Note that I've typed d as long rather than int to avoid overflow, which can happen even with the absolute-value-based calculation. (For example, think about what happens when desiredValue is at least half of the maximum 32-bit signed value, and the array contains a value with corresponding magnitude but negative sign.)
Finally, I'd write the method to return the index of the value located, rather than the value itself. In either of these two cases:
when the array has a length of zero, and
if you add a "tolerance" parameter that bounds the maximum difference you will consider as a match,
you can use -1 as an out-of-band value similar to the spec on indexOf.
//This will work
public int nearest(int of, List<Integer> in)
{
int min = Integer.MAX_VALUE;
int closest = of;
for (int v : in)
{
final int diff = Math.abs(v - of);
if (diff < min)
{
min = diff;
closest = v;
}
}
return closest;
}
If the array is sorted, then do a modified binary search. Basically if you do not find the number, then at the end of search return the lower bound.
Pseudocode to return list of closest integers.
myList = new ArrayList();
if(array.length==0) return myList;
myList.add(array[0]);
int closestDifference = abs(array[0]-numberToFind);
for (int i = 1; i < array.length; i++) {
int currentDifference= abs(array[i]-numberToFind);
if (currentDifference < closestDifference) {
myList.clear();
myList.add(array[i]);
closestDifference = currentDifference;
} else {
if(currentDifference==closestDifference) {
if( myList.get(0) !=array[i]) && (myList.size() < 2) {
myList.add(array[i]);
}
}
}
}
return myList;
Array.indexOf() to find out wheter element exists or not. If it does not, iterate over an array and maintain a variable which holds absolute value of difference between the desired and i-th element. Return element with least absolute difference.
Overall complexity is O(2n), which can be further reduced to a single iteration over an array (that'd be O(n)). Won't make much difference though.
Only thing missing is the semantics of closer.
What do you do if you're looking for six and your array has both four and eight?
Which one is closest?
int d = Math.abs(desiredNumber - array[i]);
if (d < bestDistanceFoundYet) {
// For the moment, this value is the nearest to the desired number...
nearest = array[i];
}
In this way you find the last number closer to desired number because bestDistanceFoundYet is constant and d memorize the last value passign the if (d<...).
If you want found the closer number WITH ANY DISTANCE by the desired number (d is'nt matter), you can memorize the last possibile value.
At the if you can test
if(d<last_d_memorized){ //the actual distance is shorter than the previous
// For the moment, this value is the nearest to the desired number...
nearest = array[i];
d_last_memorized=d;//is the actual shortest found delta
}
A few things to point out:
1 - You can convert the array to a list using
Arrays.asList(yourIntegerArray);
2 - Using a list, you can just use indexOf().
3 - Consider a scenario where you have a list of some length, you want the number closest to 3, you've already found that 2 is in the array, and you know that 3 is not. Without checking the other numbers, you can safely conclude that 2 is the best, because it's impossible to be closer. I'm not sure how indexOf() works, however, so this may not actually speed you up.
4 - Expanding on 3, let's say that indexOf() takes no more time than getting the value at an index. Then if you want the number closest to 3 in an array and you already have found 1, and have many more numbers to check, then it'll be faster to just check whether 2 or 4 is in the array.
5 - Expanding on 3 and 4, I think it might be possible to apply this to floats and doubles, although it would require that you use a step size smaller than 1... calculating how small seems beyond the scope of the question, though.
// paulmurray's answer to your question is really the best :
// The least square solution is way more elegant,
// here is a test code where numbertoLookFor
// is zero, if you want to try ...
import java.util.* ;
public class main {
public static void main(String[] args)
{
int[] somenumbers = {-2,3,6,1,5,5,-1} ;
ArrayList<Integer> l = new ArrayList<Integer>(10) ;
for(int i=0 ; i<somenumbers.length ; i++)
{
l.add(somenumbers[i]) ;
}
Collections.sort(l,
new java.util.Comparator<Integer>()
{
public int compare(Integer n1, Integer n2)
{
return n1*n1 - n2*n2 ;
}
}
) ;
Integer first = l.get(0) ;
System.out.println("nearest number is " + first) ;
}
}
int[] somenumbers = getAnArrayOfSomenumbers();
int numbertoLookFor = getTheNumberToLookFor();
boolean arrayContainsNumber =
new HashSet(Arrays.asList(somenumbers))
.contains(numbertoLookfor);
It's fast, too.
Oh - you wanted to find the nearest number? In that case:
int[] somenumbers = getAnArrayOfSomenumbers();
int numbertoLookFor = getTheNumberToLookFor();
ArrayList<Integer> l = new ArrayList<Integer>(
Arrays.asList(somenumbers)
);
Collections.sort(l);
while(l.size()>1) {
if(numbertoolookfor <= l.get((l.size()/2)-1)) {
l = l.subList(0, l.size()/2);
}
else {
l = l.subList(l.size()/2, l.size);
}
}
System.out.println("nearest number is" + l.get(0));
Oh - hang on: you were after a least squares solution?
Collections.sort(l, new Comparator<Integer>(){
public int compare(Integer o1, Integer o2) {
return (o1-numbertoLookFor)*(o1-numbertoLookFor) -
(o2-numbertoLookFor)*(o2-numbertoLookFor);
}});
System.out.println("nearest number is" + l.get(0));