Mohamadreza
Mohamadreza

Reputation: 323

merge_sort using vectors works well with less than 9 inputs

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();
}

Upvotes: 0

Views: 173

Answers (1)

rcgldr
rcgldr

Reputation: 28931

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
        }
    }
}

Upvotes: 1

Related Questions