C++ 替换排序范围中的元素
有一个数组C++ 替换排序范围中的元素,c++,algorithm,sorting,insert,C++,Algorithm,Sorting,Insert,有一个数组std::vector,包含唯一的元素。已经分类了。众所周知,它包含一个值为From的元素。我想用uniquevalueto以最佳方式替换它,并保持跟踪其排序属性。我可以简单地通过std::lower_bound实现它,然后替换并最终将std::sort应用于整个数组,但我知道-这是次优的,因为只有子范围[std::lower_bound(beg,end,From),std::upper_bound(beg,end,to))应该最大程度地重新排序 int From = 4; int T
std::vector
,包含唯一的元素。已经分类了。众所周知,它包含一个值为From
的元素。我想用uniquevalueto
以最佳方式替换它,并保持跟踪其排序属性。我可以简单地通过std::lower_bound
实现它,然后替换并最终将std::sort
应用于整个数组,但我知道-这是次优的,因为只有子范围[std::lower_bound(beg,end,From),std::upper_bound(beg,end,to))
应该最大程度地重新排序
int From = 4;
int To = 7;
std::vector< int > v{2, 4, 6, 8};
auto const beg = std::begin(v);
auto const end = std::end(v);
*std::lower_bound(beg, end, From) = To;
std::sort(beg, end);
int From=4;
int至=7;
向量v{2,4,6,8};
自动常数beg=std::begin(v);
自动常数结束=标准::结束(v);
*std::下限(beg、end、From)=到;
std::排序(beg,end);
如何使用STL实现所需的功能?找到要替换的元素的位置,并在插入元素后找到要插入的元素的位置(对于这两种情况都使用
下限
),然后替换元素并旋转
auto p1 = std::lower_bound(beg, end, From);
auto p2 = std::lower_bound(beg, end, To);
*p1 = To;
if (p1 < p2)
{
std::rotate(p1, p1 + 1, p2);
}
else if (p2 < p1)
{
std::rotate(p2, p1, p1 + 1);
}
auto p1=std::下限(beg、end、From);
自动p2=std::下限(beg、end、To);
*p1=至;
if(p1
本杰明·林德利的解决方案:
#include <utility>
#include <type_traits>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <deque>
#include <vector>
#include <list>
#include <cstdlib>
#include <cassert>
template< typename container, typename type >
std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< typename container::iterator >::iterator_category >::value >
replace(container & _container, typename container::value_type const & _from, type && _to)
{
auto const beg = std::begin(_container);
auto const end = std::end(_container);
auto const from = std::lower_bound(beg, end, _from);
auto const mid = std::next(from);
if (_from < _to) {
auto const to = std::lower_bound(from, end, _to);
*from = std::forward< type >(_to);
std::rotate(from, mid, to);
} else if (_to < _from) {
auto const to = std::lower_bound(beg, mid, _to);
*from = std::forward< type >(_to);
std::rotate(to, from, mid);
} else {
*from = std::forward< type >(_to);
}
}
template< typename container, typename type >
std::enable_if_t< !std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< typename container::iterator >::iterator_category >::value
&& std::is_base_of< std::forward_iterator_tag, typename std::iterator_traits< typename container::iterator >::iterator_category >::value >
replace(container & _container, typename container::value_type const & _from, type && _to)
{
auto const beg = std::begin(_container);
auto const end = std::end(_container);
if (_from < _to) {
auto const from = std::lower_bound(beg, end, _from);
auto const to = std::lower_bound(std::next(from), end, _to);
_container.insert(to, std::forward< type >(_to));
_container.erase(from);
} else if (_to < _from) {
auto const to = std::upper_bound(beg, end, _to);
auto const from = std::lower_bound(to, end, _from);
_container.insert(to, std::forward< type >(_to));
_container.erase(from);
}
}
template< typename container >
bool
test(container lhs, int from, int to, container const & rhs)
{
replace(lhs, from, to);
return (lhs == rhs);
}
template< typename container >
bool
test()
{
if (!test< container >({2, 4, 6, 8}, 2, 1, {1, 4, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 2, 2, {2, 4, 6, 8})) return false;//
if (!test< container >({2, 4, 6, 8}, 2, 3, {3, 4, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 2, 5, {4, 5, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 2, 7, {4, 6, 7, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 2, 9, {4, 6, 8, 9})) return false;
if (!test< container >({2, 4, 6, 8}, 4, 1, {1, 2, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 4, 3, {2, 3, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 4, 4, {2, 4, 6, 8})) return false;//
if (!test< container >({2, 4, 6, 8}, 4, 5, {2, 5, 6, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 4, 7, {2, 6, 7, 8})) return false;
if (!test< container >({2, 4, 6, 8}, 4, 9, {2, 6, 8, 9})) return false;
if (!test< container >({2, 4, 6, 8}, 8, 1, {1, 2, 4, 6})) return false;
if (!test< container >({2, 4, 6, 8}, 8, 3, {2, 3, 4, 6})) return false;
if (!test< container >({2, 4, 6, 8}, 8, 5, {2, 4, 5, 6})) return false;
if (!test< container >({2, 4, 6, 8}, 8, 7, {2, 4, 6, 7})) return false;
if (!test< container >({2, 4, 6, 8}, 8, 8, {2, 4, 6, 8})) return false;//
if (!test< container >({2, 4, 6, 8}, 8, 9, {2, 4, 6, 9})) return false;
if (!test< container >({2}, 2, 2, {2})) return false;//
if (!test< container >({2}, 2, 3, {3})) return false;
if (!test< container >({2}, 2, 1, {1})) return false;
return true;
}
int
main()
{
assert((test< std::vector< int > >()));
assert((test< std::deque< int > >()));
assert((test< std::list< int > >()));
return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
模板
如果::iterator\u category>::value>
替换(容器和容器,类型名称容器::值和类型常量和从,类型和到)
{
auto const beg=std::begin(_容器);
auto const end=std::end(_容器);
auto const from=std::下限(beg、end、from);
自动常数mid=std::next(从);
如果(从<\u到){
auto const to=std::下限(from、end、to);
*from=std::forward(_-to);
标准::旋转(从、中间到);
}否则如果(\u至<\u自){
自动常数to=std::下限(beg、mid、to);
*from=std::forward(_-to);
标准::旋转(到、从、中间);
}否则{
*from=std::forward(_-to);
}
}
模板
如果std::t<!std::是::iterator\u category>:value的基础,则启用
&&std::是::iterator\u category>::value>
替换(容器和容器,类型名称容器::值和类型常量和从,类型和到)
{
auto const beg=std::begin(_容器);
auto const end=std::end(_容器);
如果(从<\u到){
auto const from=std::下限(beg、end、from);
auto const to=std::下限(std::next(from)、end、\U to);
_container.insert(to,std::forward(_-to));
_容器。擦除(从);
}否则如果(\u至<\u自){
auto const to=std::上限(beg、end、to);
auto const from=std::下限(to、end、from);
_container.insert(to,std::forward(_-to));
_容器。擦除(从);
}
}
模板
布尔
测试(集装箱左侧、整备自、整备至、集装箱常数和右侧)
{
更换(左侧、从、到);
返回(lhs==rhs);
}
模板
布尔
测试()
{
如果(!test({2,4,6,8},2,1,{1,4,6,8}))返回false;
如果(!test({2,4,6,8},2,2,{2,4,6,8}))返回false//
如果(!test({2,4,6,8},2,3,{3,4,6,8}))返回false;
如果(!test({2,4,6,8},2,5,{4,5,6,8}))返回false;
如果(!test({2,4,6,8},2,7,{4,6,7,8}))返回false;
如果(!test({2,4,6,8},2,9,{4,6,8,9}))返回false;
如果(!test({2,4,6,8},4,1,{1,2,6,8}))返回false;
如果(!test({2,4,6,8},4,3,{2,3,6,8}))返回false;
如果(!test({2,4,6,8},4,4,{2,4,6,8}))返回false//
如果(!test({2,4,6,8},4,5,5,6,8}))返回false;
如果(!test({2,4,6,8},4,7,{2,6,7,8}))返回false;
如果(!test({2,4,6,8},4,9,{2,6,8,9}))返回false;
如果(!test({2,4,6,8},8,1,{1,2,4,6}))返回false;
如果(!test({2,4,6,8},8,3,{2,3,4,6}))返回false;
如果(!test({2,4,6,8},8,5,{2,4,5,6}))返回false;
如果(!test({2,4,6,8},8,7,{2,4,6,7}))返回false;
如果(!test({2,4,6,8},8,8,{2,4,6,8}))返回false//
如果(!test({2,4,6,8},8,9,{2,4,6,9}))返回false;
如果(!test({2},2,2,{2}))返回false//
如果(!test({2},2,3,{3}))返回false;
如果(!test({2},2,1,{1}))返回false;
返回true;
}
int
main()
{
断言((test>());
断言((test>());
断言((测试>());
返回退出成功;
}
有三种情况:if(From、else if(To和else{}
。但是如何正确处理std::rotate(b,std::next(b),e)
的前提是范围的有效性[b,std::next(b))
和[std::next(b),e)
。很好,它适用于单元素容器。谢谢。Is(p1
对非随机访问迭代器有效?我认为最好使用From
和to
本身的值。@Orient:不,它不有效。你当然可以检查From
是否有效。但是,如果你没有随机访问迭代器,你可能有什么?一个链表?其中可以