保持坐标排序

时间:2019-09-21 15:24:35

标签: c++ algorithm sorting

我有一些坐标(x,y),我需要对这些坐标进行排序并保持其排序。在对它们进行排序之后,每个坐标从(x,y)更改为(x + 1,y)或(x-1,y)或(x,y-1)或(x,y + 1),因此坐标为不再排序。

除了每个坐标都以+ -1改变的条件之外,是否还有更好的方法来解决此问题,对坐标进行排序,对坐标进行更改,对坐标进行再次排序,对坐标进行更改,对坐标进行再次排序?

2 个答案:

答案 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;
}

Live example

免责声明:我尚未评估此解决方案的性能。由于每次元素更新都会发生改组,因此这可能比在所有更新之后对向量进行排序要慢。