一、前提回顾
在上一期我们利用了struct结构体实现了集合的基本框架,但它存在诸多问题,列如不能完美地多次判断一个元素在一个数组的关系,以及呆板地利用数组来代表集合等,这在编程中实现能力水平和技术较低,这不是一个程序猿该有的基本水平,而今天我将向大家介绍一个全新的方法 —— 位向量集合操作,那么大家肯定有疑问,什么是位向量?C语言存在位向量吗?嘿嘿,别着急此向量非数学里的向量,等我慢慢叙来。
二、介绍集合的基本关系
写代码和了解位向量前,先要有集合的基本原理,编程其实和数学息息相关,前面我们虽然利用struct结构体写了一个菜鸟代码,但这种代码不能让人耳目一新,只是为了让大家更好的读懂代码。而这节博客相对于第一期较难,但代码逻辑依旧简单,我们先回顾一下集合的基本概念。
四、集合的基本关系
1.子集
一般地,对于两个集合A,B,如果集合 A 中任意一个元素都是集合 B 中的元素,则称为集合 A 是集合 B 的子集,记作A 包含于 B。
2.真子集
对于两个集合A,B,如果集合A 包含于 B,但存在元素 a 属于 B,且 元素 a 不属于 A,则称为集合 A 是 集合 B 的 真子集, 记作 A 真包含于 B。
3.相等集
如果构成两个集合的元素是一样的,即集合 A 中的任意一个元素都是集合 B 中的元素,集合 B 中的任意一个元素也都是集合 A 中的元素,那么称集合 A 和 集合 B 为相等集。
4.元素和集合关系
元素和集合是属于或不属于的关系。
5.集合关系的特殊性质
略,自己理会。
我着重关注前面四个集合的基本关系,特性不讲,内容过多,自己理会。
三、介绍位向量集合操作
位向量,也称为位集合。是一种用来表示一组布尔值的数据结构。该向量可以进行快速的位级别操作,可以高效地执行集合操作,如我第三期即将要讲的交集,并集,差集等。通过使用该向量,还可以在编程的常数时间内执行这些操作,更大能轻松扩展到大型数据集,这就是向量集合操作。
四、代码时间
在C 语言中,你完全可以通过位操作和位运算来表示集合,并且使用位运算的方式来执行集合间的基本关系操作,这种方法被称为位向量集合操作。
以下是使用位向量方法表示的参考代码。
首先,要想使用位向量,肯定要声明,我这里直接定义64位类型向量(看情况定义,别硬抄)。
#include <stdio.h>
typedef unsigned long long int BitSet; // 64位整数表示向量
然后,写一个子集的函数判断。不懂的,好好学学移位运算和数据类型。
子集:一般地,对于两个集合A,B,如果集合 A 中任意一个元素都是集合 B 中的元素,则称为集合 A 是集合 B 的子集,记作A 包含于 B。
int isSubset(BitSet set1, BitSet set2)
{
return (set1 & set2) == set1; // 判断是否是set2为子集
}
真子集的判断
真子集 :对于两个集合A,B,如果集合A 包含于 B,但存在元素 a 属于 B,且 元素 a 不属于 A,则称为集合 A 是 集合 B 的 真子集, 记作 A 真包含于 B。
int isProperSubset(BitSet set1, BitSet set2)
{
return isSubset(set1, set2) && set1 != set2; // 判断是否是set2的真子集
}
集合对等
3.相等集:如果构成两个集合的元素是一样的,即集合 A 中的任意一个元素都是集合 B 中的元素,集合 B 中的任意一个元素也都是集合 A 中的元素,那么称集合 A 和 集合 B 为相等集。
int isSetEqual(BitSet set1, BitSet set2)
{
return set1 == set2; // 判断是否相等
}
元素关系
4.元素和集合关系:元素和集合是属于或不属于的关系。
int isMember(BitSet set, int element)
{
return (set & (1ULL << element)) != 0; // 检查向量中对应位置是否为一
}
还有编程里的四件套: 增,删,改,查,我这里就不写很多。
增和减
void addElement(BitSet *set, int element)
{
*set |= (1ULL << element); // 将向量对应位置设置为1
}
void removeElement(BitSet *set, int element)
{
*set &= -(1ULL << element); // 对应位置设置为零
}
这里你可以,写一个函数来打印,但考虑麻烦,就直接夹杂在main函数里。
if (isMember(set2, 8))
{
printf("5 ∈ SET1\n");
}
if (isSubset(set1, set2))
{
printf("S1 ∈= S2\n");
}
if (isProperSubset(set1, set2))
{
printf("S1 ∈≠ S2\n");
}
if (isSetEqual(set1, set2))
{
printf("S1 = S2");
}
最后,main函数声明和修改
int main()
{
// 初始化向量
BitSet set1 = 0;
BitSet set2 = 0;
// 添加元素到集合
addElement(&set1, 5);
addElement(&set1, 6);
addElement(&set1, 8);
addElement(&set2, 7);
addElement(&set2, 5);
addElement(&set2, 6);
addElement(&set2, 8);
if (isMember(set2, 8))
{
printf("5 ∈ SET1\n");
}
if (isSubset(set1, set2))
{
printf("S1 ∈= S2\n");
}
if (isProperSubset(set1, set2))
{
printf("S1 ∈≠ S2\n");
}
if (isSetEqual(set1, set2))
{
printf("S1 = S2");
}
return 0;
}
怎么样?代码是不是简洁流畅了很多,这可是得益于位向量的帮助。
总结,这个参考代码使用了位向量方法来表示集合,并实现了判断元素和集合关系,子集关系和真子集关系等的函数。在main主函数中,我们创建了两个位向量集合,set1和 set2,并演示了使用不同的函数来进行集合关系的判断和输出。
总之,使用位向量方法可以有效地表示集合间的基本关系,并且在处理大型集合时具有良好的性能。
最后,大家看到这里觉得不错的话请关注赞和收藏,我会回关你的热心的。