如何在SML中找到List中的最大数字

时间:2012-09-21 00:31:49

标签: list sml smlnj

  

我们希望在给定的非空列表中找到最大值   整数。然后我们必须比较列表中的元素。自数据   值作为序列给出,我们可以从中进行比较   从列表的开头或结尾。以两种方式定义。一个)   比较从头开始b)比较结束(怎么可以   当数据值在列表中时我们这样做吗?)

我所做的是从头开始比较找到最大的数字。

我怎么能从最后做到?我应该采用什么逻辑?

这是我从头开始比较的代码。

- fun largest[x] = x
= | largest(x::y::xs) =
= if x>y then largest(x::xs) else largest(y::xs)
= | largest[] = 0;
val largest = fn : int list -> int


output

- largest [1,4,2,3,6,5,4,6,7];
val it = 7 : int

5 个答案:

答案 0 :(得分:6)

在您的函数中,比较列表的前两个元素,并将较大的值与其余元素进行比较。我认为从最后的比较意味着你首先尝试找到列表尾部的最大数量,然后将其与head元素进行比较。

fun largest [] = raise Empty 
 | largest [x] = x
 | largest (x::xs) =
      let 
        val y = largest xs
      in
        if x > y then x else y
      end

虽然不是必需的,但您应该处理空列表的完整性。如果使用max函数,则可以缩短函数。

fun largest [] = raise Empty 
 | largest [x] = x
 | largest (x::xs) = max(x, largest xs)

老实说,我更希望你的版本是尾递归的(它不会在大型列表中炸掉堆栈)。正如其他答案所示,我的函数可以被重写为尾递归,但肯定比你的函数更复杂。

答案 1 :(得分:4)

正如@pad用他的代码演示的那样,应该应用的逻辑是进行递归调用,在解决函数当前范围的问题之前递归地解决子问题

largest的情况下,向后解决它并没有任何意义,因为它只是使用更多的堆栈空间,这在“手动”执行代码时变得明显。然而,设计模式在其他情况下是有用的。想象一下名为zip的函数:

(* zip ([1,2,3,4], [a,b,c]) = [(1,a),(2,b),(3,c)] *)
fun zip (x::xs, y::ys) = (x,y) :: zip (xs, ys)
  | zip _ = []

此函数将两个列表的元组转换为多个元组的列表,并丢弃剩余值。它可能在某些情况下很有用,并且定义它也不是那么糟糕。然而,使其对应物unzip稍微复杂一点:

(* unzip ([(1,a),(2,b),(3,c)] = ([1,2,3],[a,b,c]) *)
fun unzip [] = ([], [])
  | unzip ((x,y)::xys) =
    let
      val (xs, ys) = unzip xys
    in
      (x::xs, y::ys)
    end

手动运行常规“从头开始”-largest可能如下所示:

   largest [1,4,2,3,6,5,4,6,7]
~> largest [4,2,3,6,5,4,6,7]
~> largest [4,3,6,5,4,6,7]
~> largest [4,6,5,4,6,7]
~> largest [6,5,4,6,7]
~> largest [6,4,6,7]
~> largest [6,6,7]
~> largest [6,7]
~> largest [7]
~> 7

手动运行“从最后” - 最大化,想象每个缩进级别需要在stack memory中保存函数调用的当前上下文,调用新函数并在{{1}之后返回结果}箭头,可能看起来像这样:

~>

那么为什么这些non-tail-recursive functions如果只是使用更多内存就会使早期递归调用有用呢?好吧,如果我们回到largest [1,4,2,3,6,5,4,6,7] ~> 7 \_ largest [4,2,3,6,5,4,6,7] ~> 7 \_ largest [2,3,6,5,4,6,7] ~> 7 \_ largest [3,6,5,4,6,7] ~> 7 \_ largest [6,5,4,6,7] ~> 7 \_ largest [5,4,6,7] ~> 7 \_ largest [4,6,7] ~> 7 \_ largest [6,7] ~> 7 \_ largest [7] ~> 7 并且我们想要在没有这种恼人的“反向思考”的情况下解决它,我们在构造新结果时遇到了问题,这是一个元组,因为我们没有任何地方可以放置x和y:

unzip

制作这样一个地方的一个想法是创建一个辅助函数(辅助函数),它有一些额外的函数参数用于构建(* Attempt 1 to solve unzip without abusing the call stack *) fun unzip [] = ([], []) | unzip ((x,y)::xys) = ...something with x, y and unzip xys... xs。到达xys列表的末尾时,将返回这些值:

ys

但是你可能已经意识到那些(* Attempt 2 to solve unzip without abusing the call stack *) local fun unzipAux ([], xs, ys) = (xs, ys) | unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys) in fun unzip xys = unzipAux (xys, [], []) end 最终会在结果中逆转。解决这个问题的一种快速方法是在它们上面使用(xs, ys)一次,这在基本情况下最好实现:

rev

这提出了一个有趣的问题: (* Attempt 3 to solve unzip without abusing the call stack *) local fun unzipAux ([], xs, ys) = (rev xs, rev ys) | unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys) in fun unzip xys = unzipAux (xys, [], []) end 如何实施?

答案 2 :(得分:1)

我建议使用尾递归帮助器,它将当前最大值作为累加器传递。

local
    fun helper max [] = max
      | helper max (n::ns) = helper (if n > max then n else max) ns
in
    fun largest ns = helper 0 ns
end;

答案 3 :(得分:1)

(*Find the max between two comparable items*)
fun max(a,b) = if a>b then a else b;
(*Find the max item in list which calls the maxL function recursively*)
fun maxL(L) = if L=[] then 0 else max(hd(L), maxL(tl(L)));

答案 4 :(得分:-1)

我知道回答你的问题为时已晚,但希望这会有所帮助:

fun insert (x, []) = [x]
| insert (x, y::ys) = if x<=y then x::y::ys else y::insert(x,ys);

fun insertion_sort [] = []
| insertion_sort (x::xs) = insert(x, insertion_sort xs);

fun get_last_element [] = 0
| get_last_element [x] = x
| get_last_element (x::xs) = if(xs=nil)
                                then x
                             else
                                get_last_element(xs);

fun get_min L = if(insertion_sort(L)=[]) 
                    then 0 
                else
                    hd(insertion_sort(L));
fun get_max L = get_last_element(insertion_sort(L));

你也可以调整代码,例如在插入函数中传递匿名函数...