STL样式函数用于查找STL容器的中间位置

sne*_*nek 6 c++

我是C++的新手,我请求帮助来解决问题.

我正在编写一个简单的STL样式函数,它应该返回序列的中间元素(向量,列表等)

这是我的函数,我尝试使用迭代器的概念

template <class It, class T> It  middle(It first, It last) 
{

    while(first!=last){
        ++first;
        --last;
    }
    return first;
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要,试图调用中间为一个向量的向量(我省略了包括)

int main() {
    vector<int>vi;
    int x;
    cout<<"Enter vector elemets...";
    while (cin>>x)
    vi.push_back(x);
    cout<<endl;
    cin.clear();
    cout<<"the vector is:"<<endl;
    for(int i=0;i<vi.size();++i)
    cout<<vi[i]<<" ";
    cout<<endl;
    vector<int>::iterator first=vi.begin();
    vector<int>::iterator last=vi.end();
    vector<int>::iterator ii=middle(first,last);
    cout<<"The middle element of the vector is: "<<*ii<<endl;
}
Run Code Online (Sandbox Code Playgroud)

使用g ++编译时出现以下错误:

myex21-7.cpp:79: error: no matching function for call to ‘middle(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&)’
Run Code Online (Sandbox Code Playgroud)

有人可以给我一些解决方法吗?感谢您对高级潜行的任何帮助

Jer*_*fin 8

怎么样:

auto middle = container.begin();
std::advance(middle, container.size()/2);
Run Code Online (Sandbox Code Playgroud)

如果您有C++ 11可用,则std::next允许您在一行而不是两行中执行相同操作.

还要注意,在容器支持随机访问迭代器(例如,std::vectorstd::deque)的情况下,这将是相对有效的(恒定复杂度而不是线性复杂度).


jua*_*nza 6

除非这是一个练习,否则实现某些方面可能更简单std::next.暂时忽略具有偶数元素的容器的特殊情况,您可以使用以下内容:

std::vector<SomeType> v = ....;
auto mid = std::next(v.begin(), v.size()/2);
Run Code Online (Sandbox Code Playgroud)

至于代码的问题,您的middle函数模板有两个参数:

template <class It, class T> It  middle(It first, It last) { .... }
Run Code Online (Sandbox Code Playgroud)

但是没有办法从函数参数中推导出第二个参数.由于无论如何都不需要参数,您只需删除它:

template <class It> It  middle(It first, It last) { .... } 
Run Code Online (Sandbox Code Playgroud)


Bil*_*eal 6

这里的其他答案很有趣,但它们需要访问容器本身.要成为真正的STL样式,您应该使用迭代器范围.这是一个为随机访问迭代器提供高效处理的解决方案,但也适用于前向迭代器

// http://ideone.com/1MqtuG

#include <iterator>

template <typename ForwardIt>
ForwardIt DoMidpoint(ForwardIt first, ForwardIt last, std::forward_iterator_tag)
{
    ForwardIt result = first;

    // Try to increment the range by 2
    bool sawOne = false;
    // EDIT: Note improvements to this loop in the comments

    while(first != last)
    {
        ++first;
        if (sawOne)
        {
            // If that succeeded, increment the result by 1
            ++result;
            sawOne = false;
        }
        else
        {
            sawOne = true;
        }
    }

    return result;
}

template <typename RandomAccessIt>
RandomAccessIt DoMidpoint(RandomAccessIt first, RandomAccessIt last, std::random_access_iterator_tag)
{
    return first + (last - first)/2;
}

template <typename ForwardIt>
ForwardIt midpoint(ForwardIt first, ForwardIt last)
{
    return DoMidpoint(first, last, typename std::iterator_traits<ForwardIt>::iterator_category());
}
Run Code Online (Sandbox Code Playgroud)

  • `template <class It>它的中点(它开始,它结束){return std :: advance(begin,std :: distance(begin,end)/ 2); 似乎更短了.它确实意味着在非随机访问迭代器上,我们遍历每个位置1.5次.你的循环可能会被改进为`while(first!= last){++ first; if(first == last)break; ++第一; ++结果; };`,它将循环的成对迭代折叠成一个体. (2认同)