I have implemented quicksort with 2 different approach taken in partition set
these are the programs
1.http://ideone.com/fPtQFT
2.http://ideone.com/KuXKr4
1.
int partition(int *a,int l,int r)
{
int i=l,pivot=l;
int j=l+1;
for(;j<r;j++)
{
if(a[j]<a[pivot])
{
swap(&a[i+1],&a[j]);
i++;
}
}
swap(&a[pivot],&a[i]);
return i;
}
2.
int partition(int *a,int l,int r)
{
int pivot=l;
int j=r-1;
int i=l+1;
while(1)
{
while(i<=j&&a[i]<=a[pivot])
i++;
while(i<=j&&a[j]>=a[pivot])
j--;
if(j<i)
break;
else
swap(&a[i],&a[j]);
}
swap(&a[pivot],&a[j]);
return j;
}
I am unable to figure out what's wrong in my code as the sorted output for example the test case
13 2 43 3 55 21 43 1 5 32
are wrong 1 2 3 13 21 32 42 5 43 55
Any help to figure out what's wrong in the logic of partitionset
The quicksort function takes the range in the form m to n where, m is the first element and n is one past the last element. This is done correctly in the main:
quicksort(a,0,N);
This means the second argument denotes the first element: 0, and the third argument denotes the one past the last element: N.
This is not done correctly in the first recursive call, where the last element is skipped because p-1 denotes the last element, instead of one past the last element:
quicksort(a,l,p-1);
Use this code to sort the array using quick sort Quick sort
QuickSort(A, P , R)
{
if(P < R)
{
Q = partition(A, P , R);
QuickSort(A, P, Q - 1);
QuickSort(A, Q + 1, R);
}
}
int partition(A, P , R)
{
while(1)
{
key = A[P];
i = P;
j = R;
while(key > A[i] && key != A[i])
i++;
while(key < A[j] && key != A[j])
j--;
if(i < j)
swap(A[i],A[j]);
else
return j;
}
}
this should do it:
#include <stdio.h>
#define N 10
void swap(int *a,int*b)
{
int temp=*b;
*b=*a;
*a=temp;
}
int partition(int *a,int l,int r)
{
int i=l,pivot=a[r];
int j=l;
for(;j<r;j++)
{
if(a[j]<pivot)
{
swap(&a[i],&a[j]);
i++;
}
}
swap(&a[i],&a[r]);
return i;
}
void quicksort(int *a,int l,int r){
int p;
if(l<r)
{
p=partition(a,l,r);
quicksort(a,l,p-1);
quicksort(a,p+1,r);
}
}
int main(){
int a[N] = {13, 2, 43, 3, 55, 21, 43, 1, 5, 32};
int i;
quicksort(a,0,N);
for(i=0;i<N;i++)
printf("%d ",a[i]);
return 0;
}
Related
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;
}
There are two problems I encounter in this code.
The first problem is the infinite loop, which happened from 77~79. When I change this test data and use merge method instead, I will get infinite loop and the R1 will be change to 4198739.But if I use mergeSort method, the problem won't show up as expected. Shown as below:
int M = 2;
int R1 = 4;
int arr[] = {3,9,8,20};
merge(arr, L, M, R1);
Second problem happened from 57 to 69 lines.In this mergeSort method, I tried to divide the unorder array into sub-array. However, there is no any effect on the original array.
Here is my code.
Merge Sort in C
void mergeSort(int arr[], int L, int R)
{
if(L<R) {
return ;
} else {
int M = (L+R) / 2;
mergeSort(arr, L, M);
mergeSort(arr, M+1, R);
merge(arr, L, M+1 ,R);
}
}
There are several mistakes in the logic of the code. I will address it the correct code.
A few pointers first.
The logic deals with array indices, don't confuse with array limits.
I have used sizeof operator to get the upper limit of the array.
Use if-else whenever possible.
The full code cannot be properly added here, so - https://pastebin.com/ixickcQA
Main mistake was here:
for(i=M;i<=R;i++) //1. <= as R is also an index
{
right[i-M] = arr[i];
}
here is the code linked by the (other) answer:
#include <stdio.h>
void merge(int arr[], int L, int M, int R)
{
int LEFT_SIZE = M-L;
int RIGHT_SIZE = R-M+1;
int left[LEFT_SIZE];
int right[RIGHT_SIZE];
int i,j,k;
for(i=L;i<M;i++)
{
left[i-L] = arr[i];
}
for(i=M;i<=R;i++) //1. <= as R is also an index
{
right[i-M] = arr[i];
}
i=0;
j=0;
k=L;
while(i<LEFT_SIZE && j<RIGHT_SIZE)
{
if(left[i] <= right[j]) //2. <= so that duplicates are not ignored
{
arr[k] = left[i];
i++;
}
else //3. use else to keep up the computing speed
{
arr[k] = right[j];
j++;
}
k++;
}
while(i<LEFT_SIZE)
{
arr[k] = left[i];
i++;
k++;
}
while(j<RIGHT_SIZE)
{
arr[k] = right[j];
j++;
k++;
}
}
void mergeSort(int arr[], int L, int R)
{
if(L<R) //4. Better
{
int M = (L+R) / 2;
mergeSort(arr, L, M);
mergeSort(arr, M+1, R);
merge(arr, L, M+1 ,R);
}
}
int main() {
int arr[] = {3,9,20,8,21,22};
mergeSort(arr, 0, (sizeof(arr)/sizeof(int))-1); //5. Use size-1 as we are dealing with indices
int i;
printf("Final\n");
for(i=0; i<(sizeof(arr)/sizeof(int)); i++)
{
printf("i=%d, R=%d,arr[i]=%d\n",i,(sizeof(arr)/sizeof(int)), arr[i]);
}
}
so inserting the code into an answer is no problem
In the mergeSort replace this:
if(L<R)
By this:
if(L>=R)
If L<R is present then it will always be satisfied because the index L will always be less than than R (at starting). And this is the reason that you will get infinite loop.
Your code contains a logical error on your if-statement. Try this:
void mergesort(int a[], int l, int r) {
int m;
if (l < r) {
// same as (l+r) / 2 but for avoiding overflow
m = l + (r - l) / 2;
// recur both parts
mergesort(a, l, m);
mergesort(a, m + 1, r);
merge(a, l, m, r); // merging parts
}
}
#include<stdio.h>
#include<stdlib.h>
void merge(int a[],int l,int m,int r)
{
int i,j,k;
int n1= m - l + 1;
int n2= r - m;
int L[n1],R[n2];
for(i=0;i<n1;i++)
L[i]=a[l+i];
for(j=0;j<n2;j++)
R[j]=a[m + 1+ j];
i=0;j=0;k=l;
while(i<n1 && j<n2)
{
if(L[i]<R[j])
{
a[k]=L[i];
i++;
}
else
{
a[k]=R[j];
j++;
}
k++;
}
while(i<n1)
{
a[k]=L[i];
i++;
k++;
}
while(j<n2)
{
a[k]=R[j];
j++;
k++;
}
}
void mergeSort(int a[],int l,int r)
{
if(l<r)
{
int m = l+(r-1)/2;
mergeSort(a,l,m);
mergeSort(a,m+1,r);
merge(a,l,m,r);
}
}
void printArray(int a[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n");
}
int main()
{
int a[]= {
12,76,34,45,63,98
};
int n = sizeof(a)/sizeof(a[0]);
printf("The element entered in array ");
printArray(a,n);
mergeSort(a,0,n-1);
printf("The element after sorting ");
printArray(a,n);
return 0;
}
This is a merge sort program. Why it's giving runtime error if anyone can explain? There is no error in this program
I have tried this 10 times. And unable to find the solution.
When you call mergesort(a, 3, 5) the following happens:
int m = l+(r-1)/2; // 3 + (5-1)/2 -> 3 + 4/2 -> 3 + 2 -> 5
mergeSort(a,l,m); // So this will call: mergesort(a, 3, 5) again
In other words: An endless loop.
Maybe you want this instead:
int m = (l+(r-1))/2;
^ ^
notice
So how did I find the bug?
Very easy - just use some printf-debug.
First I added a print in the start of mergesort - like:
void mergeSort(int a[],int l,int r)
{
printf("mergesort %d %d\n", l, r); // Debug print
if(l<r)
{
int m = (l+(r-1))/2;
mergeSort(a,l,m);
mergeSort(a,m+1,r);
merge(a,l,m,r);
}
}
and got the output:
mergesort 3 5
mergesort 3 5
mergesort 3 5
...
...
which told me that there was an endless loop for input values 3 and 5.
Then I added a print of m
void mergeSort(int a[],int l,int r)
{
printf("mergesort %d %d\n", l, r);
if(l<r)
{
int m = (l+(r-1))/2;
printf("m %d\n", m);
mergeSort(a,l,m);
mergeSort(a,m+1,r);
merge(a,l,m,r);
}
}
and got the output:
mergesort 3 5
m 5
mergesort 3 5
m 5
mergesort 3 5
m 5
so obviously m was calculated wrongly.
Looking close at
int m = l+(r-1)/2;
is was clear that the addition should be before the division. A set of (....) was missing.
Hope you can use this debug example for your own debug.
Below simple quick sort code with last element as pivot,almost works but except the last element fails to get sorted. Any thoughts where this program went wrong?
Here's the output:
$a.out
4 3 5 2 1 3 2 3 //input
1 2 2 3 3 3 5 4 //output
Simple swap looks fine
void swap ( int* a, int* b )
{
int t = *a;
*a = *b;
*b = t;
}
Hmm..fine too ..may issue with end?
int partition(int a[],int start,int end){
int pivot = a[end];
int pindex=start;int i;
for ( i=start; i <= end-1; i++){
if (a[i] <= pivot){
swap(&a[i],&a[pindex]);pindex++;
}
}
swap(&a[pindex],&a[pivot]);
return (pindex + 1);
}
Surely looks good.
void quicksort(int a[],int start,int end){
int pindex;
if (start < end){
pindex = partition(a,start,end-1);
quicksort(a,start,pindex-1);
quicksort(a,pindex+1,end);
}
}
Simple main call
int main(){
int a[8] = {4, 3, 5, 2, 1, 3, 2, 3};
int i=0;
for(i=0;i<8;i++)
printf(" %d", a[i]);
quicksort(a,0,8);
printf("\n");
for(i=0;i<8;i++)
printf(" %d", a[i]);
}
Okay couple of changes
As doptimusprime pointed return pindex
int partition(int a[],int start,int end){
int pivot = a[end];
int pindex=start;int i;
for ( i=start; i <= end-1; i++){
if (a[i] <= pivot){
swap(&a[i],&a[pindex]);pindex++;
}
}
swap(&a[pindex],&a[end]);
return (pindex);
}
Adjust your quicksort function accordingly
void quicksort(int a[],int start,int end){
int pindex;
if (start < end){
pindex = partition(a,start,end-1);
quicksort(a,start,pindex); // no pindex-1
quicksort(a,pindex+1,end);
}
}
Please review partition function.
It should return
return pindex;
instead of pindex+1.
Because, just take the following case:
1 2 3 4 5
As 5 is chosen as pivot, it should return 4, not 5 as pivot index.
Check for the invariant that pindex must lie between start and end (both inclusive). If pivot is to be lie at end, it must not pass the end.
Generally, partition starts from both end. You are starting it from the one end. Try to do it both the end for efficiency. Otherwise, in the 1 2 3 4 5, you will keep swapping with the same element (1 with 1, 2 with 2 and so on).
And in the partition:
swap(&a[pindex],&a[pivot]);
should be
swap(&a[pindex],&a[end]);
pivot was a value, not an index.
Another change, you required quicksort,
if (start < end){
pindex = partition(a,start,end-1);
//As here index is one past last, so make it start..pindex
quicksort(a,start,pindex);
quicksort(a,pindex+1,end);
}
Your partition function should be
int partition(int a[],int start,int end){
int pivot = a[end];
int pindex=start;int i;
for ( i=start; i <= end-1; i++){
if (a[i] <= pivot){
swap(&a[i],&a[pindex]);pindex++;
}
}
swap(&a[pindex],&a[end]);
return (pindex);
}
See https://en.wikipedia.org/wiki/Quicksort#Lomuto_partition_scheme. This partition scheme is used here.
Your program fails if someone type negative numbers.
Why are you complicating things like that ?
Here is a simple sort:
#include <stdio.h>
void bubble_sort(int *array, int length){
int i,j, k, temp;
for (i = 0 ; i < length-1; i++){
for (k = 0 ; k < length-i-1; k++){
if (array[k] > array[k+1]){
temp = array[k];
array[k] = array[k+1];
array[k+1] = temp;
}
}
}
printf("The sorted Array List:\n\n");
for ( j = 0 ; j < length ; j++ ){
printf("%d ", array[j]);
}
}
int main(void){
int array[8] = {4, 3, 5, 2, 1, -1, 2, 3};
int length = sizeof array / sizeof array[0];
bubble_sort(array, length);
printf("\n");
return 0;
}
Output:
-1 1 2 2 3 3 4 5
Here is my program it is compiling and running without syntax errors.How ever it does not sort the array.The problem lies in where I am passing the array in function
#include<stdio.h>
#include<string.h>
int partition (int *,int,int);
void quicksort (int *,int,int);
static int call=0;
int main()
{
int i,j,choice;
int length;
int a[]={81, 12, 90, 3, 49, 108, 47};
i=0;
length=sizeof(a)/sizeof(a[0]);
quicksort(a,0,length-1);
printf("the sorted array is\n");
for(i=0;i<length;i++)
printf (" %d ",a[i]);
}
int partition(int *num,int p,int r)
{
int x,j,i,temp,bak;
x=num[r];
i=p-1;
for(j=0;j<=r-1;j++)
{
if(num[j]<=x)
{
i=i+1;
temp=num[i];
num[i]=num[j];
num[j]=temp;
{
printf(" %d",num[bak]);
}
}
}
num[i+1]=num[r];
return i+1;
}
void quicksort (int *num,int p,int r)
{
int q;
if (p<r)
{
call++;
q=partition(num,p,r);
quicksort(num,p,q-1);
quicksort(num,q+1,r);
}
}
The above way of passing array in functions is that right that is what I want to know because that is giving problem in function partition.
Inside the function partition when swapping happens then I tried printing the array there itself (it is not sorted array but just to see upto what point things reached) then I saw that only 2 or 3 elements of array which I had passed are being printed and rest of the array is lost some where.So my doubt is array is not being passed properly.
To be able to see as what is the problem with array passing in a function I wrote a smaller program ka1.c
#include<stdio.h>
void pass(int *);
int main ()
{
int a[]={3,5,61,32,12};
pass(a);
}
void pass (int *num)
{
int i,j;
j=sizeof(num)/sizeof(num[0]);
for (i=0;i<j;i++)
printf(" %d",num[i]);
}
Now when I run the above code I get output just
3 5
I was expecting the complete array to be printed in output of ka1.c.
Where as if you notice rest of the array is not getting printed.Where did that go?
I have used the same logic in quicksort also hence I feel the error is same in both cases.
UPDATE1
After the comment below I checked the length of array recieved in quicsort.c paritition function via
sizeof(num)/sizeof(num[0]);
and found of original array
int a[]={81, 12, 90, 3, 49, 108, 47};
which is having length 7 here when I passed it in the function partition
the length is only 2.
The same is case with program ka1.c So why only length is 2 in both cases?
UPDATE2
As the suggestions given below now I have passed on the length also
#include<stdio.h>
#include<string.h>
int partition (int *,int,int,int);
void quicksort (int *,int,int,int);
static int call=0;
int main()
{
int i,j,choice;
int length;
int a[]={81, 12, 90, 3, 49, 108, 47};
i=0;
printf("the sorted array is\n");
length=sizeof(a)/sizeof(a[0]);
printf("length of array %d\n",length);
printf("quick sort called in main\n");
quicksort(a,0,length-1,length);
for(i=0;i<length;i++)
printf (" %d ",a[i]);
}
int partition(int *num,int p,int r,int june)
{
int x,j,i,temp,bak,length;
x=num[r];
i=p-1;
bak=0;
printf("inside the partition\n");
printf("length of june recieved =%d \n",june);
for(j=0;j<=r-1;j++)
{
if(num[j]<=x)
{
i=i+1;
temp=num[i];
num[i]=num[j];
num[j]=temp;
printf("printing array after swap\n");
for(;bak<7;bak++)
{
printf(" %d ",num[bak]);
}
}
}
num[i+1]=num[r];
return i+1;
}
void quicksort (int *num,int p,int r,int june)
{
int q,bbc,ccd;
if (p<r)
{
call++;
printf("partition called %d times p=%d r=%d\n",call,p,r);
printf("before sending to function length of june=%d \n",june);
q=partition(num,p,r,june);
bbc=q-1-p+1;
quicksort(num,p,q-1,bbc);
ccd=r-q-1+1;
quicksort(num,q+1,r,ccd);
}
}
But the program is still failing to print the sorted array.
You can compile and run the above code.
SOLVED
Finally with help of replies below I have been able to solve the above problem.
The mistake lied in function partition in statement
for (j = 0; j <= r - 1; j++)
instead it should have been
for (j = p; j <= r - 1; j++)
note j=p and j=0
here
j=0
is wrong since when recursively second partition is tried to be sorted it started disturbing the first partition and hence the result was also wrong.
In this program I faced a problem in using gdb to debug a recursive function.
Please check this thread also
Debugging recurssion was quite tricky.
SO the correct code is
#include<stdio.h>
#include<string.h>
int partition (int *, int, int, int);
void quicksort (int *, int, int, int);
static int call = 0;
int
main ()
{
int i, j, choice;
int length;
int a[] = { 81, 12, 90, 3, 49, 108, 47 };
i = 0;
printf ("the sorted array is\n");
length = sizeof (a) / sizeof (a[0]);
printf ("length of array %d\n", length);
printf ("quick sort called in main\n");
quicksort (a, 0, length - 1, length);
for (i = 0; i < length; i++)
printf (" %d ", a[i]);
}
int
partition (int *num, int p, int r, int june)
{
int x, j, i, temp, bak, length;
x = num[r];
i = p - 1;
bak = 0;
for (j = p; j <= r - 1; j++)
{
if (num[j] <= x)
{
i = i + 1;
temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}
temp=num[i+1];
num[i + 1] = num[r];
num[r]=temp;
return i + 1;
}
void
quicksort (int *num, int p, int r, int june)
{
int q, bbc, ccd;
if (p < r)
{
call++;
q = partition (num, p, r, june);
bbc = q - 1 - p + 1;
quicksort (num, p, q - 1, bbc);
ccd=r-q+1;
quicksort (num, q + 1, r, ccd);
}
}
The problem is in the way you are calculating the length of teh array.......try simply giving the number of elements in the array as the parameter for the quicksort method....i guess u will have the right answer...
and also i agree to the point made....try and passing the length of the array with the array.....try both and tell me which works...:)
NEW CODE:
#include<stdio.h>
#include<string.h>
//int partition (int *,int,int);
void q_sort(int*,int,int);
void quicksort (int *,int);
static int call=0;
int main()
{
int i,j,choice;
int length;
int a[]={81, 12, 90, 3, 49, 108, 47};
i=0;
printf("the sorted array is\n");
length=sizeof(a)/sizeof(a[0]);
printf("length of array %d\n",length);
printf("quick sort called in main\n");
quicksort(a,length);
for(i=0;i<length;i++)
printf (" %d ",a[i]);
}
/*int partition(int *num,int p,int r)
{
int x,j,i,temp,bak,length;
x=num[r];
i=-1;
bak=0;
printf("inside the partition\n");
for(j=0;j<=r-1;j++)
{
if(num[j]<=x)
{
i=i+1;
temp=num[i];
num[i]=num[j];
num[j]=temp;
printf("printing array after swap\n");
for(;bak<7;bak++)
{
printf(" %d ",num[bak]);
}
}
}
num[i+1]=num[r];
return i+1;
}
*/
/*void quicksort (int *num,int p,int r)
{
int q,bbc,ccd;
if (p<r)
{
call++;
printf("partition called %d times p=%d r=%d\n",call,p,r);
q=partition(num,p,r);
bbc=q-1-p+1;
quicksort(num,p,q-1);
ccd=r-q-1+1;
quicksort(num,q+1,r);
}
}*/
void quicksort(int numbers[], int array_size)
{
q_sort(numbers, 0, array_size - 1);
}
void q_sort(int numbers[], int left, int right)
{
int pivot, l_hold, r_hold;
l_hold = left;
r_hold = right;
pivot = numbers[left];
while (left < right)
{
while ((numbers[right] >= pivot) && (left < right))
right--;
if (left != right)
{
numbers[left] = numbers[right];
left++;
}
while ((numbers[left] <= pivot) && (left < right))
left++;
if (left != right)
{
numbers[right] = numbers[left];
right--;
}
}
numbers[left] = pivot;
pivot = left;
left = l_hold;
right = r_hold;
if (left < pivot)
q_sort(numbers, left, pivot-1);
if (right > pivot)
q_sort(numbers, pivot+1, right);
}
You need to put a ; at the end of the function declaration before main:
void pass(int *) ;
^
You have to pass the size of the array along with the array itself. The function receiving the array cannot determine its size. The receiving function only sees num as a pointer, so when you use sizeof(num) it returns the size of the pointer num, not the size of the memory allocated for the array in the main function. So, you have to do something like this:
#include<stdio.h>
void pass(int *, int);
int main ()
{
int a[]={3,5,61,32,12};
int length;
length = sizeof(a)/sizeof(a[0]);
pass(a, length);
}
void pass (int *num, int size)
{
int i;
for (i=0;i<size;i++)
printf(" %d",num[i]);
}
This post explains a similar issue in more detail:
Passing an array as an argument in C++