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
Related
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.
I'm having issues with getting my mergeSort algorithm to work properly. The code is below, but I'll briefly summarize what I have tried and what I know is not wrong with the code.
The mergeSort function takes a pointer to an array and the array's size as arguments. If the size of the array is less than 2, it returns immediately. I'm sure that this works, because I debugged this part several times. It returns 8 times, which is what I expected it to do.
Next, a variable mid is created as an index to split the array by. I tested it, and I'm pretty confident that mid is correct across all recursions. Then, two arrays are created, the first containing the elements from the indexes 0...mid-1 and the second containing the elements from the indexes mid to n. Next, the sizes of each of these arrays are computed. I tested this too, and the sizes seem correct across all recursions as well. mergeSort is called on the left array and the right array, and then merge is called.
The actual merge function takes a pointer to the original array, a pointer to the left array, a pointer to the right array, and two integer values which are the sizes of each of the left and right arrays. Then, it compares the elements in L and R and copies the smaller of the two into A, in order.
My output, however, is [2] [4] [1] [6] [8] [5] [3] [7]
My expected output is: [1] [2] [3] [4] [5] [6] [7] [8]
I'm genuinely not sure why the code isn't working. There's probably something I'm overlooking, but I've been trying to solve it for an hour and figured I'd ask for help.
If you take the time to answer, or attempt to answer this question, thank you for your time.
My code is below:
#include <stdio.h>
#include <stdlib.h>
void mergeSort(int *, int);
void merge(int *, int *, int, int *, int);
void print(int *, int);
int main() {
int A[8] = { 2, 4, 1, 6, 8, 5, 3, 7 };
int arraySize = sizeof(A) / sizeof(A[0]);
mergeSort(A, arraySize);
print(A, arraySize);
}
void mergeSort(int *A, int n) {
if (n < 2) {
return;
}
int mid = n / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++) {
L[i] = A[i];
}
for (int j = mid; j < n; j++) {
R[j - mid] = A[j + mid + 1];
}
int leftSize = sizeof(L) / sizeof(L[0]);
int rightSize = sizeof(R) / sizeof(R[0]);
mergeSort(L, leftSize);
mergeSort(R, rightSize);
merge(A, L, leftSize, R, rightSize);
}
void merge(int *A, int *L, int leftSize, int *R, int rightSize) {
int i, j, k;
while (i < leftSize && j < rightSize) {
if (L[i] < R[j]) {
A[k] = L[i];
k++;
i++;
} else {
A[k] = R[j];
k++;
j++;
}
}
}
void print(int *A, int n) {
for (int i = 0; i < n; i++) {
printf("[%d] ", A[i]);
}
printf("\n");
}
There are multiple problems:
the intialization loop for R is incorrect: you should copy A[j] instead of A[j + mid + 1]
the merge function should copy the remaining elements from the left or right arrays once the test i < leftSize && j < rightSize fails.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
void mergeSort(int *, int);
void merge(int *, int *, int, int *, int);
void print(const int *, int);
int main() {
int A[8] = { 2, 4, 1, 6, 8, 5, 3, 7 };
int arraySize = sizeof(A) / sizeof(A[0]);
mergeSort(A, arraySize);
print(A, arraySize);
return 0;
}
void mergeSort(int *A, int n) {
if (n < 2) {
return;
}
int mid = n / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++) {
L[i] = A[i];
}
for (int j = mid; j < n; j++) {
R[j - mid] = A[j];
}
int leftSize = sizeof(L) / sizeof(L[0]);
int rightSize = sizeof(R) / sizeof(R[0]);
mergeSort(L, leftSize);
mergeSort(R, rightSize);
merge(A, L, leftSize, R, rightSize);
}
void merge(int *A, int *L, int leftSize, int *R, int rightSize) {
int i, j, k;
while (i < leftSize && j < rightSize) {
if (L[i] <= R[j]) {
A[k++] = L[i++];
} else {
A[k++] = R[j++];
}
}
while (i < leftSize) {
A[k++] = L[i++];
}
while (j < rightSize) {
A[k++] = R[j++];
}
}
void print(const int *A, int n) {
for (int i = 0; i < n; i++) {
printf("[%d] ", A[i]);
}
printf("\n");
}
according to introduction to algorithms I wrote a code for quicksort using Hoare's partition in the codeblocks IDE .The code was successfully built but the sorted array is not displayed on the console,only the unsorted array is displayed followed by a blinking underscore.
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
int partition(int arr[],int p,int r)
{
int i,j,x,temp;
x=arr[p];
i=p-1;
j=r+1;
while(true)
{
do{
j=j-1;
}while(arr[j]<=x);
do{
i=i+1;
}while(arr[i]>=x);
if (i<j)
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
else
return j;
}
}
void quicksort(int arr[],int p,int r)
{
if (p<r)
{
int q=partition(arr,p,r);
quicksort(arr,p,q-1);
quicksort(arr,q-1,r);
}
}
void print(int A[],int size)
{
int i;
for(i=0;i<size;i++)
printf("%d ",A[i]);
}
int main()
{
int arr[]={1,12,56,2,67,0,98,23};
int size=sizeof(arr)/sizeof(arr[0]);
printf("\nthe array is\n");
print(arr,size);
quicksort(arr,0,size-1);
printf("\nthe sorted array is\n ");
print(arr,size);
return 0;
}
the output was as follows
the array is
1 12 56 2 67 0 98 23
`
Okay, I refactored your algorithm, based on a guide from wikipedia: https://en.wikipedia.org/wiki/Quicksort
As mentioned in my comment above, the [recursive] quicksort calls used the wrong arguments. But, then, as Weather Vane mentioned, it [still] didn't sort.
Edit: My original post was using Lomuto partitioning instead of Hoare.
The partition algorithm differed from the wiki by using a different initial value for the pivot and using <=,>= on the do/while termination conditions instead of <,>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int
partition(int arr[], int p, int r)
{
int i,
j,
x,
temp;
x = arr[(p + r) / 2];
i = p - 1;
j = r + 1;
while (1) {
do {
i += 1;
} while (arr[i] < x);
do {
j -= 1;
} while (arr[j] > x);
if (i >= j)
return j;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
void
quicksort(int arr[], int p, int r)
{
if (p < r) {
int q = partition(arr, p, r);
quicksort(arr, p, q);
quicksort(arr, q + 1, r);
}
}
void
print(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
}
int
main()
{
int arr[] = { 1, 12, 56, 2, 67, 0, 98, 23 };
int size = sizeof(arr) / sizeof(arr[0]);
printf("\nthe array is\n");
print(arr, size);
quicksort(arr, 0, size - 1);
printf("\nthe sorted array is\n ");
print(arr, size);
printf("\n");
return 0;
}
Has this function been written correctly?
It seems that something is wrong when I try to run the function with a large number of elements in the array (eg 1000).
Then its appears to stop.
int quick_sort(int n, int tablica[],int b, int a)
{
if(a==n-1 || n==0) return;
if(b==n-1)
{
b=0;
a++;
}
if(tablica[b]>tablica[b+1])
{
bufor=tablica[b];
tablica[b]=tablica[b+1];
tablica[b+1]=bufor;
}
b++;
return quick_sort(n,tablica,b,a);
}
Above code will not work even for a small array, unless the small array is unsorted in a particular way. It compares one element with the next element. If the array is say {4,3,8,7,1} the sort will fail, because it has no mechanism to push 1 to the start of the array.
For larger arrays there are too many recursion and the program hits the stack limit and simply fails.
You can use recursion in quicksort but the number of recursions has to be kept in check. For example for array of size 1000 you don't want to have to more than 1000 recursion. Example:
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void quicksort(int arr[], int low, int high)
{
if(low < 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], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
int pi = i + 1;
quicksort(arr, low, pi - 1);
quicksort(arr, pi + 1, high);
}
}
int main()
{
int arr[] = { 7,3,6,1,4,8,9,2 };
int arrsize = sizeof(arr) / sizeof(*arr);
quicksort(arr, 0, arrsize - 1);
for(int i = 0; i < arrsize; i++)
printf("%d\n", arr[i]);
return 0;
}
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.