qsort 在对 2D 点进行排序时未给出正确的结果
qsort not giving proper result while sorting 2D points
我正在尝试将 2d 空间中的点 w.r.t 排序到原点。这是代码:
double distSq(Point p1, Point p2)
{
return static_cast<double>((p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y));
}
int orientation(Point p, Point q, Point r)
{
double signedArea = double((q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y));
if (signedArea == 0) return 0; // colinear
return (signedArea > 0)? 1: 2; // clock or counterclock wise
}
int compare(const void *vp1, const void *vp2)
{
Point *p1 = (Point *)vp1;
Point *p2 = (Point *)vp2;
// Find orientation
int o = orientation(origin, *p1, *p2);
if (o == 0)
return (distSq(origin, *p2) >= distSq(origin, *p1))? -1 : 1;
return (o == 2)? -1: 1;
}
int main()
{
int n;
n = 10;
Point p[n];
int i,xx,yy;
srand(time(NULL));
p[0].set(1,1);
p[1].set(1,5);
p[5].set(5,4);
p[4].set(4,2);
p[3].set(2,1);
p[2].set(3,5);
p[6].set(2,3);
p[7].set(4,3);
p[8].set(3,4);
p[9].set(3,2);
cout << "nThe input points are n";
for(i=0;i<n;i++)
cout << p[i];
origin=findInterior(p,n);
cout << "nnThe origin is: " << origin << endl;
qsort(&p[0],n,sizeof(Point),compare);
cout << "nThe sorted points are: n";
for(i=0;i<n;i++)
cout << p[i];
cout << endl;
return 0;
}
findInterior()
函数查找为这些点形成的凸包内部的任何点。qsort
中的问题没有为某些原点(如 (2,2)
)给出正确的点排序顺序。例如:
origin(3.33333,3)
sorted order: (4,3)(5,4)(3,5)(3,4)(1,5)(2,3)(1,1)(2,1)(3,2)(4,2)
这是正确的。但对于
origin(2,2)
我得到
(3,2)(4,3)(5,4)(3,4)(2,3)(1,5)(1,1)(2,1)(4,2)(3,5)
这是不正确的。有许多这样的点会出现错误的排序顺序。Point 类(x,y)
数据类型double
。谁能告诉我为什么会出现此错误?
问题出在您的orientation
函数中。它不是传递的:如果a > b
并且b > c
则a
并不总是大于c
。这就是问题所在:如果你的比较函数不是传递的,你就不能有任何有意义的顺序。
不传递性证明:
#include <cassert>
struct Point
{
double x, y;
};
Point origin{0,0};
double distSq(Point p1, Point p2)
{ /* Skip */ }
int orientation(Point p, Point q, Point r)
{ /* Skip */ }
int compare(const void *vp1, const void *vp2)
{ /* Skip */ }
int main()
{
Point a {5, 0}, b{-5, -5}, c{-5, 5};
assert(compare(&a, &b) > 0 && "sanity assertion 1");
assert(compare(&b, &c) > 0 && "sanity assertion 2");
assert(compare(&a, &c) > 0 && "Transitivity violation");
}
断言失败!
表达式:比较(&a,&c)>0&&"传递性违规"
我认为你的第一个例子也是错误的。也许您需要像compare
或orientation
这样的函数来实现其他目的,但您不需要它们按与原点的距离对某些点进行排序。
除了您的compare
函数,仅当点是共线的时才计算距离,并且orientation
由于浮点近似,直线if (signedArea == 0) ...
容易出现舍入误差。
与给定点的距离对多个点进行排序,您可以使用如下内容:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <iomanip>
using std::cout;
using std::vector;
using std::pair;
struct Point {
double x, y;
void set( double xx, double yy ) {
x = xx;
y = yy;
}
friend std::ostream &operator<<( std::ostream &o, const Point &p );
};
std::ostream &operator<<( std::ostream & o, const Point &p ) {
return o << '(' << p.x << ',' << p.y << ')';
}
double distSq( const Point &p1, const Point &p2) {
return (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);
}
// sort the vector of points by distance from a point
void sort_points( vector<Point> &vp, Point &o ) {
// create a temp vector of pairs to store distances (calculated once)
vector<pair<double,const Point*>> dist_pts;
for ( auto && i : vp ) {
dist_pts.push_back(std::make_pair(distSq(o,i),&i));
}
// sort pairs using a lambda
std::sort(dist_pts.begin(),dist_pts.end(),
[]( pair<double,const Point*> &a, pair<double,const Point*> &b) -> bool {
return a.first < b.first;
});
// reorder the original vector
vector<Point> temp(vp.size());
for ( auto && i : dist_pts ) {
temp.push_back(*i.second);
// show the ordered points and distance, only for testing
cout << *i.second << ' ' << std::setprecision(6) << sqrt(i.first) << 'n';
}
}
int main()
{
vector<Point> points{ {1,1}, {1,5}, {5,4}, {4,2}, {2,1},
{3,5}, {2,3}, {4,3}, {3,4}, {3,2} };
Point origin{3.3333,3};
cout << "Origin: " << origin << 'n';
sort_points(points,origin);
origin.set(2,2);
cout << "nOrigin: " << origin << 'n';
sort_points(points,origin);
}
排序点的顺序变为:
Origin: (3.3333,3)
(4,3) 0.6667
(3,4) 1.05408
(3,2) 1.05408
(4,2) 1.20187
(2,3) 1.3333
(5,4) 1.94368
(3,5) 2.02758
(2,1) 2.40368
(1,1) 3.07316
(1,5) 3.07316
Origin: (2,2)
(2,1) 1
(2,3) 1
(3,2) 1
(1,1) 1.41421
(4,2) 2
(4,3) 2.23607
(3,4) 2.23607
(1,5) 3.16228
(3,5) 3.16228
(5,4) 3.60555
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- valgrind-hellgrind与泄漏检查的结果不同
- 2D数组来自文本输入,中间有空格
- 将值指定给向量(2D)的向量中的某个位置
- 用C++20 fmt限制结果的总大小
- 如何返回一个类的两个对象相加的结果
- 如何使用用户输入在C++中正确填充2D数组
- 如何在C++中检查2D数组中负值的输入验证
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 序列化,没有库的整数,得到奇怪的结果
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 如何从2D数组为QHeightMapSurfaceDataProxy创建高度图以显示2D傅立叶变换结果
- 在2D数组C 上的标签得出了错误的结果
- OpenGl 2d 纹理重复(不同设备上的结果不同)
- 2D FFT后的图像结果错误
- 2D 矢量排序不需要的结果
- qsort 在对 2D 点进行排序时未给出正确的结果
- CUDA: 2D数组索引产生意想不到的结果