Mergesort bug + warnings - c

I have the following code, followed it form a tutorial, and it doesn't seem to do anything. I tried debugging it with KDB but I can't find the problem why it doesn't sort.
Maybe someone on here can help me, thanks in advance!
#include <stdio.h>
#include <stdlib.h>
void Mergesort(int *a, int length) {
int i = 0;
int mid = 0;
int *L, *R;
mid = length / 2;
if (length < 2)
return;
else {
L = (int*)malloc(sizeof(int) * mid);
R = (int*)malloc(sizeof(int) * (length - mid));
for (i = 0; i < mid; i++) {
L[i] = a[i];
}
for (i = mid; i < length; i++) {
R[i - mid] = a[i];
}
Mergesort(L, mid);
Mergesort(R, length - mid);
Merge(a, L, R, length);
}
}
void Merge(int *a, int *L, int *R, int length) {
int i = 0, j = 0, k = 0;
int mL, mR;
mL = length / 2;
mR = length - mL;
while (i < mL && j < mR) {
if (L[i] < R[j]) {
a[k] = L[i];
i++;
} else {
a[k] = R[j];
j++;
}
k++;
}
while (i < mL) {
a[k] = L[i];
i++;
k++;
}
while (j < mR) {
a[k] = R[j];
i++;
k++;
}
}
void main() {
int a[7] = { 5, 4, 99, 13, 34, 54, 2 };
int u = 0;
Mergesort(a, 7); // call to Mergesort
for (u = 0; u < 7; u++) {
printf(" %d\t", a[u]);
}
printf("\n\n\n");
}
I would really appreciate it since I need to understand it before Thursday next week :P

Here you're incrementing i but you should increment j in Merge function.
while(j<mR)
{
a[k]=R[j];
j++;
k++;
}
Edit:
put function declation after the header files void Merge(int *a,int *L,int *R,int length); otherwise you will get implicit declaration of function ‘Merge’ warning.
#include<stdio.h>
#include<stdlib.h>
void Merge(int *a,int *L,int *R,int length);
//rest of your code

Related

(Merge sort) The code is printing nothing

I recently started learning algorithm with C. I tried to implement merge_sort. But the code is printing nothing and I can't find the problem why this happening. If you take a look at the code and give me the solution it would be very helpful for me. Thanks in advance.
Note: Here I didn't give the main function. Only the merge_sort() and merge() functions
#include <stdio.h>
void merge(int a[], int l[], int r[]);
void merge_sort(int a[], int n) {
if (n < 2) {
return;
} else {
int i;
int mid = (n - 1) / 2;
int l[mid], r[n - mid];
for (i = 0; i < mid; i++) {
l[i] = a[i];
}
for (i = mid; i < n; i++) {
r[i - mid] = a[i];
}
merge_sort(l, mid);
merge_sort(r, n - mid);
merge(a, l, r);
}
}
void merge(int a[], int l[], int r[]) {
int i = 0;
int j = 0;
int k = 0;
int nl = sizeof(l) / sizeof(l[0]);
int nr = sizeof(r) / sizeof(r[0]);
while (i < nl && j < nr) {
if (l[i] < r[j]) {
a[k] = l[i];
i++;
} else {
a[k] = r[j];
j++;
}
k++;
}
while(i < nl) {
a[k] = l[i];
i++;
k++;
}
while (j < nr) {
a[k] = r[j];
j++;
k++;
}
}
You cannot compute the size of the arrays passed as parameters with int nl = sizeof(l) / sizeof(l[0]); because sizeof(l) is the size of a pointer to int, not that of the array. sizeof(l) only evaluates to the size of the array when the definition of the array is in scope.
You should pass the sizes explicitly as arguments.
Also change the computation for mid: int mid = n / 2;
Here is a modified version:
#include <stdio.h>
void merge(int a[], int l[], int nl, int r[], int nr);
void merge_sort(int a[], int n) {
if (n < 2) {
return;
} else {
int i;
int mid = n / 2;
int l[mid], r[n - mid];
for (i = 0; i < mid; i++) {
l[i] = a[i];
}
for (i = mid; i < n; i++) {
r[i - mid] = a[i];
}
merge_sort(l, mid);
merge_sort(r, n - mid);
merge(a, l, mid, r, n - mid);
}
}
void merge(int a[], int l[], int nl, int r[], int nr) {
int i = 0;
int j = 0;
int k = 0;
while (i < nl && j < nr) {
if (l[i] <= r[j]) {
a[k] = l[i];
i++;
} else {
a[k] = r[j];
j++;
}
k++;
}
while (i < nl) {
a[k] = l[i];
i++;
k++;
}
while (j < nr) {
a[k] = r[j];
j++;
k++;
}
}

Program crashes when given a big number

I'm trying to make a merge sort algorithm in C. The problem is that it does not work for a big number of elements. If the array has 100000 elements it's OK but if it has 1e6 or 1e7 then it crashes. I thought that you cannot give such a big number of elements for an array but after I have read that this is not true, you should be able to give 1e7 elements. After that I thought that maybe int range is to small but that's not the case, int goes to 1e9. I don't really know what's the problem and why it doesn't work, so please help. Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
int n;
void merge(int *, int, int);
void mergeSort(int *, int, int);
void bubbleSort(int *, int);
int main() {
// scanf("%d",&n);
n = 10000000;
int *a = (int *)malloc(n * sizeof(int));
if (a == NULL) {
printf("Nu s-a putut aloca memorie.");
exit(0);
}
for (int i = 0; i < n; i++)
a[i] = rand() % 50;
mergeSort(a, 0, n - 1);
//bubbleSort(a, n - 1);
// for (int i = 0; i < n; i++) {
// printf("%d ", a[i]);
// }
free(a);
return 0;
}
void merge(int *a, int start, int sfarsit) {
int mij = (start + sfarsit) / 2;
int i = start;
int j = mij + 1;
int k = start;
int aux[10000000];
while (i <= mij && j <= sfarsit) {
if (a[i] < a[j])
aux[k++] = a[i++];
else
aux[k++] = a[j++];
}
while (i <= mij)
aux[k++] = a[i++];
while (j <= sfarsit)
aux[k++] = a[j++];
for (int i = start; i <= sfarsit; i++)
a[i] = aux[i];
}
void mergeSort(int *a, int start, int sfarsit) {
if (start >= sfarsit)
return ;
int mij = (start + sfarsit) / 2;
mergeSort(a, start, mij);
mergeSort(a, mij + 1, sfarsit);
merge(a, start, sfarsit);
}
This:
int aux[10000000];
is problem. That will be to much for the stack to handle. Change to this:
int *aux = malloc(sizeof(*aux) * 10000000);
Of course, you need to use free(aux) in the end of the function merge and also check if the allocation was successful.
Also, you should of course allocate in relation to sfarsit but judging from your other code, it does not seem like I need to tell you that.
Your program has this problem: the definition int aux[10000000]; in the merge function defines a temporary array with automatic storage (aka on the stack) which is:
very large, potentially too large for your system, causing a stack overflow.
not necessary large enough if the array to be sorted is larger than 10 million elements.
You should allocate this temporary array, either locally in merge or in a wrapper function that would call mergesort with an extra argument.
It is also unnecessary and quite error prone to make n a global variable.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int mergeSort(int *a, int length);
void bubbleSort(int *, int);
int main() {
int n;
int *a;
n = 10000000;
//scanf("%d", &n);
if ((a = malloc(sizeof(*a) * n)) == NULL) {
printf("Nu s-a putut aloca memorie.");
return 1;
}
for (int i = 0; i < n; i++)
a[i] = rand() % 50;
mergeSort(a, n);
//bubbleSort(a, n);
for (int i = 1; i < n; i++) {
if (a[i] < a[i - 1]) {
printf("mergeSort failed\n");
break;
}
}
free(a);
return 0;
}
void merge(int *a, int start, int mij, int sfarsit, int *aux) {
int i = start;
int j = mij + 1;
int k = start;
while (i <= mij && j <= sfarsit) {
if (a[i] <= a[j])
aux[k++] = a[i++];
else
aux[k++] = a[j++];
}
while (i <= mij)
aux[k++] = a[i++];
while (j <= sfarsit)
aux[k++] = a[j++];
for (i = start; i <= sfarsit; i++)
a[i] = aux[i];
}
void mergeSortAux(int *a, int start, int sfarsit, int *aux) {
if (start >= sfarsit)
return;
int mij = (start + sfarsit) / 2;
mergeSortAux(a, start, mij, aux);
mergeSortAux(a, mij + 1, sfarsit, aux);
merge(a, start, mij, sfarsit, aux);
}
int mergeSort(int *a, int length) {
if (length > 1) {
int *aux = malloc(sizeof(*aux) * length);
if (aux == NULL)
return -1;
mergeSortAux(a, 0, length - 1, aux);
free(aux);
}
return 0;
}
Note that you can improve this code:
using size_t instead of int for the array sizes and index variables
using the convention start included and stop excluded, which avoids the +1/-1 adjustments.
by not copying the remaining values from the right slice as they are already in place in the original array.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int mergeSort(int *a, size_t length);
int main(int argc, char *argv[]) {
size_t n = 10000000;
int *a;
int res = 0;
if (argc > 1) {
n = strtoll(argv[1], NULL, 0);
}
if ((a = malloc(sizeof(*a) * n)) == NULL) {
printf("Nu s-a putut aloca memorie.");
return 1;
}
for (size_t i = 0; i < n; i++) {
a[i] = rand() % 50;
}
if (mergeSort(a, n)) {
printf("mergeSort failed: allocation error\n");
res = 1;
} else {
for (size_t i = 1; i < n; i++) {
if (a[i] < a[i - 1]) {
printf("mergeSort failed: out of order\n");
res = 1;
break;
}
}
}
free(a);
return res;
}
void merge(int *a, size_t start, size_t mid, size_t stop, int *aux) {
size_t i = start;
size_t j = mid;
size_t k = start;
while (i < mid && j < stop) {
if (a[i] <= a[j])
aux[k++] = a[i++];
else
aux[k++] = a[j++];
}
while (i < mid)
aux[k++] = a[i++];
for (i = start; i < k; i++)
a[i] = aux[i];
}
void mergeSortAux(int *a, size_t start, size_t stop, int *aux) {
if (stop - start >= 2) {
size_t mid = start + (stop - start) / 2;
mergeSortAux(a, start, mid, aux);
mergeSortAux(a, mid, stop, aux);
merge(a, start, mid, stop, aux);
}
}
int mergeSort(int *a, size_t length) {
if (length > 1) {
int *aux = malloc(sizeof(*aux) * length);
if (aux == NULL)
return -1;
mergeSortAux(a, 0, length, aux);
free(aux);
}
return 0;
}

mergesort using C , the output goes wrong

I wrote the code in CodeBlocks 17.0.1
It seems that it only sorts some elements in the array, not all. Also, I can't find the differences between my code and the sample that I have and still don't know what goes wrong. Thank you for your help!
#include <stdio.h>
#include <stdlib.h>
void merge(float x[], float y[], int l, int m, int r)
{
int ptr_1,ptr_2,ptr_y;
ptr_1 = ptr_y = l;
ptr_2 = m+1;
while((ptr_1<=m) && (ptr_2<=r))
{
if(x[ptr_1] <= x[ptr_2])
y[ptr_y++] = x[ptr_1++];
else
{
y[ptr_y++] = x[ptr_2++];
}
}
while(ptr_1<=m)
y[ptr_y++] = x[ptr_1++];
while(ptr_2<=r)
y[ptr_y++] = x[ptr_2++];
}
void merge_sort(float a[],float b[],int l, int r)
{
if(l < r)
{ int m = l + (r-l)/2;
merge_sort(a,b,l,m);
merge_sort(a,b,m+1,r);
merge(a,b,l,m,r);
}
}
int main()
{
float a[3] ={10.3,8.5,3.23},b[3];
int i,j;
float *temp = b;
merge_sort(a,temp,0,2);
for(i=0;i<3;i++)
{
printf("%.2f ",b[i]);
}
printf("\n");
system("pause");
return 0;
}
Output: 3.23 10.30 8.50
Here is the working code:
#include <stdio.h>
#include <stdlib.h>
void merge(float a[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
float L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = a[l + i];
for (j = 0; j < n2; j++)
R[j] = a[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
a[k] = L[i];
i++;
}
else
{
a[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1)
{
a[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2)
{
a[k] = R[j];
j++;
k++;
}
}
void merge_sort(float a[],int l, int r)
{
if(l < r)
{ int m = l + (r-l)/2;
merge_sort(a,l,m);
merge_sort(a,m+1,r);
merge(a,l,m,r);
}
}
int main()
{
float a[3] ={10.3,8.5,3.23};
int i,j;
merge_sort(a,0,2);
for(i=0;i<3;i++)
{
printf("%.2f ",a[i]);
}
printf("\n");
system("pause");
return 0;
}
still don't know what goes wrong
Why were you using two different arrays?
Just one array is enough but it includes two logical arrays and the indexes l and m refer to the beginning of each array.
Add the code shown below to the end of merge to copy the data back. There are more efficient ways to do this that avoid the copy back step, but at least this fixes the code.
void merge(float x[], float y[], int l, int m, int r)
{
/* after the last line in merge, (y[ptr_y++] = x[ptr_2++];) */
/* add this code to copy from y[] back to x[] */
for(ptr_1 = l; ptr_1 <= r; ptr1++)
x[ptr_1] = y[ptr_1];
}

Why is this program giving a stack overflow?

My C merge code works when I initialize the array globally at the top of the program until the stack overflows. I'm trying to initialize the array with malloc, but when I do, the code will only read in two integers and stop running.
This program pulls random numbers from a file called alg.txt and then sorts them. Again, the code works (up until 500k integers) when defining z at the top of the program to the number of integers to be sorted, and declaring the array globally to be equal to arr[z]. How do I figure out what is going on?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int count = 0;
void merge(int arr[], 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] = arr[l + i];
count++;
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
count++;
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
count++;
}
else
{
arr[k] = R[j];
j++;
count++;
}
k++;
count++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
count++;
}
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
count++;
}
}
void mergeSort(int arr[], int l, int r)
{
if (l < r)
{
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
int main()
{
int i;
FILE *myFile;
myFile = fopen("alg.txt", "r");
int z;
printf("Enter the size of the array: ");
scanf("%d", &z);
int *arr = (int *)malloc(z*sizeof(int));
int n = sizeof(arr)/sizeof(arr[0]);
for(i=0; i < z; i++)
{
fscanf(myFile, "%d,", &arr[i]);
}
mergeSort(arr, 0, n - 1);
printf("\nSorted array is \n");
printArray(arr, n);
printf("count is %d\n", count);
return 0;
}
You are declaring the L and R array's locally (inside the merge function). They consume stack on every function call. You should initialize them globally so that they can be stored on the heap. Also, you should declare just one array (like temp_arr in the below code) as there's no need for two separate arrays like L and R.
See Local vs Global variable storage
You can improve your merge function to this:
int temp_arr[500000]; // Global declaration
void merge(int arr[], int l, int m, int r)
{
int i=l, j=m+1, k=l;
while(i<=m && j<=r)
{
if(arr[i]<arr[j])
temp_arr[++k] = arr[++i];
else temp_arr[++k] = arr[++j];
}
while(i<=m)
temp_arr[++k] = arr[++i];
while(j<=r)
temp_arr[++k] = arr[++j];
i = l;
while(i<=r)
arr[i] = temp_arr[++i]; // Storing stored array in arr
}

Merge sort algorithm in C not working as expected

I am trying to implement the merge sort algorithm in C. I understand how the algorithm is supposed to work however I am encountering some difficulties with the implementation.
I understand that there are hundreds of examples and source code for it's implementation but I was hoping someone could help me understand why mine is not working correctly.
My code is below and after the code I explain what I have tried so far.
#include <stdio.h>
void merge(int a[], int L[], int R[],int nL, int nR) //nL and nR are the lengths of L[] and R[]
{
int i = 0 , j = 0, k = 0;
while(i<nL && j <nR)
{
if(L[i] <= R[j]){
a[k] = L[i];
i++;
}
else{
a[k] = R[j];
j++;
}
k++;
}
while(i < nL){
a[k] = L[i];
i++;
k++;
}
while(j < nR) {
a[k] = R[j];
j++;
k++;
}
}
void mergesort(int a[],int n) //n is the length of a[]
{
if(n < 2) return; //BASE CASE
int mid = n / 2;
int left[mid];
int right[n-mid];
for(int i = 0; i < mid; i++)
{
left[i] = a[i];
}
for(int i = mid; i < n-1; i++)
{
right[i-mid] = a[i];
}
int nL = sizeof(left) / sizeof(left[0]);
int nR = sizeof(right) / sizeof(right[0]);
mergesort(left, nL);
mergesort(right, nR);
merge(a,left,right,nL,nR);
}
int main(void)
{
printf("Initial:\n");
printf("3 4 1 6\n");
int numbers[4] = {3,4,1,6};
int n = sizeof(numbers) / sizeof(int);
mergesort(numbers,n);
printf("Sorted:\n");
for(int i =0 ; i < 4; i++)
{
printf("%d ", numbers[i]);
}
return 0;
}
As it is and with the unsorted array [3,4,1,6] the output is 0 0 1 3.
Clearly the 1 and 3 are in the right order relative to each other but the two zeros at the beginning are clearly wrong. At first it seemed to me that I was inserting 4 and 6 to the right and out of bounds of the array.
I used some print statements to try and debug but I haven't been able to figure out what was going on. I even tried to follow my code with gdb but I still could not sort it.
Does any one have any ideas of what might be happening?
A more nearly idiomatic way of writing the merge() code would be:
void merge(int a[], int L[], int R[],int nL, int nR)
{
int i = 0, j = 0, k = 0;
while (i < nL && j < nR)
{
if (L[i] <= R[j])
a[k++] = L[i++];
else
a[k++] = R[j++];
}
while (i < nL)
a[k++] = L[i++];
while (j < nR)
a[k++] = R[j++];
}
That's about half the number of lines of your code, and within broad limits, the less code there is to read, the better. There are those who insist on having braces after each loop or conditional. I don't think that's necessary (or particularly helpful), but if that's the style you like, you can use it.
Your mergesort() code is less flabby, but could be changed to:
void mergesort(int a[],int n) //n is the length of a[]
{
if (n < 2)
return; //BASE CASE
int mid = n / 2;
int left[mid];
int right[n-mid];
for (int i = 0; i < mid; i++)
left[i] = a[i];
for (int i = mid; i < n; i++)
right[i-mid] = a[i];
mergesort(left, mid);
mergesort(right, n - mid);
merge(a, left, right, mid, n - mid);
}
This includes the fix for your main problem — the loop loading the right array was leaving the last element uncopied.
With a debugging function such as:
void dump_array(const char *tag, int n, int *a)
{
printf("%s:%d:", tag, n);
for (int i = 0; i < n; i++)
printf(" %3d", a[i]);
putchar('\n');
}
You can do a lot of effective debugging with:
void mergesort(int a[],int n)
{
if (n < 2)
return;
int mid = n / 2;
int left[mid];
int right[n-mid];
dump_array("-->>mergesort()", n, a);
for (int i = 0; i < mid; i++)
left[i] = a[i];
dump_array("left", mid, left);
for (int i = mid; i < n; i++)
right[i-mid] = a[i];
dump_array("right", n - mid, right);
mergesort(left, mid);
dump_array("merged-L", mid, left);
mergesort(right, n - mid);
dump_array("merged-R", n - mid, right);
merge(a, left, right, mid, n - mid);
dump_array("<<--mergesort()", n, a);
}
In your code, the output with the tag right would show 0 or semi-random data for the last element, rather than what you're expecting. This would be a hint as to where the trouble is. Keep the dump_array() function around; it is a useful creature to have. It's a simple-minded version; you can invent more complex versions which outputs a newline at intermediate positions for long arrays, for example.
The issue is in the following code:
for(int i = mid; i < n-1; i++)
{
right[i-mid] = a[i];
}
It should be:
for(int i = mid; i < n; i++) // right should range from mid to n - 1 *inclusive*
{
right[i-mid] = a[i];
}
This is simple implementation of merge sort without any complications. Just pass the array pointer and total number of entires in the array.
void merge(int *a, int top)// Array pointer and max entries
{
int l1, k, l2, u1, u2, size = 1, i, j;
int *sa;
sa = (int *)calloc(top, sizeof(int));
while (size < top)
{
l1 = 0;
k = 0;
while (l1 + size < top)
{
l2 = l1 + size;
u1 = l2 - 1;
u2 = ((l2 + size - 1) < top ? l2 + size - 1 : top - 1);
for (i = l1, j = l2; i <= u1 && j <= u2; )// Merging
{
sa[k++] = a[i] <= a[j] ? a[i++] : a[j++];
}
for ( ; i <= u1; )
sa[k++] = a[i++];
for ( ; j <= u2; )
sa[k++] = a[j++];
l1 = u2 + 1;
}
for (i = l1; i < top; i++) // For the left outs of the process
sa[k++] = a[i];
for (i = 0; i < top; i++)
a[i] = sa[i];
size *= 2;
}
}

Resources