prolog - bst tree to list

2019-09-06 07:44发布

问题:

I am pracising dcg technique, but I have a problem. I am going to implement converting BST tree to list (each possible) and in reversed side - list ot bst (each possible). (List means set in real here).
However,
this grammar should be ok, but it generates very much duplicates. I know cause (nil), but I can't deal with it.

 bstToList(nil) --> [].
    bstToList(t(Root, L, R)) --> [Root], bstToList(L), bstToList(R).
    bstToList(t(Root, L, R)) --> [Root], bstToList(R), bstToList(L).
    bstToList(t(Root, L, R)) -->  bstToList(R), [Root], bstToList(L).
    bstToList(t(Root, L, R)) -->  bstToList(L), [Root], bstToList(R).
    bstToList(t(Root, L, R)) --> bstToList(L), bstToList(R), [Root].
    bstToList(t(Root, L, R)) --> bstToList(R), bstToList(L), [Root].

Could you help me ?

回答1:

The problem with how you've implemented it is that you are commingling each traversal method at each traversal step. In other words, at each traversal step, your predicate will explore every traversal method.

You need to break them out at a higher level:

bst_to_list(BST, Ls) -->
    bst_to_list_pre_LR(BST, Ls, _) |
    bst_to_list_pre_RL(BST, Ls, _) |
    bst_to_list_in_LR(BST, Ls, _) |
    bst_to_list_in_RL(BST, Ls, _) |
    bst_to_list_post_LR(BST, Ls, _) |
    bst_to_list_post_RL(BST, Ls, _).

Then implement each type individually:

% Pre-order, left-to-right
bst_to_list_pre_LR(nil, Es, Es) --> [].
bst_to_list_pre_LR(t(Root, L, R), [_|Es0], Es) -->
    [Root],
    bst_to_list_pre_LR(L, Es0, Es1),
    bst_to_list_pre_LR(R, Es1, Es).

% Pre-order right-to-left
bst_to_list_pre_RL(nil, Es, Es) --> [].
bst_to_list_pre_RL(t(Root, L, R), [_|Es0], Es) -->
    [Root],
    bst_to_list_pre_RL(R, Es0, Es1),
    bst_to_list_pre_RL(L, Es1, Es).

... % Etc...

Also, read again carefully @mat's answer to your prior question, Prolog, reconstruct BST trees from inorder list, since there are useful techniques presented there for a more robust solution for each of these cases. I've incorporated that technique in the above code.

Note that you still may get duplicates since, some trees can yield the same results when traversed in different ways.


In light of the comments, it appears that a solution is sought to define a relation between a BST and a list of nodes such that the order in the BST could be arbitrary. Since the ordering could be anything, it doesn't lend itself well to a DCG. Here is a possible non-DCG solution:

bst_list_all(BST, L) :-
    tree_list_bound(BST, L, _),
    bst_list_all_(BST, L).

bst_list_all_(nil, []).
bst_list_all_(t(Root, L, R), Es) :-
    select(Root, Es, Es1),
    append(Ls, Rs, Es1),
    bst_list_all_(L, Ls),
    bst_list_all_(R, Rs).

tree_list_bound(nil, [], []).
tree_list_bound(t(_, L, R), [_|Es0], Es2) :-
    tree_list_bound(L, Es0, Es1),
    tree_list_bound(R, Es1, Es2).
tree_list_bound(t(_, L, R), [_|Es0], Es2) :-
    Es0 = [_|_],
    tree_list_bound(R, Es0, Es1),
    tree_list_bound(L, Es1, Es2).

The predicate tree_list_bound establishes a bounded framework for the solution to avoid termination issues. It "feels" like this solution could be condensed, but I haven't yet found a way to do it. However, it does seem to provide a solution to the revealed question without yielding duplicate solutions.

?- bst_list_all(t(1,nil,t(2,t(3,nil,nil),nil)), L).
L = [1, 2, 3] ;
L = [1, 3, 2] ;
L = [2, 1, 3] ;
L = [3, 1, 2] ;
L = [2, 3, 1] ;
L = [3, 2, 1] ;
false.

?- bst_list_all(BST, [1,2,3]).
BST = t(1, t(2, t(3, nil, nil), nil), nil) ;
BST = t(1, t(3, t(2, nil, nil), nil), nil) ;
BST = t(2, t(1, t(3, nil, nil), nil), nil) ;
BST = t(2, t(3, t(1, nil, nil), nil), nil) ;
BST = t(3, t(1, t(2, nil, nil), nil), nil) ;
BST = t(3, t(2, t(1, nil, nil), nil), nil) ;
BST = t(1, t(2, nil, t(3, nil, nil)), nil) ;
BST = t(1, t(3, nil, t(2, nil, nil)), nil) ;
BST = t(2, t(1, nil, t(3, nil, nil)), nil) ;
BST = t(2, t(3, nil, t(1, nil, nil)), nil) ;
BST = t(3, t(1, nil, t(2, nil, nil)), nil) ;
BST = t(3, t(2, nil, t(1, nil, nil)), nil) ;
BST = t(1, nil, t(2, t(3, nil, nil), nil)) ;
BST = t(1, nil, t(3, t(2, nil, nil), nil)) ;
BST = t(2, nil, t(1, t(3, nil, nil), nil)) ;
BST = t(2, nil, t(3, t(1, nil, nil), nil)) ;
BST = t(3, nil, t(1, t(2, nil, nil), nil)) ;
BST = t(3, nil, t(2, t(1, nil, nil), nil)) ;
BST = t(1, nil, t(2, nil, t(3, nil, nil))) ;
BST = t(1, nil, t(3, nil, t(2, nil, nil))) ;
BST = t(2, nil, t(1, nil, t(3, nil, nil))) ;
BST = t(2, nil, t(3, nil, t(1, nil, nil))) ;
BST = t(3, nil, t(1, nil, t(2, nil, nil))) ;
BST = t(3, nil, t(2, nil, t(1, nil, nil))) ;
false.

?-


标签: prolog dcg