如何在OCaml中编写BST的迭代顺序遍历

如何在OCaml中编写BST的迭代顺序遍历,ocaml,binary-search-tree,Ocaml,Binary Search Tree,在OCaml中编写递归有序遍历非常容易,但是如何编写迭代遍历呢?使用for loop或while?要求某人编写一些没有递归调用的东西是愚蠢的,但我仍然会这样做,因为这是一个有趣的练习。从递归到迭代总是同一个过程 type tree = Leaf | Node of int * tree * tree let rec in_order = function | Leaf -> [] | Node(i,l,r) -> in_order l @ (i :: in_order r)

在OCaml中编写递归有序遍历非常容易,但是如何编写迭代遍历呢?使用
for loop
while

要求某人编写一些没有递归调用的东西是愚蠢的,但我仍然会这样做,因为这是一个有趣的练习。从递归到迭代总是同一个过程

type tree = Leaf | Node of int * tree * tree

let rec in_order = function
  | Leaf -> []
  | Node(i,l,r) -> in_order l @ (i :: in_order r);;
好了,现在我们有了递归函数。第一步是将其转换为尾部递归。这实际上是最困难的一步,因为它需要真正的逻辑和算法更改

我们将向包含计算结果的函数添加一个新参数:

 let rec ino res = function
  | Leaf -> ()
  | Node(i,l,r) -> 
    begin
      ino res r ;
      res := i :: !res ;
      ino res l
    end
最后,结果是!res

现在我们有了这个,删除递归调用非常容易,我们只需要考虑当编译器有一个递归调用时会做什么。在将函数的参数和下一步要做的工作放入堆栈之后,它只执行一个while循环。我们就这么做吧

open Stack
type work = Value of int | NextNode of tree ref

let ino t : int list =
  let res = ref [] in
  let stack = Stack.create () in
  push (NextNode (ref t)) stack;
  try
    while true do
      let current = pop stack in
      match current with 
      Value i -> res := i :: !res
    | NextNode n ->
      begin
        match !n with
        Leaf -> ()
          | Node(i,l,r) -> 
        begin
          push (NextNode (ref l)) stack;
          push (Value i) stack;
          push (NextNode (ref r)) stack
        end
      end
    done;
    assert false
  with
    | Empty -> !res
在这里,我们只需记住下一步要做的事情。我们知道,当我们到达一个节点时,我们必须先处理它的右子节点,然后是节点的值,然后是它的左子节点,所以我们只需将所有这些放在堆栈中(当然顺序相反),然后继续处理堆栈的下一个元素。当堆栈为空时,我们已经访问了整棵树,可以返回


我希望这篇文章能够让一些人相信递归比迭代编程更强大。3线对26线。QED。

要求某人编写一些没有递归调用的东西是愚蠢的,但我仍然会这样做,因为这是一个有趣的练习。从递归到迭代总是同一个过程

type tree = Leaf | Node of int * tree * tree

let rec in_order = function
  | Leaf -> []
  | Node(i,l,r) -> in_order l @ (i :: in_order r);;
好了,现在我们有了递归函数。第一步是将其转换为尾部递归。这实际上是最困难的一步,因为它需要真正的逻辑和算法更改

我们将向包含计算结果的函数添加一个新参数:

 let rec ino res = function
  | Leaf -> ()
  | Node(i,l,r) -> 
    begin
      ino res r ;
      res := i :: !res ;
      ino res l
    end
最后,结果是!res

现在我们有了这个,删除递归调用非常容易,我们只需要考虑当编译器有一个递归调用时会做什么。在将函数的参数和下一步要做的工作放入堆栈之后,它只执行一个while循环。我们就这么做吧

open Stack
type work = Value of int | NextNode of tree ref

let ino t : int list =
  let res = ref [] in
  let stack = Stack.create () in
  push (NextNode (ref t)) stack;
  try
    while true do
      let current = pop stack in
      match current with 
      Value i -> res := i :: !res
    | NextNode n ->
      begin
        match !n with
        Leaf -> ()
          | Node(i,l,r) -> 
        begin
          push (NextNode (ref l)) stack;
          push (Value i) stack;
          push (NextNode (ref r)) stack
        end
      end
    done;
    assert false
  with
    | Empty -> !res
在这里,我们只需记住下一步要做的事情。我们知道,当我们到达一个节点时,我们必须先处理它的右子节点,然后是节点的值,然后是它的左子节点,所以我们只需将所有这些放在堆栈中(当然顺序相反),然后继续处理堆栈的下一个元素。当堆栈为空时,我们已经访问了整棵树,可以返回


我希望这篇文章能够让一些人相信递归比迭代编程更强大。3线对26线。QED.

这里是迭代顺序遍历的另一种方式:

type 'a node = {mutable data: 'a;
                mutable left : 'a node option;
                mutable right: 'a node option; }

let new_node data = {data; left = None; right = None;}

let insert tree new_data =
  let module Wrapper = struct exception Stop_loop end in
  let iter = ref tree in
  try
    while true do
      if new_data < !iter.data
      then match !iter.left with
        | None ->
          !iter.left <- Some (new_node new_data);
          raise Wrapper.Stop_loop
        | Some left_tree -> iter := left_tree
      else if new_data > !iter.data
      then match !iter.right with
        | None ->
          !iter.right <- Some (new_node new_data);
          raise Wrapper.Stop_loop
        | Some right_tree -> iter := right_tree
    done
  with Wrapper.Stop_loop -> ()

let in_order_traversal tree =
  let module W = struct exception Stop_loop end in
  let visited_stack = Stack.create () in
  let iter_node = ref (Some tree) in
  try while true do
      (* Inner loop, we keep trying to go left *)
      (try while true do
           match !iter_node with
           | None -> raise W.Stop_loop
           | Some left ->
             Stack.push left visited_stack;
             iter_node := left.left
         done;
       with W.Stop_loop -> ());

      (* If we have no more to process in the stack, then we're
         done *)
      if Stack.length visited_stack = 0
      then raise W.Stop_loop
      else
        (* Here we're forced to start moving rightward *)
        let temp = Stack.pop visited_stack in
        Printf.sprintf "%s " temp.data |> print_string;
        iter_node := temp.right
    done
  with W.Stop_loop -> ()

let () = 
  let root = new_node "F" in

  ["B";"G";"A";"D";"I";"C";"E";"H"] |> List.iter (insert root);
  in_order_traversal root;
  print_newline ();
type'a node={mutable data:'a;
可变左:一个节点选项;
可变右键:'节点选项;}
让新节点数据={data;left=None;right=None;}
让我们插入新的树数据=
让模块包装器=结构异常停止\u循环结束
让iter=ref树进入
尝试
尽管如此
如果有新数据<!国际热核实验堆数据
然后比赛!国际热核聚变实验堆
|无->
!iter.left iter:=左树
否则,如果新数据>!国际热核实验堆数据
然后比赛!国际热核聚变实验堆
|无->
!iter.right iter:=右树
完成
使用Wrapper.Stop_循环->()
让我们按顺序遍历树=
让模块W=struct exception Stop\u循环结束
让我们在中访问\u stack=stack.create()
让iter_node=ref(某棵树)进入
千方百计
(*内循环,我们一直尝试向左*)
(千方百计
匹配!iter_节点与
|无->上升带停止循环
|一些人离开了->
Stack.push left\u Stack;
iter_节点:=left.left
完成;
使用W.Stop_loop->());
(*如果堆栈中没有更多要处理的内容,则
完成*)
如果Stack.length\u Stack=0
然后升起W停止循环
其他的
(*这里我们被迫开始向右移动*)
让temp=Stack.pop\u Stack in
Printf.sprintf“%s”临时数据|>print_字符串;
iter_节点:=右侧温度
完成
带W.Stop_循环->()
让()=
设root=in中的新_节点“F”
[“B”;“G”;“A”;“D”;“I”;“C”;“E”;“H”]|>List.iter(插入根);
按顺序遍历根;
打印新行();

下面是迭代顺序遍历的另一种方式:

type 'a node = {mutable data: 'a;
                mutable left : 'a node option;
                mutable right: 'a node option; }

let new_node data = {data; left = None; right = None;}

let insert tree new_data =
  let module Wrapper = struct exception Stop_loop end in
  let iter = ref tree in
  try
    while true do
      if new_data < !iter.data
      then match !iter.left with
        | None ->
          !iter.left <- Some (new_node new_data);
          raise Wrapper.Stop_loop
        | Some left_tree -> iter := left_tree
      else if new_data > !iter.data
      then match !iter.right with
        | None ->
          !iter.right <- Some (new_node new_data);
          raise Wrapper.Stop_loop
        | Some right_tree -> iter := right_tree
    done
  with Wrapper.Stop_loop -> ()

let in_order_traversal tree =
  let module W = struct exception Stop_loop end in
  let visited_stack = Stack.create () in
  let iter_node = ref (Some tree) in
  try while true do
      (* Inner loop, we keep trying to go left *)
      (try while true do
           match !iter_node with
           | None -> raise W.Stop_loop
           | Some left ->
             Stack.push left visited_stack;
             iter_node := left.left
         done;
       with W.Stop_loop -> ());

      (* If we have no more to process in the stack, then we're
         done *)
      if Stack.length visited_stack = 0
      then raise W.Stop_loop
      else
        (* Here we're forced to start moving rightward *)
        let temp = Stack.pop visited_stack in
        Printf.sprintf "%s " temp.data |> print_string;
        iter_node := temp.right
    done
  with W.Stop_loop -> ()

let () = 
  let root = new_node "F" in

  ["B";"G";"A";"D";"I";"C";"E";"H"] |> List.iter (insert root);
  in_order_traversal root;
  print_newline ();
type'a node={mutable data:'a;
可变左:一个节点选项;
可变右键:'节点选项;}
让新节点数据={data;left=None;right=None;}
让我们插入新的树数据=
让模块包装器=结构异常停止\u循环结束
让iter=ref树进入
尝试
尽管如此
如果有新数据<!国际热核实验堆数据
然后比赛!国际热核聚变实验堆
|无->
!iter.left iter:=左树
否则,如果新数据>!国际热核实验堆数据
然后比赛!国际热核聚变实验堆
|无->
!iter.right iter:=右树
完成
使用Wrapper.Stop_循环->()
让我们按顺序遍历树=
让模块W=struct exception Stop\u循环结束
让我们在中访问\u stack=stack.create()
让iter_node=ref(某棵树)进入
千方百计
(*内循环,我们一直尝试向左*)
(千方百计
匹配!iter_节点与
|无->上升带停止循环
|一些人离开了->
Stack.push left\u Stack;
iter_节点:=left.left
完成;
使用W.Stop_loop->());
(*如果堆栈中没有更多要处理的内容,则
完成*)
如果Stack.length\u Stack=0
然后升起W停止循环
其他的
(*这里我们被迫开始向右移动*)
设温度=S