簡體   English   中英

用遞歸對 Haskell 中的整數列表進行排序算法

[英]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)

謝謝

您嘗試在正確的軌道上進行冒泡排序,這是排序的良好起點。 一些注意事項:

您處理列表為空或至少有兩個元素( xy )的情況,但您忘記了列表只有一個元素時的情況。 您總是會遇到這種情況,因為您是在較小的列表上遞歸調用您的函數。

ordenarMemoria [x] = -- how do you sort a 1-element list?

第二個注意事項:在這個模式中

ordenarMemoria (x:y:xs) 
    | y > x = ordenarMemoria (y:xs)
    | otherwise = ordenarMemoria (x:xs)

您正在對以兩個元素xy開頭的列表進行排序。 您將xy進行比較,然后在刪除兩個元素之一后對列表的其余部分進行排序。 這一切都很好。

我的問題是:另一個元素發生了什么? 排序列表必須具有與輸入相同的所有元素,因此您應該在輸出中同時使用xy 所以在:

    | y > x = ordenarMemoria (y:xs)

你已經忘記了x 考慮

    | y > x = x : ordenarMemoria (y:xs)

這表明輸出x ,然后是排序的余數。

另一個分支也忘記了其中一個輸入。

修復該函數后,您可能會注意到列表的排序變得更加有序,但仍然沒有完全排序。 這是冒泡排序的一個特性——您可能需要多次運行它。

我強烈建議你閱讀了解你一個Haskell,有一個在線版本在這里,它有一個章節,你可以學習如何使用遞歸,就像快速排序例如列表進行排序:

quicksort :: (Ord a) => [a] -> [a]  
quicksort [] = []  
quicksort (x:xs) =   
    let smallerSorted = quicksort [a | a <- xs, a <= x]  
        biggerSorted = quicksort [a | a <- xs, a > x]  
    in  smallerSorted ++ [x] ++ biggerSorted  

我需要對整數列表進行排序

如何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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM