std::unique

来源:互联网 发布:淘宝联盟客服在哪里找 编辑:程序博客网 时间:2024/05/16 17:08

使用 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(ForwardIteratorfirst, ForwardIterator last);

template<class ForwardIterator, class BinaryPredicate>

ForwardIterator unique(ForwardIteratorfirst, 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(InputIteratorfirst, InputIterator last, OutputIterator result);

template<class InputIterator, class OutputIterator, class BinaryPredicate>

OutputIterator unique_copy(InputIteratorfirst, InputIterator last, OutputIterator result, BinaryPredicatepred);

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: Exactlylast - first applications of the corresponding predicate.

 

         如标准所示,unique算法还有另外几种类型,但实现都大同小异。

    在标准下,stl的实现各异。Reading The Fucking Code!
0 0