I know that there are other question about this, but nobody has my implementation of quicksort so I need your help to fix this.
Here is my quicksort:
//u is first index (0) and v is last (numberOfPatients - 1)
public void quickSort(Patient arrayPatients[], int u, int v) {
int q;
if(u == v) return;
q = perno(arrayPatients, u, v);
if(u < q) quickSort(arrayPatients, u, q-1);
if(q < v) quickSort(arrayPatients, q+1, v);
}
public int perno(Patient arrayPatients[], int first, int last){
Patient temp = new Patient();
int i = first;
int j = last + 1;
long pivot = arrayPatients[first].priority;
while(i < j){
do i++;
while(arrayPatients[i].priority <= pivot && i<= last); //Line 1441
do j--;
while(arrayPatients[j].priority > pivot && j >= first);
if(i < j){
//Swap arrayPatients[i] and arrayPatients[j]
temp = arrayPatients[i];
arrayPatients[i] = arrayPatients[j];
arrayPatients[j] = temp;
}
}
//Swap arrayPatients[first] and arrayPatients[j]
temp = arrayPatients[first];
arrayPatients[first] = arrayPatients[j];
arrayPatients[j] = temp;
return j;
}
edit:
I have 4 patients, this is the error I get:
java.lang.ArrayIndexOutOfBoundsException: 4
at sorter.Sort.perno(Sort.java:1441)
at sorter.Sort.quickSort(Sort.java:1425)
at sorter.Sort.quickSort(Sort.java:1428)
at sorter.Sort.sorting(Sort.java:851)
at sorter.Home$27.run(Home.java:1314)
I've added a comment with the number of the incriminated line
Your problem is most likely due to checking array at index first, then checking if the index is within bounds at all.
Instead:
do i++;
while(arrayPatients[i].priority <= pivot && i<= last); //Line 1441
do j--;
while(arrayPatients[j].priority > pivot && j >= first);
Try:
do i++;
while(i<= last && arrayPatients[i].priority <= pivot); //Line 1441
do j--;
while(j >= first && arrayPatients[j].priority > pivot);
and see if that helps.
Related
The Output: ATXZK (Not Sorted) Why?
There are no bugs in it. I can not figure it out.
Is there any problem with the method qs(items, left, right)
It works fine with input: d x a r p j i
class Quicksort{
static void qsort(char items[]) {
qs(items, 0, items.length - 1);
}
private static void qs(char items[], int left, int right)
{
int i, j;
char x, y;
i = left; j = right;
x = items[(left + right)/2];
do {
while((items[i] < x) && (i < right)) i++;
while((x < items[j]) && (j > left)) j--;
if(i <= j) {
y = items[i];
items[i] = items[j];
items[j] = y;
i++; j--;
}
} while(i <= j);
if(left < j) qs(items, left, j);
if(i > right) qs(items, i, right);
}
}
I think you reversed your greater/less than sign in your last line of code.
Should be:
Is i (which counts from left to right) less than right: If so, keep sorting.
Currently it is:
Is i (which counts from left to right) GREATER than right (IE, out of bounds). If so, keep quicksorting.
if(i < right) qs(items, i, right);
At least, this made your fail case work on my machine. :)
Basically i built this rudementary tim sort built for a simple project and it works with a sub of 32 all the way up to 1000 integers (the next thing i tried was 5000) and then it crashes with a index out of bounds exeception i tried increasing the sub to 64 but it just dosent seem to work i was wondering if anyone could tell me what im doing wrong here.
public static void timSort(List<Comparable> nums) {
int sub = 32;
for (int i = 0; i < nums.size(); i += sub)
{
if((nums.size() -1) < (i + 31)) {
inPlaceInsertion(nums, i, (nums.size() - 1));
}else {
inPlaceInsertion(nums, i, (i + 31));
}
}
for (int size = sub; size < nums.size(); size = 2 * size)
{
for (int left = 0; left < nums.size(); left += 2 * size)
{
int mid = left + size - 1;
int right;
if((nums.size() - 1) < (left + 2 * size - 1)) {
right = nums.size() -1;
}else {
right = left + 2 * size -1;
}
merge(nums, left, mid, right);
}
}
}
public static void inPlaceInsertion(List<Comparable> nums, int first, int last){
for(int i = first; i <= last; i++){
Comparable hold = nums.get(i);
int j;
steps++;
for(j = i; j > first && hold.compareTo(nums.get(j - 1)) < 0; j--) {
nums.set(j, nums.get(j - 1));
steps+=4;
}
nums.set(j, hold);
steps++;
}
}
private static void merge(List<Comparable> nums, int first, int mid, int last){
List<Comparable> newList = new ArrayList<Comparable>();
int loopCountA = 0;
int loopCountB = 0;
while(true) {
if(loopCountB == (last - mid)) {
while(first + loopCountA <= mid) {
newList.add(nums.get(first + loopCountA)); loopCountA++;
steps++;
}
break;
}else if(first + loopCountA > mid) {
while(loopCountB < (last - mid)) {
newList.add(nums.get(mid + (loopCountB + 1))); loopCountB++;
steps++;
}
break;
}else {
if(nums.get(mid + (loopCountB + 1)).compareTo(nums.get(first + loopCountA)) < 0) {
// here is where error is (line above)
newList.add(nums.get(mid + (loopCountB + 1)));
steps += 5;
loopCountB++;
}else {
newList.add(nums.get(first + loopCountA));
steps += 5;
loopCountA++;
}
}
}
for(int i = 0; (i - 1) < (last - first); i++) {
nums.set(first + i, newList.get(i));
steps+=2;
}
}
Here's the error...
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 5024 out of bounds for length 5000
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:458)
at Sorts.merge(Sorts.java:772)
at Sorts.timSort(Sorts.java:1193)
at Sorts.sortMenu(Sorts.java:255)
at Sorts.main(Sorts.java:33)
Simple main method which demonstrates it not working
int depthLimit
= (int)(2 * Math.floor(Math.log(nums.size()) /
Math.log(2)));
introSort(nums, 0, nums.size() -1, depthLimit);
I am working on a homework task where I am supposed to make a function that will do a binary insertion sort, but my function does not seem to work properly.
Here I have tried to combine a binary search function with a insertion sort function (it is specified in the homework task that it needs to be in the form of a function: insertionSort(int[] array, int lo, int hi))
public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int x= array[i];
while (lo < hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
pos = lo;
for (int j = i; j > pos; j--) {
array[j] = array[j-1];
}
array[pos] = x;
}
}
If I try to run it with the list {2,5,1,8,3}, the output will be
2 5 1 3 1 (if lo < hi and if lo > hi)
2 5 3 8 5 (if lo==hi)
What I am expecting though, is a sorted list...
Any idea of what I am doing wrong?
Just to give you a possible idea:
public static void insertionSort(int[] array) {
if (array.length <= 1) {
return;
}
// Start with an initially sorted part.
int loSorted = array.length - 1;
//int hiSorted = array.length;
while (loSorted > 0) {
// Take one from the array
int x = array[0];
// Where in the sorted part to insert?
int insertI = insertPosition(array, loSorted);
// Insert x at insertI
...
--loSorted;
}
}
whenever I need binary search, my function looks the following way:
public static void binarySearch(int arr[], int first, int last, int key){
int mid = (first + last)/2;
while( first <= last ){
if ( arr[mid] < key ){
first = mid + 1;
}else if ( arr[mid] == key ){
System.out.println("Element is found at index: " + mid);
break;
}else{
last = mid - 1;
}
mid = (first + last)/2;
}
if ( first > last ){
System.out.println("Element is not found!");
}
}
In your main method the call looks like:
public static void main(String[] args) {
int arr[] = {10,20,30,40,50};
int key = 30;
int last=arr.length-1;
binarySearch(arr,0,last,key);
}
I hope I was able to help you!
Thank you for your input. I changed the function a little bit, and it seems to be working now
` public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int j = i -1;
int x = array[i];
while (lo <= hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
break;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
while (j >= 0 && array[j] > x) {
array[j + 1] = array[j];
j = j - 1;
}
array[j + 1] = x;
}
}
the problem seemed to lay in the last part, where I was trying to move the elements into their right positions. The function is probably not perfect tho, so constructive criticism is welcome :)
I have this java code for QuickSort that works if there are no duplicates, however if there are any duplicates, the QuickSort fails. For example, if I want to QuickSort {5,3,3,1,7} my code will output {1,3,3,7,5}, and I can't seem to figure out why this is the case.
public static void quickSort(Integer[] nums) {
quickSort(nums, 0, nums.length-1);
}
private static void quickSort(Integer[] ary, int lo, int hi) {
//pick num # lo to be pivot
int pivot = lo;
int i = lo+1;
int j = hi;
if( lo==hi) {
return;
}
while(i <j) {
if(ary[i].compareTo(ary[pivot]) <=0 ) {
i++;
}
else if(ary[j].compareTo(ary[pivot]) >=0 ) {
j--;
}
else {
int temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
}
}
if(i == hi && j == hi) {
if(ary[pivot].compareTo(hi) > 0) {
int temp = ary[pivot];
ary[pivot] = ary[hi];
ary[hi] = temp;
pivot = hi;
}
else {
int temp1 = ary[pivot];
ary[pivot] = ary[i-1];
ary[i-1] = temp1;
pivot = i-1;
}
}
if(lo < pivot -1) {
quickSort(ary, lo, pivot-1);
}
if(pivot +1 < hi) {
quickSort(ary, pivot+1, hi);
}
}
If anyone could tell me what I'm doing wrong, that would be greatly appreciated!
Hi i have modified your code, please check corresponding comments
private static void quickSort(Integer[] ary, int lo, int hi) {
//pick num # lo to be pivot
int pivot = lo;
int i = lo+1;
int j = hi;
if( lo==hi) {
return;
}
//while(i <j) {
for(;;){//change from while to infinite for
while(ary[i].compareTo(ary[pivot]) <=0 && i<hi ) {//changed from if to while with boundary conditions
i++;
}
while(ary[j].compareTo(ary[pivot]) >0 && j>lo) { //change from if to while with boundary conditions and it is not >=0 only >
j--;
}
if(i<j){ //changed from else to if
int temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
}else{//added else block
break;
}
}
//you didn't handled i>j condition properly i.e when i>j you need to swap pivot and i-1
int temp1 = ary[pivot];
ary[pivot] = ary[i-1];
ary[i-1] = temp1;
pivot = i-1;
//Not required
/*if(i == hi && j == hi) {
if(ary[pivot].compareTo(hi) > 0) {
int temp = ary[pivot];
ary[pivot] = ary[hi];
ary[hi] = temp;
pivot = hi;
}
else {
int temp1 = ary[pivot];
ary[pivot] = ary[i-1];
ary[i-1] = temp1;
pivot = i-1;
}
}*/
if(lo < pivot -1) {
quickSort(ary, lo, pivot-1);
}
if(pivot +1 < hi) {
quickSort(ary, pivot+1, hi);
}
}
Thanks
if you want to quicksort use the algorithm from this site.
Quicksort
It works for me and the explanation is quite good I think.
I have been reading through all of the QuickSort questions on SO, but I cannot resolve this specific problem. By referencing the other questions and comparing my faults to theirs I have gotten to a specific point, that I cannot find the answer to, even in Debug mode.
I was repeatedly getting out of bounds -1, so I added a conditional check for
if(pivot > 0)
and that stopped the overflow, but since I am using 0 as my partition, It partitions once and then terminates. The first partition is correct, but if I change that number to include 0, the I get infinite recursion again. If I completely take the line out, I get index out of bounds errors that I cannot seem to tackle.
Here's where I am so far:
public class QuickSort {
int[] array;
public static void main(String[] args) {
QuickSort qs = new QuickSort();
qs.array = new int[] {35, 82, 2, 24, 57, 17};
qs.quickSort(qs.array, 0, qs.array.length - 1);
for(int i = 0; i < qs.array.length; i++) {
System.out.println(qs.array[i]);
}
}
public void quickSort(int[] array, int left, int right) {
if(array.length == 1) {
return;
}
if(left < right) {
int pivot = partition(array, left, right);
quickSort(array, left, pivot - 1);
quickSort(array, pivot + 1, right);
}
}
public int partition(int[] array, int left, int right) {
if(array.length == 1) {
return right;
}
int pivot = array[0];
int pivotIndex = 0;
int leftPointer = left - 1;
int rightPointer = right + 1;
while(pivotIndex < right) {
if(leftPointer > rightPointer) {
break;
}
leftPointer++;
while(leftPointer < array.length - 1 && array[leftPointer] <= pivot) {
leftPointer++;
}
rightPointer--;
while(rightPointer > leftPointer && array[rightPointer] > pivot) {
rightPointer--;
}
if(leftPointer < rightPointer) {
int temp = array[leftPointer];
array[leftPointer] = array[rightPointer];
array[rightPointer] = temp;
} else {
int temp = array[rightPointer];
array[rightPointer] = array[pivotIndex];
array[pivotIndex] = temp;
}
}
return rightPointer;
}
EDIT: After a few more alterations, I can now get it to always return an array without overflow, but it still only partitions once.
I'm pretty sure I fixed it now. You were increasing the left and right pointers within the partition method before you wanted to (outside of the "checks"). Change your partition method as follows:
public static int partition(int[] array, int left, int right) {
if(array.length == 1)
return right;
int pivot = array[0];
int pivotIndex = 0;
int leftPointer = left; // Remove the +1
int rightPointer = right; // Remove the +1
while(pivotIndex < right) {
if(leftPointer > rightPointer) {
break;
}
//leftPointer++;
while((leftPointer < array.length - 1) && (array[leftPointer] <= pivot)) {
leftPointer++;
}
//rightPointer--;
while((rightPointer > leftPointer) && (array[rightPointer] > pivot)) {
rightPointer--;
}
if(leftPointer < rightPointer) {
int temp = array[leftPointer];
array[leftPointer] = array[rightPointer];
array[rightPointer] = temp;
}
else {
int temp = array[rightPointer];
array[rightPointer] = array[pivotIndex];
array[pivotIndex] = temp;
}
}
return rightPointer;
}
You're returning "0" from partition whenever the array length is not 1, and setting that to the pivot. The if(pivot >= 0) will always be hit in that case, or it will iterate once if you used if(pivot > 0), which I think is the problem. If that's right, then correcting your return from partition (to "left" ?) should fix the problem.
I think you should change
if(leftPointer > rightPointer) {
break;
}
to
if(leftPointer >= rightPointer) {
break;
}
inside the while loop.
Also, I think you should compare leftPointer with rightPointer after either is changed,
// move to #### to perform compare after possible change
// if(leftPointer > rightPointer) break;
//leftPointer++;
while(leftPointer < array.length - 1 && array[leftPointer] <= pivot) leftPointer++;
//rightPointer--;
while(rightPointer > leftPointer && array[rightPointer] > pivot) rightPointer--;
//####
if(leftPointer > rightPointer) break;