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.
Related
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);
}
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;
}
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;
}
The code does run. This is a little different version of quicksort I am working on. I am running into some major issues with it. First off It prints out the first element in the array as n: for example(if you set n = 3, even if you make the first element in the array 1 lets say, it will still print out 3 as the first element). Also when you print out the sorted version it doesn't actually change anything.
Example input with n = 3,
Set values = 8 , 7 , 6
Initial output will equal 3 , 7 , 6
Final output will equal 3 , 7 , 6
(The output SHOULD be 6 , 7 , 8)
I haven't been able to find any code online similar to my code, so this may be something new! Thanks.
//preprocessor directives and header files
#include <stdio.h>
#define MAX_ARRAY_SIZE 50
//function prototypes separated by data types
void print_array( int array[], int n ); // Print out the array values
void swap( int array[], int index1, int index2 ); // Swap two array elements.
void quicksort( int array[], int low, int high ); // Sorting algorithm
int populate_array( int array[] ); // Fill array with values from user.
int partition( int array[], int low, int high ); // Find the partition point (pivot)
//the main function
int main(void)
{
int array[MAX_ARRAY_SIZE];
//set n = to size of user created size of array
int n = populate_array(&array[MAX_ARRAY_SIZE]);
//print the original array to the screen
print_array(&array[MAX_ARRAY_SIZE], n );
//perform the algorithm
quicksort(array, 0, n-1);
printf("The array is now sorted:\n");
print_array(&array[MAX_ARRAY_SIZE], n);
return 0;
}
// *array and array[] are the same...
int populate_array(int array[])
{
int n = -1;
printf("Enter the value of n > ");
scanf("%d", &n);
if(n > MAX_ARRAY_SIZE)
{
printf("%d exceeds the maximum array size. Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else if(n < 0)
{
printf("%d is less than zero. Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else if(n == 0)
{
printf("%d Array of size 0? Please don't try this, and... Please try again.\n\n", n);
populate_array( &array[MAX_ARRAY_SIZE]);
}
else
{
for(int i = 0; i < n; i++)
scanf("%d", &array[i]);
}
printf("The initial array contains: \n");
return n;
}
void print_array(int array[], int n)
{
for(int i = 0; i < n; i++)
printf("%+5d\n", array[i]);
}
void quicksort(int array[], int low, int high)
{
if (low < high)
{
/* pivot is partitioning index, array[p] is now
at right place */
int pivot = partition(array, low, high);
// Separately sort elements before
// partition and after partition
quicksort(array, low, pivot - 1);
quicksort(array, pivot + 1, high);
}
}
int partition(int array[], int low, int high)
{
int pivot = array[high];
int i = low;
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (array[j] <= pivot)
{
swap(array, i, j);
i = i +1;
}
}
swap(array, i, high);
return i;
}
void swap(int array[], int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
Here is a heavily commented answer. I changed the code quite a bit.
This is now a fully functional quicksort array for user input.
The problem I was having before was with the &array[MAX_ARRAY_SIZE]. This needed to be changed to just "array" instead. The &array[MAX_ARRAY_SIZE] was trying to access a memory location past the actual size of the array.
Changing it to just "array" means that it is accessing the first element in the array.(Correct if wrong)
I also changed the populate array function to be a robust do-while loop. And instead of trying to re-call the function inside itself. The do-while loop will only allow you to change the value of 'n'.
/*
Author: Zachary Alberda
*/
//preprocessor directives and header files
#include <stdio.h>
#define MAX_ARRAY_SIZE 50
//function prototypes separated by data types
void print_array( int array[], int n ); // Print out the array values
void swap( int array[], int index1, int index2 ); // Swap two array elements.
void quicksort( int array[], int low, int high ); // Sorting algorithm
int populate_array( int array[] ); // Fill array with values from user.
int partition( int array[], int low, int high ); // Find the partition point (pivot)
//the main function
int main(void)
{
int array[MAX_ARRAY_SIZE]; //set n = to size of user created size of array
int n = populate_array(array); //print the original array to the screen
print_array(array, n ); //print array of size n
quicksort(array, 0, n-1); //perform the algorithm low is 0, high is size of array -1.
printf("The array is now sorted:\n");//Inform user that the array is sorted.
print_array(array, n);//print the sorted array
return 0; // exit without errors.
}
// *array and array[] are the same...
int populate_array(int array[])
{
int n = -1;//initialize variable n(local variable to function populate_array)
printf("Enter the value of n > ");//inform user of what to input
scanf("%d", &n);
/*
CHECK IF N IS VALID
This is a robust do while loop!
1) Performs the if-statements while 'n' is not valid in a do-while loop.
-The reason I do this is because it will cause errors
if the if-statements are individual without the do-while loop.
2)The program will not crash if you try different combinations
of inputs for 'n'. :)
3)Checks if user input is > MAX_ARRAY_SIZE
4)Checks if user input is < 0
5)Checks if user input is == 0
*/
do
{
if(n > MAX_ARRAY_SIZE)
{
printf("%d exceeds the maximum array size. Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
else if(n < 0)
{
printf("%d is less than zero. Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
else if(n == 0)
{
printf("%d Array of size 0? Please don't try this, and... Please try again.\n\n", n);
printf("Enter the value of n > ");
scanf("%d", &n);
}
}while(n <= 0 || n > MAX_ARRAY_SIZE);
//scan in array if user input is valid
for(int i = 0; i < n; i++)
scanf("%d", &array[i]);
printf("The initial array contains: \n");//Inform user of initial array
return n;
}
void print_array(int array[], int n)
{
//print array in pre/post order before and after the algorithm.
for(int i = 0; i < n; i++)
printf("%+5d\n", array[i]);
}
void quicksort(int array[], int low, int high)
{
if (low < high)
{
/* pivot is partitioning index, array[pivot] is now
at right place */
int pivot = partition(array, low, high);
// Separately sort elements before
// partition and after partition
quicksort(array, low, pivot - 1);
quicksort(array, pivot + 1, high);
}
}
int partition(int array[], int low, int high)
{
int pivot = array[high];
int i = low;
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (array[j] <= pivot)
{
swap(array, i, j);
i = i +1;
}
}
swap(array, i, high);
return i;
}
void swap(int array[], int index1, int index2)
{
//swap positions of array index 1 and 2
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
i wrote this code in C language on Xcode following the algorithm of mergesort.
The problem is that sometimes i get EXC_BAD_ACCESS and i can't manage where the error is!
The merge algorithm should work (i tried it outside the mergesort function and works!). Thank you for your help and patience!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DIM 6
void mymerge (int v[], int i1,int i2, int last); //mergesort core: merge two ordinated arrays in one bigger ordinated array
void mymergesort (int v[], int lower, int upper);//mergesort
void printv (int v[],int lower, int upper);
int main () {
int i;
srand((unsigned int)time(NULL));
int v[DIM];
for (i=0; i<DIM; i++)
v[i]=rand()%15;
printv(v, 0, DIM-1);
getc(stdin);
mymergesort(v, 0, DIM-1);
printv(v, 0, DIM-1);
}
void printv (int v[],int lower, int upper){
int i;
for (i=lower; i<=upper; i++)
printf("%d\t",v[i]);
}
void mymergesort (int v[], int lower, int upper){
int mid=(upper+lower)/2;
if (upper<lower) {
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
void mymerge (int v[], int i1,int i2, int last){
int i=i1,j=i2,k=i1,*vout;
vout=(int*)malloc((last-i1+1)*sizeof(int));
while (i<i2 && j<=last) {
if (v[i]<=v[j]) {
vout[k++]=v[i++];
}else {
vout[k++]=v[j++];
}
}
for (;i<i2;i++) vout[k++]=v[i];
for (;j<=last;j++) vout[k++]=v[j];
for (k=i1; k<=last; k++) v[k]=vout[k];
free(vout);
}
EDIT:
thank you very much! but i think think there is another problem, when I try to sort a bigger array (200 elements), the program doesn't work (i get a malloc error: incorrect checksum for freed object - object was probably modified after being freed). But if I run it from the xCode debugger everything works fine
This: vout=(int*)malloc((last-i1)*sizeof(int)); is wrong.
First, the number of elements you want is last-i1+1, not last-i1 - classic off-by-1. This kind of error is one of the reasons why the convention in C code is to make lower bounds inclusive and upper bounds exclusive - less +1 and -1 you need to do, less opportunity to screw up.
The more serious error is that you index vout starting from i1. If you do it this way, you need to allocate last+1 element for vout, and you never use the first i1 (index 0 .. i1-1).
Fix: First, allocate last-i1+1 elements. Second, initialize k to 0 at the beginning, not i1. Third, change the final copy to be
for (k=i1; k<=last; k++) v[k] = vout[k-i1];
You have two problems. The first is that your calculation of the midpoint is incorrect - you use (upper - lower)/ 2, but this is not guaranteed to lie between lower and upper. What you actually want is lower + (upper - lower) / 2. It's also not necessary to do any work if there's only 1 number in the interval to be sorted - so the mymergesort() function should look like:
void mymergesort (int v[], int lower, int upper)
{
if (upper > lower) {
int mid = lower + (upper - lower)/2;
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
The second problem is the one in the mymerge() function already pointed out by Fabian Giesen.
#include<stdio.h>
#include<stdlib.h>
void merge(int *a, int n1, int *b, int n2, int *arr)
{
int i=0, j=0, n=0;
while(i<n1 && j<n2)
{
if (a[i] < b[j])
{
arr[n++] = a[i];
i++;
}
else
{
arr[n++] = b[j];
j++;
}
}
while( i < n1)
arr[n++] = a[i++];
while( j < n2)
arr[n++] = b[j++];
}
void merge_sort(int *a, int n)
{
int left[n/2], right[n-n/2],i=0;
if (n<=1)
return ;
while(i<n/2)
left[i] = a[i++];
while(i<n)
right[i - n/2] = a[i++];
merge_sort( left, n/2 );
merge_sort( right, n-n/2);
merge(left, n/2, right, n-n/2, a);
}
void main()
{
int a[] = { 6, 5, 3, 1,9, 8, 7, 2, 4},i;
merge_sort(a,sizeof(a)/sizeof(a[0]));
for(i=0;i<9;i++)
printf("--%d",a[i]);
printf("\n");
}
-- s.k
#include<stdio.h>
#include<conio.h>
#define max 20
/*** function for merging the adjecent subarrays in sorted order ***/
void merge(int A[max],int n,int low,int high, int mid)
{
int i=low,j=mid+1,k,temp;
while((i<=j)&&(j<=high))
{
if(A[i]>A[j]) /** if element of the second half is greater then exchg and shift **/
{
temp=A[j];
for(k=j;k>i;k--) /** shifting the elements **/
{
A[k]=A[k-1];
}
A[i]=temp;
j++;
}
i++;
}
}
/******* iterative function for merge sort ********/
void merge_sort(int A[max],int n,int low,int high)
{
int mid;
if(low<high) /** terminating condition **/
{
mid=(high+low)/2; /** calculating the mid point ***/
merge_sort(A,n,low,mid); /*** recursive call for left half of the array ***/
merge_sort(A,n,mid+1,high); /*** recursive call for right half of the array ***/
merge(A,n,low,high,mid); /** merging the both parts of the array **/
}
}
/******* begening of the main function **********/
int main()
{
int A[max],n,i;
/** reading the inputs fro users **/
printf("\n enter the size of the array\n");
scanf("%d",&n);
printf("\n enter the array \n");
for(i=0;i<n;i++)
{
scanf("%d",&A[i]);
}
/*** calling merge sort ***/
merge_sort(A,n,0,n-1);
/** printing the sorted array **/
for(i=0;i<10;i++)
{
printf("\n\t%d",A[i]);
}
getch();
return 0;
}