繁体   English   中英

使用向量在 c++ 中实现合并排序

[英]Merge sort implementation in c++ using vectors

我正在尝试使用 C++ 中的向量实现合并排序,这是我正在执行的以下代码:

#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];
    }
}

当我执行此操作并输入任何值时,我会在数组中返回垃圾值a[i] = 7405024 ,由于我无法就地更改向量的值或者是还有别的东西。

问题出在merge function

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

当您使用向量实现时,建议将LR也更改为向量。 C++ 默认不支持 VLA。 一些编译器可能会接受,但应该完全避免使用。

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

我可以看到的一个明显变化是

IN merge() function

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

因为这些值必须存储在RIGHT向量中。

问题是您对R的初始化。 而不是编写循环复制到LR ,您可以直接初始化它们。

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

请注意,在任何地方都使用迭代器更容易。

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

请注意,您可以提前l直到在初始化L之前找到在*m之后排序的元素,这样可以节省一些复制。

您可以使用以下代码实现合并排序:

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

您的代码中的主要问题是您根本没有初始化R 初始化循环中有一个简单的错字,可能是剪切和粘贴错误: L[j] = a[m + 1 + j]; 应该

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

另请注意,在 C++ 中,指定一个包含第一个元素的索引并排除最后一个元素的索引的切片是惯用的。 此约定用于 C、Python 和许多其他语言,允许更简单和更通用的代码,您可以使用l == h指定空切片。 它也不太容易出错,因为不需要+1 / -1调整,并且可以安全地使用无符号索引类型(例如size_t )。

最后, int L[n1], R[n2]; 是一个 C99 声明,它是 C++ 的扩展。 即使在支持 VLA 的环境中,使用自动存储分配它们也会导致足够大的集合的堆栈溢出 您应该对这些临时 arrays 使用vector

这些向量可以直接从向量切片初始化,从而避免容易出错的复制循环:

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

这是修改后的版本:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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