归并。使用迭代器实现

时间:2013-12-23 10:21:39

标签: c++ algorithm templates sorting

我需要使用以下接口实现mergesort算法:

template <typename T, typename Comp>
void mergesort(T begin, T end, Comp comp);

其中开始结束 - 类型为T,comp的某个容器的元素的迭代器是比较元素的函数,这些元素存储在容器中。和

template <typename T, typename Comp>
void merge(T beginLeft, T endLeft, T beginRight, T endRight,
                T beginResult, Comp comp);

是合并两个已排序容器( beginLeft endLeft - 第一个容器的迭代器, beginRight endRight <的功能/ em> - 第二个),结果应该是新合并容器 beginResult 的开头的迭代器。

应该看起来像this

我为合并排序编写了递归函数,它调用了合并的过程。

template <typename T, typename Comp>
void mergesort(T begin, T end, Comp comp)
{
    if (begin == std::prev(end))
    {
        return;
    }    

    T middle = begin + std::distance(begin, end) / 2;

    mergesort<T, Comp>(begin, middle, comp);
    mergesort<T, Comp>(middle, end, comp);

    merge<T, Comp>(begin, middle, middle, end, begin, comp);
}

template <typename T, typename Comp>
void merge(T beginLeft, T endLeft, T beginRight, T endRight,
                T beginResult, Comp comp)
{
    while (beginLeft != endLeft && beginRight != endRight)
    {
        if (comp(*beginLeft, *beginRight))
        {
            *beginResult = *beginLeft;
            ++beginResult;
            ++beginLeft;
        }
        else
        {
            *beginResult = *beginRight;
            ++beginResult;
            ++beginRight;
        }
    }

    while (beginLeft != endLeft)
    {
        *beginResult = *beginLeft;
        ++beginResult;
        ++beginLeft;
    } 
    while (beginRight != endRight)
    {
        *beginResult = *beginRight;
        ++beginResult;
        ++beginRight;
    } 
}

函数 merge 正常工作,但我不太明白, mergesort 应该如何工作。我应该传递什么参数

merge<T, Comp>(begin, middle, middle, end, /?...?/, comp);

如果我在那里只传递开始,那么排序的结果是不正确的。或者我应该通过一些临时容器。但是,如果我只有迭代器的类型并且不知道元素的类型,我该如何创建呢?

我将非常感谢你的帮助。谢谢!

- ADDED ---

合并示例:

vector<int> vec1;
vector<int> vec2;
vector<int> vec3(6);
vec1.push_back(1);
vec1.push_back(3);
vec1.push_back(5);
vec2.push_back(2);
vec2.push_back(4);
vec2.push_back(6);
merge(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), vec3.begin(), std::less<int>()); 

for (int i = 0; i < vec3.size(); ++i)
{
    std::cout << vec3[i] << std::endl;
}

输出为:1 2 3 4 5 6

3 个答案:

答案 0 :(得分:2)

您肯定无法使用begin存储结果。您仍在阅读begin并合并,因此通过写入,您将覆盖可能仍未读取的数据。

您需要临时内存才能将结果写入,然后复制回原始内存。内存可以是任何类型,只要你可以通过它获得迭代器。说一句std::vector

但是存在一个根本问题。您在merge中将所有五个迭代器的类型都设置为T,但至少beginResult的类型应该是可能不同的迭代器。否则,正如您所观察到的,您无法知道要使用的临时容器。

正如您自己链接的那样,std::merge的模板为leftrightresult迭代器提供了不同的迭代器类型。


注意:要分配临时内存,您需要知道T是迭代器的元素类型。这只是由T::value_type完成的。请参阅here

答案 1 :(得分:0)

这样的事情应该有效:

template<class BiDirIt, class Compare = std::less<typename std::iterator_traits<BiDirIt>::value_type>>
void merge_sort(BiDirIt first, BiDirIt last, Compare cmp = Compare())
{
        auto const N = std::distance(first, last);
        if (N < 2) return;
        auto middle = first + N / 2;
        merge_sort(first, middle, cmp);
        merge_sort(middle, last, cmp);
        std::inplace_merge(first, middle, last, cmp);
}

答案 2 :(得分:0)

您可以这样创建矢量:

init

在辅助函数中,然后调用您的排序例程:

std::vector<std::iterator_traits<T>::value_type> result;

然后,一旦您的函数返回结果,您可以将结果复制到用户提供的迭代器表示的向量。