Im working on a project in which it reads book titles in from a .txt file and puts them into an arraylist, then the arraylist is converted to an array, The user enters a number which is the books reference number, then it does a linear search and a binary search to find that book. Im just having a trouble with the code for the binary search,as i have almost no idea how to do it, heres what I have:
private void FindItActionPerformed(java.awt.event.ActionEvent evt) {
String input;
input = Input.getText();
for(int i=0; i<bookList.length; i++){
if (bookList[i].referenceNumber.equals(input)){
Output1.setText("The Book is " + bookList[i].title);
}
}
Above is the code for the linear search, which works fine. Below is what i think i need for the binary search but again, i am not sure and cannot figure it out.
int right = 0, left = bookList.length;
while(right<= left){
int middle = (right + left)/2;
if( bookList[middle].referenceNumber.equals(input)){
Output2.setText("The book is " + bookList[middle].title);
}
}
}
Here is the class and the arrays
public class Book{
String referenceNumber, title;
public Book(String _referenceNumber, String _title){
referenceNumber = _referenceNumber;
title = _title;
}
}
ArrayList <Book> Books = new ArrayList <Book> ();
Book [] bookList;
Thanks for any help you may be able to offer, This is a bit tricky for me.
I had problems when I was learning to code binary search aswell. The first thing you should know is that you do not have to do a binary search and a linear search, you only need to do one or the other. Also to do a binary search you need to sort your array ex int[] array = {1,2,3,4,5,6,7,8,9,10};
What a binary search does is it looks at the middle element in the array and tests to see if the element is greater or less than the key. If it is less everything less then the middle element is ignored (same for bigger just everything bigger is thrown away). Then a new middle element is selected and half is thrown away, and this is done until the key is found. Below is the code for sorting a int array, you would need to modify it to return books (string? or the class book you may have written)
public static boolean binarySearch(int[] array, int key){
int partition = 0;
int right = array.length - 1;
boolean found = false;
int left = 0;
while(! found && left <= right){
if(array[partition] == key){
found = true;
}
if(array[partition] > key){//key less
right = partition - 1;
partition = (right + left) / 2;
}
if(array[partition] < key){//key greater
left = partition + 1;
partition = (left + right) / 2;
}
}
return found;
}
Also here is some code for sorting an array of ints. This is a bubble sort so it is slow On^2
public int[] bubbleSort(int[] array){
int temp;
boolean keepGoing = true;
while(keepGoing == true){
keepGoing = false;
for(int i=0; i < array.length - 1; i++){
if(array[i] > array [i + 1]){ //if i < i + 1 means greatest to smallest if
// if i > i + 1 means smallest to greatest
swap(array, i, i + 1);
keepGoing = true;
}
}
}
return array;
}
The code is simple would have to modify it to sort your books the method swap is below
public int[] swap(int[] array, int i, int j){
int temp = 0;
temp = array[i];
array[i] = array[j];
array[j] = temp;
return array;
}
There is nice visualisation of binary search at
http://balance3e.com/Ch8/search.html
For example try to enter FL and watch the algorithm looking for it step by step.
You will get it quickly :)
It works like looking up a word in a dictionary... You are looking for "cat" for example,
so you open your dictionary in half and see word "man" this is lexicographicaly bigger than "cat", so you will be looking to the left from "man" = in first half of the dictionary...
Then you only repeat this process of dividing into smaller parts until you find what you were looking for.
Related
I'm working on an assignment.
What I must create is a method that searches for an specific int in an array. It is assumed that the array is already sorted from lowest to highest number. But the condition is that it must search by cutting said array by half and checking in which of the halves the target number is in, then cut said half in half again and so on so on.
We were asked not to use recursive methods as well.
This is the code I came up with but I fail to see my mistake, any help to understand the problem better is more than appreciated!!!
public static boolean SearchInHalf(int[] array, int targetint)
{
int fin = array[array.length-1];
int init = array[0];
int range = fin-init;
if ( targetint>array[array.length-1] || targetint< array[0])
{
return false;
}
while (range>=2)
{
int half = array[range/2];
if (targetint>half)
{
init = half;
range = fin-init;
half = array[range/2];
}
else if (targetint<half)
{
fin = half;
range = fin-init;
half = array[range/2];
}
else if (targetint==half || targetint==fin || targetint==init)
{
return true;
}
}
return false;
}
Your problem is known as the "Binary Search". For binary search to work, the elements in the array must already be ordered (which is your case, let's assume ascending). The binary search first compares the key with the element in the middle of the array:
If the key is less than the middle element, you need to continue to search for the key only in the first half of the array.
If the key is greater than the middle element, you need to continue to search for the key only in the second half of the array.
If the key is equal to the middle element, the search ends with a match.
So binary search method eliminates at least half of the array after each comparison. Assuming you will call this method in your static main function:
public static int binarySearch(int[] list, int key) {
int low = 0;
int high = list.length - 1;
while(high >= low) { //search array until there is a single element left
int mid = (low + high) / 2; //mark middle index
if (key < list[mid]) //if key is smaller than the middle element..
high = mid - 1; //new high is the middle element
else if (key == list[mid]) //if key=middle element --> voila!
return mid; //returns the index of searched element if it is in your array
else
low = mid + 1; //if key is greater than the middle element new low is middle element
}
return –low - 1; //high < low, key not found
}
Solved it like this:
while (true) {
if (targetint>array[array.length-1] || targetint<array[0])
return false;
int middleInt = array[Math.round(array.length/2)];
if (middleInt == targetint) {
return true;
} else if (targetint<middleInt) {
int[] firstHalf = new int[array.length/2];
System.arraycopy(array, 0, firstHalf, 0, firstHalf.length);
array = firstHalf;
} else if (targetint>middleInt) {
int[] secondHalf = new int[array.length/2];
System.arraycopy(array, array.length/2, secondHalf, 0, secondHalf.length);
array = secondHalf;
} else if(array.length == 1)
return false;
}
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.
This is my current search method:
public static int search(int[] array, int numero) {
int start = 0;
int end = array.length - 1;
int center;
while (start <= end) {
center = (start + end) / 2;
if (array[center] == numero) {
return center;
} else if (array[center] < numero) {
start = center + 1;
} else {
end = center - 1;
}
}
return -1;
}
It searches from user input numero into a previously bubble sorted Array that's found in the Main method.
What I'm trying to figure out is how to print ALL of the coincidences found in the array, and not just the first one found.
I was thinking about adding results to a List and then returning that to Main, but as I tried that an endless loop happened at the first result found, causing it to add itself to the List repeatedly until the program crashes.
Assuming that you know the basic theory behind binary searches, separate it into 3 steps.
Search using binary search methods.
once a match is found, scan up from that point, until you find a non matching element.
Scan down, adding to a result list, until you find a non
matching element.
If you don't need to care about occurrence order, you could combine steps 2 and 3 and just scan up adding to the list, and scan down adding to the list, since due to the sorting, everything you hit is guaranteed to match until it doesn't.
If you do care about occurrence order, step 2 could be optimised by jumping ahead and checking, and writing a modified binary search that searches for a transition of matching/notmatching instead of a match.
This could be further optimised by keeping statistics or profiling, to find the perfect jump distance, or basing it off of the last up-most check.
actually it's easy because the list is already sorted, the numbers you expect to find are adjacent.
just like Ryan's answer, I'll put some code
public static List<Integer> searchAll (int[] array, int numero){
int firstMatchIndex = search( array, numero);
List<Integer> results = new ArrayList<Integer>():
results.add(firstMatchIndex);
boolean left = true;
while( left){
int i = firstMatchIndex - 1;
if(i<0 || array[i] != numero){
left = false;
}else{
results.add(i);
}
}
boolean right = true;
while( right){
int i = firstMatchIndex + 1;
if(i>array.length || array[i] != numero){
right = false;
}else{
results.add(i);
}
}
}
I have the array {1,2,3,4,4,4,5}
I want my function return index of 4.
for example : 4 found at location 4,5,6
public void binarySearch(int value){
sort(); // sorting the array
int index=-1;
int lower=0;
int upper=count-1;
while(lower<=upper){
int middle=(lower+upper)/2;
if(value==array[middle]){
index=middle;
System.out.println(value+ " found at location "+(index+1));
break;
}
else if(value<array[middle]){
upper=middle-1;
}
else lower=middle+1;
}
}
It's not too hard. We know that because the list is sorted, all of our indexes are going to be contiguous (next to one another). So once we've found one, we just have to traverse the list in both directions to find out what other indexes also match.
public static void binarySearch(int value){
sort();
int index = -1;
int lower = 0;
int upper = array.length - 1;
while(lower <= upper){
// The same as your code
}
// Create a list of indexes
final List<Integer> indexes = new LinkedList<>();
// Add the one we already found
indexes.add(index);
// Iterate upwards until we hit the end or a different value
int current = index + 1;
while (current < array.length && array[current] == value)
{
indexes.add(current);
current++;
}
// Iterate downwards until we hit the start or a different value
current = index - 1;
while (current >= 0 && array[current] == value)
{
indexes.add(current);
current--;
}
// Sort the indexes (do we care?)
Collections.sort(indexes);
for (int idx : indexes)
{
System.out.println(value + " found at " + (idx + 1));
}
}
Bear in mind that what you have implemented is already a binary search. The extra code to find additional matching indexes would not fall under the usual definition of a binary search.
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