简体   繁体   English

用递归对 Haskell 中的整数列表进行排序算法

[英]Sort algorithm for list of integers in Haskell with recursion

I need to sort an integer list on haskell, from smaller to greater numbers, but i dont know where to start.我需要在 haskell 上对一个整数列表进行排序,从小到大,但我不知道从哪里开始。

The recursion syntax is kinda difficult for me递归语法对我来说有点困难

A little bit of help would be great.一点点帮助会很棒。

Ive done this but it does not solve my problem:我已经这样做了,但它并没有解决我的问题:

ordenarMemoria :: [Int] -> [Int]
ordenarMemoria [] = []
ordenarMemoria (x:y:xs) 
    | y > x = ordenarMemoria (y:xs)
    | otherwise = ordenarMemoria (x:xs)

Thanks谢谢

You attempt is on the right track for a bubble sort , which is a good starting place for sorting.您尝试在正确的轨道上进行冒泡排序,这是排序的良好起点。 A few notes:一些注意事项:

You handle the cases when the list is empty or has at least two elements ( x and y ), but you have forgotten the case when your list has exactly one element.您处理列表为空或至少有两个元素( xy )的情况,但您忘记了列表只有一个元素时的情况。 You will always reach this case because you are calling your function recursively on smaller lists.您总是会遇到这种情况,因为您是在较小的列表上递归调用您的函数。

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

Second note: in this pattern第二个注意事项:在这个模式中

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

you are sorting a list starting with two elements x and y .您正在对以两个元素xy开头的列表进行排序。 You compare x to y , and then sort the rest of the list after removing one of the two elements.您将xy进行比较,然后在删除两个元素之一后对列表的其余部分进行排序。 This is all good.这一切都很好。

The question I have is: what happened to the other element?我的问题是:另一个元素发生了什么? A sorted list has to have all the same elements as the input, so you should use both x and y in the output.排序列表必须具有与输入相同的所有元素,因此您应该在输出中同时使用xy So in:所以在:

    | y > x = ordenarMemoria (y:xs)

you have forgotten about x .你已经忘记了x Consider考虑

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

which indicates to output x , then the sorted remainder.这表明输出x ,然后是排序的余数。

The other branch forgets about one of the inputs, too.另一个分支也忘记了其中一个输入。

After you fix the function, you might notice that the list gets a bit more sorted, but it is still not completely sorted.修复该函数后,您可能会注意到列表的排序变得更加有序,但仍然没有完全排序。 That's a property of the bubble sort—you might have to run it multiple times.这是冒泡排序的一个特性——您可能需要多次运行它。

I'll highly recommend you read Learn You a Haskell , there is an online version here , it has a chapter where you can learn how to sort lists using recursion, like Quicksort for example:我强烈建议你阅读了解你一个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  

I need to sort an integer list我需要对整数列表进行排序

How about sort from Data.List ?如何Data.List sort

$ stack ghci
Prelude> :m + Data.List
Prelude Data.List> sort [2,3,1]
[1,2,3]

There are lots of choices.有很多选择。 I generally recommend starting with bottom-up mergesort in Haskell, but heapsort isn't a bad choice either.我通常建议从 Haskell 中的自底向上归并排序开始,但堆排序也不是一个糟糕的选择。 Quicksort poses much more serious difficulties.快速排序带来了更严重的困难。

-- 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

Once you've filled in the blanks above, try optimizing the sort by making splatter produce sorted lists of two or perhaps three elements instead of singletons.一旦你填补了上面的空白,尝试通过使splatter产生两个或三个元素的排序列表而不是单例来优化排序。

Here is a modified either quicksort or insertion sort.这是经过修改的快速排序或插入排序。 It uses the fastest method of prefixing or suffixing values to the output list.它使用最快的方法为输出列表添加前缀或后缀值。 If the next value is less than or greater than the first or last of the list, it is simply affixed to the beginning or end of the list.如果下一个值小于或大于列表的第一个或最后一个,则将其简单地附加到列表的开头或结尾。 If the value is not less than the head value or greater than the last value then it must be inserted.如果该值不小于head值或大于last值,则必须插入它。 The insertion is the same logic as the so-called quicksort above.插入与上面所谓的快速排序是相同的逻辑。

Now, the kicker.现在,踢球者。 This function is made to run as a foldr function just to reduce the complexity of the the function.此函数作为foldr函数运行只是为了降低函数的复杂性。 It can easily be converted to a recursive function but it runs fine with 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]

The comments after two line can be removed and the function can be run with scanr to see how many hits are with simple prefix or suffix of values and which are inserted somewhere other that the first or last value.可以删除两行之后的注释,并且可以使用scanr运行该函数以查看有多少命中具有简单的前缀或后缀值,以及插入到第一个或最后一个值以外的其他位置。

foldr f2x [] [5,4,3,2,1,0,9,8,7,6]

Or af = foldr a2x [] ... af [5,4,3,2,1,0,9,8,7,6] >-> [0,1,2,3,4,5,6,7,8,9]或者af = foldr a2x [] ... af [5,4,3,2,1,0,9,8,7,6] >-> [0,1,2,3,4,5,6, 7,8,9]

EDIT 5/18/2018编辑 5/18/2018

The best thing about Stack Overflow is the people like @dfeuer that make you think. Stack Overflow最棒的地方是像 @dfeuer 这样让你思考的人。 @dfeuer suggested using partition . @dfeuer 建议使用partition I am like a child, not knowing how.我像个孩子,不知道怎么办。 I expressed my difficulty with partition but @dfeuer forced me to see how to use it.我表达了我在partition困难,但 @dfeuer 强迫我了解如何使用它。 @dfeuer also pointed out that the use of last in the above function was wasteful. @dfeuer 还指出,在上述函数中使用last是一种浪费。 I did not know that, either.我也不知道。

The following function uses partition imported from Data.List .以下函数使用从Data.List导入的partition partition outputs a tuple pair. partition输出一个元组对。 This function is also meant to use with foldr .此函数也适用于foldr It is a complete insertion sort function.它是一个完整的插入排序功能。

ft nv ls = b++[nv]++e where (b,e) = partition (<=nv) ls

Use it like above像上面一样使用它

foldr ft [] [5,4,3,2,1,0,9,8,7,6]

Haskell and functional programming is all about using existing functions in other functions. 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