使用流的 SML 惰性排序 int 列表
问题
1 流和惰性评估(40 分)
我们知道比较排序至少需要 O(n log n) 次比较,其中对 n 个元素进行排序。假设对于某个函数 f,我们只需要排序列表中的前 f(n) 个元素。如果我们知道 f(n) 渐近小于 log n,那么对整个列表进行排序将是浪费的。我们可以实现一个惰性排序,它返回一个表示排序列表的流。每次访问流以获取排序列表的头部时,都会在列表中找到最小的元素。这需要线性时间。从列表中删除 f(n) 个元素将花费 O(nf(n))。对于这个问题,我们使用以下数据类型定义。还定义了一些辅助函数。
(* 暂停计算 *) 数据类型'astream'=单元暂停-> '一条流 (* 惰性流构建 *) 和'流=空| 'a * 'astream' 的缺点
请注意,这些流不一定是无限的,但它们可以是。
Q1.1(20分)实现函数lazysort:int list -> int 流'。
它接受一个整数列表并返回一个表示排序列表的 int 流。这应该在恒定的时间内完成。每次强制stream'时,它都会给出Empty或Cons(v, s')。在缺点的情况下,v 是排序列表中的最小元素,s' 是表示剩余排序列表的流'。力应该花费线性时间。例如:
- val s = lazysort( [9, 8, 7, 6, 5, 4] ); val s = Susp fn : int 流' - val Cons(n1, s1) = 力(s); 值 n1 = 4 :整数 val s1 = Susp fn : int 流' - val Cons(n2, s2) = 力(s1); 值 n2 = 5 :整数 val s2 = Susp fn : int 流' - val Cons(n3, s3) = 力(s2); 值 n3 = 6 :整数 val s3 = Susp fn : int 流'
相关定义
以下是代码给出的内容:
(* 暂停计算 *) 数据类型'astream'=单元暂停-> '一条流 (* 惰性流构建 *) 和 'a 流 = 空 | 'a * 'astream' 的缺点 (*惰性流构建和暴露*) 有趣的延迟 (d) = 暂停 (d) 有趣的力量(Susp(d))= d() (* 热切的流构建 *) val 空 = Susp(fn() => 空) fun cons(x, s) = Susp(fn() => Cons(x, s)) (* 检查最多 n 个元素的流 取:int -> '一条流' -> '一个列表 take': int ->; '一个流-> '一个列表 *) 有趣的是 0 s = [] | take n (s) = take' n (力 s) 并取 ' 0 s = [] | take' n (Cons (x, xs)) = x::(take (n-1) xs)
我尝试解决方案时
尝试执行以下操作,获取 int 列表并将其转换为 int 流':
(* lazysort: int list -> int stream' *)
fun lazysort ([]:int list) = empty
| lazysort (h::t) = cons (h, lazysort(t));
但是当调用force时,它不会返回最小元素。我必须搜索最小值,但我不知道如何...我想到像下面这样进行插入排序:
fun insertsort [] = []
| insertsort (x::xs) =
let fun insert (x:real, []) = [x]
| insert (x:real, y::ys) =
if x<=y then x::y::ys
else y::insert(x, ys)
in insert(x, insertsort xs)
end;
但我必须搜索最小值并且不对列表进行排序,然后将其作为流...
任何帮助将不胜感激。
The question
1 Streams and lazy evaluation (40 points)
We know that comparison sorting requires at least O(n log n) comparisons where were are sorting n elements. Let’s say we only need the first f(n) elements from the sorted list, for some function f. If we know f(n) is asymptotically less than log n then it would be wasteful to sort the entire list. We can implement a lazy sort that returns a stream representing the sorted list. Each time the stream is accessed to get the head of the sorted list, the smallest element is found in the list. This takes linear time. Removing the f(n) elements from the list will then take O(nf(n)). For this question we use the following datatype definitions. There are also some helper functions defined.
(* Suspended computation *) datatype 'a stream' = Susp of unit -> 'a stream (* Lazy stream construction *) and 'a stream = Empty | Cons of 'a * 'a stream'
Note that these streams are not necessarily infinite, but they can be.
Q1.1 (20 points) Implement the function lazysort: int list -> int stream'.
It takes a list of integers and returns a int stream' representing the sorted list. This should be done in constant time. Each time the stream' is forced, it gives either Empty or a Cons(v, s'). In the case of the cons, v is the smallest element from the sorted list and s' is a stream' representing the remaining sorted list. The force should take linear time. For example:
- val s = lazysort( [9, 8, 7, 6, 5, 4] ); val s = Susp fn : int stream' - val Cons(n1, s1) = force(s); val n1 = 4 : int val s1 = Susp fn : int stream' - val Cons(n2, s2) = force(s1); val n2 = 5 : int val s2 = Susp fn : int stream' - val Cons(n3, s3) = force(s2); val n3 = 6 : int val s3 = Susp fn : int stream'
Relevant definitions
Here is what is given as code:
(* Suspended computation *) datatype 'a stream' = Susp of unit -> 'a stream (* Lazy stream construction *) and 'a stream = Empty | Cons of 'a * 'a stream' (* Lazy stream construction and exposure *) fun delay (d) = Susp (d) fun force (Susp (d)) = d () (* Eager stream construction *) val empty = Susp (fn () => Empty) fun cons (x, s) = Susp (fn () => Cons (x, s)) (* Inspect a stream up to n elements take : int -> 'a stream' -> 'a list take': int -> 'a stream -> 'a list *) fun take 0 s = [] | take n (s) = take' n (force s) and take' 0 s = [] | take' n (Cons (x, xs)) = x::(take (n-1) xs)
My attempt at a solution
I tried to do the following which get the int list and transforms it to int stream':
(* lazysort: int list -> int stream' *)
fun lazysort ([]:int list) = empty
| lazysort (h::t) = cons (h, lazysort(t));
But when calling force it does not return the minimum element. I have to search for the minimum, but I do not know how... I thought of doing insertion sort like following:
fun insertsort [] = []
| insertsort (x::xs) =
let fun insert (x:real, []) = [x]
| insert (x:real, y::ys) =
if x<=y then x::y::ys
else y::insert(x, ys)
in insert(x, insertsort xs)
end;
But I have to search for the minimum and to not sort the list and then put it as a stream...
Any help would be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您使用放置函数处于正确的路径上(有点...我不知道为什么您有
real
类型而不是 int,而只有int 流
如果您现在还没有意识到,您的模式将不匹配)。这是你每次都能获得最小物品的内在魔法。
使上述工作有效的一些提示/技巧
int stream'
。You are on the correct path with the placement function (sort of... I don't know why you have
real
types instead of int when there will only beint streams
. Your pattern would not match if you have not realized by now).This is your helping inner magic for getting the smallest item each time.
Some hints/tips to make the above work
cons(x, insertsort xs)
in (* 5 *) since you are returning aint stream'
with the function.我在你的班上,我认为你的处理方式完全错误。我已经解决了这个问题,但我认为与您完全共享代码对我来说有点不道德。也就是说,这里有一个指针:
I'm in your class and I think you're going about this the totally wrong way. I've solved the question, but I think it's a bit unethical for me to fully share the code with you. That said, here's a pointer: