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;
}
Related
I'm stuck with trying to get the number of searches done within a Binary search algorithm.
The goal is to test how many searches are done depending on how much data is put into the algorithm.
The program in question
//CBinarysearch.c//
#include <stdio.h>
#include <time.h>
#define NUM 100
#define MAX 200
int binary_s(int a[], int n, int s) {
int lo, hi, mid;
int c = 0;
lo = 0;//loの初期化
hi = n-1;//hiの初期化
while (lo <= hi) {
mid = (lo + hi) / 2;//midの初期化
c++;
if (s == a[mid]) break;//探索値がmidと同じ値となればloopを終了
if (s > a[mid])//探索値がmidより大きい場合
lo = mid + 1;//loの値を;1してmidへ移動
else//探索値がmidより小さい場合
hi = mid - 1;//hiの値をー1してmidへ移動
}
if (lo <= hi)
printf("The numerical value %d is in array %d (array element %d)\n", s, mid+1, mid);
else
printf("Could not be located.\n");
return c;
}
void shuffle(int a[]) {
unsigned int i, j;
int tmp;
i = MAX - 1;
while (i > 0) {//シャッフルのためのLoop
j = rand() % (i + 1);//jの値をランダム化
tmp = a[j];
a[j] = a[i];
a[i] = tmp;
i--;
}
}
int quicksort(int a[], int first, int last) {
int i, j, temp, x;
i = first;
j = last;
x = (a[i] + a[j]) / 2;//基準値は平均
while (1) {
while (a[i] < x) i++;
while (a[j] > x) j--;
//iがjより大きくなればwhile loopが解除される
if (i >= j) break;
//a[i]とa[j]を入れ替える
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
if (first < i-1) quicksort(a, first, i-1);
if (j + 1 < last) quicksort(a, j + 1, last);
return 0;
}
int main(void) {
int a[NUM];
int i;
int count;
int s;
srand((unsigned int)time(NULL));
i = rand() % NUM;
s = a[i];
for (i = 0; i < NUM; i++) {//整列数列の作成
a[i] = i + 1;
}
shuffle(a);//Fisher-Yates shuffle
quicksort(a, 0, NUM-1);//クイックソートの呼び出し
count = binary_s(a, NUM, s);
printf("\n%d ", count);//交換回数の出力
return 0;
}
I've been at this for an embarrassingly long time. And at this point I am adding more details just to make this post viable. It's been rough.
May I ask for some help, please?
You intialize s as s = a[i]; before initializing the array: this has undefined behavior. You should instead write:
s = rand() % NUM + 1;
Furthermore the shuffle function assumes the array has MAX elements whereas you define it with a length of NUM in main(). You should pass the length to shuffle().
Also note that x = (a[i] + a[j]) / 2 would have undefined behavior if the values in the array can be arbitrary large.
You should also consider adding some white space between the code and the comments to make the code more readable, especially to non Japanese readers.
Here is a modified version:
//CBinarysearch.c//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 100
int binary_s(int a[], int n, int s) {
int lo, hi, mid;
int c = 0;
lo = 0; // loの初期化
hi = n - 1; // hiの初期化
while (lo <= hi) {
mid = lo + (hi - lo) / 2; // midの初期化
c++;
if (s == a[mid]) // 探索€¤がmidと同じ€¤となればloopを終了
break;
if (s > a[mid]) // 探索€¤がmidより大きい場合
lo = mid + 1; // loの€¤を;1してmidへ移動
else // 探索€¤がmidより小さい場合
hi = mid - 1; // hiの€¤をー1してmidへ移動
}
if (lo <= hi) {
printf("The numerical value %d is in array at index %d\n",
s, lo);
} else {
printf("value %d Could not be located in array.\n", s);
}
return c;
}
void shuffle(int a[], int len) {
int i, j;
int tmp;
for (i = len - 1; i > 0; i--) { // シャッフルのためのLoop
j = rand() % (i + 1); // jの€¤をラン€ム化
tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
void quicksort(int a[], int first, int last) {
int i, j, temp, x;
if (first >= last)
return;
i = first;
j = last;
x = ((long long)a[i] + a[j]) / 2; // 基準€¤は平均
while (1) {
while (a[i] < x) i++;
while (a[j] > x) j--;
//iがjより大きくなればwhile loopが解除される
if (i >= j) break;
//a[i]とa[j]を入れ替える
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
quicksort(a, first, i - 1);
quicksort(a, j + 1, last);
}
int main(void) {
int a[NUM];
int i;
int count;
int s;
srand((unsigned int)time(NULL));
for (i = 0; i < NUM; i++) { // 整列数列の作成
a[i] = i + 1;
}
s = a[rand() % NUM];
shuffle(a, NUM); // Fisher-Yates shuffle
quicksort(a, 0, NUM - 1); // クイックソートの呼び出し
count = binary_s(a, NUM, s);
printf("iterations: %d\n", count); // 交換回数の出力
return 0;
}
What is the problem? Why is there always a fixed value of comparisons and swaps? And am I correct in counting swaps and comparisons in principle? I mean, do I accidentally count them in the wrong places? Maybe in some places it is not necessary to do this? Please help me because I really can't figure out what's wrong
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void mergeAbstract(int *a, int lb, int split, int ub, int *count, int *swaps)
{
int size = ub - lb + 1;
int *sub = (int *)malloc((ub + 1) * sizeof(int));
int i = 0, j = size - 1, k = lb;
int s;
for (s = 0; s < split + 1 - lb; s++) sub[s] = a[lb + s];
for (s = split + 1 - lb; s < size; s++) sub[s] = a[ub - (s - (split + 1 -lb))];
while (i <= j) {
(*count) += 2;
if (sub[i] > sub[j]) {
(*swaps)++;
a[k] = sub[j];
j--;
} else {
(*swaps)++;
a[k] = sub[i];
i++;
}
k++;
}
(*count)++;
free(sub);
}
void mergeSort(int *a, int lb, int ub, int *count, int *swaps) {
long split;
if (lb < ub) {
split = (lb + ub) / 2;
mergeSort(a, lb, split, count, swaps);
mergeSort(a, split + 1, ub, count, swaps);
mergeAbstract(a, lb, split, ub, count, swaps);
}
}
void arrprint(int *arr, int n) {
printf("%d", *arr);
int i;
for (i = 1; i < n; i++) printf(" %d", arr[i]);
puts("");
}
int main(int argc, char *argv[]) {
int n = 10;
int *arr = NULL;
arr = (int *)malloc(n * sizeof *arr);
int c = 0;
int *count = &c;
int h = 0;
int *swaps = &h;
srand(time(NULL));
int s;
for (s = 0; s < n; s++)
arr[s] = rand() % 50;
arrprint(arr, n);
mergeSort(arr, 0, n - 1, count, swaps);
arrprint(arr, n);
free(arr);
puts("");
printf("Comparison ans swaps : %d %d\n", *count ,*swaps);
return 0;
}
I made program that measure time of sorting n data arrays of int. Unfortunately my quicksort in worst case around 30000 numbers in array crashing program with return value 3221225725. For average case it works fine even for 500000 numbers (that is my max for testing).
Here is code for quicksort:
int part(int *tab, int left, int n)
{
int first = tab[left], i = left, j = n;
while (0 != 1)
{
while (tab[j] > first)
{
j--;
}
while (tab[i] < first)
{
i++;
}
if (i < j)
{
swap(&tab[i], &tab[j]);
i++;
j--;
}
else
return j;
}
}
void quick_sort(int *tab, int left, int n)
{
int pivot;
if (left < n)
{
pivot = part(tab, left, n);
quick_sort(tab, left, pivot);
quick_sort(tab, pivot + 1, n);
}
}
And here is code in for loop for data cases:
#include <stdio.h>
#include <stdlib.h>
#include "algorytmy.h"
#include <time.h>
int main(int argc, char *argv[]) {
srand(time(NULL));
int n;
clock_t czas1, czas2, czas3;
FILE *fw;
if (!(fw = fopen("danedowykresu_odwrotnie_zestaw2cd.txt", "w")))
{
printf("Blad otwarcia zbioru\n");
exit(2);
}
fprintf(fw,"Liczba danych;quicksort;shellsort;heapsort\n");
printf("Liczba danych;quicksort;shellsort;heapsort\n");
for(n = 25000; n < 500000; n += 1000)
{
int tab[n], i;
int *ptr = (int *)malloc(n * sizeof(int));
for (i = 0; i < n; i++)
ptr[i] = n - i;
czas1 = clock();
quick_sort(ptr, 0, n);
czas1 = clock() - czas1;
free(ptr);
for (i = 0; i < n; i++)
tab[i] = n - i;
czas2 = clock();
shell_sort(tab, n);
czas2 = clock() - czas2;
for (i = 0; i < n; i++)
tab[i] = n - i;
czas3 = clock();
heap_sort(tab, n);
czas3 = clock() - czas3;
fprintf(fw,"%d;%f;%f;%f\n", n, ((float)czas1) / CLOCKS_PER_SEC, ((float)czas2) / CLOCKS_PER_SEC, ((float)czas3) / CLOCKS_PER_SEC);
printf("%d;%f;%f;%f\n", n, ((float)czas1)/CLOCKS_PER_SEC, ((float)czas2) / CLOCKS_PER_SEC, ((float)czas3) / CLOCKS_PER_SEC);
}
fclose(fw);
return 0;
}
console screen
Your implementation is incorrect: it is unclear what you are testing with if (pocz < n). A pure implementation would test if (n - left > 1). The part() function has problems too: i and j are not properly initialized. It is always a good idea to verify correctness before even trying to measure performance.
The problem with quicksort worst case is you recurse too deep and eventually encounter a stack overflow.
Here is a modified version using a simple way to prevent deep recursion: only recurse on the smaller half and iterate on the larger one:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "algorytmy.h"
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int part(int *tab, int left, int n) {
int pivot = tab[left];
int i = left;
int j = n - 1;
for (;;) {
while (tab[i] < pivot)
i++;
while (tab[j] > pivot)
j--;
if (i < j) {
swap(&tab[i], &tab[j]);
i++;
j--;
} else {
return j + 1;
}
}
}
void quick_sort(int *tab, int left, int n) {
while (left + 1 < n) {
int p = part(tab, left, n);
if (p - left < n - p) {
quick_sort(tab, left, p);
left = p;
} else {
quick_sort(tab, p, n);
n = p;
}
}
}
int check_sorted(const int *ptr, int n, const char *name) {
for (int i = 1; i < n; i++) {
if (ptr[i - 1] > ptr[i]) {
printf("%s failed: ptr[%d] = %d > ptr[%d] = %d\n",
name, i - 1, ptr[i - 1], i, ptr[i]);
return 1;
}
}
return 0;
}
int main(int argc, char *argv[]) {
double czas1, czas2, czas3;
FILE *fw;
srand(time(NULL));
if (!(fw = fopen("danedowykresu_odwrotnie_zestaw2cd.txt", "w"))) {
printf("Blad otwarcia zbioru\n");
exit(2);
}
fprintf(fw,"Liczba danych;quicksort;shellsort;heapsort\n");
printf("Liczba danych;quicksort;shellsort;heapsort\n");
for (int n = 25000; n < 500000; n += 1000) {
int *ptr = malloc(n * sizeof(*ptr));
for (int i = 0; i < n; i++)
ptr[i] = n - i;
czas1 = clock();
quick_sort(ptr, 0, n);
czas1 = clock() - czas1;
check_sorted(ptr, n, "check_sorted");
for (int i = 0; i < n; i++)
ptr[i] = n - i;
czas2 = clock();
shell_sort(ptr, n);
czas2 = clock() - czas2;
check_sorted(ptr, n, "shell_sorted");
for (int i = 0; i < n; i++)
ptr[i] = n - i;
czas3 = clock();
heap_sort(ptr, n);
czas3 = clock() - czas3;
check_sorted(ptr, n, "heap_sorted");
fprintf(fw,"%d;%f;%f;%f\n",
n, czas1 / CLOCKS_PER_SEC, czas2 / CLOCKS_PER_SEC, czas3 / CLOCKS_PER_SEC);
printf("%d;%f;%f;%f\n",
n, czas1 / CLOCKS_PER_SEC, czas2 / CLOCKS_PER_SEC, czas3 / CLOCKS_PER_SEC);
free(ptr);
}
fclose(fw);
return 0;
}
The sorting seems to be working correctly. At least it sorts correctly :) It remains only to count the number of comparisons and swaps. How to calculate and output it?Somehow stalled at this point.. I will be very grateful for your help.If you demonstrate it with the updated code , I will be doubly grateful.
#include <stdio.h>
#include <stdlib.h>
void keyDown(int* arr, int n, int head)
{
int j;
if(2*head + 2 < n && arr[2*head + 1] < arr[2*head + 2])
{
j = 2*head + 2;
}
else j = 2*head + 1;
while(arr[head] < arr[j] && head < n / 2)
{
int tmp = arr[head];
arr[head] = arr[j];
arr[j] = tmp;
head = j;
if(2*head + 2 < n && arr[2*head + 1] < arr[2*head + 2])
{
j = 2*head + 2;
}
else j = 2*head + 1;
}
}
void heapSort(int* arr, int n)
{
int i;
for(i = n/2 - 1; i >= 0; i--)
{
keyDown(arr,n,i);
}
int l = n;
while(l > 1)
{
l--;
int tmp = arr[l];
arr[l] = arr[0];
arr[0] = tmp;
keyDown(arr,l,0);
}
}
int main(int argc, char *argv[]) {
int n=10;
int start, end,i;
int *arr;
arr=(int *)malloc(n*sizeof(int));
time_t invocation_time = time(NULL);
srand(invocation_time);
int s;
for (s=0;s<n;s++)
{
arr[s] = rand() % 50;
printf ("%d \n", arr[s]);
}
printf ("\n");
heapSort(arr, n);
for (i=0;i<n;i++){
printf ("%d \n", arr[i]);
}
return 0;
}
count the number of comparisons and swaps
make functions
//global counters
unsigned comparisons = 0, swaps = 0;
int lessthan(int a, int b) {
comparisons++;
return (a < b);
}
void swap(int *a, int *b) {
swaps++;
int tmp = *a; *a = *b; *b = tmp;
}
and then replace comparisons and swaps in your existing code with the specific function you need.
int main(int argc, char **argc) {
//...
if (lessthan(a[i], a[j])) swap(a+i, a+j);
//...
printf("comparisons: %u; swaps: %u\n", comparisons, swaps);
}
I am implementing merge sort in C. I have a merge function - merge(int array[], int start, int middle, int end) and a mergeSort function - mergeSort(int *array, unsigned int size).
The merge sort works perfectly if the first half of the original array and the second half of the original array are sorted (ex: 5,6,7,8,1,2,3,4). This is because my merge function is getting passed the original array no matter what, and it works when it is given 2 sorted arrays (as expected). My issue is when they aren't. Every time I call merge, my original array isn't being modified, even though I have programmed it to do so. Can anyone figure out where my issue is? The code is below.
When I run this code on input {10,9,8,7,6,5,4,3,2,1} it returns {5,4,3,2,1,0,10,9,8,7,6}.
void merge(int arr[], int l, int m, int r) {
int size1 = m - l + 1;
int size2 = r - m;
int arr1[size1];
int arr2[size2];
int i;
for ( i = 0; i < size1; i++ ) {
arr1[i] = arr[l + i];
}
for ( i = 0; i < size2; i++ ) {
arr2[i] = arr[m + i + 1];
}
i = 0;
int j = 0;
int k = 0;
while ( i < size1 && j < size2 ) {
if ( arr1[i] < arr2[j] ) {
arr[k] = arr1[i];
i++;
k++;
} else {
arr[k] = arr2[j];
j++;
k++;
}
}
while ( i < size1 ) {
arr[k] = arr1[i];
i++;
k++;
}
while ( j < size2 ) {
arr[k] = arr2[j];
j++;
k++;
}
}
void mergeSort(int *array, unsigned int size) {
int start = 0;
int middle = (size / 2) - 1;
int end = size - 1;
if ( size < 2 ) {
return;
}
int m = ( size / 2 );
int arr1[m];
int arr2[size - m];
int i;
for ( i = 0; i < middle + 1; i++ ) {
arr1[i] = array[i];
printf("%d\n", arr1[i]);
}
for ( i = middle + 1; i < size; i++ ) {
arr2[i - (middle + 1)] = array[i];
}
mergeSort(arr1, m);
mergeSort(arr2, size - m);
merge(array, start, middle, end);
}
In mergeSort, after doing mergeSort(arr1, m) and mergeSort(arr2, size - m), you are not actually doing anything with arr1 and arr2.
For a simple fix, I suggest not using the variables arr1 and arr2 and calling mergeSort directly on parts of array, like so:
void mergeSort(int* array, unsigned int size) {
int start = 0;
int middle = (size / 2);
int end = size - 1;
if ( size < 2 ) {
return;
}
mergeSort(array, middle);
mergeSort(array + middle, size - middle);
merge(array, start, middle - 1, end);
}
There are multiple issues in your code:
the mergeSort function splits the array into 2 local arrays and calls itself recursively to sort them, but the merge phase does not take these sorted arrays as inputs. You should instead use portions of the argument array directly.
the size computations are cumbersome, with many adjustments that would pose problems for small values of size. Use a simple convention: pass end as the offset of the first element past the end of the array. This way the size is computing simply by subtracting start from end.
the merge function initializes k to 0 instead of l.
Here is a corrected version:
void merge(int arr[], int start, int m, int end) {
int size1 = m - start;
int size2 = end - m;
int arr1[size1];
int arr2[size2];
int i, j, k;
for (i = 0; i < size1; i++) {
arr1[i] = arr[start + i];
}
for (i = 0; i < size2; i++) {
arr2[i] = arr[m + i];
}
i = j = 0;
k = start;
while (i < size1 && j < size2) {
if (arr1[i] < arr2[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while (i < size1) {
arr[k++] = arr1[i++];
}
while (j < size2) {
arr[k++] = arr2[j++];
}
}
void mergeSort(int *array, unsigned int size) {
if (size >= 2) {
int m = size / 2;
mergeSort(array, m);
mergeSort(array + m, size - m);
merge(array, 0, m, size);
}
Bob__ suggested a simplification, saving only the first half of the array to arr1 and removing the need for arr2. Here is a modified version, also removing start which is always 0 and some other simplifications:
void merge(int arr[], size_t m, size_t size) {
int arr1[m];
size_t i, j, k;
for (i = j = k = 0; j < m; j++) {
arr1[j] = arr[j];
}
while (i < m && j < size) {
if (arr1[i] < arr[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr[j++];
}
}
while (i < m) {
arr[k++] = arr1[i++];
}
}
void mergeSort(int *array, size_t size) {
if (size >= 2) {
size_t m = size / 2;
mergeSort(array, m);
mergeSort(array + m, size - m);
merge(array, m, size);
}
Note however that allocating arr1 with automatic storage, aka on the stack, may cause undefined behavior for large arrays, typically larger than a few hundreds of thousand of elements. Allocating a temporary array from the heap avoid this problem at the cost of extra overhead and the possibility for allocation failure.
Sorted merge on every recursive is done on local array created on stack and it is not carry forwarded to previous function call. End result of entire recursive call is nothing but merge of {10,9,8,7,6} and {5,4,3,2,1}.
You can find the debug verification here.
Note: output has variation in my debug code as caller of mergeSort can have different implementation
Updated snippet as follows,
#include <stdio.h>
void merge(int arr[], int l, int m, int r) {
int size1 = m - l;
int size2 = r - m;
int arr1[size1];
int arr2[size2];
int i;
for ( i = 0; i < m; i++ ) {
arr1[i] = arr[l + i];
}
for ( i = 0; i+m < r; i++ ) {
arr2[i] = arr[m + i ];
}
i = 0;
int j = 0;
int k = 0;
while ( i < size1 && j < size2 ) {
if ( arr1[i] < arr2[j] ) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while ( i < size1 ) {
arr[k++] = arr1[i++];
}
while ( j < size2 ) {
arr[k++] = arr2[j++];
}
}
void mergeSort(int* array, unsigned int size) {
if ( size < 2 ) {
return;
}
int start = 0;
int middle = (size / 2);
int end = size;
mergeSort(array, middle);
mergeSort(&array[middle], end-middle);
merge(array, start, middle, end);
}
int main()
{
int a[] = {10,9,8,7,6,5,4,3,2,1};
const int size = sizeof(a)/sizeof(a[0]);
mergeSort(a,size);
for(int i=0;i<size;i++)
printf("%d ", a[i]);
}
output : 1 2 3 4 5 6 7 8 9 10