I currently have the below code for my quick sort. As you can see it is not producing the correct output. Any help will be greatly appreciated. I need the pivot to be the first item in the array. As you can also see i am measuring the time it takes to run, but please ignore that for the time being.
edit: to be specific it works correctly when i have a list in descending order and ascending order(already sorted), but when i try a random list it does not work.
Output:
QuickSort:
Quick Sort Took 181023 nanoseconds
Quick Sort Took 0 milliseconds
Sorted Quick Sort: 25, 12, 17, 13, 20, 7, 5, 16, 11, 26, 24, 18, 9, 4, 21, 1, 23, 27, 15, 19, 28, 14, 8, 22, 6, 3, 2, 10, 29, 40, 37, 32, 44, 38, 35, 41, 39, 31, 42, 30, 43, 36, 34, 33, 45, 46, 47, 48, 49, 50,
Code:
class QuickSort {
public static int Partition(int[] numbers, int left, int right){
//selects the first item at position [0] as the pivot
//left is given 0 when the method is called
int pivot = numbers[left];
while (true)
{
while (numbers[left] < pivot)
left++;
while (numbers[right] > pivot)
right--;
if (left < right)
{
int temp = numbers[right];
numbers[right] = numbers[left];
numbers[left] = temp;
}
else
{
return right;
}
}
}
//method to check for special cases
public static void QuickSort_Check(int[] numbers, int left, int right)
{
//special case of 2 items to be sorted
if(right == 1){
if(numbers[0] >= numbers[1]){
System.out.print("This is a special case of 2 inputs: ");
System.out.print(numbers[1] + ", " + numbers[0]);
System.exit(0);
}
else {
System.out.print("This is a special case of 2 inputs: ");
System.out.print(numbers[0] + ", " + numbers[1]);
System.exit(0);
}
System.exit(0);
}
//special case of 1 item to be sorted
else if (right == 0){
System.out.print("This is a special case of 1 input: ");
System.out.print(numbers[0]);
System.exit(0);
}
else {
QuickSort_Iterative(numbers, left, right);
}
}
public static class QuickPosInfo
{
public int left;
public int right;
};
public static QuickPosInfo spot = new QuickPosInfo();
public static void QuickSort_Iterative(int[] numbers, int left, int right)
{
if(left >= right)
return; // Invalid index range
LinkedList<QuickPosInfo> list = new LinkedList< QuickPosInfo>();
spot.left = left;
spot.right = right;
list.add(spot);
while(true)
{
if(list.size() == 0)
break;
left = list.get(0).left;
right = list.get(0).right;
list.remove(0);
int pivot = Partition(numbers, left, right);
if(pivot > 1)
{
spot.left = left;
spot.right = pivot - 1;
list.add(spot);
}
if(pivot + 1 < right)
{
spot.left = pivot + 1;
spot.right = right;
list.add(spot);
}
}
}
}
This partition method correctly sorted half the array, then did not sort the other half so I believe the problem is in your QuickSort_Iterative(); when the pivot equals 21 it just infinitely swaps 20 and 21.
private static int partition(int[] arr,int left,int right) {
int pivot = arr[right];
int small = left-1;
for(int k = left;k < right;k++)
{
if(arr[right] <= pivot)
{
small++;
swap(arr,right,small);
}
}
swap(arr,right,small+1);
System.out.println("Pivot= "+arr[small+1]);//prints out every sort
System.out.println(Arrays.toString(arr));
return small+1;
}
private static void swap(int[] arr, int k, int small) {//easy swap method
int temp;
temp = arr[k];
arr[k] = arr[small];
arr[small] = temp;
}
UPDATE
Here is the requested method. I believe that the problem with your original one is that you are not modifying that values of left and right properly as the array is sorted.
void QuickSort(int arr[], int left, int right)
{
// create auxiliary stack
int stack[] = new int[right-l+1];
// initialize top of stack
int top = -1;
// push initial values in the stack
stack[++top] = left;
stack[++top] = right;
// keep popping elements until stack is not empty
while (top >= 0)
{
// pop right and l
right = stack[top--];
left = stack[top--];
// set pivot element at it's proper position
int p = partition(arr, left, right);
// If there are elements on left side of pivot,
// then push left side to stack
if ( p-1 > left )
{
stack[ ++top ] = l;
stack[ ++top ] = p - 1;
}
// If there are elements on right side of pivot,
// then push right side to stack
if ( p+1 < right )
{
stack[ ++top ] = p + 1;
stack[ ++top ] = right;
}
}
}
I don't know that will help you out or not you can also try the below code for same.
public class Demo {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSort(0, length - 1);
}
private void quickSort(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
i++;
j--;
}
}
if (lowerIndex < j)
quickSort(lowerIndex, j);
if (i < higherIndex)
quickSort(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void main(String a[]){
Demo sorter = new Demo();
int[] input = {8,693,29,3,2,8,29,82,4,26,2,62,82,6,52,9,42,6,52,66,2,8};
sorter.sort(input);
for(int i:input){
System.out.print(i);
System.out.print(" ");
}
}
}
Related
i have been doing research on the jump search algorithm in an array. But i am confused on how you can use the search method with strings. Can anyone give me a link on where to look, or an example on here? Every example i have seen has been with numbers
public class JumpSearch
{
public static int jumpSearch(int[] arr, int x)
{
int n = arr.length;
int step = (int)Math.floor(Math.sqrt(n));
int prev = 0;
while (arr[Math.min(step, n)-1] < x)
{
prev = step;
step += (int)Math.floor(Math.sqrt(n));
if (prev >= n)
return -1;
}
while (arr[prev] < x)
{
prev++;
if (prev == Math.min(step, n))
return -1;
}
if (arr[prev] == x)
return prev;
return -1;
}
public static void main(String [ ] args)
{
int arr[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21,
34, 55, 89, 144, 233, 377, 610};
int x = 55;
// Find the index of 'x' using Jump Search
int index = jumpSearch(arr, x);
System.out.println("\nNumber " + x +
" is at index " + index);
}
}
So I tried to write a code to select kth smallest element in a given input integer array using quick sort, but for some reason as you can see in the code below,
public static int partition(int[] input, int first, int end) {
int pivot = input[(first + end)/2];
int i = first - 1;
int j = end + 1;
while (true) {
do {
i++;
} while (input[i] < pivot);
do {
j--;
} while (input[j] > pivot);
if (i < j)
swap(input, i, j);
else
return j;
}
}
public static void swap(int[] input, int i, int j){
int temp = input[i];
input[i] = input[j];
input[j] = temp;
}
public static int select(int[] input, int k){
return mySelect(input, 0, input.length-1, k);
}
public static int mySelect(int[] input, int left, int right, int k){
// If k is smaller than number of elements in array
if (k > 0 && k <= right - left + 1) {
int pos = partition(input, left, right);
if (pos - left == k - 1)
return input[pos];
// If position is larger, recursive call on the left subarray
if (pos - left > k - 1)
return mySelect(input, left, pos-1, k);
// if smaller, recursive call on the right subarray
return mySelect(input, pos+1, right, k-pos+left-1);
}
System.out.println("Invalid k value");
return Integer.MAX_VALUE;
}
public static void main(String[] args){
test2 = new int[]{99, 44, 77, 22, 55, 66, 11, 88, 33};
int[] test2 = new int[]{99, 44, 77, 22, 55, 66, 11, 88, 33};
//testing for selecting kth min
System.out.println("The 1st smallest : " + select(test2, 1));
System.out.println("The 2nd smallest : " + select(test2, 2));
System.out.println("The 3rd smallest : " + select(test2, 3));
System.out.println("The 4th smallest : " + select(test2, 4));
System.out.println("The 6th smallest : " + select(test2, 6));
System.out.println("The 9th smallest : " + select(test2, 9));
}
but my 1st smallest element appears 22, 2nd smallest returns 11, while others values are normal.
can someone please help me find what is the mistake I made?
The problem in your code is in the partition. The do while is the culprit here. You are updating the positions before checking the conditions and that's causing the problem with the last swap operation.
Update your method to this and you will be good to go
public static int partition(int[] input, int first, int end) {
int pivot = input[(first + end)/2];
int i = first;
int j = end;
while (true) {
while (input[i] < pivot) {
i++;
}
while (input[j] > pivot) {
j--;
}
if (i < j)
swap(input, i, j);
else
return j;
}
}
I wrote this code while I was learning quick sort. The mistake I made was in not realizing that
'left' and 'right' are indices in array whereas,
'pivot' is one of the values stored in array
You can study my code below and determine what's wrong in your understanding of the algorithm!!
public class QuickSort
{
public static void main(String[] args)
{
int[] nums = {1,5,9,2,7,8,4,2,5,8,9,12,35,21,34,22,1,45};
quickSort(0,nums.length-1,nums);
//print nums to see if sort is working as expected,omit printing in your case
print(nums);
//now you can write code to select kth smallest number from sorted nums here
}
/**
* left and right are indices in array whereas
* pivot is one of the values stored in array
*/
static int partition(int left, int right , int pivot, int[] nums)
{
int leftIndex = left -1;
int rightIndex = right;
int temp = 0;
while(true)
{
while( nums[++leftIndex] < pivot );
while( rightIndex>0 && nums[--rightIndex] > pivot );
if( leftIndex >= rightIndex ) break;
else//swap value at leftIndex and rightIndex
{
temp = nums[leftIndex];
nums[leftIndex]= nums[rightIndex];
nums[rightIndex] = temp;
}
}
//swap value at leftIndex and initial right index
temp = nums[leftIndex];
nums[leftIndex]= nums[right];
nums[right] = temp;
return leftIndex;
}
static void quickSort( int leftIndex , int rightIndex ,int[] nums)
{
if( rightIndex-leftIndex <= 0 ) return;
else
{
int pivot = nums[rightIndex];
int partitionIndex = partition(leftIndex, rightIndex , pivot,nums);
quickSort(leftIndex,partitionIndex-1,nums);
quickSort(partitionIndex+1,rightIndex,nums);
}
}
static void print(int[] nums)
{
for( int i = 0 ; i < nums.length ; i++ )
{
System.out.print(nums[i]+", ");
}
}
}
This is my quicksort Code. It gives me a wrong answer but i think my partition function is correct.
public class Quick_Sort {
public static void main(String[] args)
{
int a[] = {99,88,5,4,3,2,1,0,12,3,7,9,8,3,4,5,7};
quicksort(a, 0, a.length-1);
}
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
int j = hi-1;
while(i<j)
{
if(a[i]<=a[pivot])
{
i++;
}
if(a[i]>a[pivot])
{
if((a[i]>a[pivot]) && (a[j]<=a[pivot]))
{
int temp= a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
if(a[j]>a[pivot])
{
j--;
}
}
}
int temp= a[i];
a[i]=a[pivot];
a[pivot]=temp;
return i;
}
static void quicksort(int[] a, int low, int hi)
{
if(low>=hi)
{
return;
}
int split = partition(a, low, hi);
quicksort(a, low, split-1);
quicksort(a, split+1, hi);
}
}
This is the final output:
1 0 3 2 3 4 4 5 5 7 3 7 8 9 12 88 99
Tried dry running it, couldn't see the error
In your partition method you have assigned j to hi - 1. It should be set to hi only.
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
// int j = hi-1; // CHANGE THIS TO
int j = hi; // THIS
while(i<j)
I got this output after I made that change:
[0, 1, 2, 3, 3, 3, 4, 4, 5, 5, 7, 7, 8, 9, 12, 88, 99]
Hope this helps!
This is C# code:
public void RecursiveQuickSort(int[] array, int start, int end)
{
if (start < end)
{
int pivot = start;
int left = start + 1;
int right = end;
while (true)
{
while (array[left] <= array[pivot] && left < right)
left++;
while (array[right] > array[pivot] && left < right)
right--;
if (left < right)
{
Swap(array, left, right);
}
else
{
pivot = (array[pivot] > array[left]) ? left : left - 1;
Swap(array, start, pivot);
RecursiveQuickSort(array, start, pivot - 1);
RecursiveQuickSort(array, pivot + 1, end);
return;
}
}
}
}
private void Swap(int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
This is a very good implementation and is much more Java standard. Maybe you want to take a look here, obviously all credits go to the original author.
http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html
this is how I made it C:
private static List<Integer> recursive_quick_sort (List<Integer> list){
if (list.size()< 2){
return list;
}else {
int pivot = list.get(0);
List<Integer> less = list.stream().filter(element -> element < pivot ).collect(Collectors.toList());
List <Integer> greater = list.stream().filter(element -> element > pivot ).collect(Collectors.toList());
List<Integer> newList = Stream.of(recursive_quick_sort(less),List.of(pivot),recursive_quick_sort(greater))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return newList;
}
}
I try to use "randomized pivot" method to find the Kth min elem among given array.
[The code]
public class FindKthMin {
// Find the Kth min elem by randomized pivot.
private static void exchange (int[] givenArray, int firstIndex, int secondIndex) {
int tempElem = givenArray[firstIndex];
givenArray[firstIndex] = givenArray[secondIndex];
givenArray[secondIndex] = tempElem;
}
private static int partition (int[] givenArray, int start, int end, int pivotIndex) {
// Debug:
//System.out.println("debug: start = " + start);
//System.out.println(">> end = " + end);
//System.out.println(">> pivotIndex = " + pivotIndex);
int pivot = givenArray[pivotIndex];
int left = start - 1;
int right = end;
boolean hasDone = false;
while (!hasDone) {
while (!hasDone) {
left ++;
if (left == right) {
hasDone = true;
break;
}
if (givenArray[left] >= pivot) {
// Exchange givenArray[left] and the givenArray[right].
exchange(givenArray, left, right);
break;
}
}
while (!hasDone) {
right --;
if (left == right) {
hasDone = true;
break;
}
if (givenArray[right] < pivot) {
// Exchange the givenArray[right] and the givenArray[left].
exchange(givenArray, right, left);
break;
}
}
}
givenArray[right] = pivot;
// Debug:
//System.out.println(">> split = " + right);
//System.out.println();
return right;
}
private static int findKthMin_RanP_Helper (int[] givenArray, int start, int end, int k) {
if (start > end) return -1;
// Generate a random num in the range[start, end].
int rand = (int)(start + Math.random() * (end - start + 1));
// Using this random num as the pivot index to partition the array in the current scope.
int split = partition(givenArray, start, end, rand);
if (k == split + 1) return givenArray[split];
else if (k < split + 1) return findKthMin_RanP_Helper(givenArray, start, split - 1, k);
else return findKthMin_RanP_Helper(givenArray, split + 1, end, k);
}
public static int findKthMin_RanP (int[] givenArray, int k) {
int size = givenArray.length;
if (k < 1 || k > size) return -1;
return findKthMin_RanP_Helper(givenArray, 0, size - 1, k);
}
// Main method to test.
public static void main (String[] args) {
// Test data: {8, 9, 5, 2, 8, 4}.
int[] givenArray = {8, 9, 5, 2, 8, 4};
// Test finding the Kth min elem by randomized pivot method.
System.out.println("Test finding the Kth min elem by randomized pivot method, rest = " + findKthMin_RanP(givenArray, 1));
}
}
But the result is unstable, sometimes right and sometimes wrong.
Please have a look at the 5th row of findKthMin_RanP_Helper method:
If I change this int split = partition(givenArray, start, end, rand); to int split = partition(givenArray, start, end, end);, the result is always correct. I really can not find what's wrong with this.
EDIT:
The problem comes from the "partition", the new partition should like this:
private static int partition_second_version (int[] givenArray, int start, int end, int pivotIndex) {
int pivot = givenArray[pivotIndex];
int left = start;
int right = end;
while (left <= right) {
while (givenArray[left] < pivot) left ++;
while (givenArray[right] > pivot) right --;
if (left <= right) {
// Exchange givenArray[left] and givenArray[right].
exchange(givenArray, left, right);
left ++;
right --;
}
}
return left;
}
And the findKthMin_RanP_Helper should be changed like this:
private static int findKthMin_RanP_Helper (int[] givenArray, int start, int end, int k) {
if (start > end) return -1;
// Generate a random num in the range[start, end].
int rand = start + (int)(Math.random() * ((end - start) + 1));
// Using this random num as the pivot index to partition the array in the current scope.
int split = partition_second_version (givenArray, start, end, rand);
if (k == split) return givenArray[split - 1];
else if (k < split) return findKthMin_RanP_Helper(givenArray, start, split - 1, k);
else return findKthMin_RanP_Helper(givenArray, split, end, k);
}
Your partition routine could be simplified...
private static int partition(int[] givenArray, int start, int end, int pivotIndex) {
final int pivot = givenArray[pivotIndex];
int left = start;
int right = end;
while (left < right) {
while (left < givenArray.length && givenArray[left] <= pivot) {
left++;
}
while (right > -1 && givenArray[right] > pivot) {
right--;
}
if (left >= right) {
break;
}
exchange(givenArray, right, left);
}
return right;
}
The one bug I see in your code is your partition routine. In the first exchange call, it is not guaranteed that the right index will always point to a value which is < pivot.
I have two methods that I intend to perform an insertion sort on an array of ints. The first method does the outer loop of the insertion sort algorithm while the second method inserts the particular element in the correct position recursively. For example:
int [] list = {20, 50, 30, 10, 60, 40};
sort(list);
The result should be {10,20,30,40,50,60}
My problem is in the insert method; Here is my code:
public static void sort(int[] list) {
int position;
for (position = 1; position < list.length; position++) {
insert(list, list[position], position);
}
}
public static void insert(int[] list, int element, int position) {
int position2 = position - 1;
if (position == list.length - 1) {
// do nothing
} else {
while ((position > 0) && (list[position - 1] > element)) {
element = list[position - 1];
insert(list, element, position - 1);
}
list[position] = element;
}
}
Currently my output is,
{20, 50, 50, 50, 60, 40}
I do not completely understand recursion. Please help
When you make some function recursive, there should be a recursion end condition along with other conditions.
Run this version and try to see what is that you're doing wrong.
Try this version:
public static void insertInOrder(int element, int[] a, int first, int last) {
if (element >= a[last])
a[last + 1] = element;
else if (first < last) {
a[last + 1] = a[last];
insertInOrder(element, a, first, last - 1);
}
else // first == last and element < a[last]
{
a[last + 1] = a[last];
a[last] = element;
}
}
public static void insertion_sort_recur(int[] arr, int first, int last) {
if (first < last) {
insertion_sort_recur(arr, first, last - 1); // avoids looping thru arr[0..last-1]
insertInOrder(arr[last], arr, first, last - 1); // considers arr[last] as the first element in the unsorted list
}
}
public static void main(String args[]) {
int A[] = { 5, 3, 2, 4, 6, 1 };
insertion_sort_recur(A, 0, 5);
for(int i=0; i < A.length; i++) {
System.out.println(A[i]);
}
}
Source:
http://analgorithmaday.blogspot.com/2011/01/insertion-sortrecursive-method.html
Try below code by providing else as an integer array, with sortedIndex as index of first element and and index as index of second element:
public static void insertionSort(int[] ele, int sortedIndex, int index) {
if (sortedIndex < ele.length) {
if (index < ele.length) {
if (ele[sortedIndex] > ele[index]) {
ele[sortedIndex] += ele[index];
ele[index] = ele[sortedIndex] - ele[index];
ele[sortedIndex] = ele[sortedIndex] - ele[index];
}
insertionSort(ele, sortedIndex, index + 1);
return;
}
if (index == ele.length) {
sortedIndex++;
}
insertionSort(ele, sortedIndex, sortedIndex + 1);
}
}