C++ Merge Sort using iterators - c++

Currently, I am trying to create a simple C++ Merge Sort Program.
using namespace std;
using Iterator = std::vector<int>::iterator;
using CIterator = std::vector<int>::const_iterator;
std::vector<int> merge(CIterator left_begin, CIterator left_end, CIterator right_begin, CIterator right_end) {
std::vector<int> result;
CIterator left = left_begin;
CIterator right = right_begin;
while (left != left_end && right != right_end) {
if (*left <= *right) {
result.push_back(*left);
left++;
} else {
result.push_back(*right);
right++;
}
}
while (left != left_end) {
result.push_back(*left);
left++;
}
while (right != right_end) {
result.push_back(*right);
right++;
}
return result;
}
I created a merge function that basically connects two sorted vectors into one and returns it (I am bound to use the following return type of the function merge). Then Trying to write the driver function merge sort I have the following code, that I think works correctly
void merge_sort(Iterator begin, Iterator end) {
auto difference = distance(begin, end);
if (difference <= 1) {
return;
}
Iterator middle = begin;
advance(middle, difference / 2);
merge_sort(begin, middle);
merge_sort(middle, end);
vector<int> result = merge(begin, middle, middle, end);
// But what to put here?
}
At the place of the comment mark, I don't understand what to write in order to move the sorted array a step up in the recursion. I tried
begin = result.begin();
end = result.end();
but this obviously doesnt work

The problem is that the type signature for merge_sort assumes an in-place algorithm:
void merge_sort(Iterator begin, Iterator end);
But your merge procedure isn't in-place but returns a merged copy of the arrays. You either need to change merge to be in-place, or you need to change merge_sort to return the sorted array. The latter solution (easier but less efficient) would be like this:
std::vector<int> merge_sort(Iterator begin, Iterator end) {
auto difference = distance(begin, end);
if (difference <= 1) {
return;
}
Iterator middle = begin;
advance(middle, difference / 2);
std::vector<int> left = merge_sort(begin, middle);
std::vector<int> right = merge_sort(middle, end);
return merge(left.begin(), left.end(), right.begin(), right.end());
}

An optimized top down merge sort that does a one time allocation of a second vector, then uses a pair of mutually recursive functions (...AtoA, ...AtoB) to alternate the direction of merge based on level of recursion. (I left out the prototypes).
void MergeSort( typename std::vector<int>::iterator &ab,
typename std::vector<int>::iterator &ae)
{
size_t sz = ae - ab;
if (sz < 2)
return;
std::vector<int> vb(sz); // temp vector
std::vector<int>::iterator bb = vb.begin();
std::vector<int>::iterator be = vb.end();
MergeSortAtoA(ab, ae, bb, be);
}
void MergeSortAtoA( typename std::vector<int>::iterator &ab,
typename std::vector<int>::iterator &ae,
typename std::vector<int>::iterator &bb,
typename std::vector<int>::iterator &be)
{
size_t sz = ae - ab;
if(sz < 2) // if 1 element return
return;
std::vector<int>::iterator am = ab+(sz/2);
std::vector<int>::iterator bm = bb+(sz/2);
MergeSortAtoB(ab, am, bb, bm);
MergeSortAtoB(am, ae, bm, be);
Merge(bb, bm, be, ab);
}
void MergeSortAtoB( typename std::vector<int>::iterator &ab,
typename std::vector<int>::iterator &ae,
typename std::vector<int>::iterator &bb,
typename std::vector<int>::iterator &be)
{
size_t sz = ae - ab;
if(sz < 2){ // if 1 element, copy it
*bb = *ab;
return;
}
std::vector<int>::iterator am = ab+(sz/2);
std::vector<int>::iterator bm = bb+(sz/2);
MergeSortAtoA(ab, am, bb, bm);
MergeSortAtoA(am, ae, bm, be);
Merge(ab, am, ae, bb);
}
void Merge( typename std::vector<int>::iterator &ab,
typename std::vector<int>::iterator &am,
typename std::vector<int>::iterator &ae,
typename std::vector<int>::iterator &bb)
{
std::vector<int>::iterator mb = ab; // left run iterator
std::vector<int>::iterator mm = am; // right run iterator
std::vector<int>::iterator bi = bb; // merge run iterator
while(1){ // merge data
if(*mb <= *mm){ // if mb <= mm
*bi++ = *mb++; // copy mb
if(mb < am) // if not end left run
continue; // continue (back to while)
while(mm < ae) // else copy rest of right run
*bi++ = *mm++;
break; // and return
} else { // else mb > mm
*bi++ = *mm++; // copy mm
if(mm < ae) // if not end of right run
continue; // continue (back to while)
while(mb < am) // else copy rest of left run
*bi++ = *mb++;
break; // and return
}
}
}

Related

Insertion sort implementation using iterators and vectors

I'm trying to implement insertion sort algorithm using iterators and it doesn't seem to work as I thought... Do you have any ideas of how to implement it?
Also, I can't use code like this one: https://www.geeksforgeeks.org/insertion-sort-using-c-stl/ because I'm intending to make an animation and it will get more complicated.
This is my source code so far:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> seq = { 5, 4, 3, 2, 1 };
std::vector<int>::iterator itj;
std::vector<int>::iterator leftmost;
// insertion sort
for (std::vector<int>::iterator iti = seq.begin() + 1; iti != seq.end(); iti = std::next(iti))
{
itj = std::prev(iti);
leftmost = iti;
while (std::distance(seq.begin(), itj) >= 0 && *itj > *leftmost)
{
std::next(itj) = itj;
itj = prev(itj);
}
std::next(itj) = leftmost;
}
// printing
for (std::vector<int>::iterator iti = seq.begin(); iti != seq.end(); iti = std::next(iti))
{
std::cout << *iti << " ";
}
}
Here's a very elegant implementation of insertion sort using iterators lifted directly from the reference page on rotate:
// insertion sort
for (auto i = v.begin(); i != v.end(); ++i) {
std::rotate(std::upper_bound(v.begin(), i, *i), i, i+1);
}
All you have to do is understand how std::rotate works, and this becomes easy to understand. (rotate is anyway a really powerful algorithm that you should be comfortable with).
Here is an implementation taken from SGI STL1:
template<class Random_it, class T>
void unguarded_linear_insert(Random_it last, T val) {
auto next = last;
--next;
while (val < *next) {
*last = *next;
last = next;
--next;
}
*last = val;
}
template<class Random_it>
void linear_insert(Random_it first, Random_it last) {
auto val = *last;
if (val < *first) {
std::copy_backward(first, last, last + 1);
*first = val;
}
else
unguarded_linear_insert(last, val);
}
template<class Random_it>
void insertion_sort(Random_it first, Random_it last) {
if (first == last)
return;
for (auto i = first + 1; i != last; ++i)
linear_insert(first, i);
}
Note how the val < *first condition and std::copy_backward are used to simplify the loop inside unguarded_linear_insert: only one condition, namely val < *next can be checked in that loop.
1 The same implementation can be found in libstdc++.

Improving my implementation of the divide and conquer form of the maximum sub-array problem

I have implemented an approach to the divide and conquer method of solving the maximum sub-array problem. I have made a struct to return solutions
#pragma once
#include <iostream>
#include <vector>
template<class T>
struct value {
private:
typedef typename std::vector<T>::iterator iter;
public:
iter max_left;
iter max_right;
T sum;
};
A class to contain static methods.
template<class T>
class SubArray
{
private:
typedef typename std::vector<T>::iterator iter;
public:
static void print(iter, iter);
// Maximum Sub-Array
static value<T> maximum_crossing_subarray(std::vector<T> &, iter, iter, iter);
static value<T> maximum_subarray(std::vector<T> &, iter, iter);
};
And the two implementations of the functions.
template<class T>
value<T> SubArray<T>::maximum_crossing_subarray(std::vector<T> & vec, iter low, iter mid, iter high) {
iter max_left;
iter max_right;
T left_sum = std::numeric_limits<T>:: min();
T right_sum = std::numeric_limits<T>:: min();
T sum = 0;
for (auto it = mid + 1; it-- != low;) {
sum = sum + *it;
if(sum > left_sum) {
left_sum = sum;
max_left = it;
}
}
sum = 0;
for (auto it = mid + 1; it <= high; ++it) {
sum = sum + *it;
if(sum > right_sum) {
right_sum = sum;
max_right = it;
}
}
return value<T> { max_left, max_right + 1, right_sum + left_sum };
}
template<class T>
value<T> SubArray<T>::maximum_subarray(std::vector<T> & vec, iter low, iter high) {
if(high == low) {
return value<T> { low, high, *low };
} else {
iter mid = low + std::floor(std::distance(low, high)/2);
value<T> left = maximum_subarray(vec, low, mid);
value<T> right = maximum_subarray(vec, mid + 1, high);
value<T> cross = maximum_crossing_subarray(vec, low, mid, high);
if(left.sum >= right.sum && left.sum >= cross.sum) {
return left;
} else if(right.sum >= left.sum && right.sum >= cross.sum) {
return right;
} else {
return cross;
}
}
}
The problem is when I call the function I have to specify the below. The -1 in the call to maximum_subarray keeps me up at night. Can i do anything to remove it?
#include "algorithms/SubArray.h"
int main() {
std::vector<int> max_me = { -1, 100, -5, -1, 20, 4, -3, 2, -6, 8, -10 };
value<int> sub_array = SubArray<int>::maximum_subarray(max_me, max_me.begin(), max_me.end() - 1);
std::vector<int> make_sub_array(sub_array.max_left, sub_array.max_right);
// make_sub_array = 100 -5 -1 20 4 -3 2 -6 8
return 0;
}
In many recursive algorithms you will want to have a wrapper that accepts whatever arguments you want for the user to provide and then transforms that into whatever the actual recursive function needs.
So you can create a wrapper that takes begin() and end() as you want and then applies the - 1 to the end before calling the recursive function.

Efficient way to find intersection of two vectors with respect to two members of vector objects

I have two vectors holding data objects. Each data object is holding coordinates and some other data. The vectors will always be sorted (first for the x coordinates and then for the y coordinates). I'm trying to delete all objects from both vectors that have coordinates that can not be found in both of the vectors. Here's an MWE of what I'm currently doing:
#include <iostream>
#include <vector>
#include <algorithm>
struct foo{
foo()=default;
foo(int x, int y, double data):x(x),y(y),data(data){}
int x;
int y;
double data;
};
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
for(auto it1=vec1.begin(); it1!=vec1.end();){
auto cur_element=*it1;
auto intersec = std::find_if(vec2.begin(),vec2.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec2.end()) it1=vec1.erase(it1);
else ++it1;
}
for(auto it2=vec2.begin(); it2!=vec2.end();){
auto cur_element=*it2;
auto intersec = std::find_if(vec1.begin(),vec1.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec1.end()) it2=vec2.erase(it2);
else ++it2;
}
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
It works and gives me the expected output.
Anyway it seems really unefficient having to loop through both of the vectors. Is there a more efficient way to achieve the same output?
EDIT: It's not enough to obtain the coordinates that are represented in both vectors. What I need is an efficient way to delete the "wrong" objects from both vectors.
Your two vectors are sorted already – perfect!
First, assuming a comparison function (with up-coming C++20, this would get the space-ship operator...):
int compare(foo const& l, foo const& r)
{
return l.x != r.x ? l.x - r.x : l.y - r.y;
}
Now you can use it in the algorithm:
auto i1 = v1.begin();
auto i2 = v2.begin();
auto end1 = i1;
auto end2 = i2;
while(i1 != v1.end() && i2 != v2.end())
{
int cmp = compare(*i1, *i2);
if(cmp < 0)
{
// skip element
++i1;
}
else if(cmp > 0)
{
++i2;
}
else
{
// matching element found, keep in both vectors...
if(i1 != end1)
*end1 = std::move(*i1);
++i1;
++end1;
if(i2 != end2)
*end2 = std::move(*i2);
++i2;
++end2;
// if you can rely on move (or fallback copy) assignment
// checking for self assignment, the following simpler
// alternative can be used instead:
//*end1++ = std::move(*i1++);
//*end2++ = std::move(*i2++);
}
}
v1.erase(end1, v1.end());
v2.erase(end2, v2.end());
Linear in both vectors...
The algorithm just moves the elements to be kept to front and finally drops all the overdue ones – similarly as would std::remove_if do...
I think this solution is linear and does what you want.
Possible further enhancement:
for large vectors with large areas of non-intersection, it may be worth caching regions to erase.
another strategy if data is cheap to move, is to conditionally build output vectors from input vectors and swap
struct foo_less
{
bool operator()(foo const&l, foo const& r) const
{
return std::tie(l.x, l.y) < std::tie(r.x, r.y);
}
};
void remove_non_matching(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
lcurrent = l.erase(lcurrent);
else if(less(*rcurrent, *lcurrent))
rcurrent = r.erase(rcurrent);
else
{
++lcurrent;
++rcurrent;
}
}
l.erase(lcurrent, l.end());
r.erase(rcurrent, r.end());
}
alternative approach will cost more memory but is theoretically more efficient:
void remove_non_matching_alt(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
}
Similar but uses a thread_local persistent cache to avoid un-necessary memory allocations:
void remove_non_matching_alt_faster(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
// optimisation - minimise memory allocations on subsequent calls while maintaining
// thread-safety
static thread_local auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
// ensure destructors of discarded 'data' are called and prep for next call
lresult.clear();
rresult.clear();
}
This is my approach, in a erase–remove idiom style, iterating only once through the vectors:
#include <iostream>
#include <vector>
#include <iterator>
#include <utility>
struct foo
{
foo() = default;
foo(int x, int y, double data) : x(x), y(y), data(data) {}
int x;
int y;
double data;
};
// Maybe better as overloaded operators
int compare_foo(const foo& foo1, const foo& foo2)
{
if (foo1.x < foo2.x) return -1;
if (foo1.x > foo2.x) return +1;
if (foo1.y < foo2.y) return -1;
if (foo1.y > foo2.y) return +1;
return 0;
}
std::tuple<std::vector<foo>::iterator, std::vector<foo>::iterator>
remove_difference(std::vector<foo>& vec1, std::vector<foo>& vec2)
{
typedef std::vector<foo>::iterator iterator;
iterator it1 = vec1.begin();
size_t shift1 = 0;
iterator it2 = vec2.begin();
size_t shift2 = 0;
while (it1 != vec1.end() && it2 != vec2.end())
{
int cmp = compare_foo(*it1, *it2);
if (cmp < 0)
{
++it1;
shift1++;
}
else if (cmp > 0)
{
++it2;
shift2++;
}
else
{
std::iter_swap(it1, std::prev(it1, shift1));
++it1;
std::iter_swap(it2, std::prev(it2, shift2));
++it2;
}
}
return std::make_tuple(std::prev(it1, shift1), std::prev(it2, shift2));
}
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
auto remove_iters = remove_difference(vec1, vec2);
vec1.erase(std::get<0>(remove_iters), vec1.end());
vec2.erase(std::get<1>(remove_iters), vec2.end());
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
Output:
vec1:
1 2
2 1
3 1
vec2:
1 2
2 1
3 1
The only thing to not is that this assumes that there are no repeated coordinates, or more specifically, that they are repeated the same number of times on both vectors, and "extra" repetitions would be removed (you could adapt the algorithm to change that if you needed, although it would make the code a bit uglier).
Maybe something like this? You choose first which vector is bigger then iterate (mainly) over the bigger one and check inside the other one.
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
std::vector<foo>::iterator it_begin;
std::vector<foo>::iterator it_end;
std::vector<foo>* main;
std::vector<foo>* other;
if( vec1.size() > vec2.size() ) {
it_begin = vec1.begin();
it_end = vec1.end();
main = &vec1;
other = &vec2;
}
else {
it_begin = vec2.begin();
it_end = vec2.end();
main = &vec2;
other = &vec1;
}
std::vector<foo> new_vec;
for( it_begin; it_begin != it_end; ++it_begin ) {
auto cur_element = *it_begin;
auto intersec = std::find_if( other->begin(),other->end(),[cur_element]
(foo & comp_element)->bool{
return( (cur_element.x==comp_element.x ) && ( cur_element.y==comp_element.y ) );
});
if( intersec != other->end() )
{
new_vec.push_back( cur_element );
}
}
vec1 = new_vec;
vec2 = new_vec;
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}

Problems with constant iterators

I'm trying write a tempate function which takes a sequence (by 2 iterators) and calculates the number of permutations of this sequence, in which there are no consecutive identical elements.
Thats what i did
template<class Iterator>
size_t count_perm(Iterator p, Iterator q)
{
if (p == q)
return 1;
size_t count = 0;
while(std::next_permutation(p, q)){
if(std::adjacent_find(p,q) != q)
++count;
}
}
/*Example
std::array<int, 3> a1 = {1,2,3};
size_t c1 = count_perm(a1.begin(), a1.end()); // 6
std::array<int, 5> a2 = {1,2,3,4,4};
size_t c2 = count_perm(a2.begin(), a2.end()); // 36*/
This code not working if i pass const iterators. What should I change to make it work with const iterators?
This code not working if i pass const iterators. What should I change to make it work with const iterators?
You can't: std::next_permutation() modify the values so is incompatible with const iterators.
-- EDIT --
The OP ask
How can i implement this function in right way?
I suggest you to follows the suggestion from Jarod42: works over a copy.
I propose something as follows
template <class Container>
size_t count_perm (Container c) // note: c is a copy
{
if ( c.cbegin() == c.cend() )
return 1;
size_t count = 0U;
std::sort(c.begin(), c.end());
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend()))
{
std::size_t ui = c.size();
for ( count = ui ; --ui > 1 ; count *= ui )
;
// count now is c.size() ! (factorial of)
}
else
{
while (std::next_permutation(c.begin(), c.end()))
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend())
++count;
}
return count; // remember this return!
}
Fixed your templated function for you (still requires non-const iterators):
template<class Iterator> size_t count_perm(Iterator p, Iterator q)
{
if (p == q || std::all_of(p, q, [&](auto &el) {return el == *p; })))
return 0;
size_t count = 1;
std::sort(p, q);
while (std::next_permutation(p, q))
if (std::adjacent_find(p, q) == q)
++count;
return count;
}
you should return count
when no adjacent elements are found, std::adjacent_find returns end, so you should == q not != q
Your example produces 6 and 37. Should it be 36 instead of 37?
Solved this exercise as follows, it works with const iterators:
template<class Iterator>
size_t count_permutations(Iterator p, Iterator q)
{
using T = typename std::iterator_traits<Iterator>::value_type;
if (p == q)
return 1;
std::vector<T> v(p,q);
std::sort(v.begin(), v.end());
size_t count = 0;
do{
if(std::adjacent_find(v.begin(),v.end()) == v.end()) {
++count;
}
} while(std::next_permutation(v.begin(), v.end()));
return count;
}
Problem was to use std::type_traits<Iterator>::value_type instead Iterator::value_type (that not working with const iters and simple pointers (like int*))

Merge Sort - return a new array instead of copying merged array to input array

I'm trying to implement a very naive version of Merge Sort (not considering all the optimizations for this purpose) where my goal is to return a new copy of the merged array rather than the traditional way of passing the input array by reference and copying the merged elements into it.
To that end, my code is as below:
vector<int> merge(vector<int> left, vector<int> right)
{
vector<int> result;
int leftIdx = 0;
int rightIdx = 0;
int resultIdx = 0;
while (leftIdx < left.size() && rightIdx < right.size()) {
if (left[leftIdx] < right[rightIdx]) {
result[resultIdx++] = left[leftIdx++];
} else {
result[resultIdx++] = right[rightIdx++];
}
}
while (leftIdx < left.size()) {
result[resultIdx++] = left[leftIdx++];
}
while (rightIdx < right.size()) {
result[resultIdx++] = right[rightIdx++];
}
return result;
}
vector<int> MergeSort(vector<int> intArr)
{
vector<int> recresult;
// base - if array is of length 1, nothing to do, return it as is
if (intArr.size() == 1) {
return intArr;
} else {
int mid = intArr.size() / 2;
// copy left half
vector<int> leftArr(intArr.begin(), intArr.begin() + mid);
// copy right half
vector<int> rightArr(intArr.begin() + mid, intArr.end());
MergeSort(leftArr);
MergeSort(rightArr);
recresult = merge(leftArr, rightArr);
}
return recresult;
}
I know that this array from merge is a local array and hence I'm returning it to mergesort which will in turn return it to main.
Am I wrong in assuming that this is not getting passed into and out from
subsequent recursive calls?
My test input to this code is {1,0,9}. I should be getting {0,1,9} but I get 32767.
What am I missing here?
The recursive calls to MergeSort do nothing, because intArr is taken by value (copied) and you're not using the result value.
Something like this should work:
auto newLeft = MergeSort(leftArr);
auto newRight = MergeSort(rightArr);
recresult = merge(newLeft, newRight);
As Slava mentioned in the comments, you also have UB when accessing result, because its size is 0:
vector<int> result; // size = 0
// ...
result[resultIdx++] = left[leftIdx++]; // UB!
You should invoke std::vector::resize before accessing the elements using operator[].
First for merge - you should pass const references to arguments, otherwise you make too many unnecessary copies. Also you get out of bound access to result as you create in empty and accessing by index. And it is not a good idea to use int for index. So simplified version could be:
vector<int> merge(const vector<int> &left, const vector<int> &right)
{
vector<int> result;
auto lit = left.begin();
auto rit = right.begin();
while( lit != left.end() || rit != right.end() ) {
bool lft = false;
if( rit == right.end() )
lft = true;
else {
if( lit != left.end() )
lft = *lit < *rit;
}
result.push_back( lft ? *lit++ : *rit++ );
}
return result;
}
or version that closer to your:
vector<int> merge(const vector<int> &left, const vector<int> &right)
{
vector<int> result( left.size() + right.size() );
auto rst = result.begin();
auto lit = left.begin();
auto rit = right.begin();
while( lit != left.end() && rit != right.end() )
*rst++ = *lit < *rit ? *lit++ : *rit++;
std::copy( lit, left.end(), rst );
std::copy( rit, right.end(), rst );
return result;
}