Thread: problem with sorting algorithim (using merge sort)

  1. #1
    Registered User
    Join Date
    Apr 2015
    Location
    Reine, Hazafon, Israel, Israel
    Posts
    11

    problem with sorting algorithim (using merge sort)

    hello guys, so I had to write a code which sorts points(x,y) according to their distance of (0,0) point.

    at first it asks for how many points will you enter? for example 3.
    and then u enter the x and the y of each point
    for example :

    1 6
    2 5
    4 4

    so the result should be printing the point sorted from shortest distance to longest which is : (2,5) (4,4) (1,6)

    the problem in my code , for the example i gave u the output is:
    (2,5) (2,5) (1,6)
    I used a two dimensional array with size [n][2] .. n is the number of points, for example in
    arr[0][0] the x of first point is stored
    arr[0][1] the y of first point is stored
    any ideas where could be the problem ? thanks

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    void initiate(int array[][2],int n)
    {
        for(int i=0;i<n;i++)
       {
           for(int j=0 ;j<2;j++)
           {
               array[i][j]=0;
           }
       }
    }
    
    
    void printarray(int TDarray[][2],int number)
    {
        printf("Sorted Points:");
       for(int i=0;i<number;i++)
        {
            printf(" (%d,%d)",TDarray[i][0],TDarray[i][1]);
    
    
        }
    }
    
    
    void merge(int a[][2], int na, int b[][2], int nb, int c[][2])
     {
       int ia, ib, ic;
       for(ia = ib = ic = 0; (ia < na) && (ib < nb); ic++)
         {
           if((a[ia][0])*(a[ia][0]) + (a[ia][1])*(a[ia][1]) < (b[ib][0])*(b[ib][0]) + (b[ib][1])*(b[ib][1])) {
               c[ic][0] = a[ia][0];
               c[ic][1] = a[ia][1];
               ia++;
         }
           else {
               c[ic][0] = b[ia][0];
               c[ic][1] = b[ia][1];
               ib++;
           }
         }
       for(;ia < na; ia++, ic++)
       {
           c[ic][0] = a[ia][0];
           c[ic][1] = a[ia][1];
       }
       for(;ib < nb; ib++, ic++)
       {
           c[ic][0] = b[ib][0];
           c[ic][1] = b[ib][1];
       }
    }
    
    
    void copyarray(int a[][2],int helper_array[][2],int n)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<2;j++)
            {
                a[i][j]=helper_array[i][j];
            }
        }
    }
    
    
    void internal_msort(int a[][2], int n, int helper_array[][2])
    {
        int left = (n/2), right = n-left;
        if (n < 2)
            {return;}
        internal_msort(a, left, helper_array);
        internal_msort(a + left, right, helper_array);
        merge(a, left, a + left, right, helper_array);
        copyarray(a, helper_array, n);
    
    
    }
    
    
    void merge_sort(int a[][2], int n)
    {
       int helper_array[n][2];
       initiate(helper_array,n);
       internal_msort(a, n,helper_array);
       printarray(a,n);
    }
    
    
    int main()
    {
        int number;
        printf("Enter number of points: ");
        scanf("%d",&number);
        int TDarray[number][2];
        initiate(TDarray,number);
        for(int i=0;i<number;i++)
        {
            printf("Enter Point: ");
            for(int j=0;j<2;j++)
            {
            scanf("%d",&TDarray[i][j]);
            }
        }
        merge_sort(TDarray,number);
      return 0;
    }

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Consider n == 10. Then here
    Code:
    int left = (n/2), right = n-left;
    you're setting both left and right to 5.

    In general, that line sets left and right to n/2 if n is even and to n/2 and n/2+1, respectively, if n is odd.

    Try something along the lines of:
    Code:
       middle = (right + left) / 2; // or (right-left)/2+left to avoid overflow
       msort from left to middle
       msort from middle+1 to right
       merge left to middle, middle+1 to right
    (The details depend on whether your upper bound is one-past-the-end or not.)

  3. #3
    Registered User
    Join Date
    Apr 2015
    Location
    Reine, Hazafon, Israel, Israel
    Posts
    11
    Quote Originally Posted by algorism View Post

    In general, that line sets left and right to n/2 if n is even and to n/2 and n/2+1, respectively, if n is odd.
    first of all thank u for responding
    so u say the code doesn't work well when n is odd , okay let's give it an n=4 ,then the points will be the same as before adding (0,0) as the first one - I mean:
    0 0
    1 6
    2 5
    4 4
    the output is : (0,0) (4,4) (4,4) (1,6)
    although n isn't prime ! :\
    what do u think my friend ?

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I didn't say the code doesn't work well if n is odd. I said it doesn't work no matter what n is. I also told you how to fix it.

  5. #5
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Are you aware that you could implement a bottom up merge instead which would skip all the recursive splitting of the array into sub-arrays? Take a look at the wiki examples on the main page and also the talk page:

    http://en.wikipedia.org/?title=Merge...implementation

  6. #6
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Is writing your own sorting routine a necessary part of this exercise? Or can you use a well-tested existing sorting routine? C already has qsort() for sorting so you don't have to reinvent the wheel (unless you're determined to reinvent it).

  7. #7
    Registered User
    Join Date
    Apr 2015
    Location
    Reine, Hazafon, Israel, Israel
    Posts
    11
    Quote Originally Posted by algorism View Post
    I didn't say the code doesn't work well if n is odd. I said it doesn't work no matter what n is. I also told you how to fix it.
    Quote Originally Posted by rcgldr View Post
    Are you aware that you could implement a bottom up merge instead which would skip all the recursive splitting of the array into sub-arrays? Take a look at the wiki examples on the main page and also the talk page:

    http://en.wikipedia.org/?title=Merge...implementation
    algorism and rcgldr thank u very much for your help , I used the bottom up merge which does as algorism said (uses middle index) and it worked , but later i tried to find what's wrong in my previous code so here it is : (a very stupid mistake of me):
    int the merge function -> first for loop -> inside else I wrote
    Code:
    c[ic][0] = b[ia][0];
    c[ic][1] = b[ia][1];
    ib++;
    it should have been the index ib not ia in the b array.
    Code:
    c[ic][0] = b[ib]0];
    c[ic][1] = b[ib][1];
    ib++;
    sorry guys,my mistake.
    Quote Originally Posted by christop View Post
    Is writing your own sorting routine a necessary part of this exercise? Or can you use a well-tested existing sorting routine? C already has qsort() for sorting so you don't have to reinvent the wheel (unless you're determined to reinvent it).
    yes it is necessary part to use merge sort , anyway it worked now thank you

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by TheShadow View Post
    I used the bottom up merge which does as algorism said (uses middle index) ...
    A bottom up merge doesn't use a middle index. The idea of a merge sort is to split up an array into "runs" (sub-arrays) of size 1, which are sorted since there's only 1 element, then to merge pairs of runs to create runs of double the size until the run size is the array size. Top down merge sort uses recursion to split up the array into runs of size 1, and only when two runs of size 1 are created does any actual merging take place. Bottom up merge sort skips the recursion and just starts off with a run size set to 1, using indexing to iterate through pairs of runs in an array. Both methods use a second array so that the merge process reads from one array while writing to the other.

    Example C++ code showing both methods. a[] contains the original data, b[] is a second "helper" array used for merging. With the bottom up merge sort example below, the sorted data can end up in either a or b so a pointer to the sorted array is returned. The top down example ends up with the sorted data in a[], but a pointer to the sorted array is still returned, in case the example code is changed. The top down example uses helper functions so that the direction of the merge (a[] to b[] or b[] to a[]) is alternated depending on the level of recursion. This eliminates having to copy data after a merge step.

    Code:
    // prototypes
    int * BottomUpMergeSort(int a[], int b[], size_t n);
    int * TopDownMergeSort(int a[], int b[], size_t n);
    void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
    void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
    void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee);
    void CopyRun(int a[], int b[], size_t ll, size_t rr);
    
    int * BottomUpMergeSort(int a[], int b[], size_t n)
    {
        for(size_t s = 1; s < n; s <<= 1){  // s = run size
            size_t ee = 0;                  // init end index
            while(ee < n){                  // merge pairs of runs
                size_t ll = ee;             // ll = start of left  run
                size_t rr = ll+s;           // rr = start of right run
                if(rr >= n){                // if only left run
                    rr = n;
                    CopyRun(a, b, ll, rr);  //   copy left run
                    break;                  //   end of pass
                }
                ee = rr+s;                  // ee = end of right run
                if(ee > n)
                    ee = n;
                MergeRuns(a, b, ll, rr, ee);
            }
            std::swap(a, b);                // swap a and b
        }
        return a;                           // return sorted array
    }
    
    int * TopDownMergeSort(int a[], int b[], size_t n)
    {
        if(n < 2)                           // if size < 2 return
            return a;
        TopDownSplitMergeAtoA(a, b, 0, n);
        return a;
    }
    
    void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
    {
        if((ee - ll) == 1)                  // if size == 1 return
            return;
        size_t rr = (ll + ee)>>1;           // midpoint, start of right half
        TopDownSplitMergeAtoB(a, b, ll, rr);
        TopDownSplitMergeAtoB(a, b, rr, ee);
        MergeRuns(b, a, ll, rr, ee);        // merge b to a
    }
    
    void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
    {
        if((ee - ll) == 1){                 // if size == 1 copy a to b
            b[ll] = a[ll];
            return;
        }
        size_t rr = (ll + ee)>>1;           // midpoint, start of right half
        TopDownSplitMergeAtoA(a, b, ll, rr);
        TopDownSplitMergeAtoA(a, b, rr, ee);
        MergeRuns(a, b, ll, rr, ee);        // merge a to b
    }
    
    void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee)
    {
        size_t o = ll;                      // b[]       index
        size_t l = ll;                      // a[] left  index
        size_t r = rr;                      // a[] right index
        while(1){                           // merge data
            if(a[l] <= a[r]){               // if a[l] <= a[r]
                b[o++] = a[l++];            //   copy a[l]
                if(l < rr)                  //   if not end of left run
                    continue;               //     continue (back to while)
                while(r < ee)               //   else copy rest of right run
                    b[o++] = a[r++];
                break;                      //     and return
            } else {                        // else a[l] > a[r]
                b[o++] = a[r++];            //   copy a[r]
                if(r < ee)                  //   if not end of right run
                    continue;               //     continue (back to while)
                while(l < rr)               //   else copy rest of left run
                    b[o++] = a[l++];
                break;                      //     and return
            }
        }
    }
    
    void CopyRun(int a[], int b[], size_t ll, size_t rr)
    {
        while(ll < rr){                     // copy left run
            b[ll] = a[ll];
            ll++;
        }
    }
    Last edited by rcgldr; 06-25-2015 at 08:03 PM.

  9. #9
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Forgot to mention, the bottom up merge sort can end up with the sorted data in a[] by calculating the number of passes needed and if the number of passes is an odd number, then the first pass swaps elements in place in a[] as needed to form runs of 2 instead of merging to b[], leaving an even number of passes remaining so the sorted data ends up in a[].

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with Merge sort algorithm
    By Nyah Check in forum C Programming
    Replies: 2
    Last Post: 12-24-2014, 07:57 PM
  2. Merge sort problem
    By thriller500 in forum C Programming
    Replies: 4
    Last Post: 03-29-2012, 04:03 PM
  3. Urgent problem with a merge sort.
    By jonnoblood in forum C Programming
    Replies: 7
    Last Post: 02-10-2010, 08:35 PM
  4. sorting a linked list using merge sort question..
    By kakaroto in forum C Programming
    Replies: 17
    Last Post: 08-07-2009, 12:13 PM
  5. Merge Sort the best sorting algorithm?
    By sehr alt in forum A Brief History of Cprogramming.com
    Replies: 21
    Last Post: 06-20-2007, 02:19 PM