0

Somehow I implemented Merge sort using vectors, the problem is: It works correctly with less than 9 inputs, but with 9 or more inputs it does something which I don't understand, such as below:

Input:
5-4-3-2-1   ---   6-5-4-3-2-1   ---   9-8-7-6-5-4-3-2-1
Output:
1-2-3-4-5   ---   1-2-3-4-5-6   ---   1-2-3-4-5-7-6-8-9

Here is the code:

#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;
void showvector(vector<int> numbers){
    for (vector<int>::iterator i = numbers.begin(); i != numbers.end(); i++)
    {
        cout << *i;
        if (i != numbers.end() - 1)cout << " - ";
    }
}

vector<int> getvector(){
    vector<int> numbers(0);
    cout << "please enter you numbers :::\n''entering any characters but numbers is the end of entry''\n";
    int counter = 0;
    do{
        int newnumber = 0;
        cout << "element(" << counter << ") = ";
        counter++;      
        cin >> newnumber; getchar();
        if (cin.good())
            numbers.push_back(newnumber);
        if (cin.fail()){
            cout << "numbers are :";
            showvector(numbers);
        }
    } while (cin.good()); getchar();
    return numbers;
}

void mergesort(vector<int>& numbers);

vector<int> merge(vector<int>& one, vector<int>& two){
    cout << "\ncomparing vector one with "; showvector(one); cout << " element(s) with vector two with "; showvector(two); cout << " element(s)\n";
    vector<int>::iterator j = two.begin();
    vector<int>::iterator i;
    for (i = one.begin(); i != one.end(); i++){
        cout << "comparing " << *i << " with " << *j<<endl;
        if (*i > *j){
            cout << "exchanging " << *i << " with " << *j << endl;;
            int c = *i;
            *i = *j;
            *j = c;
            j++;
        }
    }
    if (j != two.end() && i==one.end())
        mergesort(two); 
    cout << "\npushing vector two with "; showvector(two); cout << " element(s) back to vector one with "; showvector(one); cout << " element(s)\n";    
    for (j=two.begin(); j != two.end();j++)
            one.push_back(*j);
    cout << "returning sorted vector as\n";
    showvector(one);
    return one;
}

void mergesort(vector<int>& numbers){
    if (numbers.size() > 1){        
        vector<int> halfone(numbers.begin(), numbers.begin() + numbers.size() / 2);
        mergesort(halfone);
        vector<int> halftwo(numbers.begin() + numbers.size() / 2, numbers.end());       
        mergesort(halftwo);
        numbers = merge(halfone, halftwo);
    }               
}

int main(){
    vector<int> numbers(getvector());   
    mergesort(numbers);
    cout << "\nnumbers are :";
    showvector(numbers);
    getchar();
}
Mohamadreza
  • 313
  • 3
  • 6
  • 22
  • and what did the debugger say? – pm100 Jan 30 '15 at 21:12
  • @pm100 It doesn't say anything. – Mohamadreza Jan 30 '15 at 21:16
  • i mean did you step through the code with it to see what goes wrong – pm100 Jan 30 '15 at 21:18
  • 1
    @starman - You wrote the code, thus you had a plan in mind when you wrote it. Use the debugger to step through your code and see where the program runs counter to your plan. Just posting a mountain of code and having us do the job you're supposed to do is not how things work here. – PaulMcKenzie Jan 30 '15 at 21:18
  • Ok, I got it, I'll post the debug result here. – Mohamadreza Jan 30 '15 at 21:22
  • @starman Also, your code doesn't work for this input: `vector numbers = {5,3,2,1,4, 7,10};` So it isn't an issue with 9 numbers. Second, do as I did, and use hard-coded numbers first. – PaulMcKenzie Jan 30 '15 at 21:23
  • Yes @PaulMcKenzie the last time that I checked it out it before posting it here it worked with 7, but new i see that it also is not working with 7 input I guess I'm getting close the the solution, I'll post it here as soon as I find it. – Mohamadreza Jan 30 '15 at 21:34
  • 2
    Why does your `merge()` recursively call `mergesort()`? Shouldn't it restrict itself to, you know, __merging__ and let the `mergesort()` function take care of the recursion. – Blastfurnace Jan 30 '15 at 22:24

1 Answers1

1

Here is a pair of merge sort examples, somewhat optimized, and perhaps a bit more than what would be expected from a student.

The top example is a top down merge sort. a[] is the array to be sorted, b[] is a temp array the same size as a[]. Copying data is avoided via a pair of recursive functions that alternate the direction of the merge depending on the level of recursion.

The bottom example is a bottom up merge sort. Note the sorted array can end up in either a[] or b[]. This can be avoided by calculating the number of passes and if the number of passes is odd, swap in place for the first pass.

Both sort examples use two arrays and merge using indexes. The main difference is top down uses recursion to repeatedly split pairs of indexes until the indexes represent a run size of 1, where it then starts the actual merge process, while bottom up skips this step and just starts off with a run size of 1 and starts merging immediately. Most of the time is spent merging, so the extra overhead of recursively generating indexes is small compared to the total time it takes to sort.

top down merge sort

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);
    TopDownMerge(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);
    TopDownMerge(a, b, ll, rr, ee);     // merge a to b
}

void TopDownMerge(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
        }
    }
}

bottom up merge sort

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;
                BottomUpCopy(a, b, ll, rr); //   copy left run
                break;                      //   end of pass
            }
            ee = rr+s;                      // ee = end of right run
            if(ee > n)
                ee = n;
            BottomUpMerge(a, b, ll, rr, ee);
        }
        std::swap(a, b);                    // swap a and b ptrs
    }
    return a;                               // return sorted array
}

void BottomUpCopy(int a[], int b[], size_t ll, size_t rr)
{
    while(ll < rr){                         // copy left run
        b[ll] = a[ll];
        ll++;
    }
}

void BottomUpMerge(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
        }
    }
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61