📌  相关文章
📜  对距参考点的距离进行排序的点数组 |设置 2(使用极角)

📅  最后修改于: 2022-05-13 01:56:09.343000             🧑  作者: Mango

对距参考点的距离进行排序的点数组 |设置 2(使用极角)

给定一个数组arr[]包含N二维平面点和一个参考点P 0 (a 0 , b 0 ) ,任务是根据这些点与给定点P 0的距离对它们进行排序。

例子:

方法:解决这个问题的方法是借助极角

交叉产品

  • 叉积对于计算一个向量是否相对于另一个向量的方向是必要的。
  • 考虑任意两点 P 1和 P 2
  • 如果它们的叉积为正,则 P 1相对于原点顺时针旋转到 P 2
  • 如果叉积为负,则 P 1从 P 2逆时针方向。
  • 在上图中,
  • 如果叉积为 0,则 P A与 P B共线
  • 要确定线段 P 0 – P 1与线段 P 0 – P 2 是顺时针还是逆时针方向其中 P 0是它们的公共端点,请将点P 0平移为原点。
  • 如果叉积为正,则 P 0 -P 1顺时针到 P 0 -P 2 ,如果为负,则 P 0 -P 1逆时针到 P 0 -P 2 ,否则它们共线。

  • 在上图中,

叉积的缺点:

  • 任意两个向量之间的角度在 [0, π) 之间变化。因此,使用叉积,我们只能测量 [0, π) 之间的角度。因此,如果任何两点相对于任何参考点的极角差大于 π,我们将无法获得准确的方向。
  • 再次考虑下面给出的图表。如果我们比较 A 和 B 的极角,我们会发现 B 相对于原点 O(0, 0) 的极角比 A 大。但是,如果我们将点 A 和 B 转换为向量并找到它们的方向,我们会发现 A x B = -1,这意味着 A 相对于原点 O 的极角大于 B。这是错误的。这是因为矢量 P B = 315 o和 P A = 45 o的极角。有极角差=270 0大于π。这会导致结果不准确。

克服缺点

  • 在通过叉积比较任何点之前,比较它们的 y 坐标以检查它们是否都位于 x 轴的另一侧。如果我们这样做,那么 y 轴上方的点肯定有一个更小的极角。如果它们位于同一侧,则使用叉积进行比较。该技术可确保任意两点之间的极角差始终保持小于 π。

角落案例

  • 当两点共线时会出现极端情况。如果两个点都位于 y 轴的另一侧,则与任何其他点相比,第一象限中的点将具有较小的 0 o极角。
    • 注意:认为靠近参考点 P 0的点更小,即使它们具有相同的极角。

算法:以下方法使用归并排序算法从参考点P 0开始按照极角升序对N个点进行排序。

  • 使用归并排序,通过简单地比较它们的向量相对于参考点 P 0的方向,按极角对所有点进行排序。
  • 如果任何点 P A相对于参考点 P O与 P B处于逆时针方向,则 P A相对于 P B具有更大的极角。
  • 在我们的排序算法中使用归并排序过程。

插图:

下面是上述方法的实现:

Java
// Java code for the above approach:
  
import java.util.Arrays;
  
public class SortingPoints {
  
    // Encapsulates a 2D point
    public static class Point {
        int x;
        int y;
  
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
  
        @Override
        public String toString()
        {
            return "(" + x + ", " + y + ")";
        }
    }
  
    // Checks if directed line segment pi-pk
    // is clockwise or anti-clockwise to pi-pj
    private static int direction(
        Point pi, Point pj, Point pk)
    {
        return (pk.x - pi.x) * (pj.y - pi.y)
            - (pj.x - pi.x) * (pk.y - pi.y);
    }
  
    // Compares polar angle of two
    // points pk and pj with respect to pi.
    // In case all three points are
    // collinear, i.e. vector pi-pk
    // is collinear to vector pi-pj,
    // then it compares their
    // distance from the origin
    private static int compare(
        Point pi, Point pj, Point pk)
    {
  
        // if two points lie on opposite side
        // of x-axis, then simply return above
        // point as it has smaller polar angle
        if (pk.y - pi.y >= 0 && pj.y - pi.y < 0)
            return 1;
        if (pk.y - pi.y < 0 && pj.y - pi.y >= 0)
            return -1;
  
        // Check if both vectors are collinear
        if (direction(pi, pj, pk) == 0) {
  
            // Check if the vector lies on the y-axis
            if (pk.x - pi.x == 0 && pj.x - pi.x == 0) {
  
                // If vector lie on the y-axis
                // Then return -1, If vector pk-pi
                // has smaller magnitude
                // In comparison to pj-pi
                // Since vector with smaller
                // Magnitude has its end-point
                // Closer to the origin point p0
  
                if (Math.abs(pk.y - pi.y)
                    > Math.abs(pj.y - pi.y))
                    return -1;
                else
                    return 1;
            }
  
            // If vectors do not lie on the y-axis,
            // Then, either vector lie on the
            // x-axis or lie in the Same line.
  
            // Check if vectors lie on x-axis
            // and are on opposite side of y-axis
            // In such a case, return the vector
            // which lies on the positive x-axis
            // since it is in the first quadrant
            // and closer to origin
            if (pk.x - pi.x > 0
                && pj.x - pi.x < 0)
                return 1;
            else if (pk.x - pi.x < 0
                     && pj.x - pi.x > 0)
                return -1;
  
            // In other cases, return the point
            // closer to the reference point
            else if (Math.abs(pk.x - pi.x)
                     > Math.abs(pj.x - pi.x))
                return -1;
            else
                return 1;
        }
  
        // If vectors lie on same side
        // of y-axis and are not collinear,
        // Then compare them using Cross product
        if (direction(pi, pj, pk) > 0)
            return 1;
        else
            return -1;
    }
  
    // Merge two sorted subarray in
    // Sorted order in place in
    // The points array range of
    // First subarray: p-q range
    // Of second subarray: q + 1 - r
    private static void merge(
        Point[] points,
        int p, int q,
        int r, Point p0)
    {
        int n1 = q - p + 1;
        int n2 = r - q;
  
        Point[] L = new Point[n1];
        Point[] R = new Point[n2];
  
        for (int i = 0; i < n1; i++)
            L[i] = points[p + i];
        for (int j = 0; j < n2; j++)
            R[j] = points[q + 1 + j];
  
        int i = 0, j = 0;
  
        for (int k = p; k <= r; k++) {
            if (i == n1)
                points[k] = R[j++];
            else if (j == n2)
                points[k] = L[i++];
            else if (compare(p0, L[i], R[j]) < 0)
                points[k] = L[i++];
            else
                points[k] = R[j++];
        }
    }
  
    // Arranges the point in ascending
    // according to their polar angle
    public static void mergeSort(
        Point[] points, int p,
        int r, Point p0)
    {
        int q;
        if (p < r) {
            q = (p + r) / 2;
            mergeSort(points, p, q, p0);
            mergeSort(points, q + 1, r, p0);
            merge(points, p, q, r, p0);
        }
    }
  
    // Driver code
    public static void main(String[] args)
    {
        // EXAMPLE 1
        Point O = new Point(0, 0);
        Point[] points
            = { new Point(1, 0),
                new Point(0, -1),
                new Point(-1, 0),
                new Point(0, 1) };
  
        System.out.println(
            "Points: "
            + Arrays.toString(points));
        System.out.println();
  
        mergeSort(points, 0, 3, O);
        System.out.println(
            "After sorting with"
            + " reference point " + O);
        System.out.println(
            Arrays.toString(points));
        System.out.println();
  
        // EXAMPLE 2
        O = new Point(1, 1);
        mergeSort(points, 0, 3, O);
        System.out.println(
            "After sorting with"
            + " reference point " + O);
        System.out.println(
            Arrays.toString(points));
        System.out.println();
  
        // EXAMPLE 3
        points = new Point[] {
            new Point(-98, -65),
            new Point(-65, -60),
            new Point(65, -52),
            new Point(-10, -47),
            new Point(-7, -46),
            new Point(26, -89),
            new Point(72, -26),
            new Point(66, -52),
            new Point(69, 73),
            new Point(-64, 0)
        };
        O = new Point(0, 0);
  
        System.out.println(
            "Points: "
            + Arrays.toString(points));
        System.out.println();
  
        mergeSort(points, 0, 9, O);
        System.out.println(
            "After sorting with"
            + " reference point " + O);
        System.out.println(
            Arrays.toString(points));
    }
}


输出:

时间复杂度: O(N log N)
辅助空间: O(1)