Binary and Linear search - java

This program is suppose to detect if an integer is found or not and how long it took to find. The first one is a linear search and the second is a binary search. The problems I'm having is this. The linear search works, except I keep getting the message "Linear search successful" again and again. I'm not sure why the binary search isn't outputting anything to be honest. Any help is appreciated
public class search {
/**
* #param args
*/
public static void main(String[] args) {
Scanner scanner1 = new Scanner(System.in);
System.out.println("Please enter in an integer:");
int searchValue = scanner1.nextInt();
int[] numbers = new int[1000];
try {
Scanner scanner = new Scanner(new File("numbers.txt"));
for (int i = 0; i < 1000; i++) {
numbers[i] = scanner.nextInt();
}
} catch (FileNotFoundException e) {
System.out
.println("A problem occurred reading the file numbers.txt");
System.exit(0);
}
long time = System.nanoTime();
int linear = linearSearch(numbers, searchValue);
long end = System.nanoTime();
System.out.println(end - time);
}
public static int linearSearch(int[] numbers, int searchValue) {
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] > searchValue)
return -1;
else if (numbers[i] == searchValue)
return i;
System.out.println("Linear search successful");
}
return -1;
}
public int binarySearch(int searchValue, int[] numbers) {
long time = System.nanoTime();
int low = 0;
int high = numbers.length - 1;
while (low <= high) {
int middle = low + (high - low) / 2;
if (numbers[middle] == searchValue) {
System.out.println("Binary found");
long end = System.nanoTime();
System.out.println(end - time);
}
if (searchValue < numbers[middle])
high = middle - 1;
else if (searchValue > numbers[middle])
low = middle + 1;
else
return middle;
}
return -1;
}
}

It's because you never call the binarySearch() function. You only call linearSearch().
/* Call to linearSearch is here */
int linear = linearSearch(numbers, searchValue);
/* No call to binarySearch to put here */

System.out.println("Linear search successful")
put this outside the for loop
and for binary search to take place you need to at least call the function .

Related

How to fix method cannot be applied to given types

I am creating a program to do a binary search.
The method should be repeated a different number of times and and i want to print out the time it took to repeat the method.
They way the code is now i get an error while compiling method binary search cannot be compiled to given types and i dont know how to fix it.
public class Bin_search {
public static void main(String[] args) {
int z = Integer.parseInt(args[0]);
double k = (int)(Math.random()*1000001);
int n = 1000000;
int arr[] = new int[n];
int i = 0;
for(i = 0;i<n;i++){
arr[i] = i;
}
long startTime = System.currentTimeMillis();
for(int t= 0; t<z; t++) {
binarySearch();
}
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("It took " + elapsedTime + " ms to repeat the algorithm.");
}
int binarySearch(int n, double k, int arr[]) {
int li = 0;
int re = n+1;
int m;
while (li < re-1) {
m = (li + re) / 2;
if (k <=arr[m]){
re = m;
}
else{
li = m;
}
}
return re;
}
}
First of all, the binarySearch method is made by three arguments, and you are not providing them, secondly you should make your binarySearch method static, otherwise it cannot be called from the main method without creating an instance first.
It should be like this, i think
public class Main {
public static void main(String[] args) {
args = new String[3];
args[0] = "100";
int z = Integer.parseInt(args[0]);
double k = (int)(Math.random() * 1000001);
int n = 1000000;
int arr[] = new int[n];
int i = 0;
for(i = 0;i<n;i++){
arr[i] = i;
}
long startTime = System.currentTimeMillis();
for(int t= 0; t<z; t++) {
binarySearch(n, k, arr);
}
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("It took " + elapsedTime + " ms to repeat the algorithm.");
}
static int binarySearch(int n, double k, int arr[]) {
int li = 0;
int re = n+1;
int m;
while (li < re-1) {
m = (li + re) / 2;
if (k <=arr[m]){
re = m;
}
else{
li = m;
}
}
return re;
}
}
EDIT: Now it works, but please check if your application logic to be sure it's doing what you are expecting to do

Subset sum negative values

I was wondering how to work with negative values and a negative target, right now my program gives index out of bounds errors whenever negative values are given to these variables. I need my hasSum function work with negative values for this project, I can't just assume positive.
import java.util.Stack;
import java.util.Scanner;
public class subsetSum {
static Scanner input = new Scanner(System.in);
static {
System.out.print("Enter the target (T)" + "\n");
}
/** Set a value for target sum */
static int TARGET_SUM = input.nextInt(); //this is the target
/** Store the sum of current elements stored in stack */
static int sumInStack = 0;
Stack<Integer> stack = new Stack<Integer>();
public static void main(String[] args) {
//the size is S
System.out.println("\n" + "Enter the size of the set (S)");
int values = input.nextInt(); //size = "values"
//value of each size entry
System.out.println("\n" + "Enter the value of each entry for S");
int [] numbers = new int[values];
for(int i = 0; i < values; i++) //for reading array
{
numbers[i] = input.nextInt();
}
if(hasSum(numbers, TARGET_SUM)){
System.out.println("\n" + "Can: ");
subsetSum get = new subsetSum(); // encapsulation
get.populateSubset(numbers, 0, numbers.length);
}else{
System.out.println("\n" + "Cannot");
}
}
//method based on dynamic programming O(sum*length)
public static boolean hasSum(int [] array, int sum)
{
int i;
int len = array.length;
boolean[][] table = new boolean[sum + 1][len + 1]; //this has to be changed for negative
//If sum is zero; empty subset always has a sum 0; hence true
for(i = 0; i <= len; i++){
table[0][i] = true;
}
//If set is empty; no way to find the subset with non zero sum; hence false
for(i = 1; i <= sum; i++){
table[i][0] = false;
}
//calculate the table entries in terms of previous values
for(i = 1; i <= sum; i++)
{
for(int j = 1; j <= len; j++)
{
table[i][j] = table[i][j - 1];
if(!table[i][j] && i >= array[j - 1]){
table[i][j] = table[i - array[j - 1]][j - 1];
}
}
}
return table[sum][len]; //this has to be changed for negative
}
public void populateSubset(int[] data, int fromIndex, int endIndex) {
/*
* Check if sum of elements stored in Stack is equal to the expected
* target sum.
*
* If so, call print method to print the candidate satisfied result.
*/
if (sumInStack >= TARGET_SUM) {
if (sumInStack == TARGET_SUM) {
print(stack);
}
// there is no need to continue when we have an answer
// because nothing we add from here on in will make it
// add to anything less than what we have...
return;
}
for (int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++) {
if (sumInStack + data[currentIndex] <= TARGET_SUM) {
stack.push(data[currentIndex]);
sumInStack += data[currentIndex];
/*
* Make the currentIndex +1, and then use recursion to proceed
* further.
*/
populateSubset(data, currentIndex + 1, endIndex);
sumInStack -= (Integer) stack.pop();
}
}
}
/**
* Print satisfied result. i.e. 5 = 1, 4
*/
private void print(Stack<Integer> stack) {
StringBuilder sb = new StringBuilder();
for (Integer i : stack) {
sb.append(i).append(",");
}
// .deleteCharAt(sb.length() - 1)
System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
}
}
Are you trying to find a sum of subset or a subarray?
If a subset, then a simple recursion could do the trick, e.g.:
public static boolean hasSum(int [] array, int sum)
{
return hasSum(array, 0, 0, sum);
}
private static boolean hasSum(int[] array, int index, int currentSum, int targetSum) {
if (currentSum == targetSum)
return true;
if (index == array.length)
return false;
return hasSum(array, index + 1, currentSum + array[index], targetSum) || // this recursion branch includes current element
hasSum(array, index + 1, currentSum, targetSum); // this doesn't
}
If you're trying to find a subarray, I'd use prefix sums, e.g.:
public static boolean hasSum(int [] array, int sum)
{
int[] prefixSums = new int[array.length];
for (int i = 0; i < prefixSums.length; i++) {
prefixSums[i] = (i == 0) ? array[i] : array[i] + prefixSums[i - 1];
}
for (int to = 0; to < prefixSums.length; to++) {
if (prefixSums[to] == sum)
return true; // interval [0 .. to]
for (int from = 0; from < to; from++) {
if (prefixSums[to] - prefixSums[from] == sum)
return true; // interval (from .. to]
}
}
return false;
}
BTW I think reading the input values from Scanner inside the static initializer is a bad idea, why don't you move them to main()?

UCF HSPT 2016 - Chomp Chomp

I am having a lot of trouble finding an efficient solution to Problem #9 in the UCF HSPT programming competition. The whole pdf can we viewed here, and the problem is called "Chomp Chomp!".
Essentially the problem involves taking 2 "chomps" out of an array, where each chomp is a continuous chain of elements from the array and the 2 chomps have to have at least element between them that's not "chomped." Once the two "chomps" are determined, the sum of all the elements in both "chomps" has to be a multiple of the number given in the input. My solution essentially is a brute-force that goes through every possible "chomp" and I tried to improve the speed of it by storing previously calculated sums of chomps.
My code:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;
public class chomp {
static long[] arr;
public static long sum(int start, int end) {
long ret = 0;
for(int i = start; i < end; i++) {
ret+=arr[i];
}
return ret;
}
public static int sumArray(int[] arr) {
int sum = 0;
for(int i = 0; i < arr.length; i++) {
sum+=arr[i];
}
return sum;
}
public static long numChomps(long[] arr, long divide) {
HashMap<String, Long> map = new HashMap<>();
int k = 1;
long numchomps = 0;
while(true) {
if (k > arr.length-2) break;
for (int i = 0; i < arr.length -2; i++) {
if ((i+k)>arr.length-2) break;
String one = i + "";
String two = (i+k) + "";
String key1 = one + " " + two;
long first = 0;
if(map.containsKey(key1)) {
//System.out.println("Key 1 found!");
first = map.get(key1).longValue();
} else {
first = sum(i, i+k);
map.put(key1, new Long(first));
}
int kk = 1;
while(true){
if (kk > arr.length-2) break;
for (int j = i+k+1; j < arr.length; j++) {
if((j+kk) > arr.length) break;
String o = j + "";
String t = (j+kk) + "";
String key2 = o + " " + t;
long last = 0;
if(map.containsKey(key2)) {
//System.out.println("Key 2 found!");
last = map.get(key2).longValue();
} else {
last = sum(j, j+kk);
map.put(key2, new Long(last));
}
if (((first+last) % divide) == 0) {
numchomps++;
}
}
kk++;
}
}
k++;
}
return numchomps;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int n = Integer.parseInt(in.nextLine());
for(int i = 1; i <= n; i++) {
int length = in.nextInt();
long divide = in.nextLong();
in.nextLine();
arr = new long[length];
for(int j = 0; j < length; j++) {
arr[j] = (in.nextLong());
}
//System.out.println(arr);
in.nextLine();
long blah = numChomps(arr, divide);
System.out.println("Plate #"+i + ": " + blah);
}
}
}
My code gets the right answer, but seems to take too long, especially for large inputs when the size of the array is 1000 or greater. I tried to improve the speed of my algorithm my storing previous sums calculated in a HashMap, but that didn't improve the speed of my program considerably. What can I do to improve the speed so it runs under 10 seconds?
The first source of inefficiency is constant recalculation of sums. You should make an auxiliary array of partial sums long [n] partial;, then instead of calling sum(i, i + k) you may simply do partial[i + k] - partial[i].
Now the problem reduces to finding indices i<j<k<m such that
(partial[j] - partial[i] + partial[m] - partial[k]) % divide == 0
or, rearranging terms,
(partial[j] + partial[m]) % divide == (partial[i] + partial[k]) % divide
To find them you may consider an array of triples (s, i, j) where s = (partial[j] - partial[i]) % divide, stable sort it by s, and inspect equal ranges for non-overlapping "chomps".
This approach improves performance from O(n4) to O(n2 log n). Now you shall be able to improve it to O(n log n).

Did I make a simple mistake with my first binary search technique?

I've created an array to generate 10 random numbers between 1-100, sorted them with a for loop (supposed to use the "enhanced for loop"). The last thing left besides making my for loop enhanced is to "enter one value, search array using binary search technique to determine if value is present or not and output that. Do you see what is wrong? Thanks!
import java.util.*;
class lab4point2 //lab4.2 part 1 {
public static void main(String args[]) {
int[] array = new int[10]; //array of 10 numbers created.
Random rand = new Random(); //random class created called rand.
for (int cnt = 0; cnt < array.length; cnt++) { //for loop to generate
array[cnt] = rand.nextInt(100) + 1; // the 10 numbers randomly 1-100
}
Arrays.sort(array); //sorted
System.out.println(Arrays.toString(array));// prints the 10 numbers to screen
System.out.print("Enter a value to see if it is present. ");
Scanner scanner = new Scanner(System.in);
int value = scanner.nextint();
boolean binarySearch(array, 0, 99, value);
int size = 100;
int low = 0;
int high = size - 1;
while (high >= low) {
int middle = (low + high) / 2;
if (data[middle] == value) {
System.out.print("Value is present ");
return true;
}
if (data[middle] < value) {
low = middle + 1;
}
if (data[middle] > value) {
high = middle - 1;
}
}
System.out.print("Value is not present. ");
return false;
}
}
You have some syntax errors in your code. It should look more like the following:
class SearchArray {
private final int[] array = new int[10];
private final Random random = new Random();
public SearchArray() {
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(100) + 1;
}
Arrays.sort(array);
}
public String toString() {
return Arrays.toString(array);
}
public boolean contains(int value) {
int low = 0;
int high = array.length - 1;
while (high >= low) {
int middle = (low + high) / 2;
if (array[middle] == value) {
return true;
}
if (array[middle] < value) {
low = middle + 1;
}
if (array[middle] > value) {
high = middle - 1;
}
}
return false;
}
class lab4point2 {
public static void main(String args[]) {
SearchArray array = new SearchArray();
System.out.println(array.toString());
System.out.print("Enter a value to see if it is present. ");
Scanner scanner = new Scanner(System.in);
int value = scanner.nextint();
if (array.contains(value)) {
System.out.print("Value is present. ");
} else {
System.out.print("Value is not present. ");
}
}
}

Java--Making 10-integer ordering program recursive

I have a simple problem - I need to order 10 numbers. I had an idea how to do this recursively: Make an array of the 10 numbers, take the maximum of the ten numbers, take it out of the array, and repeat the same function with the nine numbers left. The problem was that I did not know how to implement that. I wrote the program, and it works, only it has a part that repeats all the time but with new arrays, because you cannot change the size of the array.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone {
public static void main (String[] args) throws java.lang.Exception {
int[] sortedArray = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Scanner input = new Scanner(System.in);
int in0 = input.nextInt();
int in1 = input.nextInt();
int in2 = input.nextInt();
int in3 = input.nextInt();
int in4 = input.nextInt();
int in5 = input.nextInt();
int in6 = input.nextInt();
int in7 = input.nextInt();
int in8 = input.nextInt();
int in9 = input.nextInt();
int[] numArray = new int[]{in0, in1, in2, in3, in4, in5, in6, in7, in8, in9};
int numArrayLength = numArray.length;
recursiveSort(numArray);
for (int i=0;i<numArrayLength;i++) {
System.out.print(numArray[i]+",");
}
sortedArray[0] = numArray[0];
System.out.println(" ");
int[] numArray2 = Arrays.copyOfRange(numArray, 1, numArrayLength);
int numArray2Length = numArray2.length;
recursiveSort(numArray2);
for (int j=0;j<numArray2Length;j++) {
System.out.print(numArray2[j]+",");
}
sortedArray[1] = numArray2[0];
System.out.println(" ");
int[] numArray3 = Arrays.copyOfRange(numArray2, 1, numArray2Length);
int numArray3Length = numArray3.length;
recursiveSort(numArray3);
for (int k=0;k<numArray3Length;k++) {
System.out.print(numArray3[k]+",");
}
sortedArray[2] = numArray3[0];
System.out.println(" ");
int[] numArray4 = Arrays.copyOfRange(numArray3, 1, numArray3Length);
int numArray4Length = numArray4.length;
recursiveSort(numArray4);
for (int k=0;k<numArray4Length;k++) {
System.out.print(numArray4[k]+",");
}
sortedArray[3] = numArray4[0];
System.out.println(" ");
int[] numArray5 = Arrays.copyOfRange(numArray4, 1, numArray4Length);
int numArray5Length = numArray5.length;
recursiveSort(numArray5);
for (int k=0;k<numArray5Length;k++) {
System.out.print(numArray5[k]+",");
}
sortedArray[4] = numArray5[0];
System.out.println(" ");
int[] numArray6 = Arrays.copyOfRange(numArray5, 1, numArray5Length);
int numArray6Length = numArray6.length;
recursiveSort(numArray6);
for (int k=0;k<numArray6Length;k++) {
System.out.print(numArray6[k]+",");
}
sortedArray[5] = numArray6[0];
System.out.println(" ");
int[] numArray7 = Arrays.copyOfRange(numArray6, 1, numArray6Length);
int numArray7Length = numArray7.length;
recursiveSort(numArray7);
for (int k=0;k<numArray7Length;k++) {
System.out.print(numArray7[k]+",");
}
sortedArray[6] = numArray7[0];
System.out.println(" ");
int[] numArray8 = Arrays.copyOfRange(numArray7, 1, numArray7Length);
int numArray8Length = numArray8.length;
recursiveSort(numArray8);
for (int k=0;k<numArray8Length;k++) {
System.out.print(numArray8[k]+",");
}
sortedArray[7] = numArray8[0];
System.out.println(" ");
int[] numArray9 = Arrays.copyOfRange(numArray8, 1, numArray8Length);
int numArray9Length = numArray9.length;
recursiveSort(numArray9);
for (int k=0;k<numArray9Length;k++) {
System.out.print(numArray9[k]+",");
}
sortedArray[8] = numArray9[0];
System.out.println(" ");
int[] numArray10 = Arrays.copyOfRange(numArray9, 1, numArray9Length);
int numArray10Length = numArray10.length;
recursiveSort(numArray10);
for (int k=0;k<numArray10Length;k++) {
System.out.print(numArray10[k]+",");
}
sortedArray[9] = numArray10[0];
System.out.println(" ");
sortedArray[2] = numArray3[0];
for (int dasdasd=0;dasdasd<sortedArray.length;dasdasd++) {
System.out.print(sortedArray[dasdasd]+",");
}
}
private static int[] recursiveSort(int numArray[]) {
int numArrayLength = numArray.length;
int maximum = 0;
for (int i=0;i<numArrayLength;i++) {
if (numArray[i] > maximum) {
maximum = numArray[i];
}
}
int indexOfMaximum = -1;
for (int j=0;j<numArrayLength;j++) {
if (numArray[j] == maximum) {
indexOfMaximum = j;
break;
}
}
int temporary = numArray[0];
numArray[0] = numArray[indexOfMaximum];
numArray[indexOfMaximum] = temporary;
return numArray;
}
}
As you can see, the
int[] numArray(n) = Arrays.copyOfRange(numArray(n-1), 1, numArray(n-1)Length);
int numArray(n)Length = numArray(n).length;
recursiveSort(numArray(n));
for (int k=0;k<numArray(n)Length;k++) {
System.out.print(numArray(n)[k]+",");
}
sortedArray[(n-1)] = numArray(n)[0];
System.out.println(" ");
constantly repeats, so there is probably a recursive solution that will work nicely. Maybe I can do something using ArrayLists because their size can change...
Any help will be appreciated!
Thank you!
I suggest a recursive routine that uses an explicit start index for the part that remains to be sorted:
private static void recursiveSort(int[] array, int start) {
if (start < array.length - 1) {
int maximum = array[start];
int maximumIndex = start;
for (int i = start + 1; i < array.length; ++i) {
if (array[i] > maximum) {
maximum = array[i];
maximumIndex = i;
}
}
if (maximumIndex != start) {
int tmp = array[start];
array[start] = array[maximumIndex];
array[maximumIndex] = tmp;
}
recursiveSort(array, start + 1);
}
}
This actually does recursion (unlike your code, which iterates calling a routine named "recursiveSort" but isn't recursive at all). The whole process would be started by calling:
recursiveSort(numArray, 0);
When it returns, the array will be sorted in descending order.
As a general heuristic, when you are struggling with how to make a method recursive, you should consider adding arguments to the method to help with the bookkeeping.
Is this homework or you just need to have the numbers ordered? Java has an easy way to do this if you use ArrayList() instead of array[]. You would just need to call Collections.sort(yourArrayList);
I suggest not trying to make your own sorting algorithm. Many smart people have already done that hard work for you.
The "recursive" sort that you were trying to implement (aka bubble sort which Ted has shown you how to truly make recursive) will work, but it is grossly inefficient. See a comparison of sorting algorithms here.
Below is a demo of the algorithm you were trying to implement compared to a shell sort, one of the fastest sorting algorithms available. The implementation I used was taken from here. Run it and you will see that shell sort is on average 7 to 8 times faster than bubble sort.
public class SortingDemo {
// Methods required for Shell sort
public static void shellSort(Comparable[] a) {
int N = a.length;
int h = 1;
while (h < N/3) h = 3*h + 1;
while (h >= 1) {
for (int i = h; i < N; i++) {
for (int j = i; j >= h && less(a[j], a[j-h]); j -= h) {
exch(a, j, j-h);
}
}
assert isHsorted(a, h);
h /= 3;
}
assert isSorted(a);
}
private static boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
private static void exch(Object[] a, int i, int j) {
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
}
private static boolean isSorted(Comparable[] a) {
for (int i = 1; i < a.length; i++)
if (less(a[i], a[i-1])) return false;
return true;
}
private static boolean isHsorted(Comparable[] a, int h) {
for (int i = h; i < a.length; i++)
if (less(a[i], a[i-h])) return false;
return true;
}
// Method required for "recursive" sort
private static void recursiveSort(Integer[] array, int start) {
if (start < array.length - 1) {
int maximum = array[start];
int maximumIndex = start;
for (int i = start + 1; i < array.length; ++i) {
if (array[i] > maximum) {
maximum = array[i];
maximumIndex = i;
}
}
if (maximumIndex != start) {
int tmp = array[start];
array[start] = array[maximumIndex];
array[maximumIndex] = tmp;
}
recursiveSort(array, start + 1);
}
}
public static void main(String[] args) {
int desiredArraySize = 1000;
int minSizeOfNumberInArray = 0;
int maxSizeOfNumberInArray = 100;
Integer[] array = new Integer[desiredArraySize]; // Used Integer instead of int to utilize Comparable interface
for(int i = 0; i < array.length; i++) {
int randomInt = (int) Math.random() * (maxSizeOfNumberInArray - minSizeOfNumberInArray);
array[i] = randomInt;
}
long startTime = System.nanoTime();
recursiveSort(array, 0);
long endTime = System.nanoTime();
long recursiveSortTime = endTime - startTime;
System.out.println(String.format("\"Recursive\" sort completed in %d ns", recursiveSortTime));
startTime = System.nanoTime();
shellSort(array);
endTime = System.nanoTime();
long shellSortTime = endTime - startTime;
System.out.println(String.format("Shell sort completed in %d ns", shellSortTime));
System.out.println(String.format("\"Recursive\" sort took %f times longer", (float)recursiveSortTime / (float)shellSortTime));
}
}
When learning programming, both writing your own sorting algorithms and your own recursive algorithms are great exercises for solidifying your understanding of how things work. It's time well invested, even if someone's already done it better.
You noticed a pattern that repeats, and associated that with recursion. When evaluating whether recursion is a good fit, I would encourage you to tweak that thought process with the notion of "divide-and-conquer". If you're solving only one element with each recursion, then your stack will grow very deep, which should be avoided. If you can split your problem into roughly even chunks and process each chunk recursively, then recursion will be a good fit. Otherwise, a loop is already an excellent fit for repeating patterns.

Categories