Binary search algorithm does not work properly - Java - java

I want to make my own binary search algorithm to search ArrayList of 1 000 000 elements. I decided to do the search with do-while loop. I am aware I could use while() loop. But when I run it, it takes much time to find the number. I guess something is wrong with setting the value of first and last element of ArrayList. My code is
import java.util.*;
public class BinSearchAlg {
public static void main(String[]args){
int first;
int last;
int median;//middle element of arraylist
Long element;//element with median index
Scanner scan = new Scanner(System.in);
ArrayList<Long>list = new ArrayList();
for(long l=0;l<1000000;l++){
list.add(l);//list is sorted
}
first = 0;
last = list.size();
median = (last-first)/2;
element = list.get(median);
System.out.println("Choose the number: ");
long l = scan.nextLong();
do{
if(element<l){
first = median;
median=(last-first)/2;
element = list.get(median);
}else{ //if(element>l){
last = median;
median = (last-first)/2;
element = list.get(median);
}
}while(element!=l);
}
}
Thanks for you help.

The median calculation is problematic:
median=(last-first)/2;
You should rather do:
median=(last+first)/2;
In the current code you have, when you are searching in the range [10..16], your code will try to compare the goal with the median of list.get(3).
There could be another bug, but for now I'll leave you with this. Hint: try [0, 1], which should expose the bug in the code.

As Ziyao Wei answered, you'll need to fix the median. In addition, you'll probably need a different loop exit condition - right now you've got an infinite loop if l isn't in the list. Also, your if-else needs to be an if-elseif-else - at present if l == element then the loop will actually treat this as element > l and continue looping.

You can directly use Collection class's binary search method present java.util package :-
Collections.binarySearch(myList,key.get(i),new MyTransferObjectClass());
and
public class MyTransferObjectClass implements Comparator<MyTransferObjectClass>{
#Override
public int compare(MyTransferObjectClass o1, MyTransferObjectClass o2) {
//your logic for comparison
}
}
why to add redundant code when you can use available APIs.

Related

Not getting output for simple java program to find greatest prime factor

class LargestPrimeFactor{
public static void main(String args[]){
long p=0L;
long n=600851475143L;
for(long i=2L;i<(n/2);i++){
if((BigInteger.valueOf(i)).isProbablePrime(1)){
if(n%i==0){
p=i;
}
}
}
System.out.println(p);
}
}
It's problem 3 from Project Euler. I compiled it and no errors showed up. But am not getting any output. Whats the reason?
It is working (just add a print method inside the loop to check i for example).
You are currently using the Brute-Force method:
http://www.mathblog.dk/project-euler-problem-3/
If you visit the link the guy tells you an alternative solution for it.
The problem I see without having much knowledge about this is
that the operations you currently do are way too many.
You got the value "600851475143" stored in a long datatype and you try to
reach the half (300425737571,5) using the int i (counter in your for-loop).
https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#MAX_VALUE
This tells us: "A constant holding the maximum value an int can have,
2^(31)-1." = 2147483647
This is just 0,00715 (0,7%) of what you actually need.
So this leads us to an "Overflow".
Think of using the alternative method (first link)
and change the counter of your for-loop to type "long".
int maximum value is 2147483647 which is smaller than 600851475143/2
when index i reaches max value it will wrap around and start with negative number (-2147483648)
you should make your index i a long value
You have an infinite loop on the second for iteration you can only see it when you add logging before the end of the loop. It's not because it's not printing the value, when you stare at the console the iterator is still circling through 6857.
Try running the code with extra logging below.
public static void main(String args[]) {
int p = 0;
long n = 600851475143L;
for (int i = 2; i < (n / 2); i++) {
if ((BigInteger.valueOf(i)).isProbablePrime(1)) {
if (BigInteger.valueOf(n % i).compareTo(BigInteger.valueOf(0)) == 0) {
p = i;
System.out.println("Check == true Iteration"+p);
}
System.err.println("Second iterator"+p);
}
}
System.out.println("Final Value of P: "+p);
}
EDITED
The int data type can store values upto 2,147,483,647. To store numbers beyond that, use long.
long n = 600851475143L;
Not 600851475143 L, as that one space before L causes the system to not register it.
Also, int i in the for loop should be long i.

ArrayLinkedList Insertion Sort

I have to do an Array List for an insertion sort and my teacher sent this back to me and gave me an F, but says I can make it up before Friday.
I do not understand why this isn't an A.L insertion sort.
Can someone help me fix this so it hits his criteria?
Thanks.
HE SAID:
After checking your first insertion sort you all did it incorrectly. I specifically said to shift the numbers and move the number into its proper place and NOT SWAP THE NUMBER INTO PLACE. In the assignment in MySA I said if you do this you will get a 0 for the assignment.
import java.util.ArrayList;
public class AListINSSORT {
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
private static void insertionSort() {
ArrayList<Integer> swap = new ArrayList<Integer>();
swap.add(1);
swap.add(2);
swap.add(3);
swap.add(4);
swap.add(5);
int prior = 0;
int latter = 0;
for (int i = 2; i <= latter; i++)
{
for (int k = i; k > prior && (swap.get(k - 1) < swap.get(k - 2)); k--)
{
Integer temp = swap.get(k - 2);
swap.set(k - 2, swap.get(k - 1));
swap.set(k - 1, temp);
}
}
System.out.println(swap);
}
}
First of all, it seems your teacher asked you to use a LinkedList instead of an ArrayList. There is quite a difference between them.
Secondly, and maybe more to the point. In your inner loop you are saving a temp variable and swapping the elements at position k - 2 and k - 1 with each other. From the commentary this is not what your teacher intended. Since he wants you to solve the problem with element insertion, I recommend you look at the following method definition of LinkedList.add(int i, E e): https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#add(int,%20E).
This should point you in the right direction.
As far as I see, your code does nothing at all.
The condition of the outer for loop
for (int i = 2; i <= latter; i++)
is not fulfilled.
As you start with i = 2 and as latter = 0, it never holds i <= latter.
Thus, you never run through the outer for loop and finally just give back the input values.
If you add the input values to swap in a different order (not already ordered), you will see that your code does not re-order them.
There's a lot of stuff wrong here.
Firstly, your method:
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
takes an ArrayList and completely ignores it. This should presumably be the List which requires sorting.
Then in insertionSort() you create a new ArrayList, insert some numbers already in order, and then attempt something which looks nothing like insertion sort, but slightly more like bubble sort.
So, when you call insertionSort(List) it won't actually do anything to the list at all, all the work in insertionSort() happens to a completely different List!
Since on SO we don't generally do people's homework for them, I suggest looking at the nice little animated diagram on this page
What you should have then is something like:
public void insertionSort(LinkedList<Integer> numbers) {
//do stuff with numbers, using get() and add()
}

Store element into another list

Need little help. Working on my homework and I have to sort list using ArrayDeque. I can check first and last element.
I have a list, for example
int[] list = {6, 8, 7};
First element - 6 - will go into empty array, no problem with that.
Second element - 8 - will go at behind the 6, so we will have[6,8], but then comes 7. Since I can't put it in front of the 6, and I cant put it behind 8. So I have to store 7 into some other list that I can later return. How do I do that? Any hint is welcome.
Thanks.
(And sorry if this is something that has been asked before, but couldn't find the solution)
Let me clarify your constraints first. You can only:
get the value of the first element
remove the first element
prepend before the first element
get the value of the last element
remove the last element
append after the last element
An algorithm to add values from an array into a structure described above, using a stack:
for each value in the array
if the value is smaller than the first in the deck -> prepend
else if the value is greater than the last in the deck -> append
else if the value is closer to the first:
remove the first element and push on the stack repeatedly, as long as the first element is smaller
prepend the value to the deck
while the stack is not empty, pop from it and prepend to the deck
else:
remove the last element and push on the stack repeatedly, as long as the last element is greater
append the value to the deck
while the stack is not empty, pop from it and append to the deck
If you are not allowed to use a stack, but you are allowed to use recursion, then you can use the call stack to the same end
Something you could do is to store the int value at index x into a local variable and then traverse through the array seeing if there is a value lower than the currently stored value and if so that becomes the new lower value. When it finishes going through the array you can input that into the new array.
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
ArrayDeque<Integer> container = new ArrayDeque<>();
ArrayDeque<Integer> container2 = new ArrayDeque<>();
System.out.println("Please enter 10 number with space");
for(int i=0;i<10;i++){
container.add(sc.nextInt());
}
while (!isSorted(container.isEmpty()?container2:container)) {
while (!container.isEmpty()) {
int a = container.poll();
if(container.peek()!=null && a<container.peek()){
if(container2.peek()!=null && container2.peek()>container.peek()){
container2.addFirst(a);
}else{
container2.addLast(a);
}
}else if(container.peek()!=null){
if(container2.peek()!=null && container2.peek()>container.peek()){
container2.addFirst(container.poll());
}else{
container2.addLast(container.poll());
}
container.addFirst(a);
}else{
container2.addLast(a);
}
}
while (!container2.isEmpty()) {
int a = container2.poll();
if(container2.peek()!=null && a<container2.peek()){
if(container.peek()!=null && container.peek()>container2.peek()){
container.addFirst(a);
}else{
container.addLast(a);
}
}else if(container2.peek()!=null){
if(container.peek()!=null && container.peek()>container2.peek()){
container.addFirst(container2.poll());
}else{
container.addLast(container2.poll());
}
container2.addFirst(a);
}else{
container.addLast(a);
}
}
}
while (!container.isEmpty()) {
System.out.println(container.poll());
}
System.out.println("---------------------------");
while (!container2.isEmpty()) {
System.out.println(container2.poll());
}
}
static boolean isSorted(ArrayDeque<Integer> con){
boolean answer = true;
for(int i=0;i<con.size()-1;i++){
int a = con.poll();
con.addLast(a);
if(con.peek()!=null && a>con.peek()) answer= false;
}
con.addLast(con.poll());
return answer;
}

How to divide a set of numbers into two sets such that the difference of their sum is minimum

How to write a Java Program to divide a set of numbers into two sets such that the difference of the sum of their individual numbers, is minimum.
For example, I have an array containing integers- [5,4,8,2]. I can divide it into two arrays- [8,2] and [5,4]. Assuming that the given set of numbers, can have a unique solution like in above example, how to write a Java program to achieve the solution. It would be fine even if I am able to find out that minimum possible difference.
Let's say my method receives an array as parameter. That method has to first divide the array received into two arrays, and then add the integers contained in them. Thereafter, it has to return the difference between them, such that the difference is minimum possible.
P.S.- I have had a look around here, but couldn't find any specific solution to this. Most probable solution seemed to be given here- divide an array into two sets with minimal difference . But I couldn't gather from that thread how can I write a Java program to get a definite solution to the problem.
EDIT:
After looking at the comment of #Alexandru Severin, I tried a java program. It works for one set of numbers [1,3,5,9], but doesn't work for another set [4,3,5,9, 11]. Below is the program. Please suggest changes:-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FindMinimumDifference {
public static void main(String[] args) {
int[] arr= new int[]{4,3,5,9, 11};
FindMinimumDifference obj= new FindMinimumDifference();
obj.returnMinDiff(arr);
}
private int returnMinDiff(int[] array){
int diff=-1;
Arrays.sort(array);
List<Integer> list1= new ArrayList<>();
List<Integer> list2= new ArrayList<>();
int sumOfList1=0;
int sumOfList2=0;
for(int a:array){
for(Integer i:list1){
sumOfList1+=i;
}
for(Integer i:list2){
sumOfList2+=i;
}
if(sumOfList1<=sumOfList2){
list1.add(a);
}else{
list2.add(a);
}
}
List<Integer> list3=new ArrayList<>(list1);
List<Integer> list4= new ArrayList<>(list2);
Map<Integer, List<Integer>> mapOfProbables= new HashMap<Integer, List<Integer>>();
int probableValueCount=0;
for(int i=0; i<list1.size();i++){
for(int j=0; j<list2.size();j++){
if(abs(list1.get(i)-list2.get(j))<
abs(getSumOfEntries(list1)-getSumOfEntries(list2))){
List<Integer> list= new ArrayList<>();
list.add(list1.get(i));
list.add(list2.get(j));
mapOfProbables.put(probableValueCount++, list);
}
}
}
int minimumDiff=abs(getSumOfEntries(list1)-getSumOfEntries(list2));
List resultList= new ArrayList<>();
for(List probableList:mapOfProbables.values()){
list3.remove(probableList.get(0));
list4.remove(probableList.get(1));
list3.add((Integer)probableList.get(1));
list4.add((Integer)probableList.get(0));
if(minimumDiff>abs(getSumOfEntries(list3)-getSumOfEntries(list4))){
// valid exchange
minimumDiff=abs(getSumOfEntries(list3)-getSumOfEntries(list4));
resultList=probableList;
}
}
System.out.println(minimumDiff);
if(resultList.size()>0){
list1.remove(resultList.get(0));
list2.remove(resultList.get(1));
list1.add((Integer)resultList.get(1));
list2.add((Integer)resultList.get(0));
}
System.out.println(list1+""+list2); // the two resulting set of
// numbers with modified data giving expected result
return minimumDiff;
}
private static int getSumOfEntries(List<Integer> list){
int sum=0;
for(Integer i:list){
sum+=i;
}
return sum;
}
private static int abs(int i){
if(i<=0)
i=-i;
return i;
}
}
First of all, sorting the array then putting first member in group and second in another wound never work, and here is why:
Given the input[1,2,3,100].
The result would be: [1,3] and [2,100], clearly wrong.
The correct answer should be: [1,2,3] and [100]
You can find many optimization algorithms on google for this problem, but since I assume you're a beginner, I'll try to give you a simple algorithm that you can implement:
sort the array
iterate from highest to lowest value
for each iteration, calculate the sum of each group, then add the element to the group with minimum sum
At the end of the loop you should have two fairly balanced arrays. Example:
Array: [1,5,5,6,7,10,20]
i1: `[20] []`
i2: `[20] [10]`
i3: `[20] [10,7]`
i4: `[20] [20,7,6]`
i5: `[20,5] [10,7,6]`
i6: `[20,5] [10,7,6,5]`
i7: `[20,5,1] [10,7,6,5]`
Where the sums are 26 and 28. As you can see we can further optimize the solution, if we exchange 5 and 6 resulting in [20,6,1] and [20,7,5,5] the sums are equal.
For this step you can:
find all groups of elements (x,y) where x is in group1, y is in group2, and |x-y| < |sum(group1) - sum(group2)|
loop all groups and try exchanging x with y until you get a minimum difference
after each exchange check if the minimum value in the group with the highest sum is higher then the difference of the groups, if so, transfer it to the other group
This algorithm will always return the best solution, and is a whole lot better then a greedy approach. However it is not optimal in terms of complexity, speed and memory. If one needs it for very large arrays and the resources are limited, the most optimal algorithm may differ depending on the speed/memory ration and the accepted error percentage.
This is a variation on the Partition Problem https://en.wikipedia.org/wiki/Partition_problem
If you want the optimal solution you have to test every possible combination of output sets. That may be feasible for small sets but is infeasible for large inputs.
One good approximation is the greedy algorithm I present below.
This heuristic works well in practice when the numbers in the set are
of about the same size as its cardinality or less, but it is not
guaranteed to produce the best possible partition.
First you need to put your input in a sortable collection such as a List.
1) Sort the input collection.
2) Create 2 result sets.
3) Iterate over the sorted input. If the index is even put the item in result1 else put the item in result2.
List<Integer> input = new ArrayList<Integer>();
Collections.sort(input);
Set<Integer> result1 = new HashSet<Integer>();
Set<Integer> result2 = new HashSet<Integer>();
for (int i = 0; i < input.size(); i++) {
if (i % 2 == 0) {// if i is even
result1.add(input.get(i));
} else {
result2.add(input.get(i));
}
}
I seem to have got the perfect solution for this. Below Java program works perfectly. Only assumption is that, the given problem has unique solution (just one solution). This assumption implies- only non-zero number. I am putting the program below. I request everyone to tell if the program could fail for certain scenario, or if it could be improved/optimized in some way. Credits to Mr Alexandru Severin's algorithm posted as one of the answers in this thread.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FindMinimumDifference {
static List<Integer> list1= new ArrayList<>();
static List<Integer> list2= new ArrayList<>();
public static void main(String[] args) {
int[] arr= new int[]{3,-2,9,7};
// tested for these sample data:- [1,5,9,3] ; [4,3,5,9,11] ;
//[7,5,11,2,13,15,14] ; [3,2,1,7,9,11,13] ;
//[3,1,0,5,6,9] ; [6,8,10,2,4,0] ; [3,1,5,7,0] ; [4,-1,5,-3,7] ; [3,-2,9,7]
System.out.println("the minimum possible difference is: "+returnMinDiff(arr));
System.out.println("the two resulting set of nos. are: "+list1+" and "+list2);
}
private static int returnMinDiff(int[] array){
int diff=-1;
Arrays.sort(array);
for(int a:array){
int sumOfList1=0;
int sumOfList2=0;
for(Integer i:list1){
sumOfList1+=i;
}
for(Integer i:list2){
sumOfList2+=i;
}
if(sumOfList1<=sumOfList2){
list1.add(a);
}else{
list2.add(a);
}
}
List<Integer> list3=new ArrayList<>(list1);
List<Integer> list4= new ArrayList<>(list2);
if(list3.size()!=list4.size()){ // both list should contain equal no. of entries.
//If not, add 0 to the list having lesser no. of entries
if(list3.size()<list4.size()){
list3.add(0);
}else{
list4.add(0);
}
}
Map<Integer, List<Integer>> mapOfProbables= new HashMap<Integer, List<Integer>>();
int probableValueCount=0;
for(int i=0; i<list3.size();i++){
for(int j=0; j<list4.size();j++){
if(abs(list3.get(i)-list4.get(j))
<abs(getSumOfEntries(list3)-getSumOfEntries(list4))){
List<Integer> list= new ArrayList<>();
list.add(list3.get(i));
list.add(list4.get(j));
mapOfProbables.put(probableValueCount++, list);
}
}
}
int minimumDiff=abs(getSumOfEntries(list1)-getSumOfEntries(list2));
List resultList= new ArrayList<>();
for(List probableList:mapOfProbables.values()){
list3=new ArrayList<>(list1);
list4= new ArrayList<>(list2);
list3.remove(probableList.get(0));
list4.remove(probableList.get(1));
list3.add((Integer)probableList.get(1));
list4.add((Integer)probableList.get(0));
if(minimumDiff>abs(getSumOfEntries(list3)-getSumOfEntries(list4))){ // valid exchange
minimumDiff=abs(getSumOfEntries(list3)-getSumOfEntries(list4));
resultList=probableList;
}
}
if(resultList.size()>0){ // forming the two set of nos. whose difference of sum comes out to be minimum
list1.remove(resultList.get(0));
list2.remove(resultList.get(1));
if(!resultList.get(1).equals(0) ) // (resultList.get(1).equals(0) && !list1.contains(0))
list1.add((Integer)resultList.get(1));
if(!resultList.get(0).equals(0) || (resultList.get(0).equals(0) && list2.contains(0)))
list2.add((Integer)resultList.get(0));
}
return minimumDiff; // returning the minimum possible difference
}
private static int getSumOfEntries(List<Integer> list){
int sum=0;
for(Integer i:list){
sum+=i;
}
return sum;
}
private static int abs(int i){
if(i<=0)
i=-i;
return i;
}
}
For this question, assume that we can divide the array into two subarrays such that their sum is equal. (Even thought they are not equal , it will work)
So if the sum of elements in array is S. Your goal is to find a subset with sum S/2. You can write a recursive function for this.
int difference = Integer.MAX_VALUE;
public void recursiveSum(int[] array, int presentSum, int index,Set<Integer> presentSet){
if(index == array.length){
if(Math.abs(presentSum - (S/2)) < difference)){
difference = Math.abs(presentSum - (S/2);
// presentSet is your answer
return;
}
}
recursiveSum(array,presentSum,index+1,presentSet); // don't consider the present element in the final solution
presentSet.add(array[index]);
recursiveSum(array,presentSum + array[index],index+1,presentSet); //consider the present element in the final solution
}
You can also write an equivalent O(N^2) dynamic programming code for this.
I was just demonstrating the idea.
So when you find this set with sum S/2, automatically you have divided the array in to two parts with same sum (S/2 here).
It seems that you are more interested in the algorithm than the code. So, here is my psuedocode:-
int A[];//This contains your elements in sorted (descending) order
int a1[],a2[];//The two sub-arrays
int sum1=0,sum2=0;//These store the sum of the elements of the 2 subarrays respectively
for(i=0;i<A.length;i++)
{
//Calculate the absolute difference of the sums for each element and then add accordingly and thereafter update the sum
if(abs(sum1+A[i]-sum2)<=abs(sum2+A[i]-sum1))
{a1.add(A[i]);
sum1+=A[i];}
else
{a2.add(A[i]);
sum2+=A[i];}
}
This will work for all integers, positive or negative.

Comparing elements in a list and swapping them. Java

Hi I have been working on a solution for days, and I've been trying to figure it out on my own but I just can't.
I have an ArrayList and I want to swap the elements in it. But I want to compare the list in halves. So say if the list had 8 elements in it, I would want to compare the first element in the first half of the list with the first element in the second half of the list.
So list[0] with list[4] and if 4 is bigger than 0, i want to swap them, then i want to increment 0 and by 1, and half the list by one, until i = 4.
I have to run it from the command line.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Collections;
public class TennisTournament {
public static void main (String [] args) {
Scanner input = new Scanner(System.in);
ArrayList <Integer> nums = new ArrayList<Integer>();
while (input.hasNextInt()) {
nums.add(input.nextInt());
}
tournament(nums); }
public static void tournament(ArrayList <Integer> list) {
int midPoint = list.size()/2; // returns the index number of half of the lists size
for (int i = 0; i < midPoint; i++) { // while is bigger than mid point, increment by one
if (list.get(i) < list.get(midPoint)) {
Collections.swap(list, i, midPoint);
System.out.print(list);
}
}
System.out.println(list); }
}
This is what I have so far, but when I run it from the command line, it just returns an ordinary list, and I'm completely stumped. I would much rather use a loop than the collections method as it is not a style of programming i am particular familiar with.
Look at midPoint - it never changes inside the loop. You're continually exchanging the i-th element (provided that the "if" condition is true) with the midPoint. No element after midPoint is ever touched.

Categories