Merge Sort in C using Recursion - c

This is my code for merge sort in C. I'm not able to understand what the issue is here. My knowledge of pointers is not that much. The merge function takes in 2 arrays and merges them. the sort function is a recursive function which is supposed to sort the array.
int * merge(int *fir, int n, int *sec, int m){
int res[m+n];
int x=0, y=0;
for(int i = 0; i < m+n; i++){
if(*(fir+x)<=*(sec+y)){
res[i] = *(fir+x);
x++;
}else{
res[i] = *(sec+y);
y++;
}
}
return res;
}
int * sort(int A[], int n){
if(n == 1){
return A;
}
int mid = n/2;
int AL[mid], AR[n-mid];
for(int i = 0; i < mid; i++){
AL[i] = A[i];
}
for(int i = 0; i < n-mid; i++){
AR[i] = A[i+mid];
}
int *BL, *BR;
BL = sort(AL, mid);
BR = sort(AR, n-mid);
return(merge(BL, mid, BR, n-mid));
}
int main(){
int n;
scanf("%d", &n);
int A[n];
for(int i = 0; i < n; i++){
scanf("%d", &A[i]);
}
int *sortedArray;
sortedArray = sort(A, n);
for(int i = 0; i < n; i++){
printf("%d ", *(sortedArray+i));
}
return 0;
}
And this is the output
q8.c:16:9: warning: address of stack memory associated with local variable 'res' returned [-Wreturn-stack-address]
return res;
^~~
1 warning generated.
7
23 12 56 67 11 99 97
97 32766 539779418 32767 -2002825496 32767 6 %```

There are two issues here: First, you merge your partial arrays into a temporary local array, which yoes out of bounds after you return from merge. The pointer you return points to invlid memory. That's what the warning about.
Second, you don't check whether you are reading beyond the limits of the partial arrays when you merge: The condition x < n must be true when you access fir, likewise for y < m and sec.
You are also causing confusion by returning a pointer to the first element of the sorted or merged arrays. That suggests that you create new sorted and merged arrays (and that's what you try to do in merge). This is okay for garbage-collected morern languages, but C doesn't work that way.
In C, if you need new memory, you must allocate it and later free it explicitly. In a recursive function like yours, this is tedious, because you are interested only in the final sorted array, not in the intermediate results. Therefore, C sorting algorithms usually work "in place": The same memory is used thoughout the sorting and elements are swapped. The original order of the elements is lost unless you make a copy before sorting.
For merge sort, you need auxiliary memory. In your case, you use the temporary arrays AL and AR, which are copies of the contents of the original array, A. Now when you merge, you can merge AL and AR back into A.
So istead of creating a ephemeral local array, pass in A so that it can be filled with the sorted elements:
void sort(int A[], int n)
{
if (n > 1) {
int mid = n / 2;
int AL[mid], AR[n - mid];
for (int i = 0; i < mid; i++) AL[i] = A[i];
for (int i = 0; i < n - mid; i++) AR[i] = A[i + mid];
sort(AL, mid);
sort(AR, n - mid);
merge(A, AL, mid, AR, n - mid);
}
}
Your merge function is now very similar to the one you has before, only that you have the result array as parameter and that you must catch the out-of-bound cases before accessing elements with [].
void merge(int *res, const int *fir, int n, const int *sec, int m)
{
int x = 0, y = 0;
for(int i = 0; i < m + n; i++) {
if (x == n) res[i] = sec[y++];
else if (y == m) res[i] = fir[x++];
else if (fir[x] <= sec[y]) res[i] = fir[x++];
else res[i] = sec[y++];
}
}

Related

What's wrong with this merge sort code I have done from the CLRS?

Wrong output!
I have tried each and every condition but failed to get the real result
I tried to accomplish this from the clrs book pseudo-code but I failed.
I am trying to write merge sort using iterators to implement myself pseudo-code in c language, but for some reason, this code is compiling but the outcome is not sorted. Can someone figure out what is wrong with it? it seems perfectly fine to my untrained eyes.
#include <stdio.h>
#include<math.h>
#include <stdlib.h>
int a[] = {5,3,65,6,7,3,7,8};
void print_array(int a[], int size)
{
int i;
for(i = 0;i < size;i++)
{
printf("%d ",a[i]);
}
}
void merge(int a[],int p,int q,int r)
{
int n1,n2,i,j,k;
n1 = q - p + 1;
n2 = r - q;
int l[n1];
int m[n2];
for(i = 0; i < n1; i++)
l[i] = a[i+p];
for(j = 0; j < n2; j++)
m[j] = a[q+1+j];
l[n1] = 9999999;
m[n2] = 9999999;
i = 0;
j = 0;
for(k = p;k < r; k++)
{
if(l[i] <= m[j])
{
a[k] = l[i];
i = i+1;
}
else
{
a[k] = m[j];
j = j+1;
}
}
}
void merge_sort(int a[],int p,int r)
{
if(p < r)
{
int q = floor((p + r) / 2);
merge_sort(a,p,q);
merge_sort(a,q+1,r);
merge(a,p,q,r);
}
}
int main()
{
int size = (sizeof(a) / sizeof(a[0]));
print_array(a,size);
printf("\n");
merge_sort(a,0,size);
print_array(a,size);
return 0;
}
//for this input out put is showing
//-1 -1 3 3 3 -1 6 7
Please pay attention to array bounds and sizes:
Your parameter r is not the size of the array, but the index of the rightmost element, so you should call merge_sort(a, 0, size - 1);.
When you want to use a large sentinel value, after the actual array, you must allocate space for it, so:
int l[n1];
int m[n2];
Because your value r is the index of the last element, you must consider it when merging and your loop condition should be for(k = p; k <= r; k++).
(Not really a problem, but you don't need to use floor like in JavaScript. When a and b are integers, a / b will perform a division that results in an integer.)
In C, arrays (and ranges in general) have inclusive lower bounds and exclusive upper bounds: lo is the first valid index and hi is the first invalid index after the valid range. For array indices, lo and hi are zero and the array size.
Embrace this convention. The C indices lead to the following style:
The length of a range is hi - lo;
Forward loops are for (i = lo; i < hi; i++);
Adjacent ranges share the hi and lo values.
For example, in your merge function the middle value p would be the first value in the right range, but also the exclusive upper bound of the left range.
If pseudocode or code in other languages uses one-based indices, I recommend translating it to the zero-based, exclusive upper-bound style of C. After a while, you'll get suspicious of spurious - 1's and <='s. :)

inversion count mergesort in C

A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once.
Two integers in а permutation form an inversion, when the bigger one is before the smaller one.
As an example, in the permutation 4 2 7 1 5 6 3, there are 10 inversions in total. They are the following pairs: 4–2, 4–1, 4–3, 2–1, 7–1, 7–5, 7–6, 7–3, 5–3, 6–3.
Input n and array[n] 2<=n<=100,000
First I solved problem with bubble sorting but then i met time complexity problem.
Second I solved it mergesort but I didn't do well
Here is my cord
#include <stdio.h>
#include <malloc.h>
int n;
void sizein(){
scanf("%d",&n);
}
int count=0;
static void merge(int data[],int p,int q,int r){
int i,j,l;
int k=p;
int sorted[n];
for(i=p,j=q+1;i<=q&&j<=r;){
sorted[k++]=(data[i]<=data[j]) ? data[i++]:data[j++];
if(data[i>data[j]]){
count+=q-i;
}
}
if(i>q){
for(l=j;l<=r;l++,k++){
sorted[k]=data[l];
}
}
else{
for(l=i;l<=q;l++,k++){
sorted[k]=data[l];
}
}
for(l=p;l<=r;l++){
data[l]=sorted[l];
}
}
void merge_sort(int data[],int p,int r){
if(p<r){
int q=(p+r)/2;
merge_sort(data,p,q);
merge_sort(data,q+1,r);
merge(data,p,q,r);
}
}
int main(void){
int i;
int data[n];
for(i=0;i<n;i++){
scanf("%d",&data[i]);
}
merge_sort(data,0,n);
printf("%d",count);
return 0;
}
Where should i fix it
I cannot find some implementation bits in your code that divides the arrays into sub-arrays based on the index(as quick sort sorts based on value)
kindly have a look at the code provided below
int q = p + (r - l) / 2;//recommended to be used in the function mergesort
int q=(p+r)/2;//your implementation
try this code for your function part as my code runs well with over half a million values, I cannot clearly see any subarray to which values are copied in your implementation of the function merge I have added comments to make it easier for you to understand, the terminology of the variables are slightly different.
refer "ANANY LEVETIN-INTRODUCTION TO THE DESIGN AND ANALYSIS OF ALGORITHS" book for a vivid explanation on this algorithm
Have a look and try this
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[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]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* Driver code */
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("Given array is \n");
//printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("\nSorted array is \n");
//printArray(arr, arr_size);
return 0;
}
After reading the code for some time I still can not say I understand the idea of counting the inversions. However, I can point out three things in it which seem incorrect to me.
First, I can't see where you call the sizein() function to initialize the n variable.
The second problem is the condition here:
if(data[i>data[j]]){
count+=q-i;
}
You compare the index i to the value of a data item data[j] which looks strange. Even worse, if you were to sort an array of geometric figures or an array of songs it could be just impossible due to incompatibility of the types of data to be compared. What's even worse, even if comparison succeedes, as in the case of an int index and an int value in data[],the result of comparison is an int value 1 if comparison is satisfied or 0 otherwise. As a result this condition will resolve to
if(data[0]){
count+=q-i;
}
or to
if(data[1]){
count+=q-i;
}
which is obviously wrong.
The correct code looks like this:
if (data[i] > data[j]) {
count += q - i;
}
The error would be more apparent if you left appropriate spacing between operators and their operands.
Yet another error lurks in the call to merge_sort(). First, you fill the data[] array with this loop:
for (i = 0; i < n; i ++) {
scanf("%d", &data[i]);
}
Obviously, you fill an n-items array with data at indices from 0 through n-1.
Then you call the merge-sorting routine:
merge_sort( data, 0, n);
which suggests the parameter p is the index of the first item or the part to be sorted and q is one-past-the last item. However, this disagrees with recursive calls:
merge_sort( data, p, q);
merge_sort( data, q+1, r);
Setting q as the ending index in the first call and q+1 as the starting index in the second suggests the ending index is inclusive, that is, it is the position of the last item in the segment to be sorted. Otherwise the two calls would leave the item data[q] unsorted. This also follows from internal loops, which continue while i <= q or whle l <= r etc.
So the initial call shouldn't be
merge_sort( data, 0, n);
but rather
merge_sort( data, 0, n-1);

Wrong output in Merge Sort Algorithm

I've followed all the algorithm steps very carefully , but still this always outputs me the wrong answer. I don't understand why. I think something's wrong in the merge algorithm that's causing this but cannot pinpoint what. Please help. Also if there is anything that can be done to improve the code please suggest.
Thank you
INPUT - {5,6,1,8,9,7}
OUTPUT - {1,0,7,0,9,7}
#include<stdio.h>
#include<malloc.h>
void mergeSort(int array[],int length);
void merge(int *leftArray,int *rightArray,int *array);
void main()
{
int array[] = {5,6,1,8,9,7};
int length_of_array;
length_of_array = sizeof(array) / sizeof(array[0]);
mergeSort(array,length_of_array);
int i;
for(i=0;i<length_of_array;i++)
{
printf("%d->",array[i]);
}
}
void mergeSort(int array[],int length)
{
if(length < 2)
return;
int mid;
int i;
mid = length/2;
int *leftArray, *rightArray;
leftArray = (int*)malloc(mid*sizeof(int));
rightArray = (int*)malloc((length-mid)*sizeof(int));
for(i=0;i<mid;i++)
leftArray[i] = array[i];
for(i=mid;i<length;i++)
rightArray[i-mid] = array[i];
mergeSort(leftArray, mid);
mergeSort(rightArray, length-mid);
merge(leftArray,rightArray,array);
}
void merge(int *leftArray,int *rightArray,int *array)
{
int i,j,k;
i = j = k = 0;
int leftSize = sizeof(leftArray)/sizeof(leftArray[0]);
int rightSize = sizeof(rightArray)/sizeof(rightArray[0]);
while(i < leftSize && j < rightSize)
{
if(leftArray[i]<rightArray[j])
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
else
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
while(i<leftSize)
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
while(j<rightSize)
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
As commented by #molbdnilo, you can't get the size of an array from a pointer parameter. So merge needs to take the length of the left and right arrays as well as the pointers to them.
The issue is that arrays in C are not a 'complete' data type, but rather just a convenient syntax. In your merge function, the parameter int *leftArray is exactly what it says - a pointer to an integer. So sizeof will tell you the size of a pointer. In your main function, array is known to be an array, and its length is known (from the initial value given), so sizeof can give the actual size of memory allocated to that variable. But that size is not stored anywhere with the variable, so it is not passed into merge - the only thing passed in is the pointer to the block of memory.
In addition, while it won't be causing you problems in this case, you should be freeing the leftArray and rightArray pointers that you malloc. That way you can use your sorting function in an actual application without leaking memory.

Knapsack algorithm for large input

I have developed this knapsack algorithm based on pseudo-code found on wikipedia. It works fine for small number of items and capacity (n=6, v=2014), but it crashes for large numbers (n=5, v=123456789).
Additional problem is, that my program is tested by makefile with time limit set at 1 second.
What can i do to save time and memory?
v - Knapsack capacity
n - Number of items
weight[] - Weights
value[] - Values
int knapSack(int v, int weight[], int value[], int n){
int a, i, j;
int **ks;
ks = (int **)calloc(n+1, sizeof(int*));
for(a = 0; a < (n+1); a++) {
ks[a] = (int *)calloc(v+1, sizeof(int));
}
for (i = 1; i <= n; i++){
for (j = 0; j <= v; j++){
if (weight[i-1] <= j){
ks[i][j] = max(value[i-1] + ks[i-1][j-weight[i-1]], ks[i-1][j]);
} else {
ks[i][j] = ks[i-1][j];
}
}
}
int result = ks[n][v];
for(i = 0; i < (n+1); i++) {
free(ks[i]);
}
free(ks);
return result;
}
An array of 123456789 integer elements declared on the stack will crash many implementations of C. Sounds like this is your problem. Did you declare your arrays inside of a function (on the stack)?
// on heap
static int v[123456789]={0};
// on the stack (inside a function like main() )
int foo()
{
int v[123456789]={0};
}

Enumerate and return all the combinations of choosing k out of n items in a 2-dimensional array from a recursive function in C

I am using a recursive function (from one of the posts here) to enumerate all combinations of selecting k items out of n. I have modified this function to save and return the enumerated combinations in a 2-dimensional array (which is passed to the function as arrPtr). I call this recursive function in a for loop (from main) for different values of k (k from 1 to n-1) to generate all the combinations for any value of n and k. Now, with 'count', being defined as static integer, the function generates all the combinations for k=1 and then goes to k=2, but then stops at one point. The reason is that I'm using the variable 'count' as an index for rows in arrPtr. Since it is a static variable, it does not reset to 0 when the function is called for the other rounds (k=2,3,4 etc.). So it results in access violation for arrPtr after a certain point. When I remove 'static' for 'count', it generates all the combinations for different values of k, but only the last combination in each round is saved in arrPtr (again due to removing 'static'). How can I save each generated combination in a row in arrPtr so I can get (and return) all of the combinations saved in one place pointed to by arrPtr at the end?
I tried to pass the index for rows in arrPtr to the function using pass by reference (passing the address of the variable) but that gets into trouble when the recursive function calls itself.
I searched a lot and found similar topics here (e.g., returning arrays from recursive functions), but they are mostly for other programming languages (I only use C; not even C++). I have spent many many hours on solving this and really need help now. Thank you in advance.
int** nCk(int n,int loopno,int ini,int *a,int **arrPtr, int k)
{
static int count=0;
int total; // equal to the total number of combinations of nCk
int i,j;
total = factorial(n)/(factorial(n-k)*factorial(k));
loopno--;
if(loopno<0)
{
a[k-1]=ini;
for(j=0;j<k;j++)
{
printf("%d,",a[j]);
arrPtr[count][j]=a[j];
}
printf("count =%d\n",count);
count++;
return 0;
}
for(i=ini;i<=n-loopno-1;i++)
{
a[k-1-loopno]=i+1;
nCk(n,loopno,i+1,a,arrPtr,k);
}
if(ini==0)
return arrPtr; // arrPtr is in fact an array of pointers, where each pointer points to an array of size k (one of the combinations of selecting k out of n elements
else
return 0;
}
what i understand is
you want to calculate the combination for any value of n and k in nCk,
define a factorial() function outside and
define a combi() function ... which calculates Combination value of n and k variables
both function before defining the main() function... that way you can avoid declaration and then defining (i mean avoid extra lines of code).
here is the code for combi() function
function combi(int n , int k){
int nFact, kFact, n_kFact, p;
int comb;
nFact=factorial(n);
kFact=factorial(k);
p=n-k;
n_kFact=factorial(p);
comb= nFact / ((n_kFact) * kFact);
return comb;
}
you can call this function in your main function .... use for loop to store the combination value for relative n and k .... thus you will get what you need .... also pass pointer or
&array[0][0]
i.e. starting address for the array... so that you can access that array anywhere in the program.
hope this may help you. thanks
GCC 4.7.3: gcc -Wall -Wextra -std=c99 enum-nck.c
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Textbook recursive definition of, n-choose-k.
int nCk(int n, int k) {
assert(0 < k && k <= n);
if (k == n) { return 1; }
if (k == 1) { return n; }
return nCk(n - 1, k) + nCk(n - 1, k - 1);
}
// But you asked for a procedure to enumerate all the combinations.
void aux_enum_nCk(int n, int k, int* all, int* j, int a[], int i) {
a[i] = n;
if (i == k - 1) {
memcpy(&all[*j], &a[0], k * sizeof(int));
*j += k;
return;
}
for (int c = n - 1; c > 0; --c) {
aux_enum_nCk(c, k, all, j, a, i + 1);
}
}
void enum_nCk(int n, int k, int* arr) {
assert(0 < k && k <= n);
int j = 0;
int a[k];
for (int i = 0; i < k; ++i) { a[i] = 0; }
for (int c = n; c >= n - k - 1; --c) {
aux_enum_nCk(c, k, arr, &j, a, 0);
}
}
int main(int argc, char* argv[]) {
int n = 7;
int k = 3;
int x = nCk(n, k);
printf("%d choose %d = %d\n", n, k, x);
int arr[x][k];
enum_nCk(n, k, &arr[0][0]);
for (int i = 0; i < x; ++i) {
for (int j = 0; j < k; ++j) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}

Resources