使用迭代器对向量的C 递归初始化产生不一致的结果

C++ recursive initialization of vectors using iterators produce inconsistent results

本文关键字:初始化 结果 不一致 递归 迭代器 向量      更新时间:2023-10-16

我试图通过在遇到不一致的程序行为时定义非常常见的Mergesort算法来练习C 迭代器。我的问题不是如何实施Mergesort(我知道并意识到有很多示例答案(,而是使用迭代器创建递归矢量时,我会收到不一致的最终结果。

我知道我可以通过for循环将值复制到L和R数组中来解决问题,但是我想了解为什么使用迭代器不起作用。这是用C 14在Clion上运行的。这篇文章是从向量提取子向量的最佳方法?我没有回答我的问题,因为我创建了类似于规定的方法的向量。

void merge2(vector<int> &arr, int l, int m, int r)
{
    vector<int> L{arr.begin()+l, arr.begin()+m+1};
    vector<int> R{arr.begin()+m+1,arr.begin()+r+1};
    int i = 0, j = 0, k = l;
    int n1 = m - l + 1;
    int n2 =  r - m;
    while (i < (n1) && j < (n2)){
        if (L[i]<=R[i]){ //R[i] is replaced by R[j]
            arr[k] = L[i++];
        }
        else {
            arr[k] = R[j++];
        }
        k++;
    }
    while  (i < n1)
    {
        arr[k] = L[i];
        i++;
        k++;
    }
    while(j < n2){
        arr[k] = R[j];
        j++;
        k++;
    }
}
/* l is for left index and r is right index of the
   sub-array of arr to be sorted */
void merge2Sort(vector<int> &arr, int l, int r)
{
    if (l < r)
    {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
//        int m = (l+r-l)/2;
//        int m = l+(r-l)/2;
            int m = (l+r)/2;
        // Sort first and second halves
        merge2Sort(arr, l, m);
        merge2Sort(arr, m+1, r);
        merge2(arr, l, m, r);
    }
}
int main(int argc, char **argv){
    vector<int> arr = {12, 11, 13, 5, 6, 7};
    merge2Sort(arr, 0, arr.size()-1);
    for(auto i = arr.begin(); i != arr.end(); i++){
        cout << *i << " ";
    }
    return 0;
}

有时我会收到正确的答案5 6 7 11 12 13,而其他时间不正确的答案5 6 7 11 13 12.答案不应因尝试而变化。

正确答案以反映答案和评论。答案更正索引错误并依赖迭代器。还从迭代初始化时向量的评论中注意到((,而不是{}。

template <class It>
void merge(It left, It middle, It right)
{
    // Beeing generic, you need to retrieve the type.
    using value_type = typename std::iterator_traits<It>::value_type;
    // You can copy only the first half 
    std::vector<value_type> left_side_copy(left, middle);
    It L = left_side_copy.begin();
    It R = middle;
    while (L != left_side_copy.end()  &&  R != right)
    {
        if ( *L <= *R )
        { 
            *left = *L;
            ++L;
        }
        else {
            *left = *R;
            ++R;
        }
        ++left;
    }
    // Copy only the leftovers, if there are any
    std::copy(L, left_side_copy.end(), left);
}
template <class It> 
void merge_sort(It left, It right)
{
    if (auto dist = std::distance(left, right); dist > 1)
    {
        It middle = left + dist / 2;
        merge_sort(left, middle);
        merge_sort(middle, right);
        merge(left, middle, right);
    }
}
int main(void)
{
    std::vector<int> arr {
        5, 12, 11, 13, 5, 4, 7, 13, 6
    };
    merge_sort(arr.begin(), arr.end());
    for(auto const &i : arr) {
        std::cout << ' ' << i;
    }
    std::cout << 'n';
}

您正在使用索引i,而不是向量R中的j。用R[j]替换R[i],请参见下面的

  void merge2(vector<int> &arr, int l, int m, int r)
    {
        //..
        while (i < (n1) && j < (n2)){
            if (L[i]<=R[j]){ //R[i] is replaced by R[j]
                arr[k] = L[i++];
            }
            else {
                arr[k] = R[j++];
            }
            k++;
        }
   //...
}

线int m = l+(r-l)/2;不正确。您可能是指int m = (l+r-l)/2;,尽管我认为最好保留int m = (l+r)/2;