是否有替代插入然后排序

时间:2015-05-13 14:09:16

标签: c++ sorting insert merge stl-algorithm

如果我对vector<int> foovector<int> bar进行排序,并且我想将它们合并到foo中以便最终结果排序,标准是否为我提供了方法这样做?

显然我可以这样做:

foo.insert(foo.end(), bar.begin(), bar.end());
sort(foo.begin(), foo.end());

但我希望有一步法算法来实现这一目标。

4 个答案:

答案 0 :(得分:6)

要详细说明Mat的评论,您的代码可能会使用std::merge

std::vector<int> result;
std::merge(
    foo.begin(), foo.end(),
    bar.begin(), bar.end(),
    std::back_inserter(result));

foo = result; // if desired

答案 1 :(得分:6)

使用std::inplace_merge代替std::sort可能会更快。如果有额外的可用内存,则它具有线性复杂性,否则会回退到NlogN。

auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
std::inplace_merge(foo.begin(), middle, foo.end());

答案 2 :(得分:1)

如果您需要这种合并,为什么不自己制作?

template <class Vector>
void insert_sorted(Vector& where, Vector& what)
{
    typename Container::iterator src = what.begin();
    typename Container::iterator src_end = what.end();

    size_t index = 0;

    while(src != src_end)
    {
        if(*src < where[index])
        {
            where.insert(where.begin() + index, *src);
            ++src;
        }

        ++index;
    }
}

样本用法:

vector<int> foo{ 0, 5, 7, 9, 11, 14 };
vector<int> bar{ 1, 2, 4, 8, 10, 12 };

insert_sorted(foo, bar);

for(vector<int>::iterator i = foo.begin(); i != foo.end(); ++i)
    cout << *i << " ";

输出:

0 1 2 4 5 7 8 9 10 11 12 14

实时样本:link

答案 3 :(得分:0)

因此,在查看了所有标准算法之后,我可以确认,insertsort之外别无选择。正如我在搜索标准算法时所做的那样 all 复制算法使用输入迭代器和输出迭代器唯一一次使用输入输出迭代器是在操作单个范围时。 (例如sort使用输入输出迭代器,但任何copy使用输入迭代器和输出迭代器。)

我想举例说明我的观点。因此,让我们举例说明插入合并算法与输入输出迭代器的结果:

template <class BidirectionalIterator, class InputIterator>
void func(BidirectionalIterator first1, BidirectionalIterator last1, InputIterator first2, InputIterator last2){
    bool is1Empty = first1 == last1;
    bool is2Empty = first2 == last2;
    BidirectionalIterator end = next(last1, distance(first2, last2));

    if (!is1Empty){
        --last1;
    }

    if (!is2Empty){
        --last2;
    }

    while (!is1Empty || !is2Empty){
        --end;
        if (!is1Empty){
            if (!is2Empty && *last2 > *last1){
                *end = *last2;

                if (last2 == first2){
                    is2Empty = true;
                }else{
                    --last2;
                }
            }else{
                *end = *last1;

                if (last1 == first1){
                    is1Empty = true;
                }
                else{
                    --last1;
                }
            }
        }else{
            *end = *last2;

            if (last2 == first2){
                is2Empty = true;
            }
            else{
                --last2;
            }
        }
    }
}

关于此func算法,应该注意两件事:

  1. 不尊重last1假设在last1之外分配足够的空间以包含输入范围内的所有元素
  2. func的输入输出范围不能像back_inserter那样用标准算法中的任何其他输出范围调用
  3. 因此,即使func也不能是“一步算法”。它必须像这样调用:

     foo.resize(foo.size() + bar.size());
     func(foo.begin(), next(foo.begin(), foo.size() - bar.size()), bar.begin(), bar.end());
    

    请注意Blastfurnace's answer利用它合并两个排序范围的知识,因此速度与func相当:

    auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
    inplace_merge(foo.begin(), middle, foo.end());
    

    唯一真正的“一步算法”是将此Blastfurnace的答案转换为一个函数,您可以通过传入要合并的容器来调用它。

相关问题