2017-05-09 102 views
0

我指點一下這個練習:序言插入到一個列表

寫方法插入,其中有3個參數,第一個有序 列表,第二一個int和第三有序列表,而無需重複 值等於與第一個但含有第二個參數。

例子:

> insert([5, 6, 30, 60, 90], 40, L) 
L = [5, 6, 30, 40, 60, 90] 

> insert([5, 6, 30, 60, 90], 30, L) 
L = [5, 6, 30, 60, 90] 

我會做:

insert([],_,[_]). 

insert([H],_,Result) :- 
Result < H, 
insert([],[],[Result|H]). 
insert([H],_,Result) :- 
Result > H, 
insert([],[],[H|Result]). 

insert([H,Y|Rest], _, Result):- 
_ < Y, 
insert([X|Rest], [], Result). 
insert([H,Y|Rest], _, Result):- 
_ > Y, 
insert([Y|Rest], [], Result). 

但我覺得基本情況時,只有一個元素是多餘的,沒有必要的,因爲我們有一般遞歸案例和空列表之一。我需要一些建議來改進或更好的解釋來打磨代碼。 謝謝你的時間。

+1

你不恰當地使用匿名變量('_'),您應使用一個真正的命名變量。當你不關心它是如何綁定的時候,使用匿名變量。使用'insert([],X,[X])'以及'insert([H,Y | Rest],X,Result): - X lurker

+0

謝謝lurker爲你解釋,現在我意識到_有它自己的含義,當我需要綁定變量的值時,我需要使用以大寫字母開頭的字符串。 – Enoy

回答

0

另一種方式:

% First element of the list is smaller than V 
% we keep on wth the rest of the list 
insert([H | T], V, [H|V1]) :- 
    H < V, !, % remove choice points 
    insert(T, V, V1). 

% First element of the list is equal than V 
% insert([V | T] , V, [V|T]). 
% corrected after **enoy** remark 
insert([V | T] , V, [V|T]):- !. 

% First element of the list is greater than V, found the place of V 
insert([H | T] , V, [V,H|T]). 

% insert V in an empty list (V is greater than all elements of the list) 
insert([], V, [V]). 

與相同的結果Users9213答案。

編輯避免切割的方法是

% First element of the list is smaller than V 
% we keep on with the rest of the list 
insert([H | T], V, [H|V1]) :- 
    H < V, 
    insert(T, V, V1). 

% First element of the list is equal than V 
insert([V | T] , V, [V|T]). 

% First element of the list is greater than V, found the place of V 
insert([H | T] , V, [V,H|T]):- 
    H > V. 

% insert V in an empty list (V is greater than all elements of the list) 
insert([], V, [V]). 
+0

謝謝joel76的照顧和明確回答以及評論。只是一個建議,如果你查詢:insert([1],1,L)。結果會輸出兩個語句:L = [1]; L = [1,1]只需使用cut操作符並避免第二個答案。因此該行是插入([V | T],V,[V | T]): - ! 。 – Enoy

+1

@enoy,當然作者的答案,爲什麼有切?這是沒有必要的(這是必要的,但在一般情況下並非必要),這也是錯誤的:你能看到如何? – 2017-05-10 06:48:33

2

嘗試用比較:

:- use_module(library(clpfd)). 

insert([], X, [X]). 
insert([X|Xs], New, Ys) :- 
    zcompare(Order, X, New), 
    insert(Order, X, New, Xs, Ys). 

insert(>, X, New, Xs, [New,X|Xs]). 
insert(=, X, _, Xs, [X|Xs]). 
insert(<, X, New, Xs, [X|Ys]) :- 
    insert(Xs, New, Ys). 

但也許你需要解釋嗎?令人奇怪的是,因爲你也可以只閱讀文檔,像我一樣,發現這是爲什麼足夠好實現,當然也許這是好事,說明更多的,以防萬一。

insert([], X, [X]). 

當第一個參數爲空列表,第二個參數是結果列表的唯一元素。

insert([X|Xs], New, Ys) :- 
    zcompare(Order, X, New), ... 

當第一個參數是清單至少有一個元素,取頭元素,並將其與新的元素。之後comparezcompare第一個參數的買賣盤>=<(但是這分別意味着什麼?也許猜到或者甚至閱讀文檔,如果它沒有太多的工作)。

insert(Order, X, New, Xs, Ys). 

比較以訂單和變量的休息之後....

insert(>, X, New, Xs, [New,X|Xs]). 

元素在列表的頭部比新元素大。這意味着結果列表應該有新的元素,然後頭,然後列表的其餘部分。

insert(=, X, _, Xs, [X|Xs]). 

元素在列表的頭是完全一樣的新元素。我們完成了,不需要插入任何東西只是保留原始列表作爲結果。

insert(<, X, New, Xs, [X|Ys]) :- 
    insert(Xs, New, Ys). 

元素在列表的頭部比新元素小:新的元素必須進來結果這個元素之後。因此,我們將當前元素放回列表中,並在列表的其餘部分中搜索New元素的位置。

這麼多的文字,但現在更容易理解什麼代碼說?也許或者不是?

?- insert([5, 6, 30, 60, 90], 40, L). 
L = [5, 6, 30, 40, 60, 90]. 

?- insert([5, 6, 30, 60, 90], 6, L). 
L = [5, 6, 30, 60, 90]. 

?- insert([5, 6, 30, 60, 90], 100, L). 
L = [5, 6, 30, 60, 90, 100]. 

?- insert([5, 6, 30, 60, 90], 0, L). 
L = [0, 5, 6, 30, 60, 90]. 

,但因爲它使用像zcompare/3謂詞看起來有點像compare/3但它知道整數約束,因此可以查詢還有更多有趣的事情做與此解決方案:

可以在列表[1,3,4]中插入什麼整數?

?- insert([1,3,4], X, R). 
R = [X, 1, 3, 4], 
X in inf..0 ; 
X = 1, 
R = [1, 3, 4] ; 
X = 2, 
R = [1, 2, 3, 4] ; 
X = 3, 
R = [1, 3, 4] ; 
X = 4, 
R = [1, 3, 4] ; 
R = [1, 3, 4, X], 
X in 5..sup. 

因此,你可以在前面插入任何整數< 1,也可以「插入」 1即在那裏,或者可以插入2 1和3之間,也可以「插入」 3或4 ,或者你可以在列表末尾插入5或更大的東西。