C++ 按索引对向量进行排序
Posted
技术标签:
【中文标题】C++ 按索引对向量进行排序【英文标题】:C++ Sort vector by index 【发布时间】:2021-03-07 17:20:33 【问题描述】:我需要按索引对 std::vector 进行排序。让我用一个例子来解释一下:
假设我有一个包含 12 个位置(但可以是 18 个)的 std::vector,其中填充了一些值(不必排序):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3
我想每 3 个索引对其进行排序。这意味着:前 3 个 [0-2] 留下,然后我需要有 [6-8],然后是其他人。所以最终会是这样(新索引 3 的值是之前的 idx 6):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 1 2 2 3 2 0 4 5 3
我正在尝试使用 std::sort + lambda 在一行中完成它,但我无法得到它。还发现了std::partition()函数并尝试使用,结果真的很糟糕嘿嘿
还发现了这个类似的问题,它按奇数和偶数索引排序,但不知道如何在我的情况下或即使有可能:Sort vector by even and odd index
非常感谢!
注意 0:不,我的向量并不总是排序的。这只是一个例子。我已经更改了值
注 1:我知道这听起来很奇怪......认为它就像 hte vecotr 位置一样:是 是 是 不 不 不 是 是 是 不 不 不 是 是 是...所以“是”的位置会出现相同的顺序,但在“否”位置之前
注意 2:如果 lambda 没有办法,那么我想用循环和辅助变量来制作它,但我认为它更难看。
注3:另一个例子:
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3 2 3 0 0 2 1
Sorted Values: 3 0 2 1 2 2 2 3 0 3 2 0 4 5 3 0 2 1
最终的向量值被排序(根据旧索引):0 1 2 6 7 8 12 13 14 3 4 5 9 10 11 15 16 17
您可以将这些索引想象成 2 列,所以我想要第一个左侧的,然后是右侧的:
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
【问题讨论】:
我不明白你到底想做什么。结果向量似乎没有以任何方式排序。您是否想根据索引移动元素? 你检查过这个话题吗? ***.com/questions/1577475/… @AlirezaAbbasi 是的,也找到了,但他们再次使用元素进行排序,而不是索引......我真正需要的是对索引进行排序。但是非常感谢您提供的信息:) @cigien 是的,我知道这有点棘手。索引将被排序为:是的,是的,没有的,没有的,是的,是的,没有的,没有的,所以“是”将比“否”的索引排在前面。也许现在更清楚了? 你的原始向量总是排序的吗?如果是这样,提供的答案解决了问题,但如果原始向量没有排序,它将不起作用。你能澄清一下这个问题吗? 【参考方案1】:你不想要std::sort
,你想要std::rotate
。
std::vector<int> v = 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31;
auto b = std::next(std::begin(v), 3); // skip first three elements
auto const re = std::end(v); // keep track of the actual end
auto e = std::next(b, 6); // the end of our current block
while(e < re)
auto mid = std::next(b, 3);
std::rotate(b, mid, e);
b = e;
std::advance(e, 6);
// print the results
std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, " "));
此代码假定您始终为每次旋转执行两组 3 个,但您显然可以使用您想要的任意范围。
输出看起来像你想要的:
20 21 22 26 27 28 23 24 25 29 30 31
更新:@Blastfurnace 指出std::swap_ranges
也可以。 rotate
调用可以替换为以下行:
std::swap_ranges(b, mid, mid); // passing mid twice on purpose
【讨论】:
很好的答案。我完全误解了这个问题。 如果两个部分的大小相同,那么std::swap_ranges
可能是更好的选择。它通常也比std::rotate
快。
非常感谢您的回答,但正如其他人指出的那样,这只有在对向量进行排序时才有效,而在我的情况下,它可能不是。这是一个例子,但令人困惑。对不起。刚刚添加了有关问题的信息
@Blastfurnace - 我不知道std::swap_ranges
,所以谢谢。我会更新答案。
@Megasa3 - 通过用新值替换原始值,该算法仍然提供与您想要的相同的输出。排序在哪里发挥作用?【参考方案2】:
使用 range-v3 库,你可以很方便地编写它,而且它的可读性很强。假设您的原始向量称为input
:
namespace rs = ranges;
namespace rv = ranges::views;
// input [3, 0, 2, 3, 2, 0, 1, 2, 2, 4, 5, 3, 2, 3, 0, 0, 2, 1]
auto by_3s = input | rv::chunk(3); // [[3, 0, 2], [3, 2, 0], [1, 2, 2], [4, 5, 3], [2, 3, 0], [0, 2, 1]]
auto result = rv::concat(by_3s | rv::stride(2), // [[3, 0, 2], [1, 2, 2], [2, 3, 0]]
by_3s | rv::drop(1) | rv::stride(2)) // [[3, 2, 0], [4, 5, 3], [0, 2, 1]]
| rv::join
| rs::to<std::vector<int>>; // [3, 0, 2, 1, 2, 2, 2, 3, 0, 3, 2, 0, 4, 5, 3, 0, 2, 1]
这是demo。
【讨论】:
哦,我怕我不能使用外部库,但我什至不知道它似乎太酷了!正如你所说,它非常具有可读性。非常感谢。以上是关于C++ 按索引对向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章