Intersecting Lines
Suppose P = { ( p 1 , 1 ) , , ( p n , 1 ) } and Q = { ( q 1 , 0 ) , , ( q n , 0 ) } . Suppose that p , p P and q , q Q , then we say that ( p , q ) intersects with ( p , q ) when either of the following two situations arise
  • p [ 1 ] p [ 1 ] and q [ 2 ] > q [ 2 ]
  • p [ 1 ] p [ 1 ] and q [ 2 ] > p [ 2 ]

Motivation & Correctness

Firstly note that P can be sorted to P S . For any p P S , let us denote the element in Q that forms a line with p by l ( p ) , consider the tuple formed by l ( P S ) := ( l ( p α 1 ) , l ( p α 2 ) , , l ( p α n ) ) , let us denote this tuple as Q , this is done so that for any index α i we note that p α i forms a line with q α i for

We remark that if Q happened to be sorted then there would be no crossings, this follows by the definition of a crossing. The dual of this situation is when we have α i < α j being indices into P S wherein q α i > q α j , the lines ( p α i , q α i ) and ( p α j , q β j ) must cross, this holds true because P S was sorted, which means that if α i < α j then we have p α i < p α j .

Observe that in the above remark, we've noted that for every instance of α i < α j such that q α i > q α j , we get exactly one line crossing between the two lines being defined. Therefore we've reduced this problem to counting the number of inversions in Q .

Since we have an algorithm that we have proven correct as well as showing that it's time complexity is O ( n log 2 n ) , we are able to conclude that by passing Q to count_inversions we know that this extended algorithm correctly returns the number of inversions in Q .

We also observe that the number of line crossings between P S and Q is exactly equal to the number of line crossings between P and Q , this can be seen because even though the order in which the points are observed has changed, the actual points included in the two sets doesn't, therefore the realize the same situation, so counting crossings in one yields the same answer as counting crossings in the other.

Runtime

We've proven that our algorithm is correct, we now turn to the time analysis.

Therefore the total runtime is O ( n log 2 n )

Pseudocode

        def count_line_crossings(P, Q):
            l = line_map(P, Q)
            P_s = sort(P)
            Q_prime = map(l, P_s)

            return count_inversions(Q_prime)
    

Note that line map can be thought of as a function which takes a point in P and takes it to it's corresponding point in Q it is connected to.