BinarySearch in a SortedArrayList - java

I am trying to develop a faster way than what I currently have to add an element to a sorted array list. Currently this is my strategy
public void insertSorted(E value) {
add(value);
for (int i = size() - 1; i > 0 && value.compareTo(get(i - 1)) < 0; i--) {
this.swap(i);
}
}
and my add method...
public void add(E element) {
ensureCapacity();
array[size++] = element;
}
So I read that using a binary search algorithm I could more efficiently find the best way to put an element even faster.
I tried developing that, but somehow it always outputs me 0.
private int binarySearch(E value) {
int low = 0;
int high = this.size()-1;
while (low <= high) {
int mid = (low + high) / 2;
E midVal = this.get(mid);
int cmp = midVal.compareTo(value);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid;
}
return low;
}
public void insertSorted(E value) {
int searchResult = binarySearch(value);
add(value, searchResult);
System.out.println("Value: " + value + ". Position = " + searchResult);
}
Could someone help me out? If necessary I will show full code

Rather than developing your own binary search, use built-in Arrays.binarySearch implementation. However, this wouldn't give you much improvement over your original version in terms of time.
To see why, consider the steps that you take to place the value in the sorted sequence:
Find the insertion position
Move items to the right of insertion position by one
Place the element into insertion position
The first step can be done in O(log2N). The second step takes O(N). The last step takes O(1). Overall, insertion's time complexity is O(log2N + N + 1), which is the same as O(N). The algorithm is dominated by the second step, so you might as well use linear search as you move items to the right by one.

Related

How can I make this binary search code more efficient?

public class MySearch {
public static int search(MyArray array, int value) {
int index = -1;
int start = 0, end = array.length - 1;
while(start <= end) {
int mid = (start + end) / 2;
if(array.compToValue(mid, value) == 1) end = mid - 1;
else if(array.compToValue(mid, value) == -1) start = mid + 1;
else return mid;
}
return index;
}
}
In some cases the number of comparisons is exceeded as you can see in the screenshot. I'm not allowed to use read operations (get). The number of comparisons I'm allowed to make is O(logn).
Your code says nothing about whether the array is ordered. If the array is not ordered, you can do only linear search, and a search operation in O(log n) is impossible.
If the array is ordered, as Turing85's comment says:
extract array.compToValue(mid, value) into a variable, use this variable in the if-clauses instead of calculating the value twice.
Also useful advice is to always use curly brackets. Java allows to drop it if the code block is only a single line, but doing that is a bad practice.

What counts as a binary search comparison?

I'm writing a program that determines how many comparisons it takes to run a binary search algorithm for a given number and sorted array. What I don't understand is what counts as a comparison.
// returns the number of comparisons it takes to find key in sorted list, array
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (true) {
if (left > right) {
mid = -1;
break;
}
else {
mid = (left + right)/2;
if (key < array[mid]) {
i++;
right = mid - 1;
}
else if (key > array[mid]) {
i++;
left = mid + 1;
}
else {
break; // success
}
}
}
return i;
}
The function returns i, which is supposed to be the total number of comparisons made in finding the key in array. But what defines a comparison? Is it any time there is a conditional?
Thanks for any help, just trying to understand this concept.
Usually, a comparison occurs each time the key is compared to an array element. The code seems to not be counting that, though. It is counting how many times one of the search boundaries (left or right) is changed. It's not exactly the same thing being counted, but it's pretty close to the same thing, since the number of times a boundary is shifted is directly related to the number of times through the loop and hence to the number of times a comparison is made. At most, the two ways of counting will be off by 1 or 2 (I didn't bother to figure that out exactly).
Note also that if one were to use the usual definition, the code could be rewritten to use Integer.compare(int,int) do a single comparison of key with array[mid] to determine whether key was less than, equal to, or greater than array[mid].
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right)/2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
}
else if (comp > 0) {
left = mid + 1;
}
else {
break; // success
}
}
return i;
}

Recursion calls overflows stack

I'm having a problem with the partitioning while trying to implement the Quicksort algorithm. My implementation works good with arrays up to a size of 10,000 but over that I'm getting a StackOverflowError. Note that this only happens when the input arrays are in a/descending order. Random-ordered arrays can be up to 10,000,000,000 before they cause the same issue.
I'm pretty sure that there is something wrong in the part when I'm partitioning the array, but I can't really see what's wrong. I've tried debugging but had no success with finding the issue. I understand that the error is caused by too many recursive calls but as far as I know, the stack shouldn't overflow if the partitioning is well implemented.
Thanks in advance :)
My code:
public void sort(int[] v, int first, int last) {
if (first >= last) return;
//less than two elements left in subvector
// Partition the elements so that every number of
// v[first..mid] <= p and every number of v[mid+1..last] > p.
int[]subvector = new int[2];
subvector = partition(v, first, last);
sort(v, first, subvector[0]-1);
sort(v, subvector[1], last);
}
And the partitioning method:
private int[] partition(int[] v, int first, int last) {
int low = first;
int mid = first;
int high = last;
int pivot = getPivot(v, last);
while (mid <= high) {
// Invariant:
// - v[first..low-1] < pivot
// - v[low..mid-1] = pivot
// - v[mid..high] are unknown
// - v[high+1..last] > pivot
//
// < pivot = pivot unknown > pivot
// -----------------------------------------------
// v: | | |a | |
// -----------------------------------------------
// ^ ^ ^ ^ ^
// first low mid high last
//
int a = v[mid];
if (a < pivot) {
v[mid] = v[low];
v[low] = a;
low++;
mid++;
} else if (a == pivot) {
mid++;
} else { // a > pivot
v[mid] = v[high];
v[high] = a;
high--;
}
}
return new int[]{low, high};
}
Quicksort is known to be O(n^2) worst case, which is when you give it sorted input and choose the worst pivot (the highest or lowest element). That will also have the effect of causing very deep recursion, as you have seen. You don't include your pivot selection mechanism, so I can't be sure what you're doing, but you appear to select the last element. Some googling will turn up extensive discussions on pivot selection for qsort.

How to find the median of a large number of integers (they dont fit in memory)

I know the answer is using median of medians but can someone explain how to do it?
There are linear time algorithms to do this, this page might be helpful, http://en.wikipedia.org/wiki/Selection_algorithm, if you are still confused just ask
Basically the way the selection algorithm works is like a quicksort but it only sorts on side of the pivot each time. The goal is to keep partitioning until you choose the pivot equal to the index of the element you were trying to find. Here is java code I found for quickselect:
public static int selectKth(int[] arr, int k) {
if (arr == null || arr.length <= k)
throw new Error();
int from = 0, to = arr.length - 1;
// if from == to we reached the kth element
while (from < to) {
int r = from, w = to;
int mid = arr[(r + w) / 2];
// stop if the reader and writer meets
while (r < w) {
if (arr[r] >= mid) { // put the large values at the end
int tmp = arr[w];
arr[w] = arr[r];
arr[r] = tmp;
w--;
} else { // the value is smaller than the pivot, skip
r++;
}
}
// if we stepped up (r++) we need to step one down
if (arr[r] > mid)
r--;
// the r pointer is on the end of the first k elements
if (k <= r) {
to = r;
} else {
from = r + 1;
}
}
return arr[k];
}
here is the Median of Medians algorithm. check this out
See the first two answers to this question. If the first one (frequency counts) can work for your data / available storage, you can get the exact answer that way. The second (remedian) is a robust, general method.

Binary Search Algorithm from a Sorted list

My algorithm is suppose to tell me if 'x'(which has the value 5) is in the sorted array. However, I keep getting a 0. Well since my condition states that if 'x' is not in the array show 0. Where am I going wrong?
import java.util.Arrays;
public class binarySeacg {
public static void main (String[]args)
{
int[] array = {10,7,11,5,13,8};
exchangesort(array);
binsearch(array,5);
System.out.println(Arrays.toString(array));
}
public static void exchangesort(int[] S)
{
int i,j,temp;
for(i=0;i<S.length;i++)
for(j=i+1;j<S.length;j++)
if(S[i]>S[j])
{
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
public static int binsearch(int[] S, int x)
{
int location, low, high, mid;
low = 1; high = S.length;
location = 0;
while(low<=high && location==0)
{
mid =(low + high)/2;
if(x== S[mid])
location = mid;
else if(x < S[mid])
high = mid -1;
else
low = mid + 1;
}
System.out.println(location);
return location;
}
}
You set low = 1;, and 5 is the minimal element - so it is in index 0 - so in the sublist of [1,S.length] - it is indeed not there.
You should set low = 0;, and start from the first element - not the second. (Remember that index in java starts from 0, not 1).
(PS, note that in this specific case - the algorithm is correct, since in the sorted list - 5 is in the index 0).
Here you are sorting an array and then the sorted array is used for searching the element.
And if the search is successful, then you do the below assignment
location = mid; which means you are assigning the matching element's index to the location variable.
In this case, element 5 is in 0th index.
Hence you are always getting 0 on your STDOUT
Because, you are trying to find x value, which you are passing 3 and in your list. It is not present. So, change it to other value like 5 and then try.
Also, you should start low=0 instead of low=1. Because, it will miss the first element all the time.
public static int binsearch(int[] S, int x)
{
int location, low, high, mid;
low = 0; high = S.length;
location = 0;
while(low<=high && location==0)
{
mid =(low + high)/2;
if(x == S[mid])
{
location = mid;break;
}
else if (x < S[mid])
{
high = mid - 1;
} else
{
low = mid + 1;
}
}
System.out.println(location);
return location;
}
Note : For the different output, change the value binsearch(array,5); here, which is called from main() method. Remember, change the value, which are present in your list.
in java and most languages, the index starts from 0, not 1, and ends at n-1, not n
for binary search, check carefully about when exiting the while loop, and always remember the meaning of your low and high variables, whether it is [low, high], or [low, high)
for this specific problem, u should also consider what if there r duplicates in the array. whether to return the first element or anyone in the array

Categories

Resources