您的位置:首页 > 其它

集合及其运算-prolog

2007-11-30 17:46 260 查看
集合及其运算
基本集合运算谓词
通常我们用表结构来表示集合。集合与表的差别在于:集合中不容许包含重复元素,例如,[1,2,4,3]是一个集合,而[1,1,2,4,3]不是一个集合,它包含两个1。
集合元素的枚举可以采用表元素的枚举谓词member(X, L),而一个元素是否属于集合的判断谓词可以采用表元素的判断谓词is_member(X,L)。
(1)表元素的唯一化
为了将一个表变成一个集合,需要对表中元素进行唯一化处理,即同一元素,只能在集合中出现一次。定义表的唯一化谓词unique(L,S)为:将表L进行唯一化处理,得到集合S。
unique的谓词定义如下:
unique([X|L], S):-
is_member(X, L), !,
unique(L, S).
unique([X|L], [X|S]):-
unique(L, S).
unique([], []).
第一个子句的含义为:若表[X|L]中X为L的元素,即X在表[X|L]中重复出现,则丢弃X,直接对L进行唯一化处理;cut操作是为了下面的子句中不必再进行X是否L元素的判断。
第二个子句的含义为:若X不是L的一个元素,即X是表[X|L]中的唯一元素,这样,就将X放入集合中,并进而对L进行唯一化处理。
第三个子句的含义为:空表唯一化后的结果为空集。

(2)集合的差集
两个集合差集的定义如下:
S1-S2={X|X∈S1且X/∈S2}
判别的方法为:若S1为空集,则差集亦为空集;对于集合[X|S1]中的一个元素X,若X∈S2,则X不属于S1-S2,[X|S1]-S2=S1-S2;若X不属于S2,则[X|S1]-S2=[X|S1-S2]。
递归计算的Prolog程序为:
diff([X|S1], S2, S):-
is_member(X, S2), !,
diff(S1, S2, S).
diff([X|S1], S2, [X|S]):-
!, diff(S1, S2, S).
diff([], _, []).
(3)集合的并集
两个集合并集的定义如下:
S1∪S2={X|X∈S1或者X∈S2}
求两个集合并集的最简单办法是:将两个集合作为表append在一起,然后对结果进行唯一化处理,相应的子句为:
union(S1, S2, S):-
append(S1, S2, S0),
unique(S0, S).
也可以先求子集S1和S2的差集(S1-S2),然后将其与集合S2 append在一起。由于S1-S2与S2不相交,因此,结果构成一个集合。即
S1∪S2=(S1-S2) ∪S2
(S1-S2) ∩S2=Φ
相应的Prolog程序为:
union(S1, S2, S):-
diff(S1, S2, S0),
append(S0, S2, S).
可以将求差集的过程嵌入到上面的子句中,从而形成下面的程序:
union([X|S1], S2, S):-
is_member(X, S2), !,
union(S1, S2, S).
union([X|S1], S2, [X|S]):-
!, union(S1, S2, S).
union([], S, S).
(3)集合的交集
两个集合并集的定义如下:
S1∩S2={X|X∈S1且X∈S2}
Prolog程序如下:
intersect([], _, []):-!.
intersect([X|S1], S2, [X|S]):-
is_member(X, S2), !,
intersect(S1, S2, S).
intersect([_|S1], S2, S):-
intersect(S1, S2, S).
(4)集合的异或
两个集合并集的定义如下:
S1⊕S2=(S1-S2)∪(S2-S1)
由于(S1-S2)∩(S2-S1)=Φ,因此,将S1-S2、S2-S1 直接append在一起就构成了 (S1-S2)∪(S2-S1)。
Prolog程序如下:
disjoint(S1, S2, S):-
diff(S1, S2, S3),
diff(S2, S1, S4),
append(S3, S4, S).
(5)子集的判断
我们称集合S1是集合S2的子集,如果S1的每个元素同时是S2的元素,记为S1≤S2。
其判断程序为:
is_subset([X|S1], S2):-
is_member(X, S2),
is_subset(S1, S2).
is_subset([], _).
(6)两个集合相等的判断
两个集合相等,若集合S1中的每一个元素,同时是S2中的元素,且S2中的每个元素,也是S1中的元素,即:
S1=S2 iff S1≤S2且S2≤S1
因此,判断两个集合相等的Prolog程序为:
equal(S1, S2):-
is_subset(S1, S2),
is_subset(S2, S1).
~~~~~~~~~~~~~~~~~~~~~~~~~~~
提高集合运算效率的一种有效途径是对集合元素进行排序处理。例如,如果按从小到大排列集合元素,集合运算判断谓词可以加速:
is_member(X, [X|_]):-!.
is_member(X, [Y|S]):-Y < X, is_member(X, S).
有序集的元素枚举可以直接采用表元素枚举谓词。
在下面计算有序集的各类谓词中,均假设集合按从小到大的次序进行排列。
(1)有序集的并
union([X|S1], [Y|S2], [X|S]):-X < Y, !, union(S1, [Y|S2], S).
union([X|S1], [X|S2], [X|S]):-!, union(S1, S2, S).
union(S1, [Y|S2], [Y|S]):-!, union(S1, S2, S).
union([], S, S):-!.
union(S, [], S).
(2)有序集的交
intersect([X|S1], [Y|S2], S):-X < Y, !, intersect(S1, [Y|S2], S).
intersect([X|S1], [X|S2], [X|S]):-!, intersect(S1, S2, S).
intersect(S1, [_|S2], S):-!, intersect(S1, S2, S).
intersect([], _, []):-!.
intersect(_, [], []).
(3)有序集的差
diff([X|S1], [X|S2], S):-!, diff(S1, S2, S).
diff([X|S1], [Y|S2], S):-X > Y, !, diff([X|S1], S2, S).
diff([X|S1], S2, [X|S]):-!, diff(S1, S2, S).
diff(S, [], S):-!.
diff([], _, []).
(4)有序集的异或
disjoint([X|S1], [X|S2], S):-!, disjoint(S1, S2, S).
disjoint([X|S1], [Y|S2], [Y|S]):-X > Y, !, disjoint([X|S1], S2, S).
disjoint([X|S1], S2, [X|S]):-!, disjoint(S1, S2, S).
disjoint(S, [], S):-!.
disjoint([], _, []).
(5)有序集的子集判断
is_subset([], _).
is_subset([X|S1], [Y|S2]):-
X > Y, !,
is_subset([X|S1], S2).
is_subset([X|S1], [X|S2]):-
is_subset(S1, S2).
(6)有序集相等判断
equal(S, S).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: