替换排序范围内的元素
Replace element in sorted range
有一个std::vector
唯一元素的数组。它已排序。众所周知,它包含一个值为 From
的元素。我想用唯一值替换它To
以最佳方式继续跟踪其排序的属性。我可以简单地通过 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);
如何使用STL实现期望?
找到要替换的元素的位置,并在插入元素后找到要插入的元素的位置(这两种情况都使用 lower_bound
)。然后更换元素并旋转。
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);
}
稍微改进了本杰明·林德利的解决方案:
#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;
}
相关文章:
- 为什么在全局范围内使用"extern int a"似乎不行?
- 错误:未在此范围内声明'reverse'
- 并行用于C++17中数组索引范围内的循环
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 对于多个查询,查找在 l 到 r 范围内具有相同元素的最长公共子数组
- 我应该如何使用remove_if删除两个数字范围内的元素
- 从给定范围内的向量中查找最大元素
- 矢量擦除范围内的元素
- 如何擦除矢量中的所有元素,但特定范围内最大的元素除外
- 如何在 std::map 中找到指定范围内的元素?
- 如果地图擦除范围内的第一个和最后一个相等,则是否删除该元素
- 如何在向量的给定索引范围内查找最小元素
- C++中数组范围内的有效元素计数
- 查找范围内元素数量的最快方法
- 元素在给定范围内的子矩阵中唯一元素的数目
- 替换排序范围内的元素
- 从矢量范围内删除特定元素
- 如何在C++中检查一个集合是否有某个范围内的元素
- 当C++试图访问向量的元素(在范围内)时,Qt Quick Windows应用程序崩溃
- 查找矢量中位于指定范围内的元素