简体   繁体   中英

What's the most efficient way to sort an array with a single series of inversions?

I have a list of integers that has already been sorted in a descending order, but a function that takes the value of the first element (let's call that x ) and maps subtract 1 to x values of the rest of the list (excluding the first element) is applied. (I am trying to implement the recursive algorithm to check for a graphic sequence .)

list1 = [4,4,3,2,2,2,2,1] --an example of a nonincreasing list
newList = (/s -> map (subtract 1) (fst s) ++ snd s) $ splitAt (head list1) (tail list1)
                       --newList == [3,2,1,1,2,2,1]
--only these four need to be swapped     | | | |             
sortedList = sortFunction newList --[3,2,2,2,1,1,1]

The new list needs to be sorted again in a descending order for the next step of recursion. I've tried using Data.List.sort , but this becomes fairly slow for large lists, as it is applied for every level of recursion.

The nature of mapping subtract 1 to the beginning of a list of nonincreasing integers means that there is really only one spot at where there is an inversion: for example, in the previous code, the first two 1 's only need to be exchanged with the next two 2 's in order to sort the list.

What's the most efficient (ie fastest) way to do this sorting? Also, is there a more efficient data structure to use instead of lists for this job?

You might be better off doing run-length encoding. Then you don't have to dig very far to keep the list sorted.

(WARNING: untested Haskell code.) A function

rlEncode xs = [(length xs', head xs') | xs' <- reverse $ group $ sort xs]

turns [4,4,3,2,2,2,2,1] into [(2,4),(1,3),(4,2),(1,1)] . Then we can write a "constructor"

rlCons (n, x) [] = [(n, x)]
rlCons (n, x) rle@((n', x') : rle')
    | x == x' = (n + n', x) : rle'
    | otherwise = (n, x) : rle

and a "destructor"

rlUncons [] = Nothing
rlUncons ((1, x) : rle) = Just (x, rle)
rlUncons ((n, x) : rle) = Just (x, (n - 1, x) : rle)

for run-length encoded lists. Then isGraphic , in its simplest and least efficient form, looks like this.

isGraphic [] = True
isGraphic rle = fromMaybe False $ do
    (d, rle') <- rlUncons rle
    rle'' <- deflate d rle'
    return $ isGraphic rle''

deflate 0 rle = Just rle
deflate _d [] = Nothing
deflate _d [(_,0)] = Nothing
deflate d ((n, d') : rle)
    | d < n = Just $ rlCons (n - d, d') $ rlCons (d, d' - 1) rle
    | otherwise = liftM (rlCons (n, d' - 1)) $ deflate (d - n) rle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM