Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有插入然后排序的替代方法_C++_Sorting_Insert_Merge_Stl Algorithm - Fatal编程技术网

C++ 是否有插入然后排序的替代方法

C++ 是否有插入然后排序的替代方法,c++,sorting,insert,merge,stl-algorithm,C++,Sorting,Insert,Merge,Stl Algorithm,如果我有vector foo和vector bar两个都已排序,并且我想将它们合并到foo中,以便对最终结果进行排序,那么标准是否为我提供了这样做的方法 显然,我能做到: foo.insert(foo.end(), bar.begin(), bar.end()); sort(foo.begin(), foo.end()); 但我希望有一个一步算法来完成这一点。要详细说明Mat的评论,您的代码可以使用std::merge: std::vector<int> result; std::

如果我有
vector foo
vector bar
两个都已排序,并且我想将它们合并到
foo
中,以便对最终结果进行排序,那么标准是否为我提供了这样做的方法

显然,我能做到:

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

但我希望有一个一步算法来完成这一点。

要详细说明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
std::向量结果;
合并(
foo.begin(),foo.end(),
bar.begin(),bar.end(),
标准:背向插入器(结果);
foo=结果;//如果需要
使用它可能比使用
std::sort
更快。如果有额外的可用内存,则它具有线性复杂度,否则它会返回到NlogN

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

如果你需要这种合并,为什么不自己做一个呢

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;
    }
}

实时样本:。

所以在查看了所有标准算法后,我可以确认,在搜索标准算法时,除了插入和排序没有其他选择。我注意到,所有复制算法都使用输入迭代器和输出迭代器。唯一使用输入输出迭代器的时间是在单个范围上操作时。(例如,
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
相当:

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


唯一实际的“一步算法”是将这个高炉的答案滚动到一个函数中,你可以通过传递要合并的容器来调用该函数。

@Mat:这会产生某种合并排序吗?合并到一个临时值,然后交换。更糟的是什么意思?时间复杂性——我不这么认为。内存开销-是的,可能是。交换是固定时间的,而且速度非常快。(如果您试图保存一行代码,…)@JonathanMee是否是您的一行代码的候选项?这是一个比我在问题中已经建议的更糟糕的解决方案,因为它需要创建另一个临时的
向量。此外,它不能满足“一步算法完成此任务”的要求。可以通过为
结果
预先分配存储来提高效率。它具有较低的复杂性,尽管不是一步完成的。最后一部分可能是一个动作,可能使它成为你能为此设计的最快算法。@JonathanMee在我的测试程序
std:merge
中保持
foo
bar
不变,
结果
充满了合并列表,就像上面说的那样。@Tobimnamobi你是对的,我的错误,我以为您的输出是
back\u inserter(foo)
@Lingxi:此算法试图分配一些临时缓冲内存以允许线性复杂度,如果它不能,它将使用一个效率较低的(NlogN)算法。我投了赞成票,但让我们明确一点,
std::inplace\u merge()
与TobiMcNamobi的代码做了完全相同的事情(假设有足够的内存可用),因此如果OP对该解决方案不满意,他真的应该对该解决方案同样不满意。@j_random_hacker那不是真的,TobiMcNamobi的解决方案不起作用:@JonathanMee:我们知道
insert()
使
foo.end()无效
迭代器,不考虑容器的容量。将其与评估问题的顺序结合起来,这使得单行程序的概念非常粗略。@JonathanMee:不用担心:)出于这个原因,我认为
inplace\u merge
确实是更方便的选择,而且我已经反复强调了这样一个事实,即在内部它只会做TobiMcNamobi的代码所做的事情,因此,当涉及到std算法时,编写自己的代码通常是有风险的。虽然这个特别的问题很容易,所以我可以考虑,但我不会承认这样做。你的算法有缺陷。如果
中的最后一个元素(如果有)小于
中的第一个元素,当
foo
小于
bar
时,@MateuszGrzejek断言会怎样。我同意自己写,但这不起作用。@MateuszGrzejek如果您可以从注释中对其进行解释,这可能会更有效:
for(Container::iterator toIterator=where.begin(),fromtiterator=what.begin();fromtiterator!=what.end();+fromtiterator){while(toIterator!=where.end()&*toIterator<*fromtiterator)++toIterator;toIterator=where.insert(toIterator,*fromtiterator);}
这是一个最小的解决方案,说明了可能的概念。是的,需要进行调整-但是,请注意,如果我们能够对参数的内容做出一些保证,则检查所有可能的情况(空
where
,空
what
,等等)可能没有必要。现在,由OP根据他的需要来调整。
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;
            }
        }
    }
}
 foo.resize(foo.size() + bar.size());
 func(foo.begin(), next(foo.begin(), foo.size() - bar.size()), bar.begin(), bar.end());
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
inplace_merge(foo.begin(), middle, foo.end());