I'm trying to take the standard quicksort algorithm and slightly modify it by taking the partition function and making it so that instead of taking the entire array, a low index and a high index, it takes in a pointer to the low'th element as well as how many elements I want to partition. However, I'm getting a segmentation fault and I can't figure it out. Thanks for the help.
#include <stdio.h>
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int partition(int *array, int high) {
int pivot = array[high];
int i = 0;
for (int j = 0; j < high; j++) {
if (array[j] <= pivot) {
swap(&array[i++], &array[j]);
}
}
swap(&array[i], &array[high]);
return i;
}
void quickSort(int *array, int low, int high) {
if (low < high) {
int pi = partition(array + low, high - low);
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
void printArray(int array[], int size) {
for (int i = 0; i < size; ++i) {
printf("%d ", array[i]);
}
printf("\n");
}
int main() {
int data[] = {8, 7, 2, 1, 0, 9, 6};
int n = sizeof(data) / sizeof(data[0]);
printf("Unsorted Array\n");
printArray(data, n);
// perform quicksort on data
quickSort(data, 0, n - 1);
printf("Sorted array in ascending order: \n");
printArray(data, n);
}
Given the following in your code:
int pi = partition(array + low, high - low);
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
You're partitioning using a pointer-adjusted base (array+low), and segment pure length (high-low). That's fine if that is how your partition implementation works (most do). But you need to remember the resulting pivot location, pi, will be based on a position in that segment; not in the overall array. You need to adjust for that when recursing by putting back the original offset from whence that partition was configured:
int pi = partition(array + low, high - low);
quickSort(array, low, low + pi - 1); // <== LOOK
quickSort(array, low + pi + 1, high); // <== HERE
That change alone should get your implementation running. There are other ways to do this, and I'll update this answer with a couple of them when/if I find the time.
Alternate version of a pointer based quicksort using Hoare partition scheme:
void QuickSort(int *lo, int *hi)
{
int *i, *j;
int p, t;
if(lo >= hi)
return;
p = *(lo + (hi-lo)/2);
i = lo - 1;
j = hi + 1;
while (1){
while (*(++i) < p);
while (*(--j) > p);
if (i >= j)
break;
t = *i;
*i = *j;
*j = t;
}
QuickSort(lo, j);
QuickSort(j+1, hi);
}
Related
I'm implementing Quick Sort Algorithm in C language, in which at only one particular interchange of 2 values arr[i] and pivot is not being done properly, else all the swapping is done accurately, I have debugged too and tried to understand what is the problem/mistake, maybe it is a logical error.
Here's the code:
#include <stdio.h>
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void quickSort(int arr[], int low, int high)
{
int pvt = arr[high];
int i = low;
int j = high;
while (i < j)
{
while (pvt > arr[i])
i++;
while (pvt <= arr[j])
j--;
if (i < j)
swap(&arr[i], &arr[j]);
}
swap(&arr[i], &pvt);
printArr(arr, high + 1);
}
void main()
{
int arr[] = {10, 16, 8, 12, 15, 6, 3, 9, 5};
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
}
Just after 2-3 minutes, a friend of mine helped me out, that the pivot is not present in the array so with what I'm swapping it with arr[i]? Instead I can swap 2 values for the same result, arr[i] and arr[high]. Got my mistake :P
I need to sort the content (alphabetically using strcmp() of an array of strings, but I am not allowed to use the function qsort(). With this code I managed to sort numerical values, but I am having a hard time adapting it in order to sort strings.
/* A utility function to swap two elements */
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void swap_string(char c[63], char d[63]){
char temp[63];
strcpy(temp, c);
strcpy(c, d);
strcpy(d, temp);
}
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int partition (int arr[], int low, int high)
{
int pivot = arr[high]; /* pivot */
int i = (low - 1); /* Index of smaller element */
for (j = low; j <= high- 1; j++)
{
/* If current element is smaller than the pivot */
if (arr[j] < pivot)
{
i++; /* increment index of smaller element */
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
/* Separately sort elements before */
/* partition and after partition */
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
First, you just need to create a swap function for string, not need for int
void swap(char ** a, char ** b) {
char * t = *a;
*a = *b;
*b = t;
}
Because, you sort an array of string, so using input ** arr instead of arr[]
Here, the partition function:
int partition (char ** arr, int low, int high) {
char * pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high- 1; j++) {
// If current element is smaller than the pivot
if (strcmp(arr[j],pivot) < 0) {
i++; // increment index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
And, quickSort function:
void quickSort(char **arr, int low, int high) {
if (low < high) {
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
Then the main function for test:
int main(){
char *a = "abc";
char *b = "cdf";
swap(&a, &b);
printf("a = %s, b= %s\n", a, b);
char * data[10]={"something2", "something0", "something1", "something6", "something8", "something4", "something5","something7", "something3", "something9"};
quickSort(data, 0, 9);
for(int i = 0; i < 10; i++) {
printf("%s, ", data[i]);
}
return 0;
}
UPDATE:
If you want exactly an array producer[100][63]. You can change the declaration of the function.
In this example, i use an array data[10][63] for testing. In fact, you can use 100 instead of 10.
Swap function:
void swap(char a[63], char b[63]) {
char t[63];
strcpy(t, a);
strcpy(a, b);
strcpy(b, t);
}
Then, partition function:
int partition (char arr[10][63], int low, int high) {
char * pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high- 1; j++) {
// If current element is smaller than the pivot
if (strcmp(arr[j],pivot) < 0) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
Finally, the quickSort function:
void quickSort(char arr[10][63], int low, int high) {
if (low < high) {
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
The main for test:
int main(){
char data[10][63]={"something2", "something0", "something1", "something6", "something8", "something4", "something5","something7", "something3", "something9"};
quickSort(data, 0, 9);
for(int i = 0; i < 10; i++) {
printf("%s, ", data[i]);
}
return 0;
}
In code of quicksort algorithm there is and usage of recursion without escape sequence, but the recursion stops and code finishes till end.I have found many code examples of this algorithm, but with escape sequence and this doesnt have one and still works.
I have tried to write everything on paper, but cant find why recursion stops, so function recursively continues forever,
/* C implementation QuickSort */
#include<stdio.h>
// A utility function to swap two elements
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int partition (int arr[], int low, int high)
{
int pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than the pivot
if (arr[j] < pivot)
{
i++; // increment index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
/* Function to print an array */
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("n");
}
// Driver program to test above functions
int main()
{
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr)/sizeof(arr[0]);
quickSort(arr, 0, n-1);
printf("Sorted array: n");
printArray(arr, n);
return 0;
}
In my point of view function would be stucked on
quickSort(arr, low, pi - 1);
continues even when parameter at position pi - 1 reaches 0
but it obviously doesnt.
and arr ends up sorted in 1 5 7 8 9 10
Your base case is when if (low < high) is false, by Eugene Sh.
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 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