移动列表的两个方向元素,以及它们的GCD。序言

时间:2014-12-08 20:38:13

标签: list rotation prolog elements greatest-common-divisor

我在试图解决Prolog中的2个问题时遇到了麻烦。

这是第一个:  我需要计算列表元素的de gcd

期望:

gdc([3, 9, 6], G).

G=3

这是我尝试这样做的方式:

gdcs(1, _, 1) :- !.
gdcs(_, 1, 1) :- !.
gdcs(0, B, B) :- !.
gdcs(B, 0, B) :- !.
gdcs(X, X, X) :- !.
gdcs(A, B, L) :- A < B, !, L1 = B mod A, gdc(A, L1, L).
gdcs(A, B, L) :- L1 = A mod B, gdcs(B, L1, L).
gdc([], 0).
gdc([H|T], C) :- gdc(T, D), gdcs(D, H, C).

问题是它只在我只引入0或1时有效,对于其他数字,它不起作用。

第二个: 旋转Prolog中的列表,这就是我需要的:

rot([1, 2, 1, 4, 5, 3, 5], Dir, Nr, Res). // Dir = direction(lft,rght), Nr = nr. of elements to shift, Res = List of elements

Res=[1, 4, 5, 3, 5, 1, 2]  // in this case Dir = lft, Nr = 1.

这个我不知道如何实现,在互联网上找到如何只使用一个方向,但这一个,我无法想象。

1 个答案:

答案 0 :(得分:-1)

gcd(a,b,c)= gcd(gcd(a,b),c)。这意味着,为了计算超过2个元素的gcd,您可以先计算两个第一个元素的gcd,然后将其用作递归调用列表中的元素:

% GCD calculation for two numbers
gcd2(A, 0, A).
gcd2(A, B, C) :- 
    A > B, 
    A1 is mod(A,B),
    gcd2(A1, B, C).
gcd2(A, B, C) :- gcd2(B,A,C).


% GCD of a list (the list contains at least two elements)
gcd([A,B], G) :- gcd2(A,B,G).
gcd([A,B|T], G) :-
    gcd2(A,B,A1),
    gcd([A1|T], G).

关于旋转......好的是旋转有效地将列表拆分到某个位置,然后以相反的顺序粘合它。左旋转的位置正好是所需的旋转数,而右边是列表的长度减去数字。解决方案分为拆分规则和两个不同的旋转:

% splitAt (List, Position, Leftpart, Rightpart)
splitAt([],_,[], []).
splitAt(L, 0, [], L).
splitAt([H|T], N, [H|Tleft], Right) :-
    N1 is N-1,
    splitAt(T, N1, Tleft, Right).


rotateLeft(L, N, Res) :- 
    splitAt(L, N, Left, Right),
    append(Right, Left, Res).


rotateRight(L, N, Res) :-
    length(L, Len),
    N1 is Len-N,
    splitAt(L, N1, Left, Right),
    append(Right, Left, Res).

% rot(list, Dir, Nr, Res)
rot(L, lft, N, Res) :- rotateLeft(L, N, Res).
rot(L, rght, N, Res) :- rotateRight(L, N, Res).