Algorithm sometimes works - java

I am currently trying to set up a sorting algorithm for an array that scans for the highest and lowest number and places them into a new array, two at a time. I've noticed that it appears to work only in certain conditions. For example, I can input it as {5, 3, 10, 7} or {3, 5, 10, 7}, but {7, 3, 5, 10} produces an IndexOutOfBoundsException: index 1, size: 1;
Here's the code:
import java.util.Scanner; // program uses class Scanner
import java.util.ArrayList; //helps with arrays
public class ArrayAlg
{
// main method begins execution of Java application
public static void main( String[] args )
{
// create a Scanner to obtain input from the command window
Scanner input = new Scanner( System.in );
boolean AS = false; //array sorted.
int hi = 0; //high number
int low = 100; //set to 100 for logic reasons.
int oldhi = 0;
int oldlow = 0;
int NI = 0;
int addA = 0;
int p = 0; //places, moves right after one scan to place the next int
int n = 1; //number of times, moves left after one to place the next int
String cont = "n";
ArrayList<Integer> IParray = new ArrayList<Integer>(); //input array
ArrayList<Integer> Sarray = new ArrayList<Integer>(); //sorted array
while (cont.equals("n"))
{
System.out.print("Please enter a number for the array: ");
addA = input.nextInt();
IParray.add(addA);
NI++;
System.out.print("\n is that all? (y/n): ");
cont = input.next();
}
for (int c = 0; c < NI; c++) //adds 0 so sorting will be easier
Sarray.add(0); //matches the inputted array
System.out.print("The inputted array: ");
System.out.print(IParray);
System.out.println("");
while (AS == false){
hi = 0;
low = 100;
for (int i = 0; i < IParray.size(); i++)
{
if (IParray.get(i) < low)
low = IParray.get(i);
if (IParray.get(i) > hi)
{
//if (IParray.get(i) > hi) currently commented out, doesn't effect the logic by the looks of it.
hi = IParray.get(i);
}
}//end for
Sarray.set(p, low); //sets the number in the left most position then moves to the right
Sarray.set(Sarray.size() - n, hi); //sets the number to the rightmost position and moves left
p++; //increase place count to the right
n++; //increases the place count to the left
oldhi = IParray.indexOf(hi); //oldhi becomes the index of the recent highest number.
oldlow = IParray.indexOf(low); //oldlow becomes the index of the recent lowest number
IParray.remove(oldhi); //removes the highest number at the index
IParray.remove(oldlow); //removes the lowest number at the index, exceptions occurs right here.
System.out.print("The inputted array: ");//mostly here to see what the inputted array looks like after one iteration
System.out.print(IParray);
System.out.println("");
System.out.print("The sorted array: ");
System.out.print(Sarray);
System.out.println("");
if (IParray.isEmpty() == true) //checks to see if the input array is empty
AS = true;
else
AS = false;
}//end while
} // end method main
} // end class ArrayAlg
Can anyone give me any hints on why this might be occurring? I've been trying this out for the past hour or so. Tried Googling and searching this site for answers but no luck

You are getting the index out of bounds because it is trying to remove an index that does not exist. When it is removing indexes it removes lowest first causing the whole array index to shift downwards. It does not keep it's original index.
[0] = 7
[1] = 3
[2] = 5
[3] = 10
When removing the high number, 10, it becomes:
[0] = 7
[1] = 3
[2] = 5
When removing the low number it becomes:
[0] = 7
[1] = 5
The next loop you remove 7 first leaving only 5 at index 0 but your code is calling to remove index 1 giving you an out of bounds exception.
To fix this, let it dynamically get the index when the remove method is called.
IParray.remove(IParray.indexOf(hi)); //removes the highest number at the index
IParray.remove(IParray.indexOf(low)); //removes the lowest number at the index
You should have been able to quickly find this error by running your code in debugging mode and then stepping through the code that is throwing the exception (Line 73).

You might not be able to find a higher value and lower value comparison to previous ones. For example, input array was {7, 3, 5, 10}, now hi is 10 and low is 7, they were removed from IParray.
for (int i = 0; i < IParray.size(); i++)
{
if (IParray.get(i) < low)
low = IParray.get(i); // low becomes 3
if (IParray.get(i) > hi) //!!! never able to find a higher value than 10 !!!
{
//if (IParray.get(i) > hi) currently commented out, doesn't effect the logic by the looks of it.
hi = IParray.get(i);
}
}
In that case, low and high points to previous values, which was removed from the array since last iteration, so oldhi and oldlow would be -1, and you got the exception for IParray.remove(-1)
oldhi = IParray.indexOf(hi); // 10 is not in the array anymore, you got -1
oldlow = IParray.indexOf(low);
IParray.remove(oldhi); // you got exception here as you remove(-1)
IParray.remove(oldlow);

Related

How do you determine the legal index range for an array?

I'm learning Java and walking myself through the exercises hosted online at Towson University and I'm stumped on this exercise.
Here is the code:
import java.util.Scanner;
public class Overflow2 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int[]vals = new int[10];
System.out.println("how many values should be stored in the array? ");
int count = scan.nextInt();
for (int i = 0; i < count; i++) {
vals[i] = count - i ;
}
System.out.println("Which value do you wish to retrieve? ");
int which = scan.nextInt();
System.out.println("Your value is " + vals[which]);
}
}
For the line
for (int i = 0; i < count; i++) {
vals[i] = count - i ;
}
How does one determine the legal index range? I assumed that, given
int[]vals = new int[10];
the index range would be the length of the array - 1, so 9, but this doesn't seem to be correct. The format for the solution is
number -- equality operator -- i -- equality operator -- number
Thanks for any help.
I assumed that ... the index range would be the length of the array - 1, so 9, but this doesn't seem to be correct.
It is correct. The legal indices are 0 through 9, inclusive. The program will only work if the user enters 10 or less. If they enter something bigger than 10 it will crash with an ArrayIndexOutOfBoundsException.
You're only wrong if one is being pedantic about terminology: to be precise, the maximum index is 9. A range would have two endpoints. You could describe the range variously as any of these:
0-9
[0, 10)
[0, 9]
0 ≤ i ≤ 9
0 ≤ i < 10

Testing elements in an array

Hello I have searched for a simple way to check ,
if any number of elements up to 6 in the array add up to seven. I have yet to find one my array is this,
private int[] diceRoll = new int[6];
The question is a bit vague, however, here's my attempt at an answer:
If what you're trying to do is take two indices x and y in diceRoll[] and see if they add up to 7, the simplest thing to do is
if(diceRoll[x] + diceRoll[y] ==7){
return true;}
If you're trying to see if ANY item with any other item adds up to 7, use a double for-loop (these are weird, but very helpful)
for(int i = 0; i < diceRoll.length; i++){
for(int j = 0; i < diceRoll.length; i++){
if(diceRoll[i] + diceRoll[j] != 7){
return false;
}
}
}
Hope this helps!
-katie
It sounds like what you need to do is take every subset of the diceRoll array and see which ones add up to 7. This is how it can be done.
Assuming you know that 1 & 1 = 1, and that 1 & 0 = 0, imagine each element of the array having a number in 0 0 0 0 0, if the element is selected, say element 5, the subset representation in binary form would be 0 0 0 0 1. If element 2 and 3 are selected, the subset representation would be 0 0 1 1 0. If you take a binary one, keep track of its index, and move it from right to left in the array computing index&1 each time, you can get which indexes of the array are in the current subset (if the index&1 computation results in a 1 for that index). Translating this to a smaller array called currSubset, you can sum it up and check if it is equal to 7.
The termination of the outer for loop comes from the maximum value of a 5 digit binary number, which is 11111 = 31 = 2^5-1, hence the use of the less than sign.
int sum = 0;
int index = 0;
ArrayList<ArrayList<Integer>> subsetsThatAddTo7 = new ArrayList<ArrayList<Integer>>();
for(int subsetRep = 0b00001; i < Math.pow(2,5); i++){
ArrayList<Integer> currSubset = new ArrayList<Integer>
for(index = 0; index < 5; index++){
if(subsetRep & (1 << index))
currSubset.add(diceRoll[5-index]);
}
int sum = 0;
for(int num : currSubset)
sum += num;
if(sum == 7)
subsetsThatAddTo7.add(currSubset);
}

How to change position of the elements in an array

I'm writing a program, that take 10 Integers from a keyboard and list them in an array indexed from 0-9, and reports the position of the lowest number in the array. If the lowest number has any other position than 0, then the program is supposed to switch the position of the lowest number input with the number in the first position in the array:
import java.util.Scanner;
public class q35 {
public static void main(String args[]) {
Scanner tastatur = new Scanner(System.in);
int[] helTall = new int[10];
int input;
int lowest = Integer.MAX_VALUE;
for(int i=0;i<helTall.length;i++) {
System.out.println("Integers? ");
input = tastatur.nextInt();
if (input < lowest) {
lowest = input;
}
helTall[i] = input;
}
for (int i = 0; i < helTall.length; i++) {
helTall[0] = lowest;
System.out.println(helTall[i]);
}
System.out.println("Lowest number is " + lowest);
}
}
The only problem is that instead of changing position with the lowest number with the number at helTall[0], it just completely replaces the first number in the sequence helTall[0] with the lowest Integer, that way if my input is 4 5 63 23 6 -4 7 33 23 99, then the output becomes -4 5 63 23 6 -4 7 33 23 99 (as you can see the first input number is completely erased), but it should have been -4 5 63 23 6 4 7 33 23 99 any tips/advice/solutions? Thanks in advance.
You should keep track of the index of the lowest number (each time you write lowest = input; you should add lowestIndex=i;.
Then helTall[lowestIndex] will be the lowest number.
So you swap helTall[lowestIndex] with helTall[0] instead of just overwriting the value of helTall[0].
I thought it was enough to describe the solution in words, but I guess it wasn't...
int lowest = Integer.MAX_VALUE;
int lowestIndex = 0;
for(int i=0;i<helTall.length;i++){
System.out.println("Integers? ");
input = tastatur.nextInt();
if (input < lowest){
lowest = input;
lowestIndex = i;
}
helTall[i]=input;
}
// swap the numbers
if (lowestIndex > 0) {
int temp = lowest;
helTall[lowestIndex] = helTall[0];
helTall[0] = temp;
}
// display output
for (int i = 0; i < helTall.length; i ++) {
System.out.println(helTall[i]);
}
This part is wrong:
for (int i = 0; i < helTall.length; i ++) {
helTall[0]=lowest;
System.out.println(helTall[i]);
}
First, you do not need to repeatedly (10 times) put lowest into helTall[0]. Let's move that outside first so it's only done once:
helTall[0]=lowest;
for (int i = 0; i < helTall.length; i ++) {
System.out.println(helTall[i]);
}
Next, the line we put outside the loop overwrites the helTall[0] without regard for what is already in there. We need to temporarily save that number in there elsewhere, then overwrite the spot, so that we can use it to overwrite the spot where the lowest number was:
int numberAtLocationZero = helTall[0];
helTall[0]=lowest;
// Now, on this line we need to write helTall[lowestNumberIndex] = numberAtLocationZero;
for (int i = 0; i < helTall.length; i ++) {
System.out.println(helTall[i]);
}
In the above code I wrote a comment. It relies on you either knowing where in the array the lowest number was, or to find it again. If you add a new variable to your code that takes in values called lowestNumberIndex and update that each time you detect a new lowest number, then you're pretty much done if you uncomment my comment.
You need a separate variable to store what is in the bottom of the array before you overwrite it with your new lowest input number.
helTall[0]=lowest;
should be proceeded by
int placeholder = helTall[0]
and followed by
hellTall[i] = placeholder;
This way, you'll end up swapping the two array elements, the first swapped with the lowest. Is this what you're trying to accomplish? This leaves most of the array unsorted.

Finding repeats in a 2D array

I have made a program that outputs the number of repeats in a 2D array. The problem is that it outputs the same number twice.
For example: I input the numbers in the 2D array through Scanner: 10 10 9 28 29 9 1 28.
The output I get is:
Number 10 repeats 2 times.
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 9 repeats 2 times.
Number 1 repeats 1 times.
Number 28 repeats 2 times.
I want it so it skips the number if it has already found the number of repeats for it. The output should be:
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 1 repeats 1 times.
Here is my code:
import java.util.Scanner;
public class Repeat
{
static Scanner leopard = new Scanner(System.in);
public static void main(String [] args)
{
final int ROW = 10; //Row size
final int COL = 10; //Column size
int [][] num = new int[ROW][COL];
int size;
//Get input
size = getData(num);
//Find repeat
findRepeats(num, size);
}
public static int getData(int [][] num)
{
int input = 0, actualSize = 0; //Hold input and actualSize of array
System.out.print("Enter positive integers (-999 to stop): ");
//Ask for input
for(int i = 0; i < num.length && input != -999; i++)
{
for(int j = 0; j < num[i].length && input != -999; j++)
{
input = leopard.nextInt();
//Check if end
if(input != -999)
{
num[i][j] = input;
actualSize++;
}
}
}
System.out.println();
return actualSize;
}
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 0, row = 0, col = 0;
for(int x = 0; x < size; x++)
{
//Set to number
findNum = num[row][col];
//Loop through whole array to find repeats
for(int i = 0; i < num.length; i++)
{
for(int j = 0; j < num[i].length; j++)
{
if(num[i][j] == findNum)
total++;
}
}
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 0;
}
}
}
I know why it is doing it, but I cannot figure out how to check if the number has already been checked for it to skip that number and go to the next number. I cannot use any classes or code that is not used in the code.
Since you cannot use anything other than this, lets say, basic elements of Java consider this:
Make another temporary 2D array with two columns (or just two separate arrays, personally I prefer this one). On the start of the algorithm the new arrays are empty.
When you take a number (any number) from the source 2D structure, first check if it is present in the first temporary array. If it is, just increment the value (count) in the second temporary array for one (+1). If it is not present in the first tmp array, add it to it and increase the count (+1) in the second at the same index as the newly added number in the first (which should be the last item of the array, basically).
This way you are building pairs of numbers in two arrays. The first array holds all your distinct values found in the 2D array, and the second one the number of appearances of the respective number from the first.
At the and of the algorithm just iterate the both arrays in parallel and you should have your school task finished. I could (and anyone) code this out but we are not really doing you a favor since this is a very typical school assignment.
It's counting the number two times, first time it appears in the code and second time when it appears in the code.
To avoid that keep a system to check if you have already checked for that number. I see you use check int array but you haven't used it anywhere in the code.
Do this,
Put the number in the check list if you have already found the count of it.
int count = 0;
check[count] = findNum;
count++;
Note: You can prefill you array with negative numbers at first in order to avoid for having numbers that user already gave you in input.
Next time in your for loop skip checking that number which you have already found a count for
for(int x = 0; x < size; x++) {
findNum = num[row][col];
if(check.containsNumber(findNUm)) { //sorry there is no such thing as contains for array, write another function here which checks if a number exists in the array
//skip the your code till the end of the first for loop, or in other words then don't run the code inside the for loop at all.
}
}
Frankly speaking I think you have just started to learn coding. Good luck! with that but this code can be improved a lot better. A piece of advice never create a situation where you have to use 3 nested for loops.
I hope that you understood my solution and you know how to do it.
All answers gives you some insight about the problem. I try to stick to your code, and add a little trick of swap. With this code you don't need to check if the number is already outputted or not. I appreciate your comments, structured approach of coding, and ask a question as clear as possible.
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 1, row = 0, col = 0;
int [] check = new int[size];
while(row < num.length && col < num[0].length)
{
//Set to number
findNum = num[row][col];
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Loop through whole array to find repeats
for(int i = row; i < num.length; i++)
{
for(int j = col; j < num[i].length; j++)
{
if(num[i][j] == findNum) {
total++;
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
if(row < num.length - 1 && col < num[0].length -1)
num[i][j] = num[row][col];
}
}
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 1;
}
}
you can use a HashMap to store the result. It Goes like this:
// Create a hash map
HashMap arrayRepeat = new HashMap();
// Put elements to the map
arrayRepeat.put(Number, Repeated);

Issue with randomize method

I have a method that is not working properly.
The method is supposed to sort a set of numbers from 1 to 20 randomly (each number
must appear just once).
My issue here is that when I run the program, some numbers are repeated several times.
The code is the following:
public static int randomize(int index) {
//This array will hold the 20 numbers.
int[] randomIndex = new int[20];
Random ranNum = new Random();
for (int x = 0; x<20; x++) {
int temp;
//The number is generated randomly and saved in temp.
temp = ranNum.nextInt(20);
//This loop skips the first index.
if (x != 0){
/*Here, the loop is supposed to compare a generated number with
the previous one*/
for (int y = 1; y<=x; y++) {
while(temp == randomIndex[x-y] ) {
/*If the while loop finds that temp variable matches any previous
number it will generate another random number for it until it finds
no matches.*/
temp = ranNum.nextInt(20);
}
}
}
/*Once no match has been found for temp, the number is assigned to an index,
and the loop is executed with a x variable increment.
randomIndex[x] = temp;
}
//Finally the array with the set of random numbers is sent to the main function.
return randomIndex[index];
}
And I got the following output:
19, 19, 5, 16, 6, 2, 18, 1, 15, 1, 5, 19, 11, 4, 18, 0, 5, 18, 10.
So now I have no idea what to do. :C
When you use Random.nextInt(), there's no guarantee that the numbers generated are unique.
You should generate numbers from 1 to 20 first, then shuffle the numbers. Now the question is changed to "How to shuffle the numbers randomly?"
Perhaps you can refer the implementation of JDK Collections.shuffle().
The algorithm for shuffling the numbers are simple:
Pick first element in the array and swap it with a number at random position.
Repeat step 1 until the last element.
You can avoid it by using something like this:
final Random random = new Random();
final HashSet<Integer> integers = new HashSet<>();
while(integers.size() < 20) {
integers.add(random.nextInt(20));
}
System.out.println(integers);
It looks like you're trying to generate your random numbers by rejection -- that is, by comparing each random number with all previously accepted numbers, and re-generating new ones until you find one that is is different from all of them.
As others have mentioned, it would be far more efficient to generate the numbers from 1 to 20, and shuffle them with a random permutation. However, if implemented correctly, your approach should work... eventually.
A random shuffle implementation might look something like this:
for(int i=0; i<20; i++) { // index goes from 0..19
randomIndex[i] = i + 1; // value goes from 1..20
}
for(int i=0; i<20; i++) {
int j = i + ranNum.nextInt(20 - i); // choose random j from i <= j < 20
int temp = randomIndex[i]; // swap elements i and j
randomIndex[i] = randimIndex[j];
randomIndex[j] = temp;
}
The are two reasons why your posted code generates duplicates. First, when you reject a candidate random number and re-generate a new one, you need to compare it against all existing numbers, restarting you inner (y) loop from the beginning. Your existing code doesn't do that.
Second, I believe that the new Random() constructor generates a different seed each time it is called. If so, your randomize() function is generating a completely different random list each time, and returning the selected index from it. In any case, it makes more sense to return the entire array, instead.
I edited your function for generate array from 1 to 20:
public static int[] randomize() {
int[] randomIndex = new int[20];
Random ranNum = new Random();
boolean isAlreadyIn;
boolean isZero;
int x = 0;
while (x < 20) {
isAlreadyIn = false;
isZero = false;
int temp;
temp = ranNum.nextInt(21);
for(int i = 0; i < randomIndex.length; i++){
if(temp == 0)
isZero = true;
if(temp == randomIndex[i])
isAlreadyIn = true;
}
if (!isZero && !isAlreadyIn){
randomIndex[x] = temp;
x++;
}
}
return randomIndex;
}
hope it will be helpful.

Categories