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

Merge sort implementation in c++ using vectors

本文关键字:合并 排序 实现 c++ 向量      更新时间:2023-10-16

我正在尝试使用 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函数上

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 的环境中,为它们分配自动存储也会导致足够大的集出现堆栈溢出。您应该对这些临时数组使用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;
}