Recursive binary search (integer) - java

I've written this binary search algorithm based on recursion but I'm unable to understand the reason for the error.
// Only a sorted array must be entered for binary search to work
public int binarySearch(int searchFor, int[] inArray, int from, int to){
if (to >= from){
int mid = (to-from)/2 + from;
if (inArray[mid] == searchFor){
return inArray[mid];
} else if (inArray[mid] < searchFor){
binarySearch(searchFor, inArray, ++mid, to);
} else if (inArray[mid] > searchFor){
binarySearch(searchFor, inArray, from, ++mid);
}
}
return -1;
}
Exception in thread "main" java.lang.StackOverflowError
at search.binarySearch(search.java:24)
at search.binarySearch(search.java:24)
at search.binarySearch(search.java:24)
at search.binarySearch(search.java:24)

A few issues and remarks:
In the last case, the value ++mid is wrong as argument for binarySearch. That value should be one less than mid in that case.
I would also vote against the use of ++mid or --mid here, as that suggests that it is important that mid changes value, which is not needed. You should just pass mid+1 in the first case, and mid-1 in the second.
binarySearch returns an int, but when your code calls it recursively it doesn't do anything with that return value.
You should return that value. So:
} else if (inArray[mid] < searchFor){
return binarySearch(searchFor, inArray, mid+1, to);
// ^^^^^^ ^^^^^
} else if (inArray[mid] > searchFor){
return binarySearch(searchFor, inArray, from, mid-1);
// ^^^^^^ ^^^^^
}
The expression (to-from)/2 + from is a verbose way of doing (from+to)/2...

Apart from adding return to the recursive calls of binarySearch, there are a couple of flaws in the logic:
mid should be decremented to catch values in the left part:
return binarySearch(searchFor, inArray, from, --mid);
there should be a check for valid mid, from, to values to fit inside the input array
Thus, the method should look as:
public static int binarySearch(int searchFor, int[] inArray, int from, int to) {
if (to >= from && from > -1 && to <= inArray.length) {
int mid = (to-from)/2 + from;
if (mid >= inArray.length) {
return -1;
}
// System.out.printf("from=%d to=%d mid=%d val=%d%n", from, to, mid, inArray[mid]); // debug print
if (inArray[mid] == searchFor) {
return inArray[mid];
} else if (inArray[mid] < searchFor){
return binarySearch(searchFor, inArray, ++mid, to);
} else {
return binarySearch(searchFor, inArray, from, --mid);
}
}
return -1;
}
}
Tests:
public static int binarySearch(int searchFor, int... inArray) {
System.out.printf("Searching for %d in %s%n", searchFor, Arrays.toString(inArray));
return binarySearch(searchFor, inArray, 0, inArray.length);
}
System.out.println(binarySearch(10));
System.out.println(binarySearch(10, 10));
System.out.println(binarySearch(10, 1));
System.out.println(binarySearch(10, 0, 1, 5, 8, 10, 21));
System.out.println(binarySearch( 0, 0, 1, 5, 8, 10, 21));
System.out.println(binarySearch(21, 0, 1, 5, 8, 10, 21));
System.out.println(binarySearch(10, 0, 1, 3, 5, 8, 10, 21));
System.out.println(binarySearch( 0, 0, 1, 5, 8, 10, 15, 21));
System.out.println(binarySearch(21, 0, 1, 5, 8, 10, 16, 21));
System.out.println(binarySearch(30, 0, 1, 5, 8, 10, 21));
System.out.println(binarySearch(-1, 0, 1, 5, 8, 10, 21));
System.out.println(binarySearch(7, 0, 1, 5, 8, 10, 21));
Output:
Searching for 10 in []
-1
Searching for 10 in [10]
10
Searching for 10 in [1]
-1
Searching for 10 in [0, 1, 5, 8, 10, 21]
10
Searching for 0 in [0, 1, 5, 8, 10, 21]
0
Searching for 21 in [0, 1, 5, 8, 10, 21]
21
Searching for 10 in [0, 1, 3, 5, 8, 10, 21]
10
Searching for 0 in [0, 1, 5, 8, 10, 15, 21]
0
Searching for 21 in [0, 1, 5, 8, 10, 16, 21]
21
Searching for 30 in [0, 1, 5, 8, 10, 21]
-1
Searching for -1 in [0, 1, 5, 8, 10, 21]
-1
Searching for 7 in [0, 1, 5, 8, 10, 21]
-1

Related

Sudoku solver using recursion and backtracking

I am trying to implement a Sudoku solver using Java. This is the code I've written as of now. If I try to run it, it goes on to an endless loop that keeps on printing the first row of the Sudoku board, and that too with an incorrect solution. I guess I'm implementing backtracking the incorrect way over here. I think I am printing the final and wrong as well, as only the first row is printed every time. Can someone please help me fix my code and tell me as to where I am going wrong?
public static void display(int[][] board) {
for(int[] arr : board) {
System.out.println(Arrays.toString(arr));
return;
}
}
public static boolean isSafe(int[][] board, int row, int col, int i) {
//check row
for(int a=0; a<board.length; a++) {
if(board[a][col]==i) {
return false;
}
}
//check col
for(int b=0; b<board.length; b++) {
if(board[row][b]==i) {
return false;
}
}
//check cell
int strow = row-(row%3);
int stcol = col-(col%3);
for(int x=strow; x<strow+3; x++) {
for(int y=stcol; y<stcol+3; y++) {
if(board[x][y]==i) {
return false;
}
}
}
return true;
}
public static void sudoku(int[][] board, int row, int col) {
if(row==board.length) {
display(board);
System.out.println();
return; //modify this to print ans
}
if(col==board.length) {
sudoku(board, row+1, 0);
return;
}
if(board[row][col]==0) {
for(int i=1; i<=9; i++) {
if(isSafe(board, row, col, i)) {
board[row][col]=i;
sudoku(board, row, col+1);
board[row][col]=0;
}
}
}
sudoku(board, row, col+1);
}
public static void main(String args[]) {
int[][] board=
{ {3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 0, 0, 0, 0, 0, 0, 0},
{0, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 0, 0} };
sudoku(board, 0, 0);
}
A bactracking algorithm can be applied here and the problem happens in your sudoku method.
First of all we can just pass the board and we don't want to pass the row and col.
We can just pass the board and the just traverse through each and every cell.
Only consider those cells that are 0's.
We don't want to consider any other cells as 0"s are the cells we are interested in.
Now if we see a cell which is 0, we try to find all the different possibilites from 1 to 9 which can fit in that cell and apply the 'isSafe()` logic which will just do the same check.
And we backtrack and continue with our checking.
public static void display(int[][] board) {
for(int[] arr : board) {
System.out.println(Arrays.toString(arr));
}
}
public static boolean isSafe(int[][] board, int row, int col, int i) {
//check row
for(int a=0; a<board.length; a++) {
if(board[a][col]==i) {
return false;
}
}
//check col
for(int b=0; b<board.length; b++) {
if(board[row][b]==i) {
return false;
}
}
//check cell
int strow = row-(row%3);
int stcol = col-(col%3);
for(int x=strow; x<strow+3; x++) {
for(int y=stcol; y<stcol+3; y++) {
if(board[x][y]==i) {
return false;
}
}
}
return true;
}
public static boolean sudoku(int [][] board) {
for (int i=0; i<9; i++) {
for (int j=0; j<9; j++) {
int current = board[i][j];
if (current == 0) {
for (int ch = 1; ch <= 9; ch++) {
if (isSafe(board, i, j, ch)) {
board[i][j] = ch;
if (sudoku(board)) {
return true;
}
board[i][j] = 0;
}
}
return false;
}
}
}
return true;
}
public static void main(String args[]) {
int[][] board=
{ {3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 0, 0, 0, 0, 0, 0, 0},
{0, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 0, 0} };
sudoku(board);
display(board);
}
Here is the output after the change
[3, 1, 6, 5, 7, 8, 4, 9, 2]
[5, 2, 9, 1, 3, 4, 7, 6, 8]
[4, 8, 7, 6, 2, 9, 5, 3, 1]
[2, 6, 3, 4, 1, 5, 9, 8, 7]
[9, 7, 4, 8, 6, 3, 1, 2, 5]
[8, 5, 1, 7, 9, 2, 6, 4, 3]
[1, 3, 8, 9, 4, 7, 2, 5, 6]
[6, 9, 2, 3, 5, 1, 8, 7, 4]
[7, 4, 5, 2, 8, 6, 3, 1, 9]
Note : I changed the return type to true or false inorder to make sure that a particular cell can be filled with a number say x. If its possible we return true and continue with the next cell which is 0, other wise we backtrack and check for other possibilities.
Updates :
The only change you are missing is an else block at the very end because even if the cell is 0 or any other number you are doing recursion sudoku(board, row, col+1);. So just enclose that statement in the else block and will give the desired output.
Code change without changing the return type:
public static void display(int[][] board) {
for(int[] arr : board) {
System.out.println(Arrays.toString(arr));
}
}
public static boolean isSafe(int[][] board, int row, int col, int i) {
//check row
for(int a=0; a<board.length; a++) {
if(board[a][col]==i) {
return false;
}
}
//check col
for(int b=0; b<board.length; b++) {
if(board[row][b]==i) {
return false;
}
}
//check cell
int strow = row-(row%3);
int stcol = col-(col%3);
for(int x=strow; x<strow+3; x++) {
for(int y=stcol; y<stcol+3; y++) {
if(board[x][y]==i) {
return false;
}
}
}
return true;
}
public static void sudoku(int[][] board, int row, int col) {
if(row==board.length) {
display(board);
System.out.println();
return; //modify this to print ans
}
if(col==board.length) {
sudoku(board, row+1, 0);
return;
}
if(board[row][col]==0) {
for(int i=1; i<=9; i++) {
if(isSafe(board, row, col, i)) {
board[row][col]=i;
sudoku(board, row, col+1);
board[row][col]=0;
}
}
}
else
sudoku(board, row, col+1);
}
public static void main(String args[]) {
int[][] board=
{ {3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 0, 0, 0, 0, 0, 0, 0},
{0, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 0, 0} };
sudoku(board, 0, 0);
}
Output :
[3, 1, 6, 5, 7, 8, 4, 9, 2]
[5, 2, 9, 1, 3, 4, 7, 6, 8]
[4, 8, 7, 6, 2, 9, 5, 3, 1]
[2, 6, 3, 4, 1, 5, 9, 8, 7]
[9, 7, 4, 8, 6, 3, 1, 2, 5]
[8, 5, 1, 7, 9, 2, 6, 4, 3]
[1, 3, 8, 9, 4, 7, 2, 5, 6]
[6, 9, 2, 3, 5, 1, 8, 7, 4]
[7, 4, 5, 2, 8, 6, 3, 1, 9]

Java add array to array special mode

I am working on a game in Java and I need to cache some position-based information. If I have the following array:
int[][] array = {
{1, 2, 3},
{1, 2, 3},
{1, 2, 3}
};
And then I have this other array:
int[][] otherArray = {
{4, 5, 6},
{4, 5, 6},
{4, 5, 6}
};
Now I want to combine them in a special way. I want to add otherArray to the left of array. So the result would look like this:
int[][] combinedArray = {
{4, 5, 6, 1, 2, 3},
{4, 5, 6, 1, 2, 3},
{4, 5, 6, 1, 2, 3}
};
Then I have this other combined array:
int[][] otherCombinedArray = {
{30, 17, 139, 65, 335, 99},
{50, 43, 57, 53, 423, 534},
{90, 67, 78, 24, 99, 67}
};
Now I want to add it to the top of the original combined array. So the final result would look like this:
int[][] finalCombinedArray = {
{30, 17, 139, 65, 335, 99},
{50, 43, 57, 53, 423, 534},
{90, 67, 78, 24, 99, 67},
{4, 5, 6, 1, 2, 3},
{4, 5, 6, 1, 2, 3},
{4, 5, 6, 1, 2, 3}
};
Can someone point me to a good library or built in method for doing this? I also wanted to note that the method shouldn't be too computationally heavy (like looping through all the arrays multiple times, and it shouldn't use too much memory, like 80MB).
Thank you for the help!
On it's own, Java does not provide concatenation methods, but we can use System.arraycopy (as suggested by #user16320675 above)
With System.arraycopy you specify the array to copy + the destination array -> you have array A of size 10 and B of size 2, and you use the command to copy your B array into A.
int[] source = { 1,2,3,4,5 };
int[] destination = new int[10];
// You can play with the numbers below
int COPY_AT_INDEX = 0; // Start to copy at position destination[0]
int AMOUNT_TO_COPY = 5; // Copying from 0 to source.length
System.arraycopy(source, 0, destination, COPY_AT_INDEX, AMOUNT_TO_COPY);
System.out.println(Arrays.toString(source)); // [1, 2, 3, 4, 5]
System.out.println(Arrays.toString(destination)); // [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
Now, if we use arraycopy, seems you have to determine when to copy as rows, and when to copy as columns.
// Assuming a[][] and b[][] have the same size.
public int[][] mergeAsColumns(int[][] a, int[][] b) {
int rows = a.length;
int columns = a[0].length;
int[][] merged = new int[rows][2 * columns];
for (int i = 0; i < a.length; i++) {
System.arraycopy(a[i], 0, merged[i], 0, columns);
System.arraycopy(b[i], 0, merged[i], rows, columns);
}
return merged;
}
Merging as Rows is similar to the other one, but changes in which positions you want to affect and how you create the merged array.
// Assuming a[][] and b[][] have the same size.
public int[][] mergeAsRows(int[][] a, int[][] b) {
int rows = a.length;
int columns = a[0].length;
int[][] merged = new int[2 * rows][columns];
for (int i = 0; i < rows; i++) {
System.arraycopy(a[i], 0, merged[i], 0, columns);
System.arraycopy(b[i], 0, merged[rows + i], 0, columns);
}
return merged;
}

How to delete last element in array and put new in front?

I have a question concerning Java. I started up new to Java and my google search brought many results but non was the final help.
I created a class to track historical information. I have different values for different days and need to update them un a regular basis. I want to keep track of the last 30 days and created an array with 30 elements. When I call my 'shift' function I want to drop the last n elements and put zeros in front. Here is a minial example for 5 days:
public class Testclass {
private int[] histInfo;
public Element()
{
this.histInfo = new int[5];
}
public void shift_histInfo(long m)
{
//do magic
}
}
What I want shift to do is
INPUT:
histInfo = [50,21,1,45,901]
OPERATION:
shift_histInfo(2);
RESULT:
histInfo = [0,0,50,21,1]
I am thankfull for every kind of help you can support as well for thought-provoking impulses if you think that there is a way more elegant or efficient way.
Best :-)
Unless there are very tight performance constraints using the standard Collection classes will get the job done. Have a look at java.util.LinkedList.
As a programming exercise you might consider creating a ring buffer. The idea being to avoid copying the array on every insertion.
Keep a oldestIndex value.
When writing simply replace item[oldestIndex] and increment oldestIndex.
To iterate you start at oldestIndex and use an increment method to deal with wrapping round to the start of the array.
int nextIndex(int current) {
return (current + 1) % arrayLength;
}
Writing a nice encapsulating class to hide all this would be a good exercise.
You can try this :
public static void shift_histInfo(long m)
{
int[] myIntArray = {50,21,1,45,901};
int[] myIntArray2 = {50,21,1,45,901};
for (int j=0 ;j< myIntArray.length ; j++){
int temp = (int) (j+m);
if (temp >= myIntArray.length){
temp = temp - myIntArray.length;
myIntArray2[temp] = 0;
} else {
myIntArray2[temp] = myIntArray[j];
}
}
for (int j=0 ;j< myIntArray2.length ; j++){
System.out.println(myIntArray2[j]);
}
}
Output :
when shift_histInfo(2) ,
[0,0,50,21,1]
int[] array={1,2,3,4,5,6};
int removelength=2;
int e=1;
while(e<=removelength) {
for(int i=1;i<array.length;i++)
array[array.length-i]=array[array.length-i-1];
e++;
}
for(int i=0;i<removelength;i++) {
array[i]=0;
}
for(int g:array)
{
System.out.print(g);
}
For constraints that you wanted, although I did initialise the data in the same method instead of Element(). I don't know why the parameter is of type long so I left it and made an int local variable.
All it does is copy the index value over to the new array starting at m then increments/iterates until the end of the array.
You can also make the method return type int[] and then simply return changedInfo array. Instead of histInfo = changedInfo.clone();
private int[] histInfo;
public void shift_histInfo(long m) {
int n = (int) m;
this.histInfo = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15};
int length = this.histInfo.length;
int[] changedInfo = new int[length];
if (length - n >= 0) System.arraycopy(histInfo, 0, changedInfo, n + 0, length - n); //Edit: shortened to one line.
histInfo = changedInfo.clone();
System.out.println("Remove: " + n + " - " + Arrays.toString(changedInfo) + "\n");
}
public static void main(String[] args) {
Main main = new Main();
main.shift_histInfo(0);
main.shift_histInfo(30);
main.shift_histInfo(1);
main.shift_histInfo(15);
main.shift_histInfo(29);
}
println:
Remove: 0 - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
Remove: 30 - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Remove: 1 - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Remove: 15 - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
Remove: 29 - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

How to Convert String of numbers to a distinct ArrayList

I have a troubles with an application.
I would like to move my String into this ArrayList.
My String contains numbers like 15 17 18 110 113 (numbers from 1 do 200).
I have about 80 numbers in one String, eg.:
I/System.out: 15 13 13 12 12 11 11 21 21 39 39 38 38 40 40 41 41 42 42 43 43 74 74 75 75 76 76 77 77 78 78 80 80 99 99 100 100 102 102 103 103 105 105 104
While I have List<String> tmpPath = new ArrayList<>(); and I have tried two different methods:
1.
public void transferStringToArray(string s1){
for(int i = 0; i < s1.length(); i++){
int extra = 0;
if(s1.charAt(i) != ' '){
String x = Character.toString(s1.charAt(i));
tmpPath.add(extra, x);
else extra++;
}
}
where the output is:
I/System.out: [4, 0, 1, 5, 0, 1, 5, 0, 1, 3, 0, 1, 3, 0, 1, 2, 0, 1, 2, 0, 1, 0, 0, 1, 0, 0, 1, 9, 9, 9, 9, 0, 8, 0, 8, 8, 7, 8, 7, 7, 7, 7, 7, 6, 7, 6, 7, 5, 7, 5, 7, 4, 7, 4, 7, 3, 4, 3, 4, 2, 4, 2, 4, 1, 4, 1, 4, 0, 4, 0, 4, 8, 3, 8, 3, 9, 3, 9, 3, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 5, 1]
(numbers are printed from last to first number which is wrong with my assumptions)
2.
public void transferStringToArray(string s1){
for(int i = 0; i < s1.length(); i++)
if(s1.charAt(i) != ' '){
String x = Character.toString(s1.charAt(i));
tmpPath.add(x);
}
where the output is in good order, but one number means one index of an array.
I/System.out: [1, 5, 1, 3, 1, 3, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 3, 9, 3, 9, 3, 8, 3, 8, 4, 0, 4, 0, 4, 1, 4, 1, 4, 2, 4, 2, 4, 3, 4, 3, 7, 4, 7, 4, 7, 5, 7, 5, 7, 6, 7, 6, 7, 7, 7, 7, 7, 8, 7, 8, 8, 0, 8, 0, 9, 9, 9, 9, 1, 0, 0, 1, 0, 0, 1, 0, 2, 1, 0, 2, 1, 0, 3, 1, 0, 3, 1, 0, 5, 1, 0, 5, 1, 0, 4]
Do you have any ideas how to move full number as one index separated by a space?
Also I have one more question:
How could I delete all repeated numbers? I know, that numbers are printed once or twice but in the result I have to have unique numbers.
All you need to do is a split with space s.split("\\s+"), and then put the result in a Set like this:
Set<String> set = new HashSet<>(Arrays.asList(s.split("\\s+")));
Or if you want to maintain the order, you can use :
Set<String> set = new LinkedHashSet<>(Arrays.asList(s.split("\\s+")));
If you are looking to use List and nothing else, then you can use, distinct like so :
List<String> set = Arrays.stream(s.split("\\s+"))
.distinct()
.collect(Collectors.toList());
Outputs
[15, 13, 12, 11, 21, 39, 38, 40, 41, 42, 43, 74, 75, 76, 77, 78, 80, 99, 100, 102, 103, 105, 104]
To convert space separated string into an array list :
You first need to split your string into an string array and then convert it into array list
public void convertStringToList() {
String stringToSplit = "15 13 13 12";
String[] splittedString = stringToSplit.split(" "); // Will split string based upon the space into an string array
List<String> listOfStrings = Arrays.asList(splittedString);
}
To remove the duplicates, you can insert all the array lists value into a Set. A set is a data structure in java which stores only unique values.
Set<String> uniqueValuesSet = new HashSet<>(listOfStrings);
for(String str : uniqueValuesSet) {
System.out.println(str);
}
In 2nd point, you might see your output is in random order. That is because HashSet doesn't maintain order of elements. If you need to maintain order as well. Use LinkedHashSet.
Set<String> uniqueValuesSet = new LinkedHashSet<>(listOfStrings);
for(String str : uniqueValuesSet) {
System.out.println(str);
}
Note: This solution assumes number in the original string are single space separated. If you want solution irrespective of number of spaces between 2 numbers, replace this line in point 1
String[] splittedString = stringToSplit.split(" ");
To
String[] splittedString = stringToSplit.split("\\s+");
I'm sticking with Set, as MaciejB wanted to eliminate duplicates and that's the contract of Set.
And, as MaciejB mentioned order too, I parsed them as Integer & put 'em in a TreeSet.
That looks like this:
Set<Integer> set = Stream.of(s.split("\\s+")).map(Integer::parseInt).collect(Collectors.toCollection(TreeSet::new));
Or if you prefer multiple lines:
Set<Integer> set = Stream // Result is ordered, parsed Set
.of(s.split("\\s+")) // -> String[]
.map(Integer::parseInt) // -> Integer[] for order in TreeSet
.collect(Collectors.toCollection(TreeSet::new)); // no duplicates
Outputs:
[11, 12, 13, 15, 21, 38, 39, 40, 41, 42, 43, 74, 75, 76, 77, 78, 80, 99, 100, 102, 103, 104, 105]

QuickSort Program Not Outputting Right

I am attempting to make a QuickSort program and while I feel like it should be outputting as desired, it is not. I feel the problems lies in how I have constructed my loops but that may not be the case. As you can see, the first test with the runner prints out as I want and everything eventually gets sorted right. Any help would be greatly appreciated.
My main program:
import static java.lang.System.*;
import java.util.Arrays;
//use Arrays.toString() to help print out the array
public class QuickSort
{
private static int passCount;
public static void quickSort(Comparable[] list)
{
passCount=0;
quickSort(list, 0, list.length-1);
}
private static void quickSort(Comparable[] list, int low, int high)
{
if(low >= high)
return;
int a = partition(list, low, high);
quickSort(list, low, a-1);
quickSort(list, a+1, high);
}
private static int partition(Comparable[] list, int low, int high)
{
int x = low + 1;
int y = high;
while(x <= y)
{
if(list[x].compareTo(list[low]) <= 0)
{x++;}
else if(list[y].compareTo(list[low]) > 0)
{y--;}
else if(y < x)
{break;}
else
exchange(list, x, y);
}
exchange(list, low, y);
out.println("pass " + passCount++ + " " + Arrays.toString(list) + "\n");
return y;
}
private static void exchange(Object[] list, int x, int y) {
Object temporary = list[x];
list[x] = list[y];
list[y] = temporary;
}
}
My runner:
public class QuickSortRunner
{
public static void main(String args[])
{
QuickSort.quickSort(new Comparable[]{9,5,3,2});
System.out.println("\n");
QuickSort.quickSort(new Comparable[]{19,52,3,2,7,21});
System.out.println("\n");
QuickSort.quickSort(new Comparable[]{68,66,11,2,42,31});
System.out.println("\n");
}
}
My output:
pass 0 [2, 5, 3, 9]
pass 1 [2, 5, 3, 9]
pass 2 [2, 3, 5, 9]
pass 0 [2, 7, 3, 19, 52, 21]
pass 1 [2, 7, 3, 19, 52, 21]
pass 2 [2, 3, 7, 19, 52, 21]
pass 3 [2, 3, 7, 19, 21, 52]
pass 0 [31, 66, 11, 2, 42, 68]
pass 1 [11, 2, 31, 66, 42, 68]
pass 2 [2, 11, 31, 66, 42, 68]
pass 3 [2, 11, 31, 42, 66, 68]
Desired output:
pass 0 [2, 5, 3, 9]
pass 1 [2, 5, 3, 9]
pass 2 [2, 3, 5, 9]
pass 0 [7, 2, 3, 52, 19, 21]
pass 1 [3, 2, 7, 52, 19, 21]
pass 2 [2, 3, 7, 52, 19, 21]
pass 3 [2, 3, 7, 21, 19, 52]
pass 4 [2, 3, 7, 19, 21, 52]
pass 0 [31, 66, 11, 2, 42, 68]
pass 1 [2, 11, 66, 31, 42, 68]
pass 2 [2, 11, 66, 31, 42, 68]
pass 3 [2, 11, 42, 31, 66, 68]
pass 4 [2, 11, 31, 42, 66, 68]
The x++ and y-- to skip exchanges need to be in while loops so that exchange happens only when it is called for.

Categories