Quicksort went wrong (added some duplicates) - java

I'm new to sorting algorithms and can't seem to figure out what went wrong. With an unsorted array of int [] uArr = {5,2, 10, 7, 6, 0, 8, 1, 9}, i'm given 0,1,2,5,5,6,8,10 (the nine in the org. array was replaced with a duplicate 5 and the 7 was lost). If I add duplicates to the array, I get more duplicates after the array is sorted and a few more missing numbers.
public static void main(String args[]){
int [] uArr = {5,2, 10, 7, 6, 0, 8, 1, 9};
qSort(uArr, 0, 8);
}
public static void qSort(int [] A, int low, int high){
if (low < high){
int pivotL = partition(A, low, high);
qSort(A, low, pivotL);
qSort(A, pivotL+1, high);
}
}
public static int partition(int [] arr, int low, int high){
int pivot = arr[low];
int leftwall = low;
for (int i = low + 1; i < high; i++){
if (arr[i] < pivot){
int temp = arr[i];
arr[i] = arr[leftwall];
arr[leftwall] = temp;
leftwall += 1;
}
}
int temp2 = pivot;
pivot = arr[leftwall];
arr[leftwall] = temp2;
return leftwall;
}
}

So one thing you should seriously do is start writing documentation. Even though this is a small program, you seem to have forgotten what you were doing as you were writing the code.
For example, there are 9 elements in the array, and you pass in the offsets to sort, inclusive, as 0 through 8:
qSort( uArr, 0, 8 );
But then in the partition routine you only sort elements less than the high value:
for( int i = low + 1; i < high; i++ ) {
And unlike you the last value in the array, 9, is never touched for me and never sorted. So that's an issue. Figure out if you want your indexes to be inclusive or not. For me writing documentation as I go helps me keep these ideas straight.
I'm still looking for other problems like the duplication.
Update: I'm going to just post these as I figure them out, as a sort of stream-of-consciousness of how I look for problems. One thing I was taught early on is that adding print statements to your code can be faster than using a debugger. So (after re-formatting your code, because the formatting you posted was frankly crap) I added this:
public static void qSort( int[] A, int low, int high ) {
System.out.println( Arrays.toString( A ) + " low=" + low + " high=" + high );
And got this output:
run:
[5, 2, 10, 7, 6, 0, 8, 1, 9] low=0 high=8
[2, 0, 1, 5, 6, 5, 8, 10, 9] low=0 high=3
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=0 high=2
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=0 high=0
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=1 high=2
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=1 high=1
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=2 high=2
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=3 high=3
[0, 1, 2, 5, 6, 5, 8, 10, 9] low=4 high=8
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=4 high=5
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=4 high=4
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=5 high=5
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=6 high=8
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=6 high=6
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=7 high=8
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=7 high=7
[0, 1, 2, 5, 5, 6, 8, 10, 9] low=8 high=8
[0, 1, 2, 5, 5, 6, 8, 10, 9]
BUILD SUCCESSFUL (total time: 0 seconds)
I did have to stare at the output for a while, but what I noticed next was two things. The 5 is duplicated almost immediately, and the 5 is also the first element, which means it's going to be chosen by your partition code as the pivot. So it looks as though you have problems re-merging the pivot with the array.
Update 2: OK found another problem. This one I found by writing your array out by hand and walking through each value of i and leftwall as it makes the first partition. Problem here:
When the pivot, 5, encounters the element 0 in the array, the rest of the array has not been sorted. The 10, 7, 6, etc. are not less than the pivot and have not be touched. So when you make the swap, you sawp this:
[2, 5, 10, 7, 6, 0, 8, 1, 9]
for this:
[2, 5, 0, 7, 6, 5, 8, 1, 9]
This is because leftwall was 1 (it had been swapped with the 2 but not any other number, so it only had been incremented once) and there's the duplication and losing numbers too. I'm going to stop there because you have some pretty big problems.
What you need to do in this case is swap the 10, not the pivot, with the 0. This is going to require one additional pointer at least. Quicksort algorithms need to find the lowest and highest in the array and have two loops inside the outer for loop. What you have here is a kind of weird recursive insert sort. You'll need to think a bit more how to do this, but two more loops, nest inside the first, will be required.

Related

Find number x equal to sum of 1 number from n sets

I'm having the following problem:
I have n sorted collections of integers (2<n<10).
I have a number x.
I wanna know if there is a sum (there can be multiple), in which each set needs to contribute exactly 1 number, which is equal to x
Example 1:
Collection 1: {1, 2, 3, 5, 7, 8}
Collection 2: {2, 4, 4, 5, 6, 8, 9, 11 23}
x: 9
For this example, a possible sum is 5+4. Another possibility is 1+8.
Example2:
Collection 1: {1, 1, 5, 7, 8, 9}
Collection 2: {2, 4, 5, 6, 8, 9}
x: 8
In this example, there is no possible sum. The number 8 is in both collections but since all collections need to contribute in the summation, this doesn't matter.
I don't wanna brute force this so i'm thinking recursion could make this process a bit faster but i don't really know where to begin.
I'm looking for some kind of train of thought although pseudo code or working code (java) would be appreciated :)
Try this.
static boolean existSum(List<Collection<Integer>> collections, int x) {
int size = collections.size();
return new Object() {
boolean find(int index, int sum) {
if (index >= size)
return sum == x;
for (int i : collections.get(index)) {
int newSum = sum + i;
if (newSum > x)
break;
if (find(index + 1, newSum))
return true;
}
return false;
}
}.find(0, 0);
}
public static void main(String[] args) throws Exception {
System.out.println(existSum(List.of(
List.of(1, 2, 3, 5, 7, 8),
List.of(2, 4, 4, 5, 6, 8, 9, 11, 23)), 9));
System.out.println(existSum(List.of(
List.of(1, 1, 5, 7, 8, 9),
List.of(2, 4, 5, 6, 8, 9)), 8));
}
output:
true
false

What do square brackets before a number mean in Java? e.g. []89 or [1, 2, 3]89

I'm new to Java and haven't been able to find any explanations on what the syntax such as [1, 2, 3, 4]5 means.
import java.util.*;
class SumDigPower {
static List<Long> list = new ArrayList<Long>();
public static List<Long> sumDigPow(long a, long b) {
for(long i = a; i<=b; i++) {
if(isEureka(i)) {
list.add(i);
}
}
return list;
}
public static boolean isEureka(long num) {
//convert number to string to get length and then sum each digit to the nth power
//return true or false depending on whether the number qualifies for the list
String numString = Long.toString(num);
long sum = 0;
for(int i = 0; i < numString.length(); i++) {
sum += Math.pow(Character.getNumericValue(numString.charAt(i)), i+1);
}
if(sum == num) {return true;}
else {return false;}
}
}
expected:<..., 4, 5, 6, 7, 8, 9, []89]> but was:<..., 4, 5, 6, 7, 8, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, ]89]>
JUnit uses that syntax to show why a test failed, and specifically when an expected String didn't match the actual value:
String expected = "[1, 2, 3, 4, 5, 6, 7, 8, 9, 89]";
List<Long> actualLongs = Arrays.asList(
1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L,
1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 89L);
String actualString = actualLongs.toString();
assertEquals(expected, actualString);
JUnit figures out the what's similar and different between the expected and actual, and uses the square brackets to highlight that. If you align the "expected" and "but was" bits, you get:
expected:<..., 4, 5, 6, 7, 8, 9, []89]>
but was:<..., 4, 5, 6, 7, 8, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, ]89]>
... so it's telling you that in that [] space, it expected nothing extra, but found the characters 1, 2, 3, 4, 5, 6, 7, 8, 9,.
The difference becomes a bit more obvious if it's not just extra characters. For instance, let's say you didn't have the extra values, but the last 89 were instead a 66. Then it would look like:
expected:<..., 4, 5, 6, 7, 8, 9, [89]]>
but was:<..., 4, 5, 6, 7, 8, 9, [66]]>
"Where I expected an 89, I found a 66."
I'm not as familiar with TestNG, but it wouldn't surprise me if it does a similar thing.
If you run the test in IDEA IntelliJ, it will even pick up on that syntax and show you a nice diff view of the expected-but-was. Again, I'm not familiar with other IDEs (like Eclipse), but it wouldn't surprise me if they do that as well.

Why does my insertion sort algorithm only work with single digit integers?

I've wrote a simple insertion sort algorithm for fun. It appears to be working just fine with one problem, it only works when all items in the array (the thing its trying to sort) are single digit integers. If an element is a multi-digit integer, it sorts everything up to that integer, then stops and throws an IndexOutOfBoundsException.
Note: Just so you understand the source code, the way my program works is like this: I pass the InsertionSort class a primative int array in construction. I then convert that to the ArrayList list. I know that the ArrayList list has the correct values copied over because I print it out and it matches up.
Example Runs:
Working:
{ 9, 2, 8, 5, 1, 6, 6, 7, 1}; //works perfectly ->
Unsorted List: [9, 2, 8, 5, 1, 6, 6, 7, 1]
Step 1: [9]
Step 2: [2, 9]
Step 3: [2, 8, 9]
Step 4: [2, 5, 8, 9]
Step 5: [1, 2, 5, 8, 9]
Step 6: [1, 2, 5, 6, 8, 9]
Step 7: [1, 2, 5, 6, 6, 8, 9]
Step 8: [1, 2, 5, 6, 6, 7, 8, 9]
Step 9: [1, 1, 2, 5, 6, 6, 7, 8, 9]
Sorted List: [1, 1, 2, 5, 6, 6, 7, 8, 9]
Not Working:
{ 9, 2, 8, 5, 1, 6, 6, 7, 1, 22, 823, 30, 244, 45, 5}; //doesn't work ->
Unsorted List: [9, 2, 8, 5, 1, 6, 6, 7, 1, 22, 823, 30, 244, 45, 5]
Step 1: [9]
Step 2: [2, 9]
Step 3: [2, 8, 9]
Step 4: [2, 5, 8, 9]
Step 5: [1, 2, 5, 8, 9]
Step 6: [1, 2, 5, 6, 8, 9]
Step 7: [1, 2, 5, 6, 6, 8, 9]
Step 8: [1, 2, 5, 6, 6, 7, 8, 9]
Step 9: [1, 1, 2, 5, 6, 6, 7, 8, 9]
java.lang.IndexOutOfBoundsException: Index: 9, Size: 9
Sorted List: [1, 1, 2, 5, 6, 6, 7, 8, 9]
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at InsertionSort.sort(InsertionSort.java:41)
at Executer.main(Executer.java:7)
Here is the relevant sorting code:
static ArrayList<Integer> list = new<Integer> ArrayList();
static ArrayList<Integer> list2 = new<Integer> ArrayList();
public static int[] sort() {
int s = 0;
System.out.println("Unsorted List: " + list.toString());
try {
for (int i = 0; i < list.size(); i++) {
s++;
if (i == 0) {
list2.add(list.get(i));
System.out.println("Step " + s + ": " + list2.toString());
continue;
} else {
int z = 0;
while (list2.get(z) < list.get(i)) {
z++;
}
list2.add(z, list.get(i));
}
System.out.println("Step " + s + ": " + list2.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Sorted List: " + list2.toString());
return toPrimative(list.toArray(new Integer[list.size()]));
}
It has nothing to do with single or multi digit numbers, in first example you were just lucky to have the biggest number as a first element in a list. There is an obvious mistake when you're choosing a position for the next element:
int z = 0;
while (list2.get(z) < list.get(i)) {
z++;
}
You increment index but don't do bounds check, so when it comes to number 22 you get an exception. The correct one would be
while (list2.get(z) < list.get(i) && z <= list2.size())
Mind debug. Problem is here:
while (list2.get(z) < list.get(i)) {
z++;
}
z exceeds list2 count if new value is the biggest.
First value 9 in small numbers example hid this problem.
I hope that solution is clear enough

Large arraylist, finding the product of certain amount of elements

I have an array list which contains the numbers below, and what i am trying to do is find the product of every 16 numbers.
try {
for (int z = 0; z < 1000; z++) {
System.out.println(list.subList(z, z + 16));
the above prints this
[7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2]
[3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2, 4]
[1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2, 4, 9]
[6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2, 4, 9, 1]
etc......
my solution was to put every line above in to an array and find the product of that array.However i am stuck, was wondieering if anyone can provide me a few pointers on about how to take a hit at this
list.subList(z, z + 16);
for(int i = 0; i < list.subList(z, z+16).size();i++){
Ar[i] = list.get(z);
}
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
If you had a ArrayList of ArrayList then you could do
ArrayList <ArrayList> listofList = new ArrayList ();
for (int z = 0; z < 1000; z = z + 16) {
int endpoint = z + 16; // check to see not bigger than 1000
ArrayList thisList = list.subList(z, endpoint);
listOfList.add (thisList);
System.out.println(thisList);
}
But there again you may want to just add up as you go.
ArrayList thisList = list.subList(z, endpoint);
int prod = 1;
for (int x : thisList) {
prod *= x;
}
If you look at the printout that you are showing, you will that it is just moving one number each time - not what you want.
This is the solution I came up with. Instead of printing out the answer, you coudl add it to an array or something and use it later. Fyi I subbed the zeroes for 1's so I knew it was working.
public static void main(String[] args) throws Exception
{
int[] arr = {7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 1, 6, 2, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 1, 6, 2, 4, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 1, 6, 2, 4, 9};
int counter = 0;
int product = 1;
for (int i : arr)
{
if (counter < 16)
{
product *= i;
counter++;
}
if (counter >= 16)
{
System.out.println(product);
product = 1;
counter = 0;
}
}
}
This is what printed (again I subbed the zeroes for ones):
60011280
34292160
102876480

Using specific numbers to reach a target number

For my assignment, I have to allow the player to select 6 numbers from two different lists as they please.
List<Integer> large = Arrays.asList(25, 50, 75, 100);
List<Integer> small = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10);
After they have selected their numbers say [100, 3, 5, 6, 9, 5] they then generate a target number of lets say for example 299 and they then can only use the numbers selected as a means of reaching the target using ONLY multiplication, addition, subtraction and division. So they could input for instance, 100 * 3 + 5 - 6 to reach the 299 target and this would be checked and scored appropriately.
Unfortunately I don't really have much to go on and I'm a bit confused on how to go about even starting to do that, I'm not looking for a straight up answer, maybe some pointers or external help would be much appreciated.
If we follow Bedmas (brackets exponents division multiplication addition subtraction) we can break this down into a simple function.
First turn the equation into a list of components:
100 * 3 + 5 - 6
changes to
["100", "*", "3", "+", "5", "-", "6"]
Now evaluate every element to make sure that they are valid. ie) Each value in the list of components must be in the selection list or have the value, */+-, Also if there are n nums, then there should be n-1 syms
To get the result we can then evaluate the list,.. merging num-sym-num sections as we go, in the order of bedmas
In pseudo:
func int compute_val(ListString eqn)
while not eqn.length is 1
if "*" in eqn
index = eqn.getIndex("*")
replace eqn[index -1:index +1] with str((int) eqn[index -1] * (int)eqn[index +1])
else if "/" in eqn
index = eqn.getIndex("/")
replace eqn[index -1:index +1] with str((int) eqn[index -1] / (int)eqn[index +1])
else if "+" in eqn
index = eqn.getIndex("+")
replace eqn[index -1:index +1] with str((int) eqn[index -1] + (int)eqn[index +1])
else if "-" in eqn
index = eqn.getIndex("-")
replace eqn[index -1:index +1] with str((int) eqn[index -1] - (int)eqn[index +1])
return (int)eqn[0]
This would be the progression of the list as the equation is evaluated in the loop
["100", "*", "3", "+", "5", "-", "6"] --> ["300", "+", "5", "-", "6"] -->
["305", "-", "6"] --> ["299"]
Is this helpful?
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class JavaApplication97 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] s = {1, 2, 3, 4};
List<Integer> large = new ArrayList<>(Arrays.asList(25, 50, 75, 100));
List<Integer> small = new ArrayList<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10));
List<Integer> yourNumbers = new ArrayList<>();
int numbersToSelect = 6;
while (numbersToSelect > 0) {
System.out.println("Choose " + numbersToSelect + " numbers from these numbers : " + large + " or " + small);
Integer input = in.nextInt();
boolean isItThere = false;
if (large.contains(input)) {
isItThere = true;
large.remove(input);
} else if (small.contains(input)) {
isItThere = true;
small.remove(input);
}
if (isItThere) {
yourNumbers.add(input);
numbersToSelect--;
System.out.println("Number " + input + " is added");
} else {
System.out.println("There is no such number");
}
}
}
}
Sample output :
Choose 6 numbers from these numbers : [25, 50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
25
Number 25 is added
Choose 5 numbers from these numbers : [50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
25
There is no such number
Choose 5 numbers from these numbers : [50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
5
Number 5 is added
Choose 4 numbers from these numbers : [50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
5
Number 5 is added
Choose 3 numbers from these numbers : [50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
5
There is no such number
Choose 3 numbers from these numbers : [50, 75, 100] or [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
100
Number 100 is added
Choose 2 numbers from these numbers : [50, 75] or [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]
6
Number 6 is added
Choose 1 numbers from these numbers : [50, 75] or [1, 1, 2, 2, 3, 3, 4, 4, 6, 7, 7, 8, 8, 9, 9, 10, 10]
50
Number 50 is added
You need multiple steps, and as I guess this is a homework task I'm not going to give a complete answer, however:
Parse the input string of the user
Calculate the result
Check if the result equals the target number
While 2 and 3 are trivial, the first part is probably the hardest for you and the core of the task. You can get more information on that task here: Smart design of a math parser?

Categories