I'm running a quick sort on 2000 integers read from a file and count the comparisons and swaps but I'm not sure if my counters are in the right place as my numbers seem off, or is something wrong with the sort?
public int partition(int array[], int low, int high)
{
int pivot = array[low];
while(low < high)
{
while(pivot < array[high] && low < high)
{
high = high - 1;
compCounter++;
}
if(high != low)
{
array[low] = array[high];
SwapCounter++;
low++;
}
while(array[low] < pivot && low < high)
{
low = low +1;
compCounter++;
}
if(high != low)
{
array[high] = array[low];
SwapCounter++;
high--;
}
}
SwapCounter++;
int temp = array[high];
array[high] = pivot;
return high;
}
public void quickSort(int array[], int low, int high)
{
if (low < high)
{
int pivotPoint = partition(array, low, high);
quickSort(array, low, pivotPoint-1);
quickSort(array, pivotPoint+1, high);
}
}
I check your code but I think you do some more works (and maybe produce invalid result in some special case). I change your code in some how which is true and you can find it with some search and place counter in correct place.
private static int CompCounter, SwapCounter;
public static void main(String[] args) {
int[] a = {3, 2, 1, 5, 6, 7 , 4, -1};
quickSort(a, 0, a.length - 1);
System.out.println(Arrays.toString(a));
}
public static int partition(int array[], int low, int high) {
int pivot = array[high];
int lowBound = low;
for (int i = low; i < high; i++)
{
CompCounter++;
if (array[i] < pivot) {
int temp = array[lowBound];
array[lowBound] = array[i];
array[i] = temp;
lowBound++;
SwapCounter++;
}
}
SwapCounter++;
array[high] = array[lowBound];
array[lowBound] = pivot;
return lowBound;
}
public static void quickSort(int array[], int low, int high) {
if (low < high)
{
int pivotPoint = partition(array, low, high);
quickSort(array, low, pivotPoint - 1);
quickSort(array, pivotPoint + 1, high);
}
}
If you want, you can use another way to partition for sort (another algorithm):
public static int partitionSecondWay(int array[], int low, int high) {
int pivot = array[low];
int i = low - 1;
int j = high + 1;
while (true)
{
do
{
i++;
CompCounter++;
} while (array[i] < pivot);
do
{
j--;
CompCounter++;
} while (array[j] > pivot);
if (i >= j)
{
CompCounter++;
return j; // notice if you use this way, then in quicksort you
// must use quicksort(array, low, partition) and
// quicksort(array, partition + 1, high)
}
int temp = array[i];
array[i] = array[j];
array[j] = temp;
SwapCounter++;
}
}
I hope these helps you. If something is wrong, comment it.
Related
When I use mergeSort to sort a portion of an array it gives ArrayIndexOutOfBoundsException but if I merge a portion starting from the index 0 to any other index it works why?
public static void mergeSort(int[] arr, int[] temp, int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2;
mergeSort(arr, temp, low, mid);
mergeSort(arr, temp, mid + 1, high);
merge(arr, temp, low, mid, high);
}
}
public static void merge(int[] arr, int[] temp, int low, int mid, int high) {
for (int i = low; i <= high; i++) {
temp[i] = arr[i];
}
int i = low;
int j = mid + 1;
int k = low;
while (i <= mid && j <= high) {
if (temp[i] <= temp[j]) {
arr[k] = temp[i];
i++;
} else {
arr[k] = temp[j];
j++;
}
k++;
}
while (i <= mid) {
arr[k] = temp[i];
i++;
k++;
}
}
I get an error ArrayIndexOutOfBoundsException.
The argument high in your code is the index of the last element in the slice to be sorted or merged. Are you sure you pass array.length - 1 as the second argument to the topmost call to mergeSort()?
Also make sure you allocate the temp array with the same length as the array to be sorted.
This convention is confusing and does not allow sorting empty arrays. You might instead use a more consistent convention where high is the index of the element after the last one and you pass array.length to the topmost call.
Here is a modified version:
public static void mergeSort(int[] arr, int[] temp, int low, int high) {
if (high - low > 1) {
int mid = low + (high - low) / 2;
mergeSort(arr, temp, low, mid);
mergeSort(arr, temp, mid, high);
merge(arr, temp, low, mid, high);
}
}
public static void merge(int[] arr, int[] temp, int low, int mid, int high) {
for (int i = low; i < high; i++) {
temp[i] = arr[i];
}
int i = low;
int j = mid;
int k = low;
while (i < mid && j < high) {
if (temp[i] <= temp[j]) {
arr[k++] = temp[i++];
} else {
arr[k++] = temp[j++];
}
}
while (i < mid) {
arr[k++] = temp[i++];
}
}
For a class project I am supposed to test Quicksort with different pivots (Low, High, Midpoint, Random, Median, and Mean), but I am having trouble getting it to work with wall of them. So far I have used two different Quicksort methods and I have been able to sort a random array with everything up to random, but not with mean or median. "Partition" work with Low, Midpoint and Random, while "Partition1" works with High.
Any help is greatly appreciated and If there is any more I should add just let me know.
Here is the code that I've used so far. "Partition1" is from GFG and "Partition" is from my textbook.
`
import java.util.Arrays;
import java.util.Random;
public class QSort {
public static int comparisonCount;
public static int swapCount;
public static void main(String[] args){
Random r = new Random();
int N= 10;
int[] test = new int[N]; //random integer array
for (int i =0; i < test.length; i++){
test[i] = r.nextInt(N*2);
}
System.out.println(Arrays.toString(test));
long startTime = System.nanoTime();
Quicksort(test, 0, test.length-1);
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println(Arrays.toString(test));
System.out.println("Number of Comparisons "+ comparisonCount);
System.out.println("Number of swaps "+ swapCount);//1000000
System.out.println("QuickSort Duration in millisecond is "+(duration/1000000));
System.out.println("length is "+(test.length-1));
}
public static double median(int[] arr){
double median;
if (arr.length % 2 == 0) {
median = ((double) arr[arr.length / 2] + (double) arr[arr.length / 2 - 1]) / 2;
}
else {
median = (double) arr[arr.length / 2];
}
return median;
}
static void swap(int[] arr, int i, int j)
{
swapCount++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static int Partition1(int[] arr, int low, int high)
{
int pivot =arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++)
{
if(largerThan(arr[j],pivot))
{
i++;
swap(arr, i, j);
}
}
swap(arr, i+1, high);
return (i+1);
}
public static int mean(int[] arr){
double total = 0;
for(int i=0; i<arr.length; i++){
total = total + arr[i];
}
double average = total / arr.length;
return (int)average;
}
public static int Partition(int[] numbers, int low, int high) {
int midpoint = low + (high - low)/2; // Calculate Midpoint
//Random rand= new Random(); // for random pivot
//int pivot = numbers[rand.nextInt(high-low)+low];
int pivot = numbers[high];
boolean done = false;
while (!done) {
while (largerThan(numbers[low], pivot)) {
low+=1;
}
while (largerThan(pivot, numbers[high])) {
high-=1;
}
if (low >= high) {
done = true;
}
else {
swap(numbers, low, high);
low+=1;
high-=1;
}
}
return high;
}
public static boolean largerThan( int i, int m){
comparisonCount++;
return i < m;
}
public static void Quicksort(int[] numbers, int low, int high) {
if (high <= low || low >= high) {
return;
}
var Index = Partition1(numbers, low, high);
Quicksort(numbers, low, Index-1); //Index-1 for Partion1 and just Index for Partition
Quicksort(numbers, Index + 1, high);
}
}
`
Example C code for Lomuto Partition. It swaps middle element to last, but that can be removed. Recurse on smaller, loop on larger limits stack space complexity to O(log2(n)), but worst case time complexity remains O(n^2). You don't need uint64_t either (just use int instead).
void QuickSort(uint64_t a[], int lo, int hi)
{
while (lo < hi){
uint64_t t;
uint64_t p = a[(lo+hi)/2]; /* use mid point for pivot */
a[(lo+hi)/2]= a[hi]; /* swap with a[hi] */
a[hi] = p;
int i = lo;
for (int j = lo; j < hi; ++j){ /* Lomuto partition */
if (a[j] < p){
t = a[i];
a[i] = a[j];
a[j] = t;
++i;
}
}
t = a[i];
a[i] = a[hi];
a[hi] = t;
if(i - lo <= hi - i){ /* recurse on smaller partiton, loop on larger */
QuickSort(a, lo, i-1);
lo = i+1;
} else {
QuickSort(a, i+1, hi);
hi = i-1;
}
}
}
Please help me. I need to modify quicksort with an average of O(n) time complexity that just sorts half of the array as I'm just trying to find the medium of the array.
Heres my quicksort algorithm before any changes:
static void swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static int partition(int[] arr, int low, int high){
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++){
if (arr[j] < pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return (i + 1);
}
static void quickSort(int[] arr, int low, int high){
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
I am running a quick sort on 2000 integers read from a file but the number of comparisons and swaps i am getting seem high. Are my counters in the right place? or is something wrong with the sort?
public int partition(int array[], int low, int high)
{
int pivot = array[high];
int i = (low-1);
for (int j = low; j < high; j++)
{
compCounter++;
if (array[j] <= pivot)
{
i++;
int temp = array[i];
array[i] = array[j];
array[j] = temp;
SwapCounter++;
}
}
int temp = array[i+1];
array[i+1] = array[high];
array[high] = temp;
SwapCounter++;
return i+1;
}
public void quickSort(int array[], int low, int high)
{
if (low < high)
{
int pivotPoint = partition(array, low, high);
quickSort(array, low, pivotPoint-1);
quickSort(array, pivotPoint+1, high);
}
}
Your counters are correct.
Just a quick suggestion - move the swap code in a separate function swap(array, fromIndex, toIndex)
The code is working fine for test cases like {3,3,3,3}, {1,2,3,4}, {2,4,1,3,5} etc. But it isn't working for {1,20,6,4,5,2,7,3,5}, which should return 18 inversions. My code is getting me 16 inversions.
class Test{
static int count =0;
public static void main(String[] agrs) {
int[] arr = new int[] {1,20,6,4,5,2,7,3,5};
sort(arr);
System.out.println("\n"+count);
}
private static void sort(int[] arr) {
int length = arr.length;
int tempArr[] = new int[length];
divideAndConquer(arr,tempArr,0,length-1);
}
private static void divideAndConquer(int[] arr, int[] tempArr, int low, int high) {
if(low < high){
int middle = low + (high - low) / 2;
divideAndConquer(arr, tempArr, low, middle);
divideAndConquer(arr, tempArr, middle + 1, high);
merge(arr, tempArr, low, middle, high);
}
}
private static void merge(int[] arr, int[] tempArr, int low, int middle,int high) {
for (int i = low; i <= high; i++)
tempArr[i] = arr[i];
int i = low, j = middle + 1, k = low;
while (i <= middle && j <= high) {
if(tempArr[i] < tempArr[j]) {
arr[k] = tempArr[i];
i++;
}
else {
arr[k] = tempArr[j];
if(tempArr[i] != tempArr[j])
count += middle+1 - i;
System.out.println(count);
j++;
}
k++;
}
while (i <= middle) {
arr[k] = tempArr[i];
k++;
i++;
}
}
}
Just change the line
if(tempArr[i] < tempArr[j]) {
to
if(tempArr[i] <= tempArr[j]) {
and the problem will be solved.