我试图从一组点(一个点有x和y坐标)中找到点(名为A,B和C,D)。 A和B是最左边的点,C和D是点集中最右边的点。
此外,A和B是具有相同x-坐标但B具有比A更大的y-坐标的点。 C和D是具有相同x-坐标但D具有比C更大的y-坐标的点。
这是for循环。
// pointSeq is a vector of points
// A,B,C and D are set to pointSeq[0]
for(int i = 1 ; i < pointSeq.size(); i++)
{
if (pointSeq[i].x <= A.x)
{
if(pointSeq[i].x < A.x)
{
A = pointSeq[i]; B = pointSeq[i];
}
else
{
if(pointSeq[i].y > B.y)
{
B = pointSeq[i];
}
else if(pointSeq[i].y < A.y)
{
A = pointSeq[i];
}
}
}
// from here it is to find the C and D
else if (pointSeq[i].x >= C.x)
{
if(pointSeq[i].x > C.x)
{
C = pointSeq[i], D = pointSeq[i];
}
else
{
if (pointSeq[i].y > D.y)
{
D = pointSeq[i];
}
else if (pointSeq[i].y < C.y)
{
C = pointSeq[i];
}
}
}
}
这两个部分是非常相似的过程,所以我想知道我是否可以缩短代码以使其更简单。
我想让问题变得简单。它找到位于每个x-min和x-max位置的四个点。 我可以添加更多的线来找到关于y坐标的点(即,y-min和y max的四个点,在这种情况下x坐标是不同的)。
谢谢。
答案 0 :(得分:1)
我认为简化你在这里做的一种方法是考虑定义一种比较点的方法。给定两个点(x 1 ,y 1 )和(x 2 ,y 2 ),考虑词典比较这些点,可以通过这个功能完成:
bool lexCompare(Point lhs, Point rhs) {
return (lhs.x < rhs.x) || (lhs.x == rhs.x && lhs.y < rhs.y);
}
此比较首先查看两点的x坐标。如果它们不同,它会纯粹使用x坐标将点相互排列。否则,如果x坐标相同,则比较会查看y坐标以断开关系。
您正在考虑获取最左边的两个点和最右边的两个点,具体来说,抓住最低y坐标的两个最左边的点和最高y坐标的两个最右边的点。如果你考虑一下,你在这里做的事实上是要求A和B是集合中两个按字典顺序排列的最小点,而C和D则是集合中两个按字典顺序排列的最大点。这样,A具有所有点的最低x坐标,并且对于具有最低x坐标的x的可能选择,具有最低可能的y坐标。然后D具有尽可能高的x坐标,并且在可用选项中,选择具有最高y坐标的那个。
好消息是标准库有大量可用于查找这些值的函数。例如,如果你想要一些简单易用的东西,你可以根据这个指标对点进行排序:
std::sort(pointSeq.begin(), pointSeq.end(),
[](const Point& lhs, const Point& rhs) {
return (lhs.x < rhs.x) || (lhs.x == rhs.x && lhs.y < rhs.y);
});
Point A = pointSeq[0];
Point B = pointSeq[1];
Point C = pointSeq[pointSeq.size() - 2];
Point D = pointSeq[pointSeq.size() - 1];
这在时间O(n log n)中运行,这比你上面的要慢,但是更加紧凑。
另一种选择是使用std::minmax_element
来找到最小和最大点(分别为A和D),然后将这些元素拉出来并再做一次std::minmax_element
来找到B和C:
auto comparator = [](const Point& lhs, const Point& rhs) {
return (lhs.x < rhs.x) || (lhs.x == rhs.x && lhs.y < rhs.y);
};
auto aAndD = std::minmax_element(pointSeq.begin(), pointSeq.end(), comparator);
Point A = *aAndD.first;
Point D = *aAndD.second;
/* Move A and D to the end of the sequence. */
if (aAndD.first > aAndD.second) std::swap(aAndD.first, std::aAndD.second);
std::iter_swap(aAndD.second, pointSeq.end() - 1);
std::iter_swap(aAndD.first, pointSeq.end() - 2);
/* Get B and C. */
auto bAndC = std::minmax_element(pointSeq.begin(), pointSeq.end() - 2);
Point B = *bAndC.first;
Point C = *bAndC.second;
此代码在时间O(n)中运行,并且更紧凑地传达了您尝试做的事情。
或者使用std::nth_element
重新排序元素,将前两个和后两个元素放在正确的位置:
auto comparator = [](const Point& lhs, const Point& rhs) {
return (lhs.x < rhs.x) || (lhs.x == rhs.x && lhs.y < rhs.y);
};
std::nth_element(pointSeq.begin(), pointSeq.begin() + 1, pointSeq.end(), comparator);
std::nth_element(pointSeq.begin() + 2, pointSeq.end() - 2, pointSeq.end(), comparator);
/* Sort the two-element ranges at the beginning and end. */
if (comparator(pointSeq[0], pointSet[1])) {
std::swap(pointSeq[0], pointSeq[1]);
}
if (comparator(pointSeq[pointSeq.size() - 2], pointSeq[pointSeq.size() - 1]) {
std::swap(pointSeq[pointSeq.size() - 2], pointSeq[pointSeq.size() - 1]);
}
Point A = pointSeq[0];
Point B = pointSeq[1];
Point C = pointSeq[pointSeq.size() - 2];
Point D = pointSeq[pointSeq.size() - 1];