从链接队列中删除所有出现的元素

时间:2019-03-02 01:15:57

标签: function ocaml

我的任务是创建一个函数,该函数删除由以下项定义的链接队列中所有出现的键:

type 'a qnode = { v: 'a;
                mutable next: 'a qnode option }

type 'a queue = { mutable head: 'a qnode option;
                    mutable tail: 'a qnode option }

我想出了下面列出的代码,该代码通过了我为一个空队列和一个只有一个元素的队列创建的测试,当该队列中有多个元素且该队列中出现一次键时,该超时。

let delete (elt: 'a) (q: 'a queue) : unit =
if not (valid q) then failwith "delete: given invalid queue";
let rec loop (qn: 'a qnode option) (qn2: 'a qnode option) (elt: 'a) : unit =
  begin match qn, qn2 with
  | None, None -> ()
  | None, Some x   -> if x.v = elt && x.next = None then
                      (q.head <- x.next; q.tail <- x.next)
                      else if x.v = elt && x.next <> None then
                      (q.head <- x.next; q.tail <- x.next; loop x.next q.tail elt)
                      else loop x.next q.tail elt
  | Some x, Some y -> if y.v = elt && y.next = None then 
                      (x.next <- y.next; q.tail <- y.next)
                      else if y.v = elt && y.next <> None then 
                      (x.next <- y.next; q.tail <- y.next; loop y.next q.tail elt)
                      else loop y.next q.tail elt
  | Some x, None -> ()
  end
in loop None q.head elt

我无法找到确切的地方可能存在无限循环或效率低下的地方,因此将不胜感激。

1 个答案:

答案 0 :(得分:1)

循环的基本计划是让qn2遍历队列的所有节点。在每次调用时,qn代表队列中qn2之前的节点。您需要该上一个节点,以便在找到感兴趣的节点时正确更新链接。

qn2是队列的第一个节点时,没有前一个节点。因此,在这种情况下,qn应该是None

每次调用都需要考虑两件事:首先,在节点qn2上要执行的处理。可能会删除它,也可能不会删除它。

第二,如何进行到队列的下一个节点。换句话说,递归调用应该是什么样的?您需要传递一个“上一个”节点(将是新的qn)和一个当前节点(新的qn2)。

让我们集中讨论问题的第二部分,即递归调用的细节。假设qn2不是None,即有一个要查看的节点。您应该看到,如果删除qn2,那么当前的qn还将是下一个呼叫的上一个节点。如果未删除qn2,则qn2本身将成为下一个呼叫的上一个节点。无论哪种情况,next节点的qn2字段都是要查看的新节点(下一个调用的qn2)。

如果您查看两个递归调用,则它们都不具有正确的格式。特别是,要查看的下一个节点始终设置为队列的尾部。这是不对的。您不想在处理完第一个节点后立即跳到最后。

此外,如果队列不为空,则q.tail将始终是节点(而不是None)。因此循环永远不会终止。