我试图将Prolog中的列表分成3个相等的部分(......尽可能相等)。 我的算法如下:
程序如下:
有4个参数:
div3(InitialList,FirstNewList,SecondNewList,ThirdNewList).
有2个额外参数:
div3(InitialList,FirstList,SecondList,ThirdList,InitialListSize,Counter).
这是我的代码:
div3([],[],[],[]).
div3([X],[X],[],[]).
div3([X,Y],[X],[Y],[]).
div3([X,Y,Z],[X],[Y],[Z]).
div3([X | Y],A,B,C) :- length([X | Y],Sz),
Sz1 is 0,
div3([X | Y],A,B,C,Sz,Sz1).
div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < Sz//3, % am I done adding to the 1st list?
append(X,L,A), % add to the 1st list
Sz2 is Sz1+1, % increment the counter
div3(Y,L,B,C,Sz,Sz2),!.
div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < 2*Sz//3, % am I done adding to the 2nd list?
append(X,L,B), % add to the 2nd list
Sz2 is Sz1+1, % increment the counter
div3(Y,A,L,C,Sz,Sz2),!.
div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < Sz, % am I done adding to the 3rd list?
append(X,L,C),% add to the 3rd list
Sz2 is Sz1+1, % increment the counter
div3(Y,A,B,L,Sz,Sz2),!.
答案 0 :(得分:1)
我认为代码的第一部分几乎是正确的...... 你正在寻找的是一个带有3个基本案例和一个递归子句的递归谓词。
div3([], [], [], []).
div3([X], [X], [], []).
div3([X,Y], [X], [Y], []).
div3([X,Y,Z|Tail], [X|XTail], [Y|YTail], [Z|ZTail]):-
div3(Tail, XTail, YTail, ZTail).
答案 1 :(得分:0)
在递归谓词div3 / 5的代码中没有结束情况,前3个子句仅适用于div3 / 3调用(这就是为什么调用div3([4,2,42],X,Y) ,Z)成功)
另外,你用一个元素而不是一个列表来调用append / 3,所以它失败了(除非你有一个列表但是在这种情况下,它不是你想要的)
我建议切换到更“声明”的方法,可能使用get_N_elements(List,List_N,Rest)之类的谓词来避免代码重复
答案 2 :(得分:0)
如果维护源顺序无关紧要,以下就足够了。
divide( [] , [] , [] , [] ) . % we're done when the source list is exhausted, OR ...
divide( [X] , [X] , [] , [] ) . % - it's only got 1 element, OR ...
divide( [X,Y] , [X] , [Y] , [] ) . % - it's only got 2 elements
divide( [X,Y,Z|T] , [X|Xs] , [Y|Ys] , [Z|Zs] ) :- % otherwise, split three elements amount the result lists and
divide(T,Xs,Ys,Zs) % - recurse down.
. %
上面的代码对列表进行分区
[a,b,c,d,e,f,g]
到
[a,d,g]
[b,e]
[c,f]
如果您希望维护订单,这将有效,描述什么构成正确的解决方案(例如,长度列表尽可能相等)并让append/3
找到正确的解决方案:
divide( L , X , Y , Z ) :-
append(X,T,L) , % split X off as a prefix of the source list L
append(Y,Z,T) , % divide the remainder (T) into a prefix Y and suffix Z
length(X,X1) , % compute the length of X
length(Y,Y1) , % compute the length of Y
length(Z,Z1) , % compute the length of Z
min_max([X1,Y1,Z1],Min,Max) , % determine the shortest and longest such length
Max - Min =< 1 , % and ensure that the delta is 1 or less
.
min_max([],0,0) .
min_max([H|T],Min,Max) :-
min_max(T,H,H,Min,Max)
.
min_max([],Min,Max,Min,Max) .
min_max([H|T], T1 , T2 , Min , Max ) :-
( H < T1 -> T3 = H ; T3 = T1 ) ,
( H > T2 -> T4 = H ; T4 = T2 ) ,
min_max(T,T3,T4,Min,Max)
.
以上基本上说
将列表L分为3个子列表X,Y和Z,使得长度之间的差值为 每个子列表不超过1个。
在这种情况下,您应该看到列表
[a,b,c,d,e,f,g]
分为
[a,b]
[c,d]
[e,f,g]
应该注意到这是非确定性的,回溯将找到所有可能的解决方案。