在两个范围内以降序对向量排序


14

假设我有一个整数向量:

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以实现这一目标?


4
return indices[first] > indices[second]不是return first < second;
acraig5075

2
对于简单的降序排序,可以使用std::greaterfrom <functional>代替lambda。关于您的问题,编写一个更详细的比较器以确保您的值比较所需的方式可能是最简单的方法。
sweenish

4
@ acraig5075,按降序应为return first > second
ks1322

1
@ acraig5075我觉得我缺少了什么,还是人们不知道上升下降之间的区别?
sweenish

3
也许您正在寻找std :: rotate吗?
超级

Answers:


8

您的比较函数是错误的,因为您获得的值是firstsecond的元素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;
    }
);

演示版


@NutCracker是的,我同意最好先拥有最高标准。
堆溢出

5

从功能标准算法库一样iotasortfindrotatecopy会使你的生活更轻松。您的示例可归结为:

#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指出了可以/应该通过以下方法改进的好处:

auto a = std::lower_bound(indices.begin(), indices.end(), 6, std::greater<int>{});
auto b = a + 4;

auto b = a + 4;是错误的(如果您想与之前的代码段保持一致)。这应该是auto b = a + 3;因为std::rotate您在使用b + 1
Biagio Festa

3

解决方案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::algorithms(分区)!

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{});
}

性能考量

由于分区的开销,第二种解决方案似乎较慢。可能不是因为现代处理器中的缓存和分支错误预测。

基准测试


任何好的编译器都应将其转换n <= 6 && 3 <= n 为最适合目标CPU的方式,以便通过引入数字2和7而不带来任何潜在混淆,从而使您一无所获-为何采用指向矢量的指针而不是引用?
Ted Lyngmo

不要使用`const int number`作为参数函数
Antoine Morrier

1
@AntoineMorrier为什么?
堆溢出

@HeapOverflow因为不使用const :)是相同的。
Antoine Morrier

@AntoineMorrier我认为不一样。难道不const告诉读者函数没有改变值吗?在这种单缸的情况下,可能很清楚,但总的来说不是。
堆溢出
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.