集合及其运算-prolog

 
通常我们用表结构来表示集合。集合与表的差别在于:集合中不容许包含重复元素,例如,[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).
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值