Generic Binary Search - JAVA - - java

I dont know if the functionality of my code is the correct one for binary search BUT this is not my question, I want to solve it myself.
My problem is in testing its functionality while I get the following errors:
I really dont know how to solve this issue. Please help me!
My code:
public class BinarySearchGeneric<T extends Comparable<T>>{
public int search(T[] array, T element){
int start = 0;
int end = array.length - 1;
int mid = (start + end) / 2;
while(!element.equals(array[mid]) && end != 0) {
if (element.equals(array[mid])) {
return mid;
} else if (array[mid].compareTo(element) < 0) {
end = mid - 1;
mid = (start + end) / 2;
} else if(array[mid].compareTo(element) > 0){
start = mid + 1;
mid = (start + end) / 2;
}
}
return -1;
}
}
Main Method:
public class Main {
public static void main(String[] args) {
int[] a = {1,2,3,4,5,6,7,8,9,10};
BinarySearchGeneric binarySearchGeneric = new BinarySearchGeneric(a);
System.out.println("BinarySearch Generic: " + binarySearchGeneric.search(a, 8));
}
}

There are two compilation issues here:
There is no constructor of BinarySearchGeneric which takes a parameter, but you're trying to pass the parameter. Remove it:
BinarySearchGeneric binarySearchGeneric = new BinarySearchGeneric();
int[] is not an acceptable parameter to a generic method expecting an array, because int is a primitive type, not a reference type, and so can't be used in generics. The solution is simply to declare an array of Integer, rather than int:
Integer[] a = {1,2,3,4,5,6,7,8,9,10};
The compiler converts these int literals to Integer instances automatically.
But there are more issues.
You're declaring a variable of raw type. This basically switches off the compiler's type checking associated with that variable, making it likely that you will make a type error. Add the generic parameters:
BinarySearchGeneric<Integer> binarySearchGeneric = new BinarySearchGeneric<>();
Arrays and generics don't really play well together. Things would start get a bit messy if you declared a generic, comparable class:
class GenericComparable<T> extends Comparable<T> { ... }
and then tried to declare an array of GenericComparables to pass to binarySearchGeneric, since you can't directly create a generic array.
It's much easier simply to avoid arrays, and use a List<T> instead:
public int search(List<T> array, T element){
Potentially, you have inconsistent behaviour, because you are mixing equals and compareTo in the search. Whilst compareTo should be consistent with equals (in the sense that a.compareTo(b) <=> a.equals(b), it isn't necessarily true.
You can make the behaviour consistent by only using compareTo:
int c = array[mid].compareTo(element);
if (c == 0) {
// ...
} else if (c < 0) {
// ...
} else {
// ...
}

I don't see a user defined constructor for the BinarySearchGeneric class, so your code should look something like this:
BinarySearchGeneric binarySearchGeneric = new BinarySearchGeneric();
System.out.println("BinarySearch Genetic: ", binarySearchGeneric(a, 8));

Related

Converting from Integer wrapper class to int primitive class

I've been trying to convert an Integer Wrapper class to int primitive class. I haven't yet found a proper way to make the code compile. I'm using Intellij IDEA, Java 11 Amazon Coretto, but I need to run it on a computer that runs java 8.
Here's the original code below:
static class Line<Integer> extends ArrayList<Integer> implements Comparable<Line<Integer>> {
#Override
public int compareTo(Line<Integer> other) {
int len = Math.min(this.size(), other.size());
for (int i = 0; i < len; i++) {;
if ((int) this.get(i) != (int) other.get(i)) {
if ((int this.get(i) < (int) this.get(i)) {
return -1;
} else if ((int) this.get(i) > (int)this.get(i)) {
return 1;
} else {}
}
}
...
note that the Line is inserted to an ArrayList.
Originally I used forced casting on all the Integer objects so it'll be like (int) this.get(i). It worked on my local terminal and my Intellij wasn't bothered about it, but unfortunately not the other computer. It couldn't compile there
I thought it was because of the forced casting, since the other computer returned
Main.java:159: error: incompatible types: Integer cannot be converted to int
if ((int) this.get(i) != (int) other.get(i)) {
^
where Integer is a type-variable:
Integer extends Object declared in class Line
so I deleted them all and thought I could let the machine unbox the Integer wrapper on its own. It still didn't compile.
If the code is left like what's written above (no forced casting), it will return "Operator '<' not applicable for 'Integer', 'Integer'"
So I used the .compareTo() method. Compile error.
Then I tried to assign them to an int variable. Intellij IDEA was screaming at me that it required int but found Integer instead. So I force-casted, like so
int thisLine = (int) this.get(i);
int otherLine = (int) other.get(i);
if (thisLine != otherLine) {
if (thisLine < otherLine) {
return -1;
} else if (thisLine > otherLine) {
return 1;
} else {}
Nope, didn't work. Removing the cast also didn't work.
I looked up the Javadocs (https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#intValue--) this time about the Integer class and found a promising little method called intValue(). Problem is? Intellij cannot resolve that method (oddly, VSCode does not consider this an error). I used it like this
int thisLine = this.get(i).intValue();
int otherLine = other.get(i).intValue();
if (this.get(i) != other.get(i)) {
if (thisLine < otherLine) {
return -1;
} else if (thisLine > otherLine) {
return 1;
and sure enough, another compile error on that stubborn computer.
I'm running out of options. I'm seriously considering creating a new custom class just so I can store int values in an ArrayList without having to deal with all this Java backwards incompatibility nonsense.
Anyone here know a consistent method for converting an Integer wrapper object to an int primitive object in Java?
This is the clue in the error message that explains it:
where Integer is a type-variable:
Integer extends Object declared in class Line
Integer is not java.lang.Integer but a type variable with a confusing name...
You declared the type variable here:
static class Line<Integer> extends ArrayList<Integer> implements Comparable<Line<Integer>>
It's as if you declared it like this:
static class Line<T> extends ArrayList<T> implements Comparable<Line<T>>
but by naming the type variable Integer instead of T, and then you try to cast objects of the type T to int later on.
Fix it by not declaring a type parameter named Integer, you don't need that here:
static class Line extends ArrayList<Integer> implements Comparable<Line<Integer>>
You shouldn't have to cast an Integer to an int at all. Integer class has .compareTo methods which compare two integers.
A 0 means value1 is equal to value2. -1 is value1 is less than value2 and a 1 is value1 is greater than value2.
Try the following:
public int compareTo(Line<Integer> other) {
//get the smallest length
int len = this.size() <= other.size() ? this.size() : other.size();
for (int i = 0; i < len; i++) {
int compare = this.get(i).compareTo(other.get(i));
if (compare != 0) { //if compare is not zero they are not the same value
return compare;
}
}
//If we get here, everything in both lists are the same up to "len"
return 0;
}
The compareTo() method is a method of Integer class under java. lang
package. ... It returns the result of the value 0 if Integer is equal
to the argument Integer, a value less than 0 if Integer is less than
the argument Integer and a value greater than 0 if Integer is greater
than the argument Integer.
In you class "Integer" is not a java.lang.Integer but a Generic class that is the reason

Java : To write a method that can be applied on any kind of array

Hi and thanks for noticing my problem. I want to write a method that can be used by different types of arrays. But my code always looks like this:
public int indexOf_1(int[] a,int b){
//Find the first matched result and return, otherwise report -1
int index = -1;
for(int j=0;j<a.length;j++){
if (a[j]==b)
{index=j;}
}
return index;
}
public int indexOfChar_1(char[] a,int b){
//Consider merged to the previous method?
int index = -1;
for(int j=0;j<a.length;j++){
if (a[j]==b)
{index=j;}
}
return index;
}
That seems to be redundant and I'm completely uncomfortable with such code duplication. Is there any way to write a searching method for all kinds of array to avoid repeating in this case? Thanks!
Unfortunately because the way arrays and the JVM work, this can't be reduced. Not even generics can help since int[] cannot be safely cast to Object[] without explicit conversion.
This looks like a common util function. If you're not comfortable with the code duplication, you can consider using one of the many libraries which provide this functionality. Guava and Commons-Lang are a few.
Guava puts them in the class relevant to the primitive type. Commons-Lang arranges them in the ArrayUtils class
e.g.
Bytes.indexOf(byteArray, (byte) 2);
Ints.indexOf(intArray, 22);
ArrayUtils.indexOf(intArray, 6);
Well you could use Object[] but you might not want to use ==, since it will compare identity of objects instead of values, instead you probably want to use .equals(). (Unless you know the value will always be a char or int) Perhaps this:
public int indexOf(Object[] a, int b) {
int index = -1;
for (int j = 0; j < a.length; j++) {
if (a[j].equals(b)) {
index = j;
}
}
return index;
}
public static <T> int index_Of(Object[] input,T value){
//Find the first matched result and return, otherwise report -1
for(int j=0;j<input.length;j++){
if(input[j].equals(value))
return j;
}
return -1;
}
You can generalize you method to deal with all kind of arrays. However, please pay more attention to the type. If you want to use Object referring to primitive type, when declaring a primitive type array, you need to use reference type. For example,
Character [] a = new Character[]{'a','b','c'};
DO NOT use char, since it will compile error when type checking.

Effective Java Item42, at least one input argument

Effective java 2, Item 42 propose an elegant way for a method take at least one argument, and fail at compile time if the input is empty. The code is shown below in the min() method, however I am wondering what is the elegant way to call this method, because now simply passing list will trigger an compiler error.
public class OneOrMoreArgs {
public static int min(int firstArg, int... remaining){
// but then how do you call the function with a int[] ?
int _min = firstArg;
for(int x: remaining){
if(_min < x ){
_min = x;
}
}
return _min;
}
public static int sum(int... list){
int s = 0;
for(int a: list){
s += a;
}
return s;
}
public static void main(String []args){
int[] list = {1,2,3,4,5};
System.out.println(OneOrMoreArgs.sum(list));
System.out.println(OneOrMoreArgs.min(list));
}
}
Well, the elegant way to call it would be to do
OneOrMoreArgs.min(1, 2, 3, 4, 5);
If you need to pass in an array, you could add an additional method signature like this:
public static int min(int[] args){
if (args == null || args.length < 1) {
throw new IllegalArgumentException("... some error message...");
}
return min(args[0], Arrays.copyOfRange(args, 1, args.length));
}
It needs to be noted that:
This solution is inefficient as it requires the array to be copied.
The check is executed at runtime instead of compile time, so you lose the benefits of the solution proposed by Item 42.
It looks like for your use case, you're better off just declaring a method that takes an array parameter, like the sum() in your example.

Generic method to find largest in 2D array

So guys I have to write a generic method to find the maximum element in a 2-D array then I have to test using integers, strings, and objects.
I'm a little sleep deprived so I apologize for what is probably a very very simple fix.
I have my generic method:
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (int i = 0; i < stuff.length; i++)
for(int j = 0; j <stuff.length; i++)
if (stuff[i][j].compareTo(max) > 0)
max = stuff[i][j];
return max;
}
}
and simply trying to test with integers first
public class GenericTester {
public static void main(String[] args) {
Integer[][] myArray = { {0,1,2,3}, {3,2,1,0}, {3,5,6,1}, {3,8,3,4} };
System.out.println(Generic.Max(myArray));
}
}
Ok I fixed the previous error, dumb mistake, but yes now I am getting The method Max(T[][]) in the type Generic is not applicable for the arguments (int[][])
what would be the best fix for this problem?
Thanks for any and all help
Presumably you need Generic.Max(myArray) or else you need to
import static Generic.Max;
at the top of GenericTester.java.
Generics will not work with primitive types, so T cannot be bound to int. Note, in particular, that int does not extend Comparable<int>. You will need to use an Integer[][] array instead of int and similarly for the other primitive types.
EDIT In addition to the above, your loops need some work. First, the increment on the inner loop is wrong (this is why you are seeing an ArrayIndexOutOfBoundsException). Second, your code requires that the matrix is square and full (since you use stuff.length for the inner loop limit). Here's how I would write them (using enhanced for loop syntax):
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (T[] row : stuff) {
for (T elt : row) {
if (elt.compareTo(max) > 0) {
max = elt;
}
}
}
return max;
}
}
For a truly general method, you would want to check that stuff[0][0] exists.

What does "T" represent in this code?

T get(int i) {
if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException();
return a[i];
}
T set(int i, T x) {
if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException();
T y = a[i];
a[i] = x;
return y;
}
I'm looking over some coding examples from my textbook, but they never mention what T is. I'm not sure how to search about this since I don't know what it's called or it's purpose.
I was wondering if someone can show me a write-up or some info about this. Thank you
T represents an object type using generics.
Whatever type x is in the set call, the set method will return that same type. In the get call, the return type is T, too. That type must be defined somewhere else, probably in the type of the class, where it might show up as <T>.
So if this is a class that is some sort of collections (since it is dealing with indexes), it might be defined as:
public class SomeCollection<T> {
Then it might get instantiated like:
SomeCollection<String> arr = new SomeCollection<String>();
In that case, T would be String, and the return type of the get and set methods, and the type of set parameter x, would all be String.
If it gets instantiated like:
SomeCollection<Integer> arr = new SomeCollection<Integer>();
then T is an Integer.
You could have both in the same code, without having to write two (or more) different versions of SomeCollection.

Categories