[swarthmore cs75] Lab 1 — OCaml Tree Programming
课程回顾
Swarthmore学院16年开的编译系统课,总共10次大作业。本随笔记录了相关的课堂笔记以及第2大次作业。
比较两个lists的逻辑:
let rec cmp l ll =
match (l,ll) with
| [], [] -> 0
| [],_ -> -1
| _,[] -> 1
| (h::t), (hh::tt) -> if h > hh then 1
else if h < hh then -1
else cmp t tt;;
编程作业
1. 平衡二叉树(AVL tree)
- 一颗AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1)。
在进行插入时,有四种情况会破坏树的平衡性质,需要通过相应的旋转操作来恢复树的平衡。这四种情况如下所示:- 情况一:对左儿子的左子树进行一次插入(通过单旋转恢复平衡)
- 情况一:对左儿子的左子树进行一次插入(通过单旋转恢复平衡)
if k2左子树高度 - k2右子树高度 = 2 > 1 then
RotateLeft k2: Node(k2, Node(k1, X, Y), Z) -> Node(k1, X, Node(k2, Y, Z))
- 情况二:对左儿子的右子树进行一次插入(通过双旋转恢复平衡)
if k3左子树高度 - k3右子树高度 = 2 > 1 then
if k1左子树高度 - k1右子树高度 = -1 < 0 then
RotateRight k1: Node(k1, A, Node(k2, B, C)) -> Node(k2, Node(k1, A, B), C)
RotateLeft k3: Node(k3, Node(k2, Node(K1, A, B), C), D) -> Node(k2, Node(k1, A, B), Node(k3, C, D))
- 情况三:对右儿子的左子树进行一次插入 (和情况二镜像对称)
略 - 情况四:对右儿子的右子树进行一次插入 (和情况一镜像对称)
略
上面的情况一和情况二的if条件可以合并一下,同理适用于情况三和情况四,分析清楚后就有了下面的代码:
type ('k, 'v) avlnode =
| Leaf
| Node of int * 'k * 'v * ('k, 'v) avlnode * ('k, 'v) avlnode
let height (n : ('k, 'v) avlnode) : int =
match n with
| Leaf -> -1
| Node(h, _, _, _, _) -> h
let create k v l r =
Node(1 + max (height l) (height r), k, v, l, r)
let rotate_left n =
let k,v,l,r = get_elems n in
let lk,lv,ll,lr = get_elems l in
create lk lv ll (create k v lr r)
let rotate_right n =
let k,v,l,r = get_elems n in
let rk,rv,rl,rr = get_elems r in
create rk rv (create k v l rl) rr
let balance (n : ('k, 'v) avlnode) : ('k, 'v) avlnode =
let k,v,l,r = get_elems n in
if (height l)-(height r) > 1 then
let _, _, ll, lr = get_elems l in
rotate_left (
if (height ll)-(height lr) < 0 then
create k v (rotate_right l) r
else n
)
else if (height l)-(height r) < -1 then
let _, _, rl, rr = get_elems r in
rotate_right (
if (height rl)-(height rr) > 0 then
create k v l (rotate_left r)
else n
)
else n
let rec set (n : ('k, 'v) avlnode) (key : 'k) (value : 'v) : ('k, 'v) avlnode =
match n with
| Leaf -> create key value Leaf Leaf
| Node(_, k, v, l, r) ->
balance (
if k = key then create key value l r
else if key < k then create k v (set l key value) r
else create k v l (set r key value)
)
let add_all (n : ('k, 'v) avlnode) (keys : ('k * 'v) list) : ('k, 'v) avlnode =
List.fold_left (fun a (k, v) -> set a k v) n keys
2. 表达式求值
- 这里定义了一个算数类型,
例如表达式:
5 * 3 + y
可以表示为:
Plus(Times(Num(5), Num(3)), Variable("y"))
type arith =
| Plus of arith * arith
| Times of arith * arith
| Variable of string
| Num of int
- 实现了一个方法计算表达式的值,
例如执行:
evaluate (Times(Plus(Variable("x"), Variable("y")), Num(5))) (add_all Leaf [("x", 5); ("y", 7)])
会返回:
60
let rec evaluate (a : arith) (vars : (string, int) avlnode) : int =
let get_variable_value (key : string) (value : int option) : int =
match value with
| Some(num) -> num
| None -> failwith ("Variable " ^ key ^ " is not contained in vars in the expression")
in
match a with
| Plus(l, r) -> (evaluate l vars) + (evaluate r vars)
| Times(l, r) -> (evaluate l vars) * (evaluate r vars)
| Variable(var) -> get_variable_value var (get vars var)
| Num(num) -> num
- 实现一个方法把算数类型解析成数学表达式,
例如执行:
pretty (Plus(Plus(Times(Plus(Num(5), Variable("y")), Variable("x")), Num(2)), Num(1)))
会返回:
(5 + y)x + 2 + 1
let rec pretty (a : arith) : string =
let rec helper (a: arith) : string =
match a with
| Plus(_) -> "(" ^ pretty a ^ ")"
| _ -> pretty a
in
match a with
| Plus(l, r) -> pretty l ^ " + " ^ pretty r
| Times(l, r) -> helper l ^ helper r
| Variable(var) -> var
| Num(num) -> string_of_int num
3. 测试用例
- 省略了一些test case,仅演示用法
let t_any name value expected = name>::
(fun _ -> assert_equal expected value ~printer:dump);;
let a_tree = Node(0, "a", 5, Leaf, Leaf);;
let get_tests = [
t_any "get1" (get a_tree "a") (Some(5));
t_any "get2" (get (Node(0, "b", 15, a_tree, Leaf)) "a") (Some(5));
t_any "get3" (get (Node(0, "b", 15, a_tree, Leaf)) "c") None;
];;
let evaluate_tests = [
t_any "evaluate1" (evaluate (Times(Plus(Variable("x"), Variable("y")), Num(5))) (add_all Leaf [("x", 5); ("y", 7)])) 60;
];;
let pretty_tests = [
t_any "pretty1" (pretty (Plus(Plus(Times(Plus(Num(5), Variable("y")), Variable("x")), Num(2)), Num(1)))) "(5 + y)x + 2 + 1";
];;
let all_tests =
get_tests @
evaluate_tests @
pretty_tests
;;
let suite = "suite">:::all_tests;;
run_test_tt_main suite
- @函数的定义为:
val append : 'a list -> 'a list -> 'a list
Concatenate two lists. Same as the infix operator @. Not tail-recursive (length of the first argument).
参考资料
Lab 1 — OCaml Tree Programming
[swarthmore cs75] Lab 1 — OCaml Tree Programming的更多相关文章
- [swarthmore cs75] Lab 0 Warmup & Basic OCaml
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第1次大作业. 什么是编译 编译就是执行Program->Program'转换的过程,如下 ...
- [swarthmore cs75] Compiler 4 – Diamondback
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第6次大作业. 函数声明 增加函数声明.函数调用的抽象语法:在转换成anf之前还要检查函数声明和 ...
- [swarthmore cs75] Compiler 2 – Boa
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第4次大作业. A-Normal Form 在80年代,函数式语言编译器主要使用Continua ...
- [swarthmore cs75] Compiler 1 – Adder
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第3次大作业. 编译的过程:首先解析(parse)源代码,然后成抽象语法树(AST),再生成汇编 ...
- [swarthmore cs75] inlab1 — Tiny Compiler
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了inlab1的实践过程. tiny compiler 这个迷你的编译器可以将一个源文件,编译成可执行的二进制代码. ...
- [swarthmore cs75] Compiler 6 – Garbage Snake
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第9次大作业. 赋值的副作用:循环元组 下面的代码展示了Python3是如何处理循环列表(pri ...
- [swarthmore cs75] Compiler 6 – Fer-de-lance
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第8次大作业. First-class function: It treats function ...
- [swarthmore cs75] Compiler 5 – Egg-eater
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第7次大作业. 抽象语法: 存储方式: 栈中的数据如果最后三位(tag bits)是001表示元 ...
- [swarthmore cs75] Compiler 3 – Cobra
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第5次大作业. 增加了bool数据表示和比较运算符的支持,具体语法参考下图: 第一种int和bo ...
随机推荐
- 史上最全最详细的环境搭建教程,行百里者手把手教你在windows下搭建Anaconda+pycharm+库文件(TensorFlow,numpy)环境搭建
我是在搭建TensorFlow开发环境的道路上走了很多弯路 掉了很多头发,为了让广大同学们不在受苦受累 下面我将手把手教你学习如特快速搭建python环境 快速导入numpy,PIL,pillow,等 ...
- git命令行获取某分支代码
参考https://www.cnblogs.com/nylcy/p/6569284.html git clone -b branch1 http://xxx.xx.xxx... git clone - ...
- 转载:IIS 之 连接数、并发连接数、最大并发工作线程数、队列长度、最大工作进程数
一.IIS连接数 一般购买过虚拟主机的朋友都熟悉购买时,会限制IIS连接数,顾名思义即为IIS服务器可以同时容纳客户请求的最高连接数,准确的说应该叫“IIS限制连接数”. 客户请求的连接内容包括: [ ...
- 牛客小白月赛13 小A的柱状图(单调栈)
链接:https://ac.nowcoder.com/acm/contest/549/H来源:牛客网 题目描述 柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的 ...
- POJ—1321(棋盘问题)
题目链接:https://cn.vjudge.net/contest/65959#problem/A 入门dfs,给一张地图,由“#”和“.”组成,“#”处可以放棋子,且棋子不能同行同列,问放满所有“ ...
- RPC -dubbo 服务导出实现
在阅读此文章之前,我希望阅读者对Spring 扩展机制的有一定的了解,比如:自定义标签与Spring整合, InitializingBean 接口,ApplicationContextAware,Be ...
- 用7ch中断例程完成jmp near ptr s指令的功能,用bx向中断例程传送转移位移。
应用举例:在屏幕的第12行,显示data段中以0结尾的字符串. assume cs:code data segment db data ends code segment start: mov ax, ...
- 手把手教学在Springboot中搭建使用Guava cache,包教包会,不会我输一包辣条给你
guava cache使用简介 概述 缓存是日常开发中经常应用到的一种技术手段,合理的利用缓存可以极大的改善应用程序的性能. Guava官方对Cache的描述连接 缓存在各种各样的用例中非常有用.例 ...
- 为什么23种设计模式没有 MVC
MVC的是为了把数据(Model)和视图(View)分离开来,然后用控制器(Controller)来粘合M和V之间的关系. MVC是观察者模式(Observer), 策略模式(Strategy)和组合 ...
- Thread类与Runnable接口的深入理解
Thread类与Runnable接口的深入理解1.Thread类实现了Runnable接口,实现run方法,其中target参数对应的就是一个Runnable接口的实现类 @Override publ ...