根据偶数值对整数向量进行排序
Sort a vector of integers based on the even values
我有一个整数向量,元素数量为偶数。位置 0 和 1 处的元素属于一起,位置 2 和位置 3 处的元素相同,依此类推......
我想根据偶数元素对这个向量进行排序。奇数元素应与其相应的偶数元素保持在一起。我不想使用boost,但我想使用std::sort。
示例:
输入 = {4,40,5,50,3,30,2,20,1,10}输出 = {1,10,2,20,3,30,4,40,5,50}
我想出了以下解决方案。这安全吗?有更好的解决方案吗?
std::vector<int> values = {4,40,5,50,3,30,2,20,1,10};
auto begin = reinterpret_cast<std::array<int, 2>*>(values.data());
auto end = reinterpret_cast<std::array<int, 2>*>(values.data() + values.size());
std::sort(begin, end, [](const std::array<int, 2>& a, const std::array<int, 2>& b)
{
return std::get<0>(a) < std::get<0>(b);
});
编辑:我还应该提到,我无法将向量更改为对向量。当然,总是可以将内容复制到对向量中,但我对使用更少内存的解决方案感兴趣。
这样做的方法之一,假设你绝对不能修改你存储数据的方式,并且没有心情编写自己的排序例程,就是使用可怕的std::qsort
。
在您的示例中,这将是(感谢@chux发现潜在的溢出和@JeJo注意到不正确的大小(:
std::vector<int> values = {4,40,5,50,3,30,2,20,1,10};
std::qsort(values.data(), values.size() / 2, sizeof(values[0]) * 2, [](const void* a, const void* b) {
const int* a_1 = static_cast<const int*>(a);
const int* b_1 = static_cast<const int*>(b);
return (*a_1 > *b_1) - (*a_1 < *b_1);
});
请注意,众所周知,std::sort
比std::qsort
快,有时非常明显。
我试图使用std::sort
和包装std::vector::iterator
的自定义迭代器类型来解决这个问题 (或其他标准容器的迭代器(。这涉及重新实现随机访问迭代器,这 非常长,并且存在兼容性问题(见下文(。
想法
std::sort
的文档指定了可用作其参数的迭代器的要求。 从理论上讲,所需要的只是编写一个符合这些要求的迭代器类,而不是 一次交换一个元素,交换 2 个(或通常为 N 个(元素。
特别是,需要以下事项:
-
符合
RandomAccessIterator
要求的迭代器类 -
底层迭代器的包装器,它作为我们迭代器的"值" - 我称之为
iter_wrapper
-
swap
iter_wrapper
专业化 -
迭代器的
std::iterator_traits
专业化
我冒昧地将这个问题推广到任何兼容std::sort
的容器和 N 迭代器序列(而不是 2(。
我得出了以下实现(底部的示例使用(:
#include <iostream>
#include <vector>
#include <algorithm>
template<typename IteratorType, std::size_t Count>
struct multi_iterator
{
struct iter_wrapper
{
IteratorType first_iter;
friend void swap(iter_wrapper a, iter_wrapper b)
{
for(std::size_t i = 0; i < Count; ++i)
{
using std::swap;
swap(*(a.first_iter + i), *(b.first_iter + i));
}
}
};
IteratorType first_iter;
explicit multi_iterator(const IteratorType& first_iter)
: first_iter(first_iter)
{}
iter_wrapper operator *() { return {first_iter}; }
multi_iterator operator +(std::ptrdiff_t n) const
{ return multi_iterator(first_iter + n * Count); }
multi_iterator operator -(std::ptrdiff_t n) const
{ return multi_iterator(first_iter - n * Count); }
std::ptrdiff_t operator -(const multi_iterator& other) const
{ return (first_iter - other.first_iter) / Count; }
multi_iterator& operator +=(std::ptrdiff_t n)
{
first_iter += n * Count;
return *this;
}
multi_iterator& operator -=(std::ptrdiff_t n)
{
first_iter -= n * Count;
return *this;
}
multi_iterator& operator ++()
{
first_iter += Count;
return *this;
}
multi_iterator& operator --()
{
first_iter -= Count;
return *this;
}
bool operator <(const multi_iterator& other) const
{ return first_iter < other.first_iter; }
bool operator >(const multi_iterator& other) const
{ return first_iter >= other.first_iter; }
bool operator >=(const multi_iterator& other) const
{ return first_iter >= other.first_iter; }
bool operator <=(const multi_iterator& other) const
{ return first_iter <= other.first_iter; }
bool operator ==(const multi_iterator& other) const
{ return first_iter == other.first_iter; }
bool operator !=(const multi_iterator& other) const
{ return first_iter != other.first_iter; }
};
namespace std
{
template<typename IteratorType, std::size_t Count>
struct iterator_traits<multi_iterator<IteratorType, Count>>
{
using value_type = typename multi_iterator<IteratorType, Count>::iter_wrapper;
using reference = typename multi_iterator<IteratorType, Count>::iter_wrapper&;
using pointer = typename multi_iterator<IteratorType, Count>::iter_wrapper*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
};
}
template<typename Type>
void print(const std::vector<Type>& v)
{
std::cout << "[";
for(std::size_t i = 0; i < v.size(); ++i)
{
if(i > 0) std::cout << ", ";
std::cout << v[i];
}
std::cout << "]n";
}
int main()
{
std::vector<int> values {7, 6, 2, 1, 5, 4, 10, 9};
std::cout << "before: ";
print(values);
using iter_type = multi_iterator<std::vector<int>::iterator, 2>;
std::sort(iter_type(values.begin()), iter_type(values.end()),
[](const iter_type::iter_wrapper& a, const iter_type::iter_wrapper& b)
{ return *a.first_iter < *b.first_iter; });
std::cout << "after: ";
print(values);
return 0;
}
结果
我已经用两种std::sort
实现测试了这段代码:fromlibc++
(clang的一个(和libstdc++
(gcc的一个(。
使用libc++
,此实现按预期工作。对于输入[7, 6, 2, 1, 5, 4, 10, 9]
,它输出[2, 1, 5, 4, 7, 6, 10, 9]
.
有了libstdc++
它不起作用。库似乎不尊重我们的自定义sort
重载 - 相反, 它尝试直接移动multi_iterator::operator *()
的结果。这会破坏实现,因为它需要自定义移动/交换实现。
摘要(目前(
我想演示如何使用std::sort
和自定义迭代器类型解决 OP 的问题。它是部分可用的(给定 正确实现sort
( - 这还不够:(
但是,我认为:
对其他人来说可能很有趣
更重要的是 - 也许有人有一些想法来改进这一点并使可行?也许我错过了什么?
我将尝试再次查看此内容,并在明天使用MSVC进行测试,届时我将有更多时间。如果有人在这种方法中穿会更新这篇文章。
- 将结构向量排序为子组
- C++数组与向量排序(在我的情况下,向量比数组慢~2.5倍(无优化))
- 如何在对向量排序后更改索引值?c++
- C++向量排序给出0作为输出
- 将许多向量排序在一起
- 根据一个向量对多个向量排序
- 编译错误向量排序和联合
- C++我自己的函数进行向量排序
- 将字符串的向量排序为日期"yyyymmdd"
- C++ 通过使用旧向量进行预排序来改进向量排序
- C 向量排序 .h .cpp中的单独文件
- 向量排序-c++
- 将向量排序到一个无序映射c++11中
- 向量的向量排序
- c++向量排序方法编译失败,返回预期表达式
- 如何对bitset向量排序
- 向量排序的基础上只有先
- 我如何以相同的方式对两个向量排序,而条件只使用其中一个向量
- 列表排序和结构体向量排序之间的性能差距.c++
- 如何基于第二个字符串对字符串向量的向量排序