0

I am trying to write a recursive function that uses head::tail. I understand that head in the first element of the list and tail is all other elements in the list. I also understand how recursions works. What I am wondering is how to go about sorting the elements in the list. Is there a way to compare the head to every element in the tail then choose the smallest element? My background in C++ and I am not allowed to use the List.sort(). Any idea of how to go about it? I have looked at the tutorials on the msdn site and still have had no luck

Aaron
  • 21
  • 1
  • 3

2 Answers2

2

You need to decide a sorting methodology before worrying about the data structure used. If you were to do, say, insertion sort, you would likely want to start from the end of the list and insert an item at each recursion level, being careful how you handle the insertion itself.

Technically at any particular level you only have access to one data element, however you can pass a particular data element as a parameter to preserve it. For instance here is the inserting part of an insertion sort algorithm, it assumes the list is sorted.

let rec insert i l =
    match l with
    | [] -> [i]
    | h::t -> if h > i then
                  i::l
              else
                  h::(insert i t)

Note how I now have access to two elements, the cached one and the remainder. Another variation would be a merge sort where you had two sorted lists and therefore two items to work with any particular iteration.

Daniel's commented answer mentions a particular implementation (quicksort) if you are interested.

Finally list's aren't optimal for sorting algorithms due to their rigid structure, and the number of allocations required. Given that all known sorting algorithms are > O(n) complexity, you can translate you list to and from an array in order to improve performance without hurting your asymptotic performance.

EDIT:
Note that above isn't in tail recursive format, you would need to do something like this:

let insert i l =
    let rec insert i l acc =
        match l with
        | [] -> List.foldBack (fun e a -> e :: a) acc [i]
        | h::t -> if h > i then
                      List.foldBack (fun e a -> e :: a) acc i::l
                  else
                      insert i l (i::acc)
    insert i l []

I don't remember offhand the best way to reverse a list so went with an example from https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lists

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • Thanks you, just a follow up, sorry if it seems to novice but I am new to F#. In my program I am using random numbers to generate my list. code// let nonList = randomNumberList 10 //. How would I pass in the correct parameters to the insert function. I noticed that insert has two parameters, but I only have one parameter to pass in? – Aaron May 23 '11 at 17:07
  • as far as I understand this is not tail-call friendly, so be careful – user1623521 Jan 17 '18 at 11:01
  • @user1623521: That is correct, you would need to transform it use an accumulated list if you wanted it to be in tail call form. I left it non-tail call friendly as I find tail call form to be confusing at times when simply focusing on the recursion method. – Guvante Jan 24 '18 at 21:58
  • @user1623521: Since performing the transformation is difficult given the downvotes I added one that builds up a backwards list of the prefix parts of the list before reversing them in front once we have the insert location. – Guvante Feb 08 '18 at 00:00
2

Here is recursive list-based implementation of quicksort algorithm in F#

let rec quicksort list =
    match list with
    | [] -> []
    | h::t ->
        let lesser = List.filter ((>) h) t
        let greater = List.filter ((<=) h) t
        (quicksort lesser) @[h] @(quicksort greater)
Ivan Akcheurov
  • 2,173
  • 19
  • 15