【ProLog】6.0 List进阶

【append/3 连接两个List】
我们将定义一个重要的谓词append / 3,其参数均为列表
如果列表L3是将列表L1和L2串联在一起的结果,则append(L1,L2,L3)为true

?- append([a,b,c,d],[3,4,5],[a,b,c,d,3,4,5]).
   yes 
?- append([a,b,c],[3,4,5],[a,b,c,d,3,4,5]).
   no

如果我们将第三个变量设置变量,则可以得到前两个List连接后的结果

?- append([a,b,c,d],[1,2,3,4,5], X). 
    X=[a,b,c,d,1,2,3,4,5]
    yes  

append/3的内部定义

append([ ], L, L).
append([H|L1], L2, [H|L3]):-append(L1, L2, L3). 

基本:将空列表附加到任何列表会产生相同的列表
递归步骤:当将非空列表[H | T]与列表L连接起来时,结果是一个具有头H的列表以及连接了T和L的结果
搜索图如下

Tips:
在append/3中,实质上所有的递归都是在第一个参数中进行的,所以当我们把元素更少的列表设置成第一个参数,可以帮助我们更快地进行运算(在不关心列表中的元素的顺序的时候这么干)
如果这样做,它可以帮助提高Prolog代码的效率

【反转列表】

naiveReverse([],[]).  
naiveReverse([H|T],R):- 
                        naiveReverse(T,RT),    
                        append(RT,[H],R). 

这种写法是简单且正确的,不过它进行了过多的append/3运算,降低了效率
下面有一种更好的办法——使用累加器
累加器将是一个列表,当我们开始反转时,它将为空
我们要做的只是选择要反转的列表的头,然后将其添加到累加器列表的头
这么一直进行下去,累加器将会变成我们要的,反转的List

accReverse([ ],L,L).
accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev).

posted @ 2021-04-19 23:01  RetenQ  阅读(94)  评论(0编辑  收藏  举报