binary search on a array with a string prefix - java

How can i go about adding the elements of a sorted array which contain a specific string prefix using binary search and those elements as the order they appear in the array to a arraylist..
It is not hard to code but i am having difficulty with binary search. To use the string prefix the String class provides startswith. I just need help to start the binary search
public static <T extends Comparable<T>> ArrayList prefixMatch(T[] list,
String prefix) {
}

Use the binarySearch method from the API.
String[] objString = {"a","b","c"};
System.out.println(Arrays.binarySearch(objString,"c"));
Or if you want to create your own Binary search implementation. Here it is.
/* BinarySearch.java */
public class BinarySearch {
public static final int NOT_FOUND = -1;
public static int search(int[] arr, int searchValue) {
int left = 0;
int right = arr.length - 1;
return binarySearch(arr, searchValue, left, right);
}
private static int binarySearch(int[] arr, int searchValue, int left, int right) {
if (right < left) {
return NOT_FOUND;
}
/*
int mid = mid = (left + right) / 2;
There is a bug in the above line;
Joshua Bloch suggests the following replacement:
*/
int mid = (left + right) >>> 1;
if (searchValue > arr[mid]) {
return binarySearch(arr, searchValue, mid + 1, right);
} else if (searchValue < arr[mid]) {
return binarySearch(arr, searchValue, left, mid - 1);
} else {
return mid;
}
}
}
public class BinarySearchTest {
public static void main(String[] args) {
int[] arr = {1, 5, 2, 7, 9, 5};
Arrays.sort(arr);
System.out.println(BinarySearch.search(arr, 2));
}
}

I had a similar requirement - given the array of Strings find indexes of each string which starts with a new letter, i.e. for Africa Angela Beach Bamboo Zorro, I needed algorithm which would return [ 0, 2, 4 ]
I found that there's a modification of well known Binary Search algorithm which uses 'deferred equality test' and this has the side effect of finding exactly needed indexes - ones which start the range.
You can read about it in this Wikipedia article (also there's a very simple example based on which I implemented my own).

Related

why is this not executing in vs code editor?

public class binsearch {
public static void main(String args[])
{
int arr[]={2,45,-21,56,23};
int target=45;
int answer=binarysearch(arr, target);
System.out.println(answer);
}
static int binarysearch(int arr[],int target)
{
int start=0;
int end=arr.length-1;
int mid=start+end/2;
while(start<=end)
{
if(target<arr[mid])
{
mid=end-1;
}
else if(target>arr[mid])
{
mid=mid+1;
}
else
{
return mid;
}
}
return -1;
}
}
I have tried running this code multiple times but it just doesnt run. I dont think there is any problem with the logic for binary search in this code. Please do help.Thank you.
Your code runs. It has an infinite loop so it never terminates.
In order for a binary search to work. The array must be sorted in ascending order. So just sort the array before you do the binary search. Below code uses class java.util.Arrays to sort the array but you can sort it anyway you like. Just make sure that the array is sorted before you do the binary search.
Also, the calculation of mid needs to be inside the while loop because it always changes since its value is determined by the values of both start and end and those values are changed inside the while loop.
Note that I changed the name of the class so as to adhere to Java naming conventions. The conventions make it easier for other people to read and understand your code.
import java.util.Arrays;
public class BinSearch {
static int binarysearch(int arr[], int target) {
int start = 0;
int end = arr.length - 1;
while (start <= end) {
int mid = start + ((end - start) / 2);
if (target < arr[mid]) {
end = mid - 1;
}
else if (target > arr[mid]) {
start = mid + 1;
}
else {
return mid;
}
}
return -1;
}
public static void main(String[] args) {
int arr[] = {2, 45, -21, 56, 23};
Arrays.sort(arr);
int target = 45;
int answer = binarysearch(arr, target);
System.out.println(answer);
}
}
The answer is 3 because, after the sort, 45 is the second last element in the [sorted] array because it is the second largest number in the array.
If you want to search without sorting the array then a binary search is not appropriate.

Sorting ArrayList of bytes array

I have some code in python which does the following:
for day in server_message.keys():
for epoch in server_message[day].keys():
assert sorted(server_message[day][epoch]) == server_message[day][epoch]
I need to write that code in Java. The problem is that the structure of server_message is as such:
Map<Integer, Map<Integer, ArrayList<byte[]>>>
How can sort ArrayList of bytes? Both Arrays.sort() and Collections.sort() don't return a new sorted array instead the work on the provided array.
Is there anything in Java that I can do to solve this problem, or do I need to write my own sorting algorithm for this kind of sort? How can I compare two bytes array?
Array.sort() uses quick algorithm at back-end and I'm surprised to see why Array.sout() is not working but you can use quick sort for this.
public class QuickSort {
public static void main(String[] args) {
int i;
int[] arr={90,23,101,45,65,23,67,89,34,23};
quickSort(arr, 0, 9);
System.out.println("\n The sorted array is: \n");
for(i=0;i<10;i++)
System.out.println(arr[i]);
}
public static int partition(int a[], int beg, int end)
{
int left, right, temp, loc, flag;
loc = left = beg;
right = end;
flag = 0;
while(flag != 1)
{
while((a[loc] <= a[right]) && (loc!=right))
right--;
if(loc==right)
flag =1;
elseif(a[loc]>a[right])
{
temp = a[loc];
a[loc] = a[right];
a[right] = temp;
loc = right;
}
if(flag!=1)
{
while((a[loc] >= a[left]) && (loc!=left))
left++;
if(loc==left)
flag =1;
elseif(a[loc] <a[left])
{
temp = a[loc];
a[loc] = a[left];
a[left] = temp;
loc = left;
}
}
}
returnloc;
}
static void quickSort(int a[], int beg, int end)
{
int loc;
if(beg<end)
{
loc = partition(a, beg, end);
quickSort(a, beg, loc-1);
quickSort(a, loc+1, end);
}
}
}
I think your problem is to sort an array of bytes (byte[]) and not a list of arrays of bytes (List<byte[]>) which doesn't make any sense.
If you want to get a sorted array of bytes without modifying the existing one you can clone the original array before :
byte[] bytes = {0, 23, 127, -12 };
byte[] clone = bytes.clone();
Arrays.sort(clone);

Java Recursive MergeSort for ArrayLists

I have been having a problem with my mergesort function, as I am not able to sort a series of integers or strings whenever inputting it into the program. I have an outside class that calls items into it, however it simply doesn't sort the numbers/strings. The two methods are below, I don't know where the problem is. Numbers are randomly inputted.
CODE:
/**
* Takes in entire vector, but will merge the following sections together:
* Left sublist from a[first]..a[mid], right sublist from a[mid+1]..a[last].
* Precondition: each sublist is already in ascending order
*
* #param a
* reference to an array of integers to be sorted
* #param first
* starting index of range of values to be sorted
* #param mid
* midpoint index of range of values to be sorted
* #param last
* last index of range of values to be sorted
*/
private void merge(ArrayList<Comparable> a, int first, int mid, int last) {
int x;
int i;
ArrayList<Comparable> left = new ArrayList<Comparable>();
ArrayList<Comparable> right = new ArrayList<Comparable>();
mergeSort(a,first,mid);
for(i = 0; i < a.size() - mid; i++){
left.add(i,a.get(i));
a.remove(i);
}
mergeSort(a,mid,last);
for (x = mid; x < a.size(); x++) {
right.add(x,a.get(x));
a.remove(x);
}
if ((left.get(i).compareTo(right.get(x))) > 0) {
i++;
a.add(i);
} else if (i < x) {
x++;
a.add(x);
}
System.out.println();
System.out.println("Merge");
System.out.println();
}
/**
* Recursive mergesort of an array of integers
*
* #param a
* reference to an array of integers to be sorted
* #param first
* starting index of range of values to be sorted
* #param last
* ending index of range of values to be sorted
*/
public void mergeSort(ArrayList<Comparable> a, int first, int last) {
int mid = (first + last)/2;
if(first == last){
}else if(last - first == 1){
merge(a,first, mid ,last);
}else{
last = mid;
}
}
I have an outside class that calls items into it, however it simply doesn't sort the numbers/strings. The two methods are below, I don't know where the problem is.
The first problem is that if you call your mergeSort method with first = 0 and last = a.size() you won't sort anything as you only call merge if last-first == 1 :
public void mergeSort(ArrayList<Comparable> a, int first, int last) {
int mid = (first + last)/2;
if(first == last){
}else if(last - first == 1){
// you only merge if last - first == 1...
merge(a,first, mid ,last);
}else{
last = mid;
}
}
Appart from this point, I don't get how you're trying to implement the Merge Sort algorithm. It's neither a top down, nor a bottom up implementation. You're splitting inside the merge method which is also really odd. It would have been easier to help you if you had provided your pseudo code + the way you call your public method. IMHO you have a real issue with your algorithm.
In fact the merge sort algorithm is really simple to implement. To illustrate this, I wrote this top down implementation of the merge sort algorithm using Deque instead of List objects:
import java.util.Deque;
import java.util.LinkedList;
public class Example {
private LinkedList<Comparable> merge(final Deque<Comparable> left, final Deque<Comparable> right) {
final LinkedList<Comparable> merged = new LinkedList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if (left.peek().compareTo(right.peek()) <= 0) {
merged.add(left.pop());
} else {
merged.add(right.pop());
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public void mergeSort(final LinkedList<Comparable> input) {
if (input.size() != 1) {
final LinkedList<Comparable> left = new LinkedList<Comparable>();
final LinkedList<Comparable> right = new LinkedList<Comparable>();
// boolean used to decide if we put elements
// in left or right LinkedList
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.pop());
} else {
right.add(input.pop());
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}
}
I used Deque because peek()/ pop() is ways prettier IMHO than get(0) and remove(0) but it's up to you. If you absolutely want to use ArrayList here follows the corresponding implementation.
import java.util.ArrayList;
import java.util.List;
public class Example {
private List<Comparable> merge(final List<Comparable> left, final List<Comparable> right) {
final List<Comparable> merged = new ArrayList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if (left.get(0).compareTo(right.get(0)) <= 0) {
merged.add(left.remove(0));
} else {
merged.add(right.remove(0));
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public void mergeSort(final List<Comparable> input) {
if (input.size() != 1) {
final List<Comparable> left = new ArrayList<Comparable>();
final List<Comparable> right = new ArrayList<Comparable>();
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.remove(0));
} else {
right.add(input.remove(0));
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}
}
Both implementation work with Integerand String or other Comparable.
Hope it helps.
There are several problems but an important one is that you should not iterate over a list while modifying the list, i.e. in:
for (i = 0; i < a.size() - mid; i++){
left.add(i,a.get(i));
a.remove(i);
}
because once you remove an element, indexes for others are not the same... So you add in left elements of a that are not what you think.
A working code is the following (with some comments) :
private static void merge(ArrayList<Comparable> a) {
if (a.size()<=1) return; // small list don't need to be merged
// SEPARATE
int mid = a.size()/2; // estimate half the size
ArrayList<Comparable> left = new ArrayList<Comparable>();
ArrayList<Comparable> right = new ArrayList<Comparable>();
for(int i = 0; i < mid; i++) left.add(a.remove(0)); // put first half part in left
while (a.size()!=0) right.add(a.remove(0)); // put the remainings in right
// Here a is now empty
// MERGE PARTS INDEPENDANTLY
merge(left); // merge the left part
merge(right); // merge the right part
// MERGE PARTS
// while there is something in the two lists
while (left.size()!=0 && right.size()!=0) {
// compare both heads, add the lesser into the result and remove it from its list
if (left.get(0).compareTo(right.get(0))<0) a.add(left.remove(0));
else a.add(right.remove(0));
}
// fill the result with what remains in left OR right (both can't contains elements)
while(left.size()!=0) a.add(left.remove(0));
while(right.size()!=0) a.add(right.remove(0));
}
It has been tested on some inputs... Example:
[4, 7, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11]
[0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
For efficiency you may use subList method to avoid constructing too much sub lists explicitly, it will need to take care about indices.
A WARNING about Kraal's implementation that got the checkmark. It's a great implementation, but Kraal's Merge sort doesn't preserve the relative order of items that have the same value, which in some cases, when sorting objects for instance, is an important strength that merge sort has that other sorting algorithms, like quicksort, do not have. I modified Kraal's code to preserve relative orders.
private static List<Object> merge(final List<Object> left, final List<Object> right) {
printArr("left", left);
printArr("Right", right);
final List<Object> merged = new ArrayList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if(left.get(0).getValue()-right.get(0).getValue() <= 0){
merged.add(left.remove(0));
} else {
merged.add(right.remove(0));
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public static void mergeSort(final List<Object> input) {
if (input.size() > 1) {
final List<Object> left = new ArrayList<Object>();
final List<Object> right = new ArrayList<Object>();
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.remove(0));
} else {
right.add(input.remove(input.size()/2));
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}
If you want to sort an array using Merge sort, and not to implement a sorting algorithm by yourself,
I recommend using standard Java sorting algorithms because it implements "Merge sort" algorithm for non primitive types.
Collections.sort();
If you would like to implement your own version of Merge sort then you should look first at this implementation.
And if you are interested in better understanding sorting algorithms I recommend this book.
public class MergeSort{
public void sort(List<Integer> list){
sortAndMerge(list, 0, list.size()-1);
}
public void sortAndMerge(List<Integer> list, int start, int end){
if((end - start) >= 2){
int mid = (end - start)/2;
sortAndMerge(list, start, start + mid);
sortAndMerge(list, start + mid +1, end);
int i=start;
int j=start + mid +1;
while(i<j && j<=end){
if(list.get(i) > list.get(j)){
list.add(i, list.remove(j));
i++;
j++;
}else if(list.get(i) == list.get(j)){
list.add(i+1, list.remove(j));
i++;
j++;
}else{
i++;
}
}
}else{
if(end > start){
if(list.get(start) > list.get(end)){
int endValue = list.remove(end);
list.add(start, endValue);
}
}
}
}

Problems implementing a binary search

I'm feeling very very stupid because I've solved much harder stuff than this.
This is supposed to be an implementation of ordered binary search. Whenever I trace the 12, a stackoverflow error pops up. Any help please?
public class binarySearch {
public static void main(String[] args) {
int[] arr = { 1, 5, 6, 8, 12, 88 };
System.out.println(binaryHelper(0, arr.length - 1, 12, arr));
}
public static int binaryHelper(int first, int last, int target, int[] arr) {
if(first > last) return -1;
else {
int mid = first + last / 2;
if(arr[mid] == target) return mid;
else if(arr[mid] > target) return binaryHelper(first, mid - 1, target, arr);
else return binaryHelper(mid + 1, last, target, arr);
}
}
}
This is due to the precedence order of your operators in your mid variable computation. It should be computed as:
int mid = (first + last) / 2;
instead of
int mid = first+last/2;
Error is here:
int mid = first+last/2;
this means mid is equal to first + last dividied by 2 which is wrong
so it should be like
int mid = (first+last)/2;

Binary search does not work with doubles

This program works very well with integers, but not doubles. There are no errors, but the program returns -1. Sorry if this is a stupid question, but I am new to programming.
public class binarySearchProject
{
public static int binarySearch(double[] arr, double x, int high, int low)
{
int mid=(high+low)/2;
if(high==low || low==mid || high==mid)
{
return -1;
}
if(arr[mid]>x)
{
return binarySearch(arr, x, high, mid);
}
else if(arr[mid]<x)
{
return binarySearch(arr, x, mid, low);
}
else if(arr[mid]==x)
{
return mid;
}
return -1;
}
public static void main(String args[])
{
double i = 45.3;
double[] a = {-3, 10, 5, 24, 45.3, 10.5};
int size = a.length;
System.out.println(binarySearch(a, i, size, 0));
}
}
You should change the conditions:
if (arr[mid] > x) should be if (arr[mid] < x)
else if (arr[mid] < x) should be else if (arr[mid] > x)
Also note that in order to make this work, the array must be sorted (That's the whole point of binary search), you can use Arrays#sort:
Arrays.sort(a);
I recommend you rename your class so it begins with an upper case (Following Java Naming Conventions).
As #tobias_k pointed out:
For binary search to work, you need to sort the array first.
See Wikipedia for details.

Categories