简体   繁体   中英

Merge sort implementation in c++ using vectors

I'm trying to implement merge sort using vectors in C++, this is the following code I'm executing:

#include <iostream>
#include <vector>

using namespace std;

void merge(vector<int> &a, int l, int m, int r) {
    int i, j, k;
    int n1 = m - l + 1;
    int n2 = r - m;
    
    int L[n1], R[n2];
    for (i = 0; i < n1; i++) {
        L[i] = a[l + i];
    }
    for (j = 0; j < n2; j++) {
        L[j] = a[m + 1 + j];
    }
    i = 0;
    j = 0;
    k = l;     //merged array
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            a[k] = L[i];
            i++;
        } else {
            a[k] = R[j];
            j++;
        }
        k++;
    }
    while (i < n1) {
        a[k] = L[i];
        i++;
        k++;
    }
    while (j < n2) {
        a[k] = R[j];
        j++;
        k++;
    }
}

void mergeSort(vector<int> &a, int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(a, l, m);
        mergeSort(a, m + 1, r);
        merge(a, l, m, r);
    }
}

int main() {
    int n;
    std::cin >> n;
    vector<int> a(n);
    for (int i = 0; i < a.size(); i++) {
        cin >> a[i];
    }
    mergeSort(a, 0, a.size() - 1);
    for (int i = 0; i < a.size(); i++) {
        cout << a[i];
    }
}

When I execute this and enter any values, I get garbage values returned in the array, a[i] = 7405024 , Is the code giving me error due to the fact that I can't change values of the vector in-place or is there something else.

The problem is in the merge function

for(j=0;j<n2;j++)
{
    R[j]=a[m+1+j]; // not L[j]
}

As you are implementing using vectors, suggest to change L and R to vectors as well. VLAs are not supported by C++ by default. Some compilers may accept, but should avoid using altogether.

std::vector<int> L(n1);
std::vector<int> R(n2);

One obvious change that I can see is

IN merge() function

for(j=0;j<n2;j++)
{
    R[j]=a[m+1+j];
}

as those values have to be stored in RIGHT vector.

The problem is your initialisation of R . Rather than writing loops to copy into L and R , you can just initialise them directly.

std::vector<int> L(a.begin() + l, a.begin() + m + 1);
std::vector<int> R(a.begin() + m + 1, a.begin() + r + 1);

Note that it's easier to just use iterators everywhere.

using iter = std::vector<int>::iterator;

void merge(iter l, iter m, iter r) {
    std::vector<int> L(l, m);
    std::vector<int> R(m, r);
    
    iter i = L.begin();
    iter j = R.begin();
    while (i != L.end() && j != R.end()) {
        if (*i < *j) {
            *l = *i;
            i++;
        } else {
            *l = *j;
            j++;
        }
        l++;
    }

    std::copy(i, L.end(), l);
}

void mergeSort(iter l, iter r) {
    std::size_t d = std::distance(l, r);
    if (d > 1) {
        iter m = l + (d / 2);
        mergeSort(l, m);
        mergeSort(m, r);
        merge(l, m, r);
    }
}

int main() {
    std::size_t n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int & i : a) {
        std::cin >> i;
    }
    mergeSort(a.begin(), a.end());
    for (int i : a) {
        std::cout << i;
    }
}

Note that you can advance l until you find an element ordered after *m before initialising L , which saves some copying.

You can implement Merge Sort using the below code:

vector<int> merge(vector<int> l,vector<int> r)
        {
    
       vector<int> res;
            
            int i=0;
            int j=0;
            while(i!=l.size() && j!=r.size())
            {
                if(l[i]<=r[j])
                {
                    re.push_back(l[i++]);
                }
                else
                {
                    re.push_back(r[j++]);
                }
            }
            
            while(i!=l.size())
                re.push_back(l[i++]);
            
            while(j!=r.size())
                re.push_back(r[j++]);
            
            return res;
        }
        
        
        vector<int> merge_d(vector<int>&A, int s,int e)
        {
            if(s-e==0)
            {
                vector<int> t;
                t.push_back(A[s]);
                return t;
            }
        
            int m=(s+e)/2;
            
            vector<int> l;
            vector<int> r;
            l=merge_d(A,s,m);
            r=merge_d(A,m+1,e);
            
            return merge(l,r);
        }

The main problem in your code is you do not initialize R at all. There is a simple typo in the initialization loop, probably a cut and paste error: L[j] = a[m + 1 + j]; should be

R[j] = a[m + 1 + j];

Note also that it is idiomatic in C++ to specify a slice with the index of the first element included and the index of the last element excluded. This convention, used in C, Python and many other languages, allows for simpler and more generic code you can specify an empty slice with l == h . It is also less error prone as no +1 / -1 adjustments are necessary and unsigned index types such as size_t can be used safely.

Finally, int L[n1], R[n2]; is a C99 declaration that is an extension to C++. Even in environments where VLAs are supported, allocating them with automatic storage will cause a stack overflow for sufficiently large sets. You should use vector for these temporary arrays.

These vectors can be initialized directly from a vector slice, which avoids the error-prone copying loops:

vector<int> L(a.begin() + l, a.begin() + m);
vector<int> R(a.begin() + m, a.begin() + r);

Here is a modified version:

#include <iostream>
#include <vector>

using namespace std;

void merge(vector<int> &a, size_t l, size_t m, size_t r) {
    vector<int> L(a.begin() + l, a.begin() + m);
    vector<int> R(a.begin() + m, a.begin() + r);

    size_t i = 0;
    size_t j = 0;
    size_t k = l;     // index into the merged vector slice
    size_t n1 = m - l;
    size_t n2 = r - m;

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            a[k++] = L[i++];
        } else {
            a[k++] = R[j++];
        }
    }
    while (i < n1) {
        a[k++] = L[i++];
    }
    // the last loop in redundant as the remaining elements from R are already at
    // the end of a
}

void mergeSort(vector<int> &a, size_t l, size_t r) {
    if (r - l >= 2) {
        size_t m = l + (r - l) / 2;
        mergeSort(a, l, m);
        mergeSort(a, m, r);
        merge(a, l, m, r);
    }
}

int main() {
    size_t n;
    std::cin >> n;
    vector<int> a(n);
    for (size_t i = 0; i < a.size(); i++) {
        cin >> a[i];
    }
    mergeSort(a, 0, a.size());
    for (size_t i = 0; i < a.size(); i++) {
        cout << a[i];
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM