Issue
So I'm trying to complete an exercise where I've been asked to implement a method that does a binary search in an ArrayList of objects. From the exercise:
Binary search
In the Main-class, implement a method public static int binarySearch(ArrayList<Book> books, int searchedId), which searches the list it received as a parameter, for a book with an id variable that matches the value of searchedId variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value -1.
The method must be implemented as a binary search, which assumes the list is ordered. You should also assume, that the ids towards the beginning of the list, are always smaller than the ids towards the end of the list.
I have created two methods, one to check whether the arraylist is sorted (isItSorted) and the other one that will perform the binary search if the aforementioned method evaluates to true (binarySearch). Please see below:
public static boolean isItSorted(ArrayList<Book> books) {
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
if (!(boo.contains("false"))) {
return true;
}
return false;
}
public static int binarySearch(ArrayList<Book> books, long searchedId) {
if (searchedId < 0 || books.isEmpty()) {
return -1;
} else if (isItSorted(books)) {
int start = 0;
int end = books.size() - 1;
int middle = (start + end) / 2;
if (books.get(middle).getId() == searchedId) {
return middle;
} else if (books.get(middle).getId() > searchedId) {
end = middle - 1;
} else if (books.get(middle).getId() < searchedId) {
start = middle + 1;
}
while (start <= end) {
if (books.get(start).getId() == searchedId) {
return start;
}
start++;
}
}
return -1;
}
Inside these java files, there's a test package that tests whether my solution is correct or not. While 95% of the tests are successful, when it reaches the method below (where it compares the time of execution compared to my other method (linear search)), I get the error Java outOfMemory heap Space. I use NetBeans. I've already tried the JVM commands. My solution seems to work with every number of objects I've tried, so perhaps there's something wrong with the test code below?
@Test
@Points("07-05.2")
public void binarySearchIsFasterThanLinearSearch() throws Throwable {
ArrayList<Book> books = generateBooks(10000);
Collections.sort(books, (k1, k2) -> k1.getId() - k2.getId());
int searched = 1000001;
long bSearchStart = System.nanoTime();
int binarySearchId = Searching.binarySearch(books, searched);
long bSearchEnd = System.nanoTime();
assertTrue("When binary search does not find what was searched for, it must return -1", binarySearchId == -1);
long lSearchStart = System.nanoTime();
int linearSearchId = Searching.linearSearch(books, searched);
long lSearchEnd = System.nanoTime();
assertTrue("When linear search does not find what was searched for, it must return -1", linearSearchId == -1);
long bSearchTime = bSearchEnd - bSearchStart;
long lSearchTime = lSearchEnd - lSearchStart;
assertTrue("When there are 10000 books to search, and the searched book is not found, binary search should be a lot faster than linear search. Current this isn't so", bSearchTime * 2 < lSearchTime);
}
Solution
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
Adds on the order of 100 million items to the ArrayList boo.
If you want to check if something is sorted you can use much simpler code:
Book prev = books[0];
for (int i = 1; i < books.size(); i++) {
if (prev.getId() > books[i].getId())
return false;
}
return true;
But you shouldn't need to call it inside binarySearch() because that will defeat the purpose of binarySearch() and make it as slow as linearSearch().
Answered By - AminM
Answer Checked By - Terry (JavaFixing Volunteer)