ALGO: fix runtime complexity in KDTree

The old code in fact increased the complexity to O(n^2), because
we applied 'elem' which is O(n) to every element of xs.

Instead we compare (in case of partitioning against Y) the y-value
of every element of xs with the y-value of the pivot which tells us
if x lies within ys.
This commit is contained in:
hasufell 2014-12-02 18:56:40 +01:00
parent a332f3f3c3
commit 899afc7287
No known key found for this signature in database
GPG Key ID: 220CD1C5BDEED020

View File

@ -69,15 +69,16 @@ kdTree xs' = go (sortedX xs') (sortedY xs')
-- partition' (pivot xs) (ys, xs) -- partition' (pivot xs) (ys, xs)
-- and get ((y1, y2), (x1, x2)). -- and get ((y1, y2), (x1, x2)).
partition' :: PT -- ^ the pivot to partition against partition' :: PT -- ^ the pivot to partition against
-> (PT -> PT -> Ordering) -- ^ ptCmpY or ptCmpX
-> ([PT], [PT]) -- ^ both lists (X, Y) or (Y, X) -> ([PT], [PT]) -- ^ both lists (X, Y) or (Y, X)
-> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) or -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) or
-- ((y1, y2), (x1, x2)) -- ((y1, y2), (x1, x2))
partition' piv (xs, ys) = ((x1, x2), (y1, y2)) partition' piv cmp' (xs, ys) = ((x1, x2), (y1, y2))
where where
y1 = takeWhile (/= piv) ys y1 = takeWhile (/= piv) ys
y2 = tailDef [] . dropWhile (/= piv) $ ys y2 = tailDef [] . dropWhile (/= piv) $ ys
x1 = foldr (\x y -> [x | x `elem` y1] ++ y) [] xs x1 = foldr (\x y -> [x | cmp' x piv == LT] ++ y) [] xs
x2 = foldr (\x y -> [x | x `elem` y2] ++ y) [] xs x2 = foldr (\x y -> [x | cmp' x piv == GT] ++ y) [] xs
-- |Partition two sorted lists of points X and Y against the pivot of -- |Partition two sorted lists of points X and Y against the pivot of
@ -85,7 +86,7 @@ partition' piv (xs, ys) = ((x1, x2), (y1, y2))
-- pivot. -- pivot.
partitionY :: ([PT], [PT]) -- ^ both lists (X, Y) partitionY :: ([PT], [PT]) -- ^ both lists (X, Y)
-> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2))
partitionY (xs, ys) = partition' (fromJust . pivot $ ys) (xs, ys) partitionY (xs, ys) = partition' (fromJust . pivot $ ys) ptCmpY (xs, ys)
-- |Partition two sorted lists of points X and Y against the pivot of -- |Partition two sorted lists of points X and Y against the pivot of
@ -94,7 +95,7 @@ partitionY (xs, ys) = partition' (fromJust . pivot $ ys) (xs, ys)
partitionX :: ([PT], [PT]) -- ^ both lists (X, Y) partitionX :: ([PT], [PT]) -- ^ both lists (X, Y)
-> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2))
partitionX (xs, ys) = (\(x, y) -> (y, x)) partitionX (xs, ys) = (\(x, y) -> (y, x))
. partition' (fromJust . pivot $ xs) $ (ys, xs) . partition' (fromJust . pivot $ xs) ptCmpX $ (ys, xs)
-- |Execute a range search in O(log n). It returns a tuple -- |Execute a range search in O(log n). It returns a tuple