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.