问题
I have written a code for mergesort to sort an array of structures in c it works fine when i give no. of entries as a power of 2 but does not even sort the records for other no. of entries. I Would like to learn where is my logic going wrong??
Here is my code:
void Mergesort(struct record r[],int n)
{
int k;
if(n>1)
{
int i,j;
struct record r1[n/2];
struct record r2[n-n/2];
for(i=0,j=n/2;i<n/2 && j<n;i++,j++)
{
r1[i]=r[i];
r2[i]=r[j];
}
Mergesort(r1,n/2);
Mergesort(r2,n/2);
r=Merge(r1,r2,r,n);
}
}
struct record * Merge(struct record r1[],struct record r2[],struct record r[],int n)
{
int i=0,j=0,k=0;
while(i<n/2 && j<n/2)
{
if (strcmp(r1[i].a,r2[j].a)<=0)
{
r[k]=r1[i];
i=i+1;
}
else
{
r[k]=r2[j];
j=j+1;
}
k=k+1;
}
if(i==n/2)
{
for(j;j<n/2 && k<n;j++,k++)
{
r[k]=r2[j];
}
}
else
{
for(i;i<n/2 && k<n;i++,k++)
{
r[k]=r1[i];
}
}
return r;
}
Any Help would be greatly appreciated.!!
Sample Input for 8 entries:
CS003 Vinay 10
CS005 Mouli 9.94
CS010 Gautham 9.94
CS020 Sneha 9.94
CS200 Mohit 9.93
CS012 Aarti 9.9
CS002 Adithya 9.78
CS001 Adithya 9.58
Getting correct output as follows:
CS012 Aarti 9.90
CS002 Adithya 9.78
CS001 Adithya 9.58
CS010 Gautham 9.94
CS200 Mohit 9.93
CS005 Mouli 9.94
CS020 Sneha 9.94
CS003 Vinay 10.00
**[Sorted according to the Names in the record]**
Sample input for 7 entries:
CS003 Vinay 10
CS005 Mouli 9.94
CS010 Gautham 9.94
CS020 Sneha 9.94
CS200 Mohit 9.93
CS012 Aarti 9.9
CS002 Adithya 9.78
Output(Weird):
CS200 Mohit 9.93
CS005 Mouli 9.94
CS020 Sneha 9.94
CS012 Aarti 9.90
CS003 Vinay 10.00
CS010 Gautham 9.94
CS002 Adithya 9.78
[Not at all sorted according to the names]
回答1:
I would make the below changes:
void Mergesort(struct record r[],int n)
{
int k;
if(n>1)
{
int i,j;
struct record r1[n/2];
struct record r2[n-n/2];
for(i=0; i<n/2; i++)
{
r1[i]=r[i];
}
for(i=0,j=n/2; j < n; i++,j++) // This is required because your previous logic used to skip the last element of j when n is odd.
{
r2[i]=r[j];
}
Mergesort(r1,n/2);
Mergesort(r2,n-n/2);//this is 'n - n/2'
r=Merge(r1,r2,r,n/2, n-n/2); //The sizes are different so pass both
}
}
struct record * Merge(struct record r1[],struct record r2[],struct record r[],int r1N, int r2N)
{
int i=0,j=0,k=0;
while(i<r1N && j<r2N)
{
if (strcmp(r1[i].a, r2[j].a)<=0)
{
r[k]=r1[i];
i=i+1;
}
else
{
r[k]=r2[j];
j=j+1;
}
k=k+1;
}
if(i==r1N)
{
for(j;j< r2N && k < (r1N + r2N);j++,k++)
{
r[k]=r2[j];
}
}
else
{
for(i;i < r1N && k < (r1N+r2N); i++,k++)
{
r[k] = r1[i];
}
}
return r;
}
回答2:
The problem is with this loop:
for(i=0,j=n/2;i<n/2 && j<n;i++,j++) { ... }
Since you are filling r1[]
and r2[]
in the same loop, you are filling each array with the same number of items. However, if n
is an odd number, you will need to put the last remaining element of r[]
into one of these arrays. The easiest solution would be to have two separate loops.
回答3:
Your main mistake is
- not considering unequal 'halves' of
n
in case of odd value, which means your code works only if all divisions ofn
-s by halves produce even numbers (until it went down to 2=1+1); that implies the starting value ofn
must be a power of 2.
That is reflected in following errors:
- a single
for()
loop to fill bothr1[]
andr2[]
despite the fact they are different lengths; - the recursive call to
Mergesort
withr2
passing wrong length (n/2
while it should ben-n/2
); - passing the
n
parameter alone toMerge
and not calculatingn-n/2
forr2[]
insideMerge
.
In addition, unused variable k
declared in Mergesort
and useless r
assignment at the end of the function.
Please see the code below.
void Mergesort(struct record r[], int n)
{
if (n > 1)
{
int n1 = n/2;
int n2 = n - n1;
int i;
struct record r1[n1];
struct record r2[n2];
for (i = 0; i < n1; i++) // fill r1[] with n1 items from r[]
r1[i] = r[i];
for (i = 0; i < n2; i++) // fill r2[] with n2 items from r[]
r2[i] = r[n1+i]; // skipping n1 already copied to r1[]
Mergesort(r1, n1); // pass appropriate lengths
Mergesort(r2, n2);
Merge(r1, r2, r, n1, n2); // pass arrays with lengths
}
}
void Merge(struct record r1[], struct record r2[], struct record r[], int n1, int n2)
{
int i=0, j=0, k=0;
while (i < n1 && j < n2) // any items left in both sub-arrays?
{
if (strcmp(r1[i].a, r2[j].a) <= 0) // append the smaller one
r[k++] = r1[i++]; // or earlier if they're equal
else
r[k++] = r2[j++];
}
while (i < n1) // append the remaining part, if any
r[k++] = r1[i++];
while (j < n2)
r[k++] = r2[j++];
}
You might also simplify the code a bit by dropping indices and operating directly on pointers and decrementing lengths of remaining parts:
void Merge(struct record r1[], struct record r2[], struct record r[], int n1, int n2)
{
while (n1 && n2) // any items left in both sub-arrays?
{
if (strcmp(r1->a, r2->a) <= 0) // append the smaller one
*r++ = *r1++, n1--; // or earlier if they're equal
else
*r++ = *r2++, n2--;
}
while (n1--) // append the remaining part, if any
*r++ = *r1++;
while (n2--)
*r++ = *r2++;
}
来源:https://stackoverflow.com/questions/35158903/weird-output-of-merge-sort-for-no-of-entries-not-being-a-power-of-2-c