Некоторые сомнения в реализации Пролога 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) предикат TRUE, если искомый элемент находится в указанном Tree */

% BASE CASE: Предмет, найденный в листе, поэтому конец
in (Item, l (Item)).

/* CASE 1: Я ищу элемент во внутреннем node, имеющем одно значение метки          поэтому этот внутренний node имеет 2 поддеревья
*/
in (Item, n2 (T1, M, T2)): - gt (M, Item),% IF Значение метки метки лексикографически соответствует найденному значению Item                        !,                        in (Item, T1)% THEN Элемент поиска в левом поддереве                        ; % (; является OR)                        в (п, Т2). % В противном случае поиск позиции в правом поддереве

/* CASE 2: Я ищу Intem во внутреннем node, имеющем 2 значения метки, так что это          внутренний node имеет 3 поддерева
*/

in (Item, n3 (T1, M2, T2, M3, T3)): - gt (M2, Item), значение IF IF M2 лексикографически соответствует найденному значению Item                               !,                               in (Item, T1)% THEN Элемент поиска в левом поддереве                               ; % (; является OR)                               /* IF M3 значение метки лексикографически соответствует найденному значению Item                                  НО это НЕ ИСТИНА, что M2 > Элемент                               */                               GT (М3, позы),                               !,                               in (Item, T2)% THEN Пункт поиска в центральном поддереве                               ; % (; является OR)                               в (п, Т3). % ELSE (истинно, что Item > M3) поиск в правом поддереве


/*
*/

% Вставка в словарь 2-3

/* Добавить X в Дерево, дающее Tree1  СЛУЧАЙ 1: После вставки X в Дерево Tree1 не растет вверх (значит, это означает, что внутренние узлы          имея 2 дочерних поддерева, теперь имеет 3 дочерних элемента поддерева, поэтому исходное дерево выросло в ширину)
*/
add23 (Дерево, X, Дерево 1): - ins (Дерево, X, Дерево 1).

/* CASE 2: Дерево растет вверх: это означает, что если после вставки X высота нового дерева          так что предикат ins/5 определяет два поддерева T1 и T2, которые затем объединены          в большее дерево
*/
add23 (Дерево, X, n2 (T1, M2, T2)): - ins (Дерево, X, T1, M2, T2).

del23 (Дерево, X, Дерево 1): - add23 (Дерево1, X, Дерево). % Удалить X из дерева, дающего Tree1


/* BASE CASE: Вставка элемента X в дерево voil (nil) означает получение дерева             состоящий из единственного нового листа l (X)
*/
ins (nil, X, l (X)).

/* BASE CASES: относится к вставке нового элемента X в дерево, составленное              один лист
*/
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), так что дерево - это дерево, имеющее 2 поддеревья T1 и T2  M: является МИНИМАЛЬНЫМ ЭЛЕМЕНТОМ T2
  ЕСЛИ это ИСТИНА, M > X (минимальный элемент в T2 является > новым элементом X)  Мне нужно вставить X в LEFT-поддеревьях (в T1, который становится NT1 и  теперь есть 2 листа)
*/
ins (n2 (T1, M, T2), X, n2 (NT1, M, T2)): - gt (M, X),                                         ins (T1, X, NT1).


/* Tree = n2 (T1, M, T2), так что дерево - это дерево, имеющее 2 поддеревья T1 и T2  M: является МИНИМАЛЬНЫМ ЭЛЕМЕНТОМ T2.
  ЕСЛИ это ИСТИНА, M > X (минимальный элемент в T2 является > новый элемент X) и  ЕСЛИ я могу вставить
*/
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)):  (X, M),  ins (T2, X, NT2a, Mb, NT2b).


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

/* Tree = n3 (T1, M2, T2, M3, T3), поэтому Tree - это дерево, имеющее 3 поддерева: T1, T2 и T2  и ROOT дерева - это node (M2, M3)
  M2: МИНИМАЛЬНЫЙ ЭЛЕМЕНТ поддерева T2  M3: МИНИМАЛЬНЫЙ ЭЛЕМЕНТ поддерева T3
  Если бы у меня был элемент X, то Дерево должно расти в высоту
  ЕСЛИ это ИСТИНА, что M2 > X Я мог бы попытаться вставить элемент X в поддерево T1  ЕСЛИ он ИСТИНА, что X добавляется в T1, а T1 разделяется на NT1a и NT1b с корнем Mb
  поэтому новое дерево: 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)):                   (M2, X),                   ins (T1, X, NT1a, Mb, NT1b).ins(n3 (T1, M2, T2, M3, T3), X, n3 (T1, M2, NT2, M3, T3)):  (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)):  (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)):  (X, M3),  (T3, X, NT3).

(n3 (T1, M2, T2, M3, T3), X, n2 (T1, M2, T2), M3, n2 (NT3a, Mb, NT3b)):  (X, M3),  (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, которые:

 /* Добавить X в Дерево, дающее Tree1  СЛУЧАЙ 1: После ввода X в Дерево Tree1 не растет вверх (значит, это означает, что внутренние узлы          имея 2 дочерних поддерева, теперь имеет 3 дочерних элемента поддерева, поэтому исходное дерево выросло в ширину)
*/
add23 (Дерево, X, Дерево 1): - ins (Дерево, X, Дерево 1).

/* CASE 2: Дерево растет вверх: оно мешает, что если после вставки X высота нового дерева будет          так что предикат ins/5 определяет два поддерева T1 и T2, которые затем объединяются          в большее дерево
*/
add23 (Дерево, X, n2 (T1, M2, T2)): - ins (Дерево, X, T1, M2, T2).
Код>

Как пишут в комментариях, я думаю, что первый из них связан с случаем, когда новое дерево не растет вверх (так, например, у меня было дерево, содержащее 2 поддерева и вставляя новый элемент, который я создаю новое поддерево, которое имеет свои листья на том же уровне, что и все остальные (и, следовательно, внутренний node теперь будет иметь 2 метки). Правильно ли это?

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

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

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

Если предикат 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)):                   (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 (узел (левый, M, правый), элемент): -   сравнить (Order, Item, M),   in_2 (Order, Item, node (Left, M, Right).
in (узел (левый, M1, средний, M2, правый), элемент): -   сравнить (Order, Item, M1),   in_3 (Order, Item, node (Left, M1, Mid, M2, Right)).

in_2 (<, Item, node (Left, _, _)): -   в (слева, элемент).
in_2 (=, Item, node (_, _, Right)): -   в (справа, пункт).
in_2 (>, Item, node (_, _, Right)): -   в (справа, пункт).

in_3 (<, Item, node (Left, _, _, _, _)): -   в (слева, элемент).
in_3 (=, Item, node (_, _, Mid, _, _)): -   в (Середина, Позиция).
in_3 (>, Item, node (Left, M1, Mid, M2, Right)): -   сравнить (Order, Item, M2),   in_3a (Order, Item, node (Left, M1, Mid, M2, Right)).

in_3a (<, Item, node (_, _, Mid, _, _)): -   в (Середина, Позиция).
in_3a (=, Item, node (_, _, _, _, Right)): -   в (справа, пункт).
in_3a (>, Item, node (_, _, _, _, Right)): -   в (справа, пункт).
Код>

Что касается вставки дерева, это немного сложнее, чем я думаю, вы поняли.

Одна из ключевых особенностей 2-3 деревьев состоит в том, что все листья находятся на одной и той же глубине. Это означает, что когда вы вставляете элемент, вам нужно пройти по дереву, чтобы найти, где среди листьев вам нужно вставить его, а затем распространять изменения, поддерживая дерево, чтобы он оставался сбалансированным. Эти слайды из лекции структур данных описать алгоритм. Попробуйте просто перевести их в Prolog. Слайды четко излагают, что такое разные случаи. Код примера, который я дал выше, должен помочь вам с первой фазой алгоритма вставки (найти правильный нижний уровень node для вставки нового листа). Используйте тот же подход, когда вы работаете с деревом.

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

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