在两个范围内按降序对向量进行排序
Sorting a vector in descending order within two ranges
假设我有一个整数向量:
std::vector<int> indices;
for (int i=0; i<15; i++) indices.push_back(i);
那我按降序排列:
sort(indices.begin(), indices.end(), [](int first, int second) -> bool{return indices[first] > indices[second];})
for (int i=0; i<15; i++) printf("%i\n", indices[i]);
这会产生以下结果:
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
现在想把3、4、5、6移到最后,并保持降序排列(最好不用第二次用sort
) .即,这就是我想要的:
14
13
12
11
10
9
8
7
2
1
0
6
5
4
3
我应该如何修改std::sort
的比较函数来实现?
您的比较函数是错误的,因为您作为 first
和 second
获得的值是 std::vector
的元素。因此,没有必要将它们用作索引。所以,你需要改变
return indices[first] > indices[second];
至
return first > second;
现在,关于您要解决的问题...
你可以将 3、4、5 和 6 不与其他元素进行比较,但仍将其相互比较:
std::sort(
indices.begin(), indices.end(),
[](int first, int second) -> bool {
bool first_special = first >= 3 && first <= 6;
bool second_special = second >= 3 && second <= 6;
if (first_special != second_special)
return second_special;
else
return first > second;
}
);
来自 standard algorithms library 的函数,例如 iota
、sort
、find
、rotate
和 copy
将使您的生活更轻松。您的示例归结为:
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> indices(15);
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(), std::greater<>());
auto a = std::find(indices.begin(), indices.end(), 6);
auto b = std::find(indices.begin(), indices.end(), 3);
std::rotate(a, b + 1, indices.end());
std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
输出:
14
13
12
11
10
9
8
7
2
1
0
6
5
4
3
评论中的@TedLyngmo 提出了 could/should 改进的要点:
auto a = std::lower_bound(indices.begin(), indices.end(), 6, std::greater<int>{});
auto b = a + 4;
解决方案 1
使用非线性比较器的直接方法。
inline constexpr bool SpecialNumber(const int n) noexcept {
return n < 7 && 2 < n;
}
void StrangeSortSol1(std::vector<int>* v) {
std::sort(v->begin(), v->end(), [](const int a, const int b) noexcept {
const bool aSpecial = SpecialNumber(a);
const bool bSpecial = SpecialNumber(b);
if (aSpecial && bSpecial) return b < a;
if (aSpecial) return false;
if (bSpecial) return true;
return b < a;
});
}
解决方案 2
使用std::algorithm
s(分区)!
inline constexpr bool SpecialNumber(const int n) noexcept {
return n < 7 && 2 < n;
}
void StrangeSortSol2(std::vector<int>* v) {
auto pivot = std::partition(v->begin(), v->end(), std::not_fn(SpecialNumber));
std::sort(v->begin(), pivot, std::greater{});
std::sort(pivot, v->end(), std::greater{});
}
性能注意事项
由于分区的开销,第二个解决方案可能看起来更慢。可能不是,因为现代处理器中的缓存和未命中分支预测。
假设我有一个整数向量:
std::vector<int> indices;
for (int i=0; i<15; i++) indices.push_back(i);
那我按降序排列:
sort(indices.begin(), indices.end(), [](int first, int second) -> bool{return indices[first] > indices[second];})
for (int i=0; i<15; i++) printf("%i\n", indices[i]);
这会产生以下结果:
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
现在想把3、4、5、6移到最后,并保持降序排列(最好不用第二次用sort
) .即,这就是我想要的:
14
13
12
11
10
9
8
7
2
1
0
6
5
4
3
我应该如何修改std::sort
的比较函数来实现?
您的比较函数是错误的,因为您作为 first
和 second
获得的值是 std::vector
的元素。因此,没有必要将它们用作索引。所以,你需要改变
return indices[first] > indices[second];
至
return first > second;
现在,关于您要解决的问题...
你可以将 3、4、5 和 6 不与其他元素进行比较,但仍将其相互比较:
std::sort(
indices.begin(), indices.end(),
[](int first, int second) -> bool {
bool first_special = first >= 3 && first <= 6;
bool second_special = second >= 3 && second <= 6;
if (first_special != second_special)
return second_special;
else
return first > second;
}
);
来自 standard algorithms library 的函数,例如 iota
、sort
、find
、rotate
和 copy
将使您的生活更轻松。您的示例归结为:
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> indices(15);
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(), std::greater<>());
auto a = std::find(indices.begin(), indices.end(), 6);
auto b = std::find(indices.begin(), indices.end(), 3);
std::rotate(a, b + 1, indices.end());
std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
输出:
14
13
12
11
10
9
8
7
2
1
0
6
5
4
3
评论中的@TedLyngmo 提出了 could/should 改进的要点:
auto a = std::lower_bound(indices.begin(), indices.end(), 6, std::greater<int>{});
auto b = a + 4;
解决方案 1
使用非线性比较器的直接方法。
inline constexpr bool SpecialNumber(const int n) noexcept {
return n < 7 && 2 < n;
}
void StrangeSortSol1(std::vector<int>* v) {
std::sort(v->begin(), v->end(), [](const int a, const int b) noexcept {
const bool aSpecial = SpecialNumber(a);
const bool bSpecial = SpecialNumber(b);
if (aSpecial && bSpecial) return b < a;
if (aSpecial) return false;
if (bSpecial) return true;
return b < a;
});
}
解决方案 2
使用std::algorithm
s(分区)!
inline constexpr bool SpecialNumber(const int n) noexcept {
return n < 7 && 2 < n;
}
void StrangeSortSol2(std::vector<int>* v) {
auto pivot = std::partition(v->begin(), v->end(), std::not_fn(SpecialNumber));
std::sort(v->begin(), pivot, std::greater{});
std::sort(pivot, v->end(), std::greater{});
}
性能注意事项
由于分区的开销,第二个解决方案可能看起来更慢。可能不是,因为现代处理器中的缓存和未命中分支预测。