Quicksort not working well - c

I have tried to implement a quicksort using a pseudo-code from a book(looks like the one from wikipedia), but I can't get it to make it work.
This source code:
int partitionare(int a[], int n, int p, int r)
{
int x, i, j, aux;
x = a[r]; // pivot
i = p - 1;
for (j = p; j < r; j++)
{
if (a[j] <= x)
{
i++;
aux = a[j];
a[j] = a[i];
a[i] = aux;
}
}
aux = a[i + 1];
a[i + 1] = a[r];
a[r] = aux;
return i + 1;
}
void quicksort(int a[], int n, int p, int r)
{
if (p < r)
{
int q = partitionare(a, n, p, r);
partitionare(a, n, p, q - 1);
partitionare(a, n, q + 1, r);
}
}
where p and r are the beggining and the end of the array
And the call function:
quicksort(a, n, 0, n-1);
Don't mind that second argument, n. That is just for testing purpose only.

Accoding to the Wikipedia article the last calls inside the function quicksort() are to itself recursively (not to the function partition())
void quicksort(int a[], int n, int p, int r)
{
if (p < r)
{
int q = partitionare(a, n, p, r);
partitionare(a, n, p, q - 1); /* recursive quicksort() here */
partitionare(a, n, q + 1, r); /* recursive quicksort() here */
}
}

Related

Segmentation error using merge/quicksort on C on very large arrays containing ints

I am writing different functions that sort a list of arrays to test their efficiency, as shown below I tried implementing merge/sort with recursivity which works just fine with arrays sizes lower than 10^5 going more than that crashes and gives the code error : Process finished with exit code -1073741571 (0xC00000FD). After some googling I realized the issue is a stack overlow meaning my stack can not hold all of the recusrion calls, tried increasing the heap size (I am on Clion)
that didnt work.
Here is the quicksort implementation :
int devide(int t[], int low, int high){
int devide(int t[], int low, int high){
int pivot_value = t[high];
int i = low;
for(int j =low;j<high;j++){
if(t[j]<=pivot_value){
swap(&t[j],&t[i]);
i++;
}
}
swap(&t[i],&t[high]);
return i;
}
void quicksort_recursion(int array[], int low, int high){
if(low < high) {
int pivot_index = devide(array, low, high);
quicksort_recursion(array, low, pivot_index - 1);
quicksort_recursion(array, pivot_index + 1, high);
}
}
void quicksort_last(int t[], int length){
quicksort_recursion(t,0,length-1);
}
And here is the merge implementation :
void merge_sorted_arrays(int a[], int l, int m, int r) {
int left_length = m - l + 1;
int right_length = r - m;
int temp_left[left_length];
int temp_right[right_length];
int i, j, k;
for (i = 0; i < left_length; i++)
temp_left[i] = a[l + i];
for (i = 0; i < right_length; i++)
temp_right[i] = a[m + 1 + i];
for (i = 0, j = 0, k = l; k <= r; k++) {
if ((i < left_length) &&
(j >= right_length || temp_left[i] <= temp_right[j])) {
a[k] = temp_left[i];
i++;
}
else {
a[k] = temp_right[j];
j++;
}
}
}
void merge_sort_recursion(int a[], int l, int r)
{
if (l < r)
{
int m = l + (r - l) / 2;
merge_sort_recursion(a, l, m);
merge_sort_recursion(a, m + 1, r);
merge_sorted_arrays(a, l, m, r);
}
}
void merge(int a[], int length)
{
merge_sort_recursion(a, 0, length - 1);
}
I want to know if there is work around the stack overflow using recursion or if this should be implemented as an iterative function.
PS : swap(int *x, int *y) is just a function that swaps 2 elements of an array.

quickSort for C strings

I'm trying to make a quicksort that sorts c strings instead of ints. When I call quickSort all the strings in my array are emptied and unsorted and I cant figure out why
'''''''''''''''''''''''''''''''''''''''''''''
void swap(char** A, int i, int j){
//printf("swap\n");
char* temp=malloc(strlen(A[i])*sizeof(char));
temp = A[i];
free(A[i]);
A[i]=malloc((1+strlen(A[j])) * sizeof(char));
A[i] = A[j];
free(A[j]);
A[j] = malloc((1+strlen(temp)) * sizeof(char));
A[j]=temp;
}
int Partition(char** A, int p, int r){
//printf("partion\n");
int i, j;
char* x;
//printf("x\n");
x = A[r];
i = p-1;
for(j=p; j<r; j++){
if( strcmp(A[j], x) < 0){
i++;
swap(A, i, j);
}
}
swap(A, i+1, r);
return(i+1);
}
void QuickSort(char** A, int p, int r){
int q;
if( p<r ){
q = Partition(A, p, r);
QuickSort(A, p, q-1);
QuickSort(A, q+1, r);
}
}
'''''''''''''''''''''''''''''''''

QuickSort Algorithm Number of Comparisons

I have been taking a class at Coursera and we had an assignment which was to count the number of comparisons QuickSort does on a 10,000 size array a numbers.
#include <stdio.h>
#define SIZE 10000
int ComparsionCount = 0;
void swap(int a[], int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
int partition(int a[], int l, int r){
int p = a[l];
int i = l + 1;
int j;
for (j = l + 1; j <= r; j++) {
if (a[j] < p) {
swap(a, j, i);
i++;
}
}
swap(a, l, i - 1);
return (i - 1);
}
void add(int i) {
ComparsionCount += i;
}
int QuickSort(int a[], int l, int r){
int pivot;
if (r > 1) {
add(r - 1);
pivot = partition(a, l, r);
QuickSort(a, l, pivot - 1);
QuickSort(a, pivot + 1, r);
}
return pivot;
}
int main() {
FILE *fr;
int arr[SIZE];
int i = 0;
int elapsed_seconds;
char line[80];
fr = fopen("QuickSort.txt", "r");
while (fgets(line, 80, fr) != NULL)
{
/* get a line, up to 80 chars from fr. done if NULL */
sscanf (line, "%ld", &elapsed_seconds);
/* convert the string to a int */
arr[i] = atoi(line);
i++;
}
fclose(fr); /* close the file prior to exiting the routine */
printf("%d\n",QuickSort(arr,0,SIZE-1));
}
I am getting an segmentation error. I have identified that the problem lies in two recursive calls of QuickSort.
I have no idea of how to solve this problem,your help would be appreciated a lot
Thanks in advance.
I think you should add the code in the partition function like this:
for (j = l + 1; j <= r; j++) {
count++;
if (a[j] < p) {
...
}
Note: count is a global variable initialized to 0.

C Parallel merge sort working sometimes

I'm learning how to parallize the merge sort in C following this tutorial
http://elc.yonsei.ac.kr/courses/csi2110/PP-L05-ScalableAlgorithmicTechniques.pdf But it only works sometimes. I run the code in the terminal about 10 times, and sometimes I get segmentation fault, other times, I get random numbers in my array, or sometimes, it works.
I'm not sure where I'm going wrong so any help would indeed be most appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
pthread_t LThread;
pthread_t RThread;
void MergeSort(float A[], int p, int r);
void ParallelMergeSort(float A[], int p, int r, int depth, int max_depth);
void Merge(float A[], int p, int q, int r);
struct arg {
float* A;
int p;
int r;
int depth;
int max_depth;
};
void* PMSort(void* ptr){
struct arg* MyArg = (struct arg*) ptr;
ParallelMergeSort(MyArg->A, MyArg->p, MyArg->r, MyArg->depth, MyArg->max_depth);
return 0;
}
void ParallelMergeSort(float A[], int p, int r, int depth, int max_depth){
if (depth == max_depth){
MergeSort(A, p, r);
}
else {
/*
1) Spawn 2 threads for left and right sub array
2) Join the 2 threads
3) Perform the merge
*/
int q;
if (p < r){
q = (p+r) / 2;
struct arg* LeftArg = malloc(sizeof(struct arg));
struct arg* RightArg = malloc(sizeof(struct arg));
LeftArg->A = A;
LeftArg->p = p;
LeftArg->r = q;
LeftArg->depth = depth + 1;
LeftArg->max_depth = max_depth;
RightArg->A = A;
RightArg->p = q + 1;
RightArg->r = r;
RightArg->depth = depth + 1;
RightArg->max_depth = max_depth;
pthread_create(&LThread, NULL, PMSort, (void*)LeftArg);
pthread_create(&RThread, NULL, PMSort, (void*)RightArg);
pthread_join(LThread, NULL);
pthread_join(RThread, NULL);
Merge(A, p, q, r);
}
}
}
void Merge(float A[], int p, int q, int r){
int n1 = q -p + 1;
int n2 = r - q;
int i = 0;
int j = 0;
int L[r];
int R[r];
for (i = 0; i < n1; i ++){
L[i] = A[p + i];
}
for (j = 0; j < n2; j ++){
R[j] = A[q + j + 1];
}
L[n1] = INFINITY;
L[n2] = INFINITY;
i = 0;
j = 0;
for (int k = p; k <= r; k ++){
if (L[i] <= R[j]){
A[k] = L[i];
i ++;
}
else {
A[k] = R[j];
j ++;
}
}
}
void MergeSort(float A[], int p, int r){
int q;
if (p < r){
q = (p + r)/2;
MergeSort(A, p, q);
MergeSort(A, p+1, r);
Merge(A, p, q, r);
}
}
int main(void){
float array[] = {5,2,4,7,1,3,2,6};
ParallelMergeSort(array, 0, 7, 0, 3);
for (int i = 0; i <= 7; i ++){
printf("%f ", array[i]);
}
printf("\n");
return 0;
}
Don't ignore return values from function calls in C. Start out by adding perror calls if your pthread calls do not return 0 and see what happens. You will see that the pthread_join calls are failing because you have RThread and LThread declared as globals. So you keep re-assigning them new values as you spawn off threads. Move those pthread_t declarations so they are declared inside the ParallelMergeSort function instead.
That won't fix any sorting issues with your algorithm but at least you will get consistent results.

Quicksort implementation in C using first element as pivot

I am a complete beginner to stackoverflow and this is my first post. Please forgive if this is not the correct place to post these kinds of queries. I have written code for the Quicksort algorithm, based on the algorithm given in the Algorithms course in Coursera(It is not for any assignments though).
Basically, there are two functions Quicksort which is called recursively and partition() function that returns the index of the pivot. I select the pivot as the first element of the array every time. I checked the partition() function and it works fine but the array is not sorted even after I call the Quicksort() function.
Any help is appreciated. Thanks.
#include <stdio.h>
void swap(int *p, int i, int j)
{
int temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;
}
int partition(int *q, int l, int r)
{
int i = l+1, j;
int p = l;
int len = r-l +1;
for (j = l+1; j < len; j++)
{
/*printf("%d \n", j);*/
if ( *(q+j) < *(q+p) )
{
swap(q, i, j);
i += 1;
}
}
swap(q, l, i-1);
/*printf("%d", i-1);*/
return (i-1);
}
void quicksort(int *ptr, int low, int high)
{
if (low < high)
{
int p = partition(ptr, low, high);
printf("%d\n", p);
quicksort(ptr, low, p);
quicksort(ptr, p+1, high);
}
}
int main(){
int i;
int a[] = {3, 8, 2, 5, 1, 4, 7, 6};
int len = sizeof(a)/sizeof(a[0]);
for ( i = 0; i < len; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
int *ptr = a;
quicksort(ptr, 0, len-1);
for (i = 0; i < sizeof(a)/sizeof(a[0]); ++i)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
2 corrections.
Small one: Change 3rd line inside if block in QuickSort function
from
quicksort(ptr, low, p);
to
quicksort(ptr, low, p-1);
This will improve performance.
Main error:
Your partition function is wrong. Specifically the loop where j runs from l+1 to r-l+1, because, r-l+1 can be less than l+1
I'll write the partition function for you if you want (post a comment if you face any problem with that) though I'd advice you to do it yourself.
EDIT:
A possible partition function:
int partition(int *q, int l, int r){
int i,j;
int p = *(q + l);
for(i = l + 1, j = r; ;){
while(*(q + i) <= p)
i++;
while(*(q + j) >= p)
j--;
if(i >= j)
break;
swap(q, i, j);
}
return i;
}
Changes noted in comments.
int partition(int *q, int l, int r)
{
int i = l+1, j;
int p = l;
/* fix: int len = r-l+1; is not used */
for (j = l+1; j <= r; j++) /* fix: j <= r */
{
if ( *(q+j) <= *(q+p) ) /* fix: <= */
{
swap(q, i, j);
i += 1;
}
}
swap(q, l, i-1);
return (i-1);
}
void quicksort(int *ptr, int low, int high)
{
if (low < high)
{
int p = partition(ptr, low, high);
quicksort(ptr, low, p-1); /* optimization: p-1 */
quicksort(ptr, p+1, high);
}
}
If interested, Hoare partition scheme is faster. If you switch to this, don't forget to change the two quicksort calls to quicksort(lo, p) and quicksort(p+1, hi) ). You might want to change the Hoare pivot to pivot = A[(lo+hi)/2], which will avoid worst case issue with sorted or reverse sorted array.
http://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme

Resources