Swaps and Comparisons in Quicksort - c

I think I have managed to figure the comparisons but I am trying to figure out how can I count the numbers of swaps. I have a problem with the value of swapcounter and the recursion. Any ideas?
int quicksort (int nums[],int n,int left,int right){//quicksort takes an array, the leftmost index and the rightmost index
int swapCounter=0;
int i=left,j=right,temp;
int comparisonCounter = 0;
int pivot = nums[(left + right) / 2];
/* partition */
while(i<=j){
comparisonCounter++;
while(nums[i]<=pivot)
i++;
while(nums[j]>pivot)
j--;
if(i<=j){
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
i++;
j--;
swapCounter++;
}
}
/* recursion */
if (left < j)
comparisonCounter+=quicksort(nums,n, left, j);
if (i < right)
comparisonCounter+=quicksort(nums,n, i, right);
printf("\nSwaps=%d\n",swapCounter);
return comparisonCounter;
}

You can:
Make swapcounter global.
Make the function take a pointer to the variable.
Make the function call another function to do the counting, thus making maintaining the counter state Someone Else's problem.

Related

C Lang: Quick sorting 5 elements but doesn't sort 10 elements

I am confused on why code only sorts 5 elements but not 10 elements. This method was described to me during my office visit with my professor. So I followed his instructions when I coded this. Can someone please help me fix this problem? My code works but it doesn't work on a bigger array. I know it is too late for someone to help before its due but I just want to understand what I had done in this code.
Thank You
/* Homework3.c
Qucksort arrays
Jared DaRocha
3/1/2020
*/
#include <stdio.h>// preprocessor
int partition(int arr[], int first, int end);// function declaration
void quickSort(int arr[], int first, int end);// function declaration
int main(void)// beginning of main
{
//Data
int array[5];// creates an array of 5 elements
int size = sizeof(array) / sizeof(array[0]); // calculates size of the array
// prompt user to input data to input int the array
printf("Enter 5 numbers to add in the array");
// prompts user to input 10 numbers
for(int i =0;i<size; i++)
{
scanf("%d", &array[i]);// stores user-defined data into the array
}
// call the function to sort the array
quickSort(array, 0, size -1);
// prints array
for (int i = 0; i < size; i++)
{
printf("%d ", array[i]);
}
printf("\n");
return 0;
}
int partition(int arr[], int low, int high)// Function declaration
{
//Data
int partition = arr[low]; // partition number
// infinite for loop
for (;;)
{
// decrement high while partition is smaller than element of high
while(partition <arr[high])
{
high--;
}
// if partition is greater than element of high, swap high with low element since low element is the pivot
if(partition > arr[high]){
int temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;
low++;
}
// increment low while partition is greater than element of low
while(partition > arr[low])
{
low++;
}
// swap low and next element in the right if partition is less than element of low
if(partition < arr[low])
{
int temp = arr[low];
arr[low] = arr[low+1];
arr[low+1] = temp;
}
// if low is same as high then exit loop
if(high == low)
{
break;
}
}
return low;
}
void quickSort(int arr[], int first, int end) // function definition
{
if (first < end)
{
int partitionIndex = partition(arr, first, end);
quickSort(arr, first, (partitionIndex - 1));
quickSort(arr, (partitionIndex+1 ), end);
}
}
`
If you check the algorithm quicksort, you'll find how the array is divided into two slices that don't overlap, but also don't leave a single element hung around. You do this, just between both slices, you leave a single element. You divide the array in two slices and one single array element that doesn't participate in the recursive calls to the other slices.... and that's incorrect. What you know is that all elements of the inferior slice are less than the token, and the rest are greater than or equal than the token... but the point of division can be any element of the array subpart that corresponds.
By the way, the code or partition is completely incorrect. You first select one element that will act as a token, you can select it as any element of the array or as the average value of all of them, it doesn't matter... you are not going to put it in the array. then search from the end elements that are under the array, and search from the beginning elements that are over the token, once you have one such pair, switch them, but you exchange the found elements with the token, which not only doesn't do what is expected, but introduces copies of the token (and change its value) thing that will trash your array.
You are not searching for an array element... you are searching for a place (between to adjacent elements) where to divide your array, and the subarrays will be from beg, to pos-1, and from pos to end, (or from beg to pos, then from pos + 1 to end) but don't ignore the central element, because you know it belongs to an array, but it's not necessary the token.

Can not print properly a quicksort arranged matrix

I can not properly print the steps given by the quicksort algorithm. This function works when N=1, which means that the values in the matrix only repeat once, but for N>1 it does not print it properly.
This is for a program I am writing to represent the different sorting algorithms steps with the console.
void quicksort(int *target, int left, int right) {
char charac[MAX*N][MAX]; // this is the array I am going to print on screen
if(left >= right)
return;
int i = left, j = right;
int tmp, pivot = target[i];
for(;;) {
while(target[i] < pivot)
i++;
while(pivot < target[j])
j--;
if(i >= j)
break;
tmp = target[i];
target[i] = target[j];
target[j] = tmp;
i++; j--; //normal quicksort until here
for(int k=0;k<MAX*N;k++){ /*Here begin two loops that put the cursor on a certain point on the screen and then gives values to char[][]*/
GotoXY(k+30,5);
for(int l=0;l<MAX;l++){
If(l<target[k]) // if the value of the given vector is lower than l writes a space
charac[k][l]=32;
else
charac [k][l]=219; // else a block
printf("%c ",charac[k][l]); // print the block or space
GotoXY(k+35,5+l); // go to the next point of the column
}
printf("\n");
}
system("cls"); // clear the screen for the next graph
}
quicksort(target, left, i-1);
quicksort(target, j+1, right);
}
I expect to sort the values properly even if they are repeated but the result are not even close to that.
Here it is for N=1 at the beginning:
At the end:
With N=2 it is generated properly:
But this is the result:
It is not even close to something fine.
Thanks for your time.

Recursive function to find the number of continuous sub-sequences in an array having a sum in the given range

I wrote this code. The idea is to split the array into 2 parts and find the number of sub-sequences that satisfy the given condition. Now there can also be a sub-sequence with elements from both subarrays. Hence I wrote the crossub function.
The subarray function is going on an infinite loop (It's continuously printing the debug statement "BBBBBBBB"). I spent some time on this, but I guess I need some help.
Note : New to programming. I know the code is a piece of shit. But I am getting better.
#include <stdio.h>
#include <stdlib.h>
void crossub(int * A,int mid, int start, int end, int lbound, int ubound, int **k)
{
int leftsum = A[mid];
int crossum;
int rightsum = 0;
int i;int j;
for(i = mid -1; i>=0; i--)
{
leftsum = leftsum + A[i];
for(j = mid +1; j <=end; j++)
{
rightsum = rightsum + A[j];
crossum = rightsum + leftsum;
if (lbound <= crossum && crossum <= ubound) k++;
else if(crossum > ubound) break;
}
}
return;
}
void subarray(int * A, int start, int end, int lbound, int ubound, int *count)
{
printf("BBBBBBBBB ");
if(start == end)
{
if(lbound <= A[start] && A[start] <= ubound)
{
count++;
}
return;
}
int **k; int mid;
k = &count;
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
return;
}
int numRange(int* A, int n, int lbound, int ubound)
{
// printf("AAAAAAAAAAA");
int p = 0;
int *count;
count = &p;
subarray(A, 0, n-1,lbound,ubound, count);
return p;
}
int main()
{
int A[] = {30, 5,1,0,2, 15,20,25};
int n = sizeof(A)/sizeof(A[0]);
printf("%d", n);
int lbound = 6; int ubound = 8;
int k = numRange(A, n,lbound, ubound);
printf("%d ", k);
return 0;
}
I'm not sure that recursion is relevant here. The way here is to always have a range and check its sum. Initial range should contain the single first item (range can be defined via start and end indexes), initial value for sum should be equal to value of . Further processing is:
If your sum is less than you're looking for, expand range incrementing its end index and adding value of new item to current value of range's sum;
If your sum is greater than you're looking for, reduce range incrementing its start index and substracting value of excluded item from range's sum;
If your sum is OK for you, return it.
Dealing with ranges:
If your sum is less than you're looking for, and you're unable to increment its end index because it points to the last item in array you're looking through, you may return a result that says no range is satisfying your requirements;
If your sum is greater than you're looking for, and you're unable to increment its start index because it points to the last item in array, you may also return same "no answer" result.
I'm sure there is no efficient way of dealing with ranges using "divide and conquer" strategy.
Regarding your infinite loop, the issue is in the subarray function, namely:
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
As you can see, this is going to keep going forever, because you never change the values of start/end, so you keep calling subarray on the same section.
Although, as already stated by the first answer, this might not be the best way, but you can remove the while loop and see if it works, even if it might not be the best solution.

Kth Ranked Element Among 2 Unsorted Arrays

Let us suppose we have two arrays A[] and B[]. Each array contains n distinct integers which are not sorted. We need to find kth ranked element in the union of the 2 arrays in the most efficient way possible.
(Please dont post answers about merging the arrays and then sorting them to return kth index in the merged array)
You can use the selection algorithm to find the Kth item, in O(N) time, where N is the sum of the sizes of the arrays. Obviously, you treat the two arrays as a single large array.
Union of arrays can be done in linear time. I am skipping that part.
You can use the partition() algorithm which is used in the quick sort. In quick sort, the function will have to recurse two branches. However here we will just conditionally invoke the recursive call and thus only 1-branched recursion.
Main concept: partition() will place the chosen PIVOT element at its appropriate sorted position. Hence we can use this property to select that half of the array in which we are interested and just recurse on that half. This will prevent us from sorting the entire array.
I have written the below code based on the above concept. Assumption rank = 0 implies the smallest element in the array.
void swap (int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int partition (int a[], int start, int end)
{
/* choose a fixed pivot for now */
int pivot = a[end];
int i = start, j;
for (j = start; j <= end-1; j++) {
if (a[j] < pivot) {
swap (&a[i], &a[j]);
i++;
}
}
/* Now swap the ith element with the pivot */
swap (&a[i], &a[end]);
return i;
}
int find_k_rank (int a[], int start, int end, int k)
{
int x = partition (a, start, end);
if (x == k) {
return a[x];
} else if (k < x) {
return find_k_rank (a, start, x-1, k);
} else {
return find_k_rank (a, x+1, end, k);
}
}
int main()
{
int a[] = {10,2,7,4,8,3,1,5,9,6};
int N = 10;
int rank = 3;
printf ("%d\n", find_k_rank (a, 0, N-1, rank));
}

Stable Merge sort C

I am writing a simple merge sort function to sort based on a given compar function:
void merge(int left, int mid, int right, int(*compar)(const void *, const void *))
{
// sublist sizes
int left_size = mid - left + 1;
int right_size = right - mid;
// counts
int i, j, k;
// create left and right arrays
B *left_list = (B*) malloc(left_size*sizeof(B));
B *right_list = (B*) malloc(right_size*sizeof(B));
// copy sublists, could be done with memcpy()?
for (i = 0; i < left_size; i++)
left_list[i] = list[left + i];
for (j = 0; j < right_size; j++)
right_list[j] = list[mid + j + 1];
// reset counts
i = 0; j = 0;
for (k = left; k <= right; k++)
{
if (j == right_size)
list[k] = left_list[i++];
else if (i == left_size)
list[k] = right_list[j++];
// here we call the given comparision function
else if (compar(&left_list[i], &right_list[j]) < 0)
list[k] = left_list[i++];
else
list[k] = right_list[j++];
}
}
void sort(int left, int right, int(*compar)(const void *, const void *))
{
if (left < right)
{
// find the pivot point
int mid = (left + right) / 2;
// recursive step
sort(left, mid, compar);
sort(mid + 1, right, compar);
// merge resulting sublists
merge(left, mid, right, compar);
}
}
I am then calling this several times on the same list array using different comparison functions. I am finding that the sort is stable for the first call, but then after that I see elements are swapped even though they are equal.
Can anyone suggest the reason for this behaviour?
I'm not sure if this will do it but try changing this line:
compar(&left_list[i], &right_list[j]) < 0
to this:
compar(&left_list[i], &right_list[j]) <= 0
This will make it so that if they are already equal it does the first action which will (hopefully) preserve the stability rather than moving things around.
This is just a guess though.
I think you got your sizes wrong
int left_size = mid - left;
And, as pointed by arasmussen, you need to give preference to the left list in order to mantain stability
compar(&left_list[i], &right_list[j]) <= 0
In adition to all of this, you are not calling free after malloc-ing the helper lists. This will not make the algorithm return incorrect results but will cause your program's memory use to grow irreversably everytime you call the sort function.

Resources