我有一些坐标(x,y),我需要对这些坐标进行排序并保持其排序。在对它们进行排序之后,每个坐标从(x,y)更改为(x + 1,y)或(x-1,y)或(x,y-1)或(x,y + 1),因此坐标为不再排序。
除了每个坐标都以+ -1改变的条件之外,是否还有更好的方法来解决此问题,对坐标进行排序,对坐标进行更改,对坐标进行再次排序,对坐标进行更改,对坐标进行再次排序?
答案 0 :(得分:1)
std::set
将为您处理所有这一切。特别是,内容本质上是由set成员的operator<
函数排序的,因此,当您插入新项目时,您无需自己进行任何排序。插入的复杂度为O(log(N))。
对于正确地对坐标进行排序,您可以像这样使用std::pair
定义operator<
的事实:
If lhs.first<rhs.first, returns true. Otherwise, if rhs.first<lhs.first, returns false. Otherwise, if lhs.second<rhs.second, returns true. Otherwise, returns false.
这就是你想要的。
总而言之,您可以执行以下操作:
#include <utility>
#include <set>
using coordinate = std::pair<int, int>;
std::set<coordinate> stored_coordinates;
其中std::pair
中代表coordinate
的第一个成员是x
,第二个成员是y
。
最后,如果要将数据项与每个坐标关联,请改用map
,并以std::pair
作为键。
答案 1 :(得分:1)
在更新坐标时,可以通过将坐标移动到更新后的正确位置来保持排序顺序。
如果您正在做(x+1, y)
或(x, y+1)
,则坐标将在向量中其当前位置之前的某个位置。如果您正在做(x-1, y)
或(x, y-1)
,则坐标将在向量中其当前位置的后面。
(如果坐标相对于向量中的其他元素仍然正确,也有可能不需要更改位置。)
使用此选项,您可以在向前(或向后)搜索需要更新坐标的位置。搜索时,您可以向后(或向前)复制元素,以缩小当前元素留下的空白。
| a | b | c | d |
| {1,1} | {1,2} | {2,0} | {2,2} |
在上面的示例中,请考虑将c
更新为{1,0}
。我们向后移动,检查c < b
是正确的,因此我们向前b
随机播放:
| a | | b | d |
| {1,1} | | {1,2} | {2,2} |
我们再次向后移动,检查c < a
,这也是正确的,因此我们向前a
随机播放。
| | a | b | d |
| | {1,1} | {1,2} | {2,2} |
这时我们已经到达向量的开头,因此我们知道c
必须位于这个位置。
| c | a | b | d |
| {1,0} | {1,1} | {1,2} | {2,2} |
另一种极端情况是c
不小于您要检查的元素。
这与向前的方向类似。
一些代码可以证明这个想法:
#include <algorithm>
#include <ctime>
#include <iostream>
#include <random>
#include <vector>
struct Point {
int x;
int y;
void Adjust(int i) {
switch (i) {
case 0: x++; return;
case 1: y++; return;
case 2: x--; return;
case 3: y--; return;
}
}
bool operator<(const Point & rhs) {
if (x == rhs.x)
return y < rhs.y;
return x < rhs.x;
}
bool operator>(const Point & rhs) {
if (x == rhs.x)
return y > rhs.y;
return x > rhs.x;
}
};
int main() {
std::vector<Point> points;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j)
points.push_back({i,j});
}
std::sort(std::begin(points), std::end(points));
std::default_random_engine rng{std::time(nullptr)};
std::uniform_int_distribution<int> distrib{0, 3};
for (int i = 0; i < 10000; ++i) {
for (auto iter = std::begin(points); iter != std::end(points); ++iter) {
auto p = *iter;
int adjustment = distrib(rng);
p.Adjust(adjustment);
auto current = iter;
if (adjustment < 2) {
auto next = std::next(current);
while (next != std::end(points) && p > *next) {
*current = *next;
current = next;
next = std::next(current);
}
*current = p;
}
else if (current != std::begin(points)) {
auto prev = std::prev(current);
while (p < *prev) {
*current = *prev;
current = prev;
if (current != std::begin(points))
prev = std::prev(current);
else
break;
}
*current = p;
}
}
}
for (auto && p : points)
std::cout << "{" << p.x << "," << p.y << "}\n";
std::cout << "is_sorted = "
<< std::is_sorted(std::begin(points), std::end(points))
<< std::endl;
return 0;
}
免责声明:我尚未评估此解决方案的性能。由于每次元素更新都会发生改组,因此这可能比在所有更新之后对向量进行排序要慢。