关于Prolog实现2-3词典的一些疑问

时间:2013-05-07 16:45:51

标签: tree prolog search-tree 2-3-tree

我正在使用SWI Prolog学习Prolog,我对如何在Prolog中实现 2-3 dictionary 的工作有所怀疑。

我知道 2-3词典的理论是树,其内部节点可以生成2或3个具有以下属性的子树:

1)所有商品都存储在树叶中,并从较小的订购到较大的商品

2)所有树叶都处于同一水平

3)内部节点不包含插入的项目,但包含以下列方式指定子树的最小元素的标签

  • 如果内部节点有2个子树,则此内部节点中的标签包含其RIGHT SUBTREE的MINIMAL ELEMENT(因此,如果我搜索的项目X小于标签,我确定它位于左子树中)
  • 如果内部节点有3个子树,则此内部节点中的标签包含2个值:M2和M3,其中M1是CENTER SUBTREE中存在的MINIMAL VALUE,M3是最小值,即右子树< / LI>

因此,搜索这种词典中是否存在一个项目非常简单。

插入更复杂,我理解它的理论,但我对Prolog的解释只有一些问题。

这是我的程序(摘自Ivan Bratko的书:人工智能编程):

/* in(Item, Tree) predicate is TRUE if the searched Item is in the specified Tree */

% BASE CASE: Item found in a leaf, so end
in(Item, l(Item)).  

/* CASE 1: I am searching Item in an internal node having a single label value
           so this internal node have 2 subtrees
*/
in(Item, n2(T1,M,T2)) :- gt(M,Item), % IF M label value lexicographically follows the searched Item value
                         !,
                         in(Item,T1)    % THEN search Item in the left subtree
                         ;      % (; is an OR)
                         in(Item,T2).   % Otherwise search Item in the right subtree

/* CASE 2: I am searching Intem in an internal node having 2 label values so this
           internal node have 3 subtrees
*/

in(Item, n3(T1,M2,T2,M3,T3)) :- gt(M2,Item), % IF M2 label value lexicographically follows the searched Item value
                                !,
                                in(Item,T1) % THEN search Item in the left subtree
                                ;       % (; is an OR)
                                /* IF M3 label value lexicographically follows the searched Item value 
                                   BUT this is NOT TRUE that M2>Item
                                */
                                gt(M3,Item),
                                !,
                                in(Item,T2) % THEN search Item in the central subtree
                                ;       % (; is an OR)
                                in(Item,T3).    % ELSE (it is TRUE that Item>M3) search in the right subtree 


/* 
*/

% Insertion in the 2-3 dictionary

/* Add X to Tree giving Tree1
   CASE 1: After the insertion of X into Tree, Tree1 does not grow upwards (so it means that an internal nodes 
           having 2 subtrees child, now have 3 subtrees child, so the original tree has grown in width)
*/
add23(Tree, X, Tree1) :- ins(Tree, X, Tree1).                    

/* CASE 2: Tree grows upwards: It means that  if after the insertion of X the height of the new tree is 
           increased so the ins/5 predicate determines the two subtrees T1 and T2 which are then combined
           into a bigger tree    
*/
add23(Tree, X, n2( T1, M2, T2)) :- ins(Tree, X, T1, M2, T2).

del23(Tree, X, Tree1) :- add23(Tree1, X, Tree).    % Delete X from Tree giving Tree1


/* BASE CASE: Inserting the X item into a voil (nil) tree means to obtain a tree 
              consisting of the single new leaf l(X)
*/
ins(nil, X, l(X)).

/* BASE CASES: related to inserting a new item X into a tree composed by 
               a single leaf
*/
ins(l(A), X, l(A), X, l(X)) :- gt(X, A).

ins(l(A), X, l(X), A, l(A)) :- gt(A, X).


/* Tree = n2(T1, M , T2) so Tree is a tree having 2 subtrees T1 and T2
   M: is the MINIMAL ELEMENT OF T2

   IF it is TRUE that M>X (the minimal element in T2 is > the new X item)
   I have to insert X in the LEFT subtrees (into T1 that becomes NT1 and
   now have 2 leaves)
*/
ins(n2(T1, M , T2), X, n2(NT1, M, T2)) :- gt(M, X),
                                          ins(T1, X, NT1).


/* Tree = n2(T1, M , T2) so Tree is a tree having 2 subtrees T1 and T2
   M: is the MINIMAL ELEMENT OF T2.

   IF it is TRUE that M>X (the minimal element in T2 is > the new X item) and
   IF I can insert 
*/ 
ins(n2(T1, M, T2), X, n3(NT1a, Mb, NT1b, M, T2)) :- gt(M, X),
                                                    ins(T1, X, NT1a, Mb, NT1b).


ins(n2(T1, M, T2), X, n2(T1, M, NT2)) :- gt(X, M),
                                         ins(T2, X, NT2).

ins( n2( T1, M, T2), X, n3( T1, M, NT2a, Mb, NT2b))  :-
   gt( X, M),
   ins( T2, X, NT2a, Mb, NT2b).


ins( n3( T1, M2, T2, M3, T3), X, n3( NT1, M2, T2, M3, T3))  :-
   gt( M2, X),
   ins( T1, X, NT1).

/* Tree = n3(T1, M2, T2, M3, T3) so Tree is a tree having 3 subtree: T1,T2 and T2
   and the ROOT of Tree is the node (M2,M3)

   M2: MINIMAL ELEMENT of T2 subtree
   M3: MINIMAL ELEMENT of T3 subtree

   If I had the item X then Tree have to grow in height

   IF it is TRUE that M2 > X I could try to insert the X item into T1 subtree
   IF it is TRUE that X is added in T1 and T1 is splitted in NT1a and NT1b having root Mb

   so the new tree is: n2(NT1a, Mb, NT1b), M2, n2(T2, M3, T3)


*/
ins(n3(T1, M2, T2, M3, T3), X, n2(NT1a, Mb, NT1b), M2, n2(T2, M3, T3)) :-
                    gt(M2, X),
                    ins(T1, X, NT1a, Mb, NT1b).


ins(n3(T1, M2, T2, M3, T3), X, n3(T1, M2, NT2, M3, T3)) :-
   gt(X, M2), gt(M3, X),
   ins(T2, X, NT2).

ins( n3( T1, M2, T2, M3, T3), X, n2( T1, M2, NT2a), Mb, n2( NT2b, M3, T3)) :-
   gt( X, M2), gt( M3, X),
   ins( T2, X, NT2a, Mb, NT2b).


ins( n3( T1, M2, T2, M3, T3), X, n3( T1, M2, T2, M3, NT3))  :-
   gt( X, M3),
   ins( T3, X, NT3).

ins( n3( T1, M2, T2, M3, T3), X, n2( T1, M2, T2), M3, n2( NT3a, Mb, NT3b))  :-
   gt( X, M3),
   ins( T3, X, NT3a, Mb, NT3b).

在这个实现中,我有:

  • l(X)在我的树中出现
  • n2(T1,M,T2)表示具有2个子索T1和T2的树,其中M是T2中的最小元素
  • n3(T1,M2,T2,M3,T3)**表示具有3个子树的树:T1,T2,T3其中M2是T2中的最小元素,M3是T3中的最小元素

第一个疑问与 add23 ins 谓词之间存在的关系有关:

/* Add X to Tree giving Tree1
   CASE 1: After the insertion of X into Tree, Tree1 does not grow upwoards (so it means that an internal nodes 
           having 2 subtrees child, now have 3 subtrees child, so the original tree has grown in width)
*/
add23(Tree, X, Tree1) :- ins(Tree, X, Tree1).                    

/* CASE 2: Tree grows upwards: It meaans that  if after the insertion of X the height of the new tree is 
           increased so the ins/5 predicate determines the two subtrees T1 and T2 wich are then combined
           into a bigger tree    
*/
add23(Tree, X, n2( T1, M2, T2)) :- ins(Tree, X, T1, M2, T2).

正如在评论中写的那样,我认为第一个与新的树不会长大的情况有关(例如,我有一棵树,有2个子树,插入一个新项目,我是创建一个新的子树,其叶子处于同一级别所有其他子叶子(因此内部节点现在将有2个标签)是不是?

所以在逻辑中我可以把它读作:如果 ins(Tree,X,Tree1)谓词为TRUE,那么我将X添加到Tree,生成具有相同高度的新Tree1树,但包含X项(因此它必须有一个内部节点有3个孩子)

第二种情况与案例有关,我有一棵树,我必须在已经有3个子树的节点中插入一个新项目,所以我必须将两棵树中的旧树分开作为标签从旧原始节点的2个标签中获取单个标签。所以我可以插入新项目作为叶子和新树的新根。

所以在逻辑上我可以把它读作:

如果谓词 ins(树,X,T1,M2,T2)为TRUE则表示谓词为TRUE: add23(树,X,n2(T1, M2,T2))

我将原始树Tree(具有 3个子树)拆分为两个不同的树:T1和T2,以root为单位的节点具有单个最小标签原树树的旧根。

所以碰巧我肯定会有一个树有两个子树,另一个有一个子树,所以我可以将新插入的项添加到这个子树中,并将它作为newtree的新根用高度增加一级。

是不是?我不确定这个...

在这本书中,我找到了对 ins 谓词的三个具体案例的解释,我对它的工作方式有很多疑问:

案例1:

ins(n2(T1, M , T2), X, n2(NT1, M, T2)) :- gt(M, X),
                                          ins(T1, X, NT1).

这个案例告诉我原始树是: n2(T1,M,T2)我将X插入树中,这是一棵只有 2个子树:T1和T2。

M 右边的最低元素

因此,如果 gt(M,X)为TRUE,则表示M> X,因此这意味着X可能是 LEFT SUBTREE ,变为 NT1 < / strong>(为什么?它可能取决于旧T1在其子树中只有一片叶子的事实?)因此,最后,原始树变为 n2(NT1,M,T2)< /强>

我认为这种情况很简单

案例2:

ins(n2(T1, M, T2), X, n3(NT1a, Mb, NT1b, M, T2)) :- gt(M, X),
                                                    ins(T1, X, NT1a, Mb, NT1b).

此案例告诉我,原始树是: n2(T1,M,T2),我将X插入树只是一棵树 2个子树:T1和T2。

M 右边的最低元素

如果它是真的M> X并且这是正确的谓词: ins(T1,X,NT1a,Mb,NT1b)

这意味着我将T1拆分为2个子树NT1a和NT1b将第三个子项添加到原始树 n3(NT1a,Mb,NT1b,M,T2)

好的,这很清楚,但我的问题是:在完整的代码中,这个谓词必须要满足什么?我在混淆......

案例3:

ins(n3(T1, M2, T2, M3, T3), X, n2(NT1a, Mb, NT1b), M2, n2(T2, M3, T3)) :-
                    gt(M2, X),
                    ins(T1, X, NT1a, Mb, NT1b).

这种情况是原始树有三个子树的情况,当我必须插入它时,我必须将原始树分成两个树(n3(T1,M2,T2,M3,T3)和n2( NT1a,Mb,NT1b)),将新项X插入其中一个子树中,并使用第二个子树的最小元素作为左子树的根作为新树的根(现在高于一个级别)

我的疑问是:在前一种情况下, NewTree n2(NT1a,Mb,NT1b),M2,n2(T2,M3,T3)

所以M2(右子树的最小元素)是新根,因为它是真的,M2> X?

你能给我一些提示来更好地理解这些东西吗?

1 个答案:

答案 0 :(得分:1)

首先,有几个风格点。您不需要为n2n3设置单独的构造函数,因为arities将为您处理。其次,你应该怀疑任何削减它的谓词,特别是你在/ 2中使用的红色削减。通常更好(和更快)地进行明确的案例分析。另外,如果可以的话,在第一个参数中进行比较,并将其作为默认情况下的索引。

我在/ 2中重写为

in(leaf(Item), Item).
in(node(Left, M, Right), Item):-
    compare(Order, Item, M),
    in_2(Order, Item, node(Left, M, Right).
in(node(Left, M1, Mid, M2, Right), Item):-
    compare(Order, Item, M1),
    in_3(Order, Item, node(Left, M1, Mid, M2, Right)).

in_2(<, Item, node(Left, _, _)):-
    in(Left, Item).
in_2(=, Item, node(_, _, Right)):-
    in(Right, Item).
in_2(>, Item, node(_, _, Right)):-
    in(Right, Item).

in_3(<, Item, node(Left, _, _, _, _)):-
    in(Left, Item).
in_3(=, Item, node(_, _, Mid, _, _)):-
    in(Mid, Item).
in_3(>, Item, node(Left, M1, Mid, M2, Right)):-
    compare(Order, Item, M2),
    in_3a(Order, Item, node(Left, M1, Mid, M2, Right)).

in_3a(<, Item, node(_, _, Mid, _, _)):-
    in(Mid, Item).
in_3a(=, Item, node(_, _, _, _, Right)):-
    in(Right, Item).
in_3a(>, Item, node(_, _, _, _, Right)):-
    in(Right, Item).

至于树插入,它比我想象的要复杂得多。

2-3棵树的一个关键特征是所有叶子都处于相同的深度。这意味着,当您插入项目时,您必须遍历树以查找需要插入树叶的位置,然后将更改传播回树中以确保其保持平衡。这些slides from a data structures lecture概述了算法。尝试将它们翻译成Prolog。幻灯片清楚地列出了不同的案例。我上面给出的示例代码应该可以帮助您完成插入算法的第一阶段(找到正确的底层节点来插入新的叶子)。当你重新开始工作时,采用相同的方法。