Некоторые сомнения в реализации Пролога 2-3 Словаря

Я изучаю Prolog с использованием SWI Prolog, и у меня есть некоторые сомнения в том, как работать с этой реализацией словаря 2-3 в Prolog.

Я знаю теорию словаря 2-3, которые являются деревьями, внутренние узлы которых могут генерировать 2 или 3 поддеревья, обладающие следующими свойствами:

1) Все элементы хранятся в листьях и упорядочены от меньшего до большего

2) Все листы находятся на одном уровне

3) Внутренние узлы не содержат вставленный элемент, но содержат метку, которая указывает минимальные элементы поддеревьев следующим образом:

  • Если внутренний node имеет 2 поддерева, метка в этом внутреннем node содержит МИНИМАЛЬНЫЙ ЭЛЕМЕНТ ПРАВИЛЬНОГО SUBTREE (так что если я ищу элемент X, который меньше, чем метка, я уверен, что это в левом поддереве)
  • Если внутренний node имеет 3 поддеревья, метка в этом внутреннем node содержит 2 значения: M2 и M3, где M1 - МИНИМАЛЬНОЕ ЗНАЧЕНИЕ, которое присутствует в SUBTREE CENTER, а M3 - МИНИМАЛЬНОЕ ЗНАЧЕНИЕ, которое является правое поддерево

Итак, поиск, если элемент существует в этом словаре, довольно прост.

Вставка сложнее, я понимаю ее теорию, но у меня есть только некоторые проблемы с интерпретацией Prolog.

Это моя программа (возьмите книгу Ивана Братко: "Программирование для искусственного интеллекта" ):

/* 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) представляет дерево с двумя поднаборами T1 и T2, где M - минимальный элемент в T2
  • n3 (T1, M2, T2, M3, T3) ** представляет дерево с тремя поддеревьями: 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 поддерева и вставляя новый элемент, который я создаю новое поддерево, которое имеет свои листья на том же уровне, что и все остальные (и поэтому внутренний node теперь будет иметь 2 метки). Правильно ли это?

Итак, в логике я могу прочитать это как: если предикат ins (Tree, X, Tree1) имеет значение TRUE, тогда я добавляю X в Tree, генерируя новое дерево1, имеющее ту же самую высоту старого Дерево, но содержит элемент X (поэтому он должен иметь внутренний node, имеющий 3 дочерних элемента)

Второй случай связан в случае с wicht. У меня есть дерево, и мне нужно вставить новый элемент в node тот, у которого уже есть три поддерева, поэтому мне нужно разбить старое дерево на 2 дерева, которые как root имеют как метку, так и одну метку, взятую из двух ярлыков старого оригинала node. Поэтому я могу вставить новый элемент в виде листа и как новый корень нового дерева.

Итак, в логике я могу читать его как:

Если предикат ins (Tree, X, T1, M2, T2) имеет значение TRUE, это означает, что это TRUE предикат: add23 (Дерево, X, n2 (T1, M2, T2))

Это тот случай, когда я разделил исходное дерево Tree с 3 поддеревами на два разных дерева: T1 и T2, которые с правами root имеют node с одной минимальной меткой возьмите из старого корня исходного дерева Tree.

Итак, я уверен, что у одного из этих деревьев будет два поддерева, а у другого - одно поддерево, поэтому я могу добавить новый вставленный элемент в это поддерево, а также использовать его как новый корень newtree который увеличивается по высоте на один уровень.

Правильно ли это? Я не уверен в этом...

В книге я нашел объяснение трех конкретных случаев предиката ins, и у меня есть много сомнений в том, как это работает:

CASE 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 является МИНИМАЛЬНЫМ ЭЛЕМЕНТОМ ПРАВИЛЬНОГО SUBTREE

Итак, если gt (M, X) ИСТИНА, это означает, что M > X, поэтому это означает, что X может быть LEFT SUBTREE, который стал NT1(почему? возможно, это зависит от того, что старый T1 имеет только один лист в одном из его поддеревьев?), и поэтому в конце исходное дерево стало n2 (NT1, M, T2)

Я думаю, что этот случай прост

CASE 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 является МИНИМАЛЬНЫМ ЭЛЕМЕНТОМ ПРАВИЛЬНОГО SUBTREE

ЕСЛИ это ИСТИНА, что M > X, и это TRUE предикат: ins (T1, X, NT1a, Mb, NT1b)

это означает, что я разбил T1 на 2 поддерева NT1a и NT1b, добавив третий дочерний элемент в исходное дерево, которое стало n3 (NT1a, Mb, NT1b, M, T2)

Хорошо, это довольно ясно, но моя проблема заключается в следующем: в полном коде, что такое предикат, который должен удовлетворять? Я делаю путаницу...

CASE 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).

Этот случай - это случай, когда исходное дерево Tree имеет 3 поддеревья, и когда мне нужно его вставить, я должен разбить исходное дерево на два дерева (n3 (T1, M2, T2, M3, T3) и n2 ( NT1a, Mb, NT1b)), вставьте новый элемент X в одно из этих поддеревьев и используйте минимальные элементы второго поддерева как корень левого поддерева как корень нового дерева (который теперь выше уровня)

Я сомневаюсь: в предыдущем случае NewTree - n2 (NT1a, Mb, NT1b), M2, n2 (T2, M3, T3)

так что M2 (минимальный элемент правого поддерева) является новым корнем, потому что он TRUE, что M2 > X?

Можете ли вы дать мне несколько советов, чтобы лучше понять эту вещь?

4
задан AndreaNobili 07 мая '13 в 19:45
источник поделиться
1 ответ

Во-первых, несколько точек стиля. Вам не нужно иметь отдельные конструкторы для n2 и n3, так как арки будут иметь дело с этим для вас. Во-вторых, вы должны быть подозрительны к любому предикату, у которого есть сокращения, особенно красные сокращения, которые вы используете в /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 деревьев состоит в том, что все листья находятся на одной и той же глубине. Это означает, что когда вы вставляете элемент, вам нужно пройти по дереву, чтобы найти, где среди листьев вам нужно вставить его, а затем распространять изменения, поддерживая дерево, чтобы он оставался сбалансированным. Эти слайды из лекции по структурам данных описывают алгоритм. Попробуйте просто перевести их в Prolog. Слайды четко излагают, что такое разные случаи. Код примера, который я дал выше, должен помочь вам с первой фазой алгоритма вставки (найти правильный нижний уровень node для вставки нового листа). Используйте тот же подход, когда вы работаете с деревом.

1
ответ дан Neil Smith 18 июля '14 в 2:18
источник поделиться

Другие вопросы по меткам