std::unique

使用 std::unique

       因爲要把vector中的相同相鄰元素去掉,便想到了算法unique。

              std::unique(intvect.begin(), intvect.end());

可是調用了以後發現程序依然和調用前相同的行爲,感覺很奇怪。調試發現vector的大小根本沒變,也就是說相同元素沒被刪除。

 

我在visual c++ 2005 下工作,一直使用的是Microsoft提供的stl庫。unique的代碼…/Microsoft Visual Studio 8/VC/include/algorithm中,代碼不多:

        // TEMPLATE FUNCTION unique

        template<class _FwdIt> inline

            _FwdIt _Unique(_FwdIt _First, _FwdIt _Last)

            {   // remove each matching previous

            _DEBUG_RANGE(_First, _Last);

            for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )

                if (*_Firstb == *_First)

                {   // copy down

                    for (; ++_First != _Last; )

                        if (!(*_Firstb == *_First))

                            *++_Firstb = *_First;

                    return (++_Firstb);

                }

                return (_Last);

            }

 

        template<class _FwdIt> inline

            _FwdIt unique(_FwdIt _First, _FwdIt _Last)

            {   // remove each matching previous

            _ASSIGN_FROM_BASE(_Last,

                _Unique(_CHECKED_BASE(_First), _CHECKED_BASE(_Last)));

            return (_Last);

            }

    Unique只是把不同的相鄰元素copy到了前面,返回的iterator是沒有相同相鄰元素的下一個迭代位置。

_Firstb指向的是結果的末尾元素,傳入參數_First用來遞增遍歷元素,當它找到與_Firstb不相等的元素時,就把這個元素copy到_Firstb的下一個位置。當然,_Firstb的下一個元素將被覆蓋,它被丟棄了。這是裏面的for循環所做的事。

外層的for循環只是保證當有相鄰相同元素時才進入到裏層for中進行copy工作,這是一種優化。雖然有兩層for,但算法的複雜度爲O(n)。

 

看如下的例子:

std::vector<int> intvect(3, 10);

intvect.insert(intvect.end(), 2, 11);

std::unique(intvect.begin(), intvect.end());

std::copy(intvect.begin(), intvect.end(), std::ostream_iterator<int>(std::cout, "/n"));

    intvect中的值在unique之前是10,10,10,11,11

                         之後是10,11,10,11,11。

    unique返回的iterator指向第三個元素,也就是正確結果(第二個)的下一個。intvect 在調用unique之後元素被改變了,不考慮順尋,它個元素和調用前也已經不相同了。所以在使用完unique之後要調用vector::erase將後面的元素刪除。

intvect.erase(std::unique(intvect.begin(), intvect.end()), intvect.end());

    這樣寫,一切就正常了。

 

    爲什麼unique不刪除已經沒用的元素?因爲它不會刪,它只是個template算法,它連傳入iterator的容器是什麼都不知道,當然也無法刪除了。

 

    C++標準對此也沒多說,爲了方便我把標準有關unique的內容摘錄如下:

 

25.2.8 Unique [lib.alg.unique]

template<class ForwardIterator>

ForwardIterator unique(ForwardIterator first, ForwardIterator last);

template<class ForwardIterator, class BinaryPredicate>

ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred);

1 Effects: Eliminates all but the first element from every consecutive group of equal elements referred to by the iterator i in the range [first, last) for which the following corresponding conditions hold:

*i == *(i - 1) or pred(*i, *(i - 1)) != false

2 Returns: The end of the resulting range.

3 Complexity: If the range (last - first) is not empty, exactly (last - first) - 1 applications of the corresponding predicate, otherwise no applications of the predicate.

 

template<class InputIterator, class OutputIterator>

OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result);

template<class InputIterator, class OutputIterator, class BinaryPredicate>

OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred);

4 Requires: The ranges [first, last) and [result, result+(last-first)) shall not overlap.

5 Effects: Copies only the first element from every consecutive group of equal elements referred to by the iterator i in the range [first, last) for which the following corresponding conditions hold:

*i == *(i - 1) or pred(*i, *(i - 1)) != false

6 Returns: The end of the resulting range.

7 Complexity: Exactly last - first applications of the corresponding predicate.

 

         如標準所示,unique算法還有另外幾種類型,但實現都大同小異。

    在標準下,stl的實現各異。Reading The Fucking Code!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章