我们希望在给定的非空列表中找到最大值 整数。然后我们必须比较列表中的元素。自数据 值作为序列给出,我们可以从中进行比较 从列表的开头或结尾。以两种方式定义。一个) 比较从头开始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
答案 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));
你也可以调整代码,例如在插入函数中传递匿名函数...