我目前正在为练习编写自己的合并排序实现。合并列表的左右部分时,创建一个只包含两边较小的临时列表是有意义的。但是,逻辑会根据复制到temp的一侧而改变。
我的功能有以下签名:
template<class RandomIt, class Compare>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp);
我有一个聪明的想法,在开始时检查[begin,middle)
和[middle,end)
的长度,如果左边更大,则将迭代器转换为反向迭代器并递归调用该函数。像这样:
template<class RandomIt, class Compare>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp) {
size_t leftLength = std::distance(begin, middle);
size_t rightLength = std::distance(middle, end);
if (leftLength > rightLength) {
using ReverseIterator = std::reverse_iterator<RandomIt>;
Merge(ReverseIterator(end), ReverseIterator(std::next(middle)), ReverseIterator(begin), Comp);
return;
}
//Now [begin,middle) is guaranteed <= [middle,end)
//...
}
但是,编译器会出现相当粗的错误。
fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
我创建了一个little stand-alone application on ideone.com来重现错误。
编辑:对于mergesort,我只是意识到这不会起作用,因为需要反转Compare函数。
答案 0 :(得分:2)
这里的问题是,您在递归的每个步骤创建函数Merge
的新实例化,即首次从reverse_iterator
创建randomaccess_iterator
。然后编译器从reverse_iterator
创建reverse_iterator
,依此类推......
正如您在创建reverse_iterator
时必须注意到的那样,迭代器的模板类型会一直在改变...创建模板化函数的新实例。
简而言之,使用迭代器是错误的。
这可能有效:
template <class RandomIt, class RevIt>
void Test(RandomIt begin, RandomIt middle, RandomIt end, RevIt rit) {
size_t leftLength = std::distance(begin, middle);
size_t rightLength = std::distance(middle, end);
if (leftLength > rightLength) {
Test(RevIt(end), RevIt(middle), RevIt(begin), rit);
return;
}
}
template <typename RandomIt>
void Test(RandomIt begin, RandomIt middle, RandomIt end) {
Test(begin, middle, end, std::reverse_iterator<RandomIt>());
}
int main() {
std::vector<int> nums = { 2, 1, 123, 1, 23, 123, 123, 5234, 52, 3, 452, 3, 452, 5 };
int middle;
std::cin >> middle;
Test(nums.begin(), nums.begin()+middle, nums.end());
return 0;
}
答案 1 :(得分:0)
问题是Merge<it>
需要Merge<std::reverse_iterator<it>>
,这需要Merge<std::reverse_iterator<std::reverse_iterator<it>>
,这需要Merge<std::reverse_iterator<std::reverse_iterator<std::reverse_iterator<it>>>
,这需要Merge<std::reverse_iterator<std::reverse_iterator<std::reverse_iterator<std::reverse_iterator<it>>>>
,这需要......
所以你想要的是已经反转的迭代器的ReverseIterator(
使用原始迭代器。所以你需要帮助函数:
template <class RandomIt>
RandomIt ReverseIt(std::reverse_iterator<RandomIt> it) {
return it.base();
}
template <class RandomIt>
std::reverse_iterator<RandomIt> ReverseIt(RandomIt it) {
return std::reverse_iterator<RandomIt>(it);
}
template<class RandomIt, class Compare=std::less<typename std::iterator_traits<RandomIt>::value_type>>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp={}) {
size_t leftLength = std::distance(begin, middle);
size_t rightLength = std::distance(middle, end);
if (leftLength > rightLength) {
Merge(ReverseIt(end), ReverseIt(std::next(middle)), ReverseIt(begin), Comp);
return;
}
//Now [begin,middle) is guaranteed <= [middle,end)
//...
}