SML 二叉搜索树插入函数
SML Binary Search Tree Insert Function
我是 SML 的新手,正在尝试实施 BST。我已经想出如何解析树,但正在努力创建插入函数。我希望函数是: insert(bst, key, value) of type BST * int * int -> BST 它将键值对插入给定树和 returns 结果树。不过,我在创建这个过程中遇到了困难,因为我对确保函数的类型正确感到有点困惑。
到目前为止,这是我的代码,我还包含了一个示例树
(* left subtree, right subtree, key, value *)
datatype BST = Empty | Node of BST * BST * int * int;
fun parsePost [] = Empty
| parsePost lst =
let
fun pP(stack, (0, k, v)::str) = pP(Node(Empty, Empty, k, v)::stack, str)
| pP(L::stack, (1, k, v)::str) = pP(Node(L, Empty, k, v)::stack, str)
| pP(R::stack, (2, k, v)::str) = pP(Node(Empty, R, k, v)::stack, str)
| pP(R::L::stack, (3, k, v)::str) = pP(Node(L, R, k, v)::stack, str)
| pP(T::stack, []) = T;
in
pP([], lst)
end;
val exTree1 = [(0, 1, 1), (0, 3, 3), (3, 2, 2)];
我正考虑这样启动插入功能:
fun insert(Empty, x, y) = Empty
但我不太确定从那里去哪里。
如果你将一个键值对插入到一个空树中,你真的期望得到一个空树吗?我很怀疑这是你所期望的。
相反,您可能期望一棵树有那对,但树枝是空的。
fun insert(Empty, x, y) = Node(Empty, Empty, x, y)
如果树不是空的呢?
让我们考虑一个简单的例子:
val ex1 = Node(Empty, Empty, 1, 4)
这看起来像:
(1,4)
/ \
/ \
/ \
Empty Empty
好吧,如果我们评估 insert(ex1, 2, 5)
那么大概结果应该是这样的:
(1,4)
/ \
/ \
/ \
Empty (2,5)
/ \
/ \
/ \
Empty Empty
为了得到这个,我们必须意识到正确的分支与我们评估 insert(Empty, 2, 5)
.
时得到的结果相同
(2,5)
/ \
/ \
/ \
Empty Empty
由于树数据类型是递归的,因此您的解决方案也是如此。我们需要检查您要插入的键是否与已存储在节点中的键相同。如果是,我们无需更改任何内容。
如果小于已经存在的键,我们插入左分支,如果大于,我们插入右分支。
fun insert(Empty, x, y) = Node(Empty, Empty, x, y)
| insert((n as Node(l, r, k, v)), x, y) =
case Int.compare(x, k) of
EQUAL => n
| LESS => Node(insert(l, x, y), r, k, v)
| GREATER => Node(l, insert(r, x, y), k, v)
此策略可扩展到任何深度的树结构,因为最终一个分支将始终包含您要查找的键,或者有一个空分支。
我是 SML 的新手,正在尝试实施 BST。我已经想出如何解析树,但正在努力创建插入函数。我希望函数是: insert(bst, key, value) of type BST * int * int -> BST 它将键值对插入给定树和 returns 结果树。不过,我在创建这个过程中遇到了困难,因为我对确保函数的类型正确感到有点困惑。
到目前为止,这是我的代码,我还包含了一个示例树
(* left subtree, right subtree, key, value *)
datatype BST = Empty | Node of BST * BST * int * int;
fun parsePost [] = Empty
| parsePost lst =
let
fun pP(stack, (0, k, v)::str) = pP(Node(Empty, Empty, k, v)::stack, str)
| pP(L::stack, (1, k, v)::str) = pP(Node(L, Empty, k, v)::stack, str)
| pP(R::stack, (2, k, v)::str) = pP(Node(Empty, R, k, v)::stack, str)
| pP(R::L::stack, (3, k, v)::str) = pP(Node(L, R, k, v)::stack, str)
| pP(T::stack, []) = T;
in
pP([], lst)
end;
val exTree1 = [(0, 1, 1), (0, 3, 3), (3, 2, 2)];
我正考虑这样启动插入功能:
fun insert(Empty, x, y) = Empty
但我不太确定从那里去哪里。
如果你将一个键值对插入到一个空树中,你真的期望得到一个空树吗?我很怀疑这是你所期望的。
相反,您可能期望一棵树有那对,但树枝是空的。
fun insert(Empty, x, y) = Node(Empty, Empty, x, y)
如果树不是空的呢?
让我们考虑一个简单的例子:
val ex1 = Node(Empty, Empty, 1, 4)
这看起来像:
(1,4)
/ \
/ \
/ \
Empty Empty
好吧,如果我们评估 insert(ex1, 2, 5)
那么大概结果应该是这样的:
(1,4)
/ \
/ \
/ \
Empty (2,5)
/ \
/ \
/ \
Empty Empty
为了得到这个,我们必须意识到正确的分支与我们评估 insert(Empty, 2, 5)
.
(2,5)
/ \
/ \
/ \
Empty Empty
由于树数据类型是递归的,因此您的解决方案也是如此。我们需要检查您要插入的键是否与已存储在节点中的键相同。如果是,我们无需更改任何内容。
如果小于已经存在的键,我们插入左分支,如果大于,我们插入右分支。
fun insert(Empty, x, y) = Node(Empty, Empty, x, y)
| insert((n as Node(l, r, k, v)), x, y) =
case Int.compare(x, k) of
EQUAL => n
| LESS => Node(insert(l, x, y), r, k, v)
| GREATER => Node(l, insert(r, x, y), k, v)
此策略可扩展到任何深度的树结构,因为最终一个分支将始终包含您要查找的键,或者有一个空分支。