[英]Sort algorithm for list of integers in Haskell with recursion
我需要在 haskell 上對一個整數列表進行排序,從小到大,但我不知道從哪里開始。
遞歸語法對我來說有點困難
一點點幫助會很棒。
我已經這樣做了,但它並沒有解決我的問題:
ordenarMemoria :: [Int] -> [Int]
ordenarMemoria [] = []
ordenarMemoria (x:y:xs)
| y > x = ordenarMemoria (y:xs)
| otherwise = ordenarMemoria (x:xs)
謝謝
您嘗試在正確的軌道上進行冒泡排序,這是排序的良好起點。 一些注意事項:
您處理列表為空或至少有兩個元素( x
和y
)的情況,但您忘記了列表只有一個元素時的情況。 您總是會遇到這種情況,因為您是在較小的列表上遞歸調用您的函數。
ordenarMemoria [x] = -- how do you sort a 1-element list?
第二個注意事項:在這個模式中
ordenarMemoria (x:y:xs)
| y > x = ordenarMemoria (y:xs)
| otherwise = ordenarMemoria (x:xs)
您正在對以兩個元素x
和y
開頭的列表進行排序。 您將x
與y
進行比較,然后在刪除兩個元素之一后對列表的其余部分進行排序。 這一切都很好。
我的問題是:另一個元素發生了什么? 排序列表必須具有與輸入相同的所有元素,因此您應該在輸出中同時使用x
和y
。 所以在:
| y > x = ordenarMemoria (y:xs)
你已經忘記了x
。 考慮
| y > x = x : ordenarMemoria (y:xs)
這表明輸出x
,然后是排序的余數。
另一個分支也忘記了其中一個輸入。
修復該函數后,您可能會注意到列表的排序變得更加有序,但仍然沒有完全排序。 這是冒泡排序的一個特性——您可能需要多次運行它。
我需要對整數列表進行排序
如何從Data.List
sort
?
$ stack ghci
Prelude> :m + Data.List
Prelude Data.List> sort [2,3,1]
[1,2,3]
有很多選擇。 我通常建議從 Haskell 中的自底向上歸並排序開始,但堆排序也不是一個糟糕的選擇。 快速排序帶來了更嚴重的困難。
-- Given two lists, each of which is in increasing
-- order, produce a list in increasing order.
--
-- merge [1,4,5] [2,4,7] = [1,2,4,4,5,7]
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ???
merge xs [] = ???
merge (x : xs) (y : ys)
| x <= y = ???
| otherwise = ???
-- Turn a list of elements into a list of lists
-- of elements, each of which has only one element.
--
-- splatter [1,2,3] = [[1], [2], [3]]
splatter :: [a] -> [[a]]
splatter = map ????
-- Given a list of sorted lists, merge the adjacent pairs of lists.
-- mergePairs [[1,3],[2,4],[0,8],[1,2],[5,7]]
-- = [[1,2,3,4],[0,1,2,8],[5,7]]
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs [] = ????
mergePairs [as] = ????
mergePairs (as : bs : more) = ????
-- Given a list of lists of sorted lists, merge them all
-- together into one list.
--
-- mergeToOne [[1,4],[2,3]] = [1,2,3,4]
mergeToOne :: Ord a => [[a]] -> [a]
mergeToOne [] = ???
mergeToOne [as] = ???
mergeToOne lots = ??? -- use mergePairs here
mergeSort :: Ord a => [a] -> [a]
mergeSort as = ???? -- Use splatter and mergeToOne
一旦你填補了上面的空白,嘗試通過使splatter
產生兩個或三個元素的排序列表而不是單例來優化排序。
這是經過修改的快速排序或插入排序。 它使用最快的方法為輸出列表添加前綴或后綴值。 如果下一個值小於或大於列表的第一個或最后一個,則將其簡單地附加到列表的開頭或結尾。 如果該值不小於head
值或大於last
值,則必須插入它。 插入與上面所謂的快速排序是相同的邏輯。
現在,踢球者。 此函數作為foldr
函數運行只是為了降低函數的復雜性。 它可以很容易地轉換為遞歸函數,但它與foldr
一起運行良好。
f2x :: (Ord a) => a -> [a] -> [a]
f2x n ls
| null ls = [n]
| ( n <= (head ls) ) = n:ls -- ++[11]
| ( n >= (last ls) ) = ls ++ [n] -- ++ [22]
| True = [lx|lx <-ls,n > lx]++ n:[lx|lx <-ls,n < lx]
可以刪除兩行之后的注釋,並且可以使用scanr
運行該函數以查看有多少命中具有簡單的前綴或后綴值,以及插入到第一個或最后一個值以外的其他位置。
foldr f2x [] [5,4,3,2,1,0,9,8,7,6]
或者af = foldr a2x []
... af [5,4,3,2,1,0,9,8,7,6]
>-> [0,1,2,3,4,5,6, 7,8,9]
編輯 5/18/2018
Stack Overflow最棒的地方是像 @dfeuer 這樣讓你思考的人。 @dfeuer 建議使用partition
。 我像個孩子,不知道怎么辦。 我表達了我在partition
困難,但 @dfeuer 強迫我了解如何使用它。 @dfeuer 還指出,在上述函數中使用last
是一種浪費。 我也不知道。
以下函數使用從Data.List
導入的partition
。 partition
輸出一個元組對。 此函數也適用於foldr
。 它是一個完整的插入排序功能。
ft nv ls = b++[nv]++e where (b,e) = partition (<=nv) ls
像上面一樣使用它
foldr ft [] [5,4,3,2,1,0,9,8,7,6]
Haskell 和函數式編程都是關於在其他函數中使用現有函數。
putEleInSortedListA :: Ord a => a -> [a] -> [a]
putEleInSortedListA a [] = [a]
putEleInSortedListA a (b:bs)
| a < b = a : b : bs
| otherwise = b: putEleInSortedListA a bs
sortListA :: Ord a => [a] -> [a]
sortListA la = foldr (\a b -> putEleInSortedListA a b) [] la
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.