Search code examples
cfunctionrecursionmergesort

Writing merge sort in C without pointers


I am trying to write code for homework in C that will take 10 integers from user input into an array and sort it using a recursive merge sort. We have not gone over pointers yet so I wanted to avoid using that in my code (many online examples use pointers).

Here is my code:

/* This code will take input for 10 integers given by the user
into an array, sort them with a recursive merge function
and print the updated array in ascending order. */

#include <stdio.h>
#define ARRSIZE 10

void merge_sort (int arr[], int temp[], int left, int right);
void merge (int arr[], int temp[], int left, int mid, int right);

int main (void){
    int arr[ARRSIZE], temp[ARRSIZE], left, right, i;

    printf("Enter 10 integers for an array:");
    for(i=0;i<ARRSIZE;i++){
        printf("\narray value %d:", i+1);
        scanf("%d", &arr[i]);
    }
    left = 0;
    right = ARRSIZE-1;

    merge_sort(arr, temp, left, right);

    printf("\nHere is your updated array:");
    printf("\n{");
    for(i=0;i<ARRSIZE;i++){
        printf("%d,", arr[i]);
    }
    printf("}");

    return 0;
}

void merge_sort (int arr[], int temp[], int left, int right){
    if(left<right){
        int mid = (right-left)/2;
        merge_sort(arr, temp, left, mid);
        merge_sort(arr, temp, mid+1, right);
        merge(arr, temp, left, mid, right);
    }
}

void merge (int arr[], int temp[], int left, int mid, int right){
    int i, j, tempi = 0;
    for(i=left, j=mid+1; i<=mid && j<=right ;){
        // mid+1 is the start of the right array
        if(arr[i]<arr[j] && i<=mid){
            temp[tempi] = arr[i];
            tempi++;
            i++;
        }
        else if(arr[i]>arr[j] && j<=right){
                temp[tempi] = arr[j];
                tempi++;
                j++;
             }
    }
    for(i=0,j=right; i<=j; i++){
        arr[i] = temp[i];
    }
}

I keep getting a segmentation fault when I run this in my linux shell. Any suggestions?


Solution

  • Well, I've found one subtle bug already: int mid = (right-left)/2; should be int mid = (left+right)/2;

    Also, what flows I've found:

    1. You should use tempi = left for simplicity. Simply copy incoming part of array to corresponding part of temporary array.

    2. In your merge cycle, you can place incrementing tempi inside for definition:

      for( ...; ...; ++tempi)

    3. Inside that loop you check boundaries AFTER you have read values from that place. This is very bad. VERY. Although, You haven't encounter any problems here just because you are checking boundaries inside for definition :) simply remove them:

      for (i = left, j = 1 + mid; i <= mid && j <= right; ++tempi)
      {  
          if (arr[i] < arr[j])        temp[tempi] = arr[i++];
          else /* arr[j] <= arr[i] */ temp[tempi] = arr[j++];
      }
      
    4. Cause this loop exits when either subarray has reached end, you have to copy rest of items from another subarray to temp[]:

      if (i > mid) i = j; /* if we need to copy right subarray */
      for (; tempi <= right; ++tempi, ++i) temp[tempi] = arr[i];
      
    5. So, your copying back from temporary array will look like

       for (i = left; i <= right; ++i) arr[i] = temp[i];