簡體   English   中英

為什么向量迭代器指向超出邊界?

[英]Why does the vector iterator point out of bounds?

我正在研究遞歸mergesort算法,並且一個迭代器超出范圍。 我很肯定我的問題的根源是我的算法存在缺陷,但是我已經花了幾天時間傾倒它,我只是沒有看到我的錯誤。 我不知道要采取什么方向。 有人比我看一看更有經驗/更聰明嗎? (在這里 ,Github上提供了帶驅動程序的完整程序。)

輸出是:

before: 50 5 40 10 30 15 20 20 10 25 
after : -1808873259 5 10 10 15 20 20 25 30 40 50 
/*      ^  
 *      Extra recursive call, and out-of-bounds.
 */

為了清楚起見,我被約束為返回類型為T的向量,在本例中為int,但我從這篇文章中知道使用void函數更好。

template <typename T>
vector<T> mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
    vector<T> newVector;
    if (begin!=end){
        vector<T> tmp1;
        vector<T> tmp2;
        typename vector<T>::iterator mid1 = begin;
        typename vector<T>::iterator mid2 = begin;

        long origDistance = distance(begin,end);
        long endOfRange1 = origDistance/2;
        long begOfRange2 = endOfRange1+1;

        advance(mid1,endOfRange1);
        advance(mid2,begOfRange2);

        tmp1 = mergesort<T>(begin,mid1);
        tmp2 = mergesort<T>(mid2,end);

        //"merge()" is from the STL, link in comments. 
        merge(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(), back_inserter(newVector));

    } else {
        newVector.push_back(*begin);
    }
    return newVector;
}

取消引用beginbegin == end 這是未定義的行為。 可能你想要if (origDistance == 1)然后push_back單個元素並返回。

如果end指向向量的最后一個元素,那么你的函數看起來可以工作。 但是在您的示例程序中,您可以這樣稱呼它:

 newVector = mergesort<int>(vec.begin(), vec.end()); 

vec.end()指向矢量的末尾,它不指向最后一個元素。 因此,您的函數會混亂,因為它最終會嘗試訪問您傳入的第二個迭代器所指向的元素。

可以調用你的函數: mergesort<int>(vec.begin(), vec.end() - 1);

但是,這會讓其他人閱讀您的代碼感到驚訝。 重寫mergesort函數以遵循正常的C ++范圍約定會更好,也就是說,名為end的參數應該是past-the-end。 mid1應該等於mid2

好吧 - 如果不把它搞清楚就無法入睡,並且John ZwinckMM為了讓我朝着正確的方向而獲得了巨大的榮譽 - 這是獲得正確輸出的代碼:

template <typename T>
vector<T> mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
    vector<T> newVector;
    long origDistance = distance(begin,end); /*Get distance first.*/

    if (origDistance==1){ /*Added better anchor case checking for distance.*/
        newVector.push_back(*begin);
        return newVector;
    }

    vector<T> tmp1;
    vector<T> tmp2;
    typename vector<T>::iterator mid1 = begin;
    typename vector<T>::iterator mid2 = begin;

    long endOfRange1 = origDistance/2;
    long begOfRange2 = endOfRange1;/*Edited from: endOfRange+1*/

    advance(mid1,endOfRange1);
    advance(mid2,begOfRange2);

    tmp1 = mergesort<T>(begin,mid1);
    tmp2 = mergesort<T>(mid2,end);

    merge(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(), back_inserter(newVector));
        return newVector;
}

在這里,我將向您展示如何做到這一點。

template <typename T>
void mergesort(typename vector<T>::iterator, typename vector<T>::iterator);

// ...

    mergesort<int>(vec.begin(), vec.end());
    newVector = vec;

// ...

template <typename T>
void mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
    auto const N = std::distance(begin, end);
    if (N <= 1) return;                   
    auto const middle = std::next(begin, N / 2);
    mergesort<T>(begin, middle);
    mergesort<T>(middle, end);
    std::inplace_merge(begin, middle, end); 
}

正確輸出:

before: 50 5 40 10 30 15 20 20 10 25 
after : 5 10 10 15 20 20 25 30 40 50 

STL已經有inplace_merge,為什么要重新實現呢? 通過這種方法,您不必認為邊界很難。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM