之前离散数学课上,老师教了一种列真值表的方式来判断两个集合是否相等,这种方法很机械,非常适合写程序来打表。
集合的部分运算的表示
首先我们需要用计算机能理解的方式表示集合的运算。按照老师上课说的,0和1表示的就是元素是否属于集合,0不属于,1属于,然后接下来看看每个运算的表示方法。
注意,下面计算中任何看起来是集合的东西,表示的都是元素是否在集合中,并不是集合。运算的结果看起来也是集合,但是表示的也是这个元素是否在结果集合中。
补集
首先从最简单的补集开始,根据定义,显然如果x属于A,那么x不属于A的补集,相反x不属于A,那么x一定属于A的补集,画成表应该是下面这样
$A$ | $\overline{A}$ |
---|---|
1 | 0 |
0 | 1 |
可以很明显的看出来,这个就是逻辑运算或者布尔运算里面的“非”运算,用代码来写大概就是这样
1 | //补集运算 |
并集
并集就是把两个集合拼起来,新集合包含两个集合的所有的元素,或者说原本两个集合中的元素都能够在新的集合中找到。
所以显然,如果一个元素属于任意一个集合,那就必定属于这两个集合的交集,这就跟逻辑运算的“或”是一样的
$A$ $B$ | $A \cup B$ |
---|---|
1 1 | 1 |
1 0 | 1 |
0 1 | 1 |
0 0 | 0 |
代码如下
1 | //并集运算 |
交集
看了上面两个例子之后应该可以很容易的推出,交集相当于逻辑运算中的“且”,元素要同时属于两个集合,才会属于两个集合的交集。
$A$ $B$ | $A \cup B$ |
---|---|
1 1 | 1 |
1 0 | 1 |
0 1 | 1 |
0 0 | 0 |
代码如下
1 | //交集运算 |
打表实现
打表主要就两件事,
- 根据变量的数量枚举所有可能情况
- 对于每一种情况代入表达式求值
枚举所有可能可以用递归实现,在递归的最后一层的时候代入求值,代码大致应该是这样:
1 | vector<bool>S; |
S是一个全局列表,保存表达式用到的每一个变量,g是表达式求值函数。
其实最好还是写一个将字符串解析为表达式的函数,用户的输入就是字符串,例如“补(交(A,B))”然后构造一个函数对象。
最终实现
综合考虑,我最后决定用js写,一来有现成的Function可以将字符串解析为函数,二来可以用html来打表,比C++控制台显示的好看点,三来web端的程序使用都比较方便
事实证明,js并不好写,或者说前端都不好写,逻辑上很简单,但是前端写起来很麻烦。
又更新了一下,现在不需要输入字符串了,全部操作都可以从下拉列表中选择,新测试版本地址