Linear array search - java

I'm pretty new to java and I'm trying to learn so I'm just wondering how I could preform a linear search through my array.
This is what I've done so far but it doesn't work.
public boolean contains(Object elem)
{
boolean result = false;
for(int i=0;i<this.vector.length;i++)
if(elem.equals(this.vector[i]))
result=true;
else
result=false;
return result;
}
public int indexOf(V elem)
{
int pos = 0;
for(int i=0;i<this.vector.length;i++)
if(this.vector[i].equals(elem))
pos=i;
else
pos= -1;
return pos;
}

Your contains() function only returns true if the passed elem is the last item in the array. If you find it, you should return true immediately.
Your indexOf() method suffers from the same issue.

You're missing a break after you've found the element.

Oneliner:
Arrays.asList(vector).indexOf(elem);
It just creates and deletes one more object (ArrayList) in the memory. Should not be a problem in the most of situations.

You need to break your loop when you find your match.

There are a few problems with that code: in both methods, you always search through the entire array, even if you have found the element already. In both methods, this is the source of a bug (and less importantly: it is not as efficient as it could be).
for(int i=0;i<this.vector.length;i++)
if(elem.equals(this.vector[i]))
return true;
return false;
(and similar for the other method) might be a better implementation.

Related

Implementing an equals method recursively

Basically, I need to compare two arrays and check if they have the same values in the same positions (recursively of course). I get an error with my current code: Array out of index exception:20
The code I have right now looks as follows:
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd){
if (first[iStart] == second[iStart]){
if (equalsHelper(first,second,(iStart+1),iEnd))
{
return true;
}
}
if (iStart == iEnd){
return first[iEnd] == second[iEnd];
}
return false;
}
You simply need to put you stop condition at the begin of you code. This will work if iStart is 0 at the beginning and iEnd is array length - 1.
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) { // you need to check this first
return first[iEnd] == second[iEnd];
}
if (first[iStart] == second[iStart]) {
if (equalsHelper(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
If you want to use the array length as input for iEnd you just need to change the code a little
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) {
return true;
}
if (first[iStart] == second[iStart]) {
if (equalsHelper2(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
Since performance was mentioned a few times I will say a few things about it.
The stack contains information about local variables and function calls. So each recursiv call will save these informations on the stack which will lead to a stackoverflow on huge inputs since the stack only has limited space. It is also slower in terms of execution due to more assembler commands in comparison to loops.
This can be avoided by using tail recursive functions.
A tail recursive call means simply that your recursive call must be the last statement that is executed in your method. The compiler will translate this into a loop. This is faster and uses less space on the stack.
A tail recursive version of your equals method would look like this:
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd)
{
if (iStart == iEnd)
{
return true;
}else{
if(first[iStart] != second[iStart])
{
return false;
} else
{
return equalsHelper2(first, second, iStart + 1, iEnd);
}
}
}
Leaving aside the question of whether recursion is the right solution (it really isn't, iteration here is trivial and will perform better), the problem is that the termination condition (iStart == iEnd) is not checked until after the recursive call.
Any recursive algorithm must a) check whether it is appropriate to continue recursing, and b) do the recursive call after that check. Failing to include the first step, or doing the steps out of order, will result in infinite recursion until an error is reached (StackOverflowError if nothing else happens first).
You do have a condition check before your recursive call, but it's for the method's overall purpose rather than for ending recursion. You also have a condition check for ending recursion, but it's done after the recursive call. The solution is to swap their order - take the if (iStart == iEnd) block and move it to before the if (first[iStart] == second[iStart]) block.
Recursion is a powerful programming technique, but has some draw backs in the Java language. If a method in java calls itself recursively an excessive number of times before returning it will lead to a StackOverflowError. It this instance, comparing equality of two Array's is almost guaranteed to do so.
Other languages like Scala allow you to write recursive functions which are optimised for recursion (tail recursive) and execute in constant stack space.
That been said, you should think whether recursion is really the correct solution here. It neither optimises the solution, nor adds code clarity.
Note: If you just want to compare two Array's in Java, then java.util.Arrays already has you covered.

What do I return if there is no numerical solution for my int returning method to find?

This is my method for finding a single duplicate within an array. What should I return when an array has no duplicates?
public int findDuplicate(int[] array) {
Arrays.sort(array);
int duplicate = 0;
for(int i = 0; i < array.length; i++)
{
if(array[i] == duplicate)
{
return duplicate;
}
duplicate = array[i];
}
return ???;
}
Three possible solutions come to mind:
Return the matching index or -1 if there is no duplicate. You can't return -1 if you return the duplicate value because it may be -1.
Use Integer and return null. I don't like that kind of APIs personally.
Split your method in boolean hasDuplicate() and int getDuplicate() and throw an exception if there is no duplicate. This feels wrong, because raising an exception because everything is fine is quite odd.
You might want to change some details of your code, too:
Copy the array before you sort it, so the callers stuff won't be modified
Document the corner cases. Which duplicate is found? The first? The last?
Generate and return array of duplicated values. If it has zero size, then no duplicates were found.
I can think of three possible solutions:
You can either return a value that the method should never return under normal circumstances, such as -1 in your case.
You can change the return type to Integer and return a null. Automatic boxing and unboxing can simplify the work needed to make this change.
You can throw an exception.
-1 is the best option. Or add another method for detecting if there is a duplicate in an array or not.

Using a break to get out of an enhanced for loop

Hi everyone I was asked to write the following method for homework and I need some clarification. Basically I want to know if the Comparable item given as a parameter is part of the comparableList array. Assuming the array is sorted, I was told to stop checking the array if the comparableList has the item in it or if item is smaller than the following item of the array. I used break but I am not sure if break will get me out of the enhanced for loop to avoid checking the whole array if any of the conditions are true. I want to make sure that if there are 50,000 items in the array and I find the item at position 5 to stop checking the rest of the array. I have never used break before so I am not sure if it will get me out of the for loop.
public boolean contains(Comparable item) {
Comparable[] comparableList= getStore();
boolean isThere = false;
for(Comparable p : comparableList)
{
if(item.compareTo(p)==0)
{
isThere = true;
break;
}
if(item.compareTo(p)<0)
{
break;
}
}
return isThere;
}
The break will break out of any loop, including the enhanced one. Your solution will work.
However, since you are returning as soon as you find your item, you could change the loop to return as soon as the item is found, or as soon as you know that you are not going to find it:
Comparable[] comparableList= getStore();
for(Comparable p : comparableList) {
if(item.compareTo(p)==0) {
return true;
}
if(item.compareTo(p)<0) {
return false;
}
}
return false;
Moreover, since the array is sorted, linear search is not your best strategy: implementing Binary Search could make your algorithm significantly faster.
If you want to know the best way of stopping once it's found, just do this:
public boolean contains(Comparable item) {
Comparable[] comparableList= getStore();
for(Comparable p : comparableList)
{
if(item.compareTo(p)==0)
{
return true;
}
if(item.compareTo(p)<0)
{
return false;
}
}
return false;
}

Iterating through array - java

I was wondering if it was better to have a method for this and pass the Array to that method or to write it out every time I want to check if a number is in the array.
For example:
public static boolean inArray(int[] array, int check) {
for (int i = 0; i < array.length; i++) {
if (array[i] == check)
return true;
}
return false;
}
Thanks for the help in advance!
Since atleast Java 1.5.0 (Java 5) the code can be cleaned up a bit. Arrays and anything that implements Iterator (e.g. Collections) can be looped as such:
public static boolean inArray(int[] array, int check) {
for (int o : array){
if (o == check) {
return true;
}
}
return false;
}
In Java 8 you can also do something like:
// import java.util.stream.IntStream;
public static boolean inArray(int[] array, int check) {
return IntStream.of(array).anyMatch(val -> val == check);
}
Although converting to a stream for this is probably overkill.
You should definitely encapsulate this logic into a method.
There is no benefit to repeating identical code multiple times.
Also, if you place the logic in a method and it changes, you only need to modify your code in one place.
Whether or not you want to use a 3rd party library is an entirely different decision.
If you are using an array (and purely an array), the lookup of "contains" is O(N), because worst case, you must iterate the entire array. Now if the array is sorted you can use a binary search, which reduces the search time to log(N) with the overhead of the sort.
If this is something that is invoked repeatedly, place it in a function:
private boolean inArray(int[] array, int value)
{
for (int i = 0; i < array.length; i++)
{
if (array[i] == value)
{
return true;
}
}
return false;
}
You can import the lib org.apache.commons.lang.ArrayUtils
There is a static method where you can pass in an int array and a value to check for.
contains(int[] array, int valueToFind)
Checks if the value is in the given array.
ArrayUtils.contains(intArray, valueToFind);
ArrayUtils API
Using java 8 Stream API could simplify your job.
public static boolean inArray(int[] array, int check) {
return Stream.of(array).anyMatch(i -> i == check);
}
It's just you have the overhead of creating a new Stream from Array, but this gives exposure to use other Stream API. In your case you may not want to create new method for one-line operation, unless you wish to use this as utility.
Hope this helps!

DFS tree traversal function modification

Please find below my implementation for DFS.
protected void DFS(String search) {
for(Tree<T> child : leafs) {
if(child.value.equals(search))
return;
else
child.DFS(search);
System.out.println(child.value);
}
}
The objective is to stop traversal on finding the node whose value is in the variable search. However, the above function goes on traversing the tree even beyond the declared search node. Could someone help me modify the above function?
Thank you.
Edit 1
protected boolean DFS(String anaphorKey) {
boolean found = false;
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
found = child.DFS(anaphorKey);
if(found == true)
break;
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return found;
}
Tried implementing the given answer suggestion (#SJuan76). The implementation above isn't working as desired. Could you point me to the place where code is not as per the logic suggested?
rookie, might I suggest an implementation using the classic for-loop (as opposed to the enhanced for-loop being used now) which allows integration of your stop-condition a bit better, something like:
protected boolean DFS(String key) {
boolean found = false;
for(int i = 0; i < leafs.size() && !found; i++) {
Tree<T> child = leafs.get(i);
if(child.head.equals(key))
found = true;
else
found = child.DFS(key);
}
return found;
}
So as soon as your found condition is hit, the 'found' becomes true and your loop stops.
What you may have forgotten is the "found = child.DFS(key)" portion of the recursion, where you need to remember the result of your recursive calls so ALL your for-loops on up the chain all break as soon as you return.
Hope that helps.
Option A (Nice): the function returns a value, when the node is found it returns a different value that if the node was not found. When you call to method, if you get the found value you stop the loop and return the found value too.
Option B (Ugly): When found, thow an Exception (better if it is your own implementation of it). Don't forget to catch it.
Option C (Uglier): The same with global (static) variables.
UPDATE 1:
It looks like your method should run ok now, can you check (System.out.println) if your value is ever found?
In a more personal opinion, I would find
protected boolean DFS(String anaphorKey) {
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
if(child.DFS(anaphorKey)) // No need to store value. No need to check == true (it is implicit)
return true; // If we are in this line the value was found, always return true
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return false; // If the method did not exit previously it was because the value was not found, so in this line always return false
}
more readable (but it should work exactly as your implementation)

Categories