实现集合之间的交 并 补 差 对称差
通过类进行实现集合之间的关系题目相关数学知识功能实现学生类学生类实现学生集合类学生集合类实现主函数总结题目通过使用c++的类 ,容器等相关知识来实现集合间的:交 并 补 差 对称差这五种关系这里不直接set中有关集合关系的函数相关数学知识并集:设A与B是任意两个集合,由至少属于集合A与集合B之一的一切元素构成的集合成为A与B的并集,记作A∪B(或B∪A),读作“A并B”(或“B并A”),即A∪B=
题目
通过使用c++的类 ,重载,vector容器等相关知识来实现集合间的:交 并 补 差 对称差这五种关系
这里不直接set使用有关集合关系的函数
相关数学知识
并集:设A与B是任意两个集合,由至少属于集合A与集合B之一的一切元素构成的集合成为A与B的并集,记作A∪B(或B∪A),读作“A并B”(或“B并A”),即A∪B={x|x∈A,或x∈B}。
交集:对于给定的两个集合A 和 集合B 的交集是指含有所有既属于 A 又属于 B 的元素所构成的集合。由属于A且属于B的相同元素组成的集合,记作A∩B(或B∩A)读作“A交B”(或“B交A”),即A∩B={x|x∈A,且x∈B}。
差集:设A与B是任意两个集合,由属于A但不属于B的一切元数构成的集合称为A与B的差集,记为A\B或A-B,即A\B={x|x∈A且x∉B}。
补集:设S是一个集合,A是S的一个真子集,由S中所有不属于A的元素组成的集合,叫做子集A在S中的补集,于集也称为补集,记作CsA或Ac或A’。即Ac=S\A。
对称差:两个集合的对称差是只属于其中一个集合,而不属于另一个集合的元素组成的集合。设A与B是任意两个集合,集合 A 和 B 的对称差可记为 AΔB,对称差相当于两个相对补集的并集,即AΔB=(A-B)∪(B-A)。也可以表示为两个集合的并集减去它们的交集,即AΔB=(A∪B)-(B∩A)。
功能实现
通过创建两个类,一个学生类,一个学生集合类,分别代表元素和集合,将学生类里面的数据放在一个vector的容器中可以在学生集合类里进行储存及使用。
头文件以及实现
学生类
创建一个学生类
class Student
{
private:
int m_uiId;
public:
Student();
Student(int id);
Student(const Student& student);
Student& operator=(const Student& student);
bool operator==(const Student& student) const;
bool operator!=(const Student& student) const;
int GetID() const { return m_uiId; }
};
学生类实现
默认构造:为其赋初值,在使用rand ()
函数在使用时是已经固定的值,所以创建一个随机种子来改变其值,同时用srand(time(NULL))
实现随机种子,根据时间变化而产生学号,这个可以避免学号创建出来是一样的情况
Student::Student(){
srand((unsigned int)time(NULL));
m_uiId = rand() % 20 + 1;
}
随机产生学生学号范围在1-20之间
rand() % 20 + 1;
有参构造
实现参数id保证传入的参数的准确性
Student::Student(int id){
m_uiId=id;
}
拷贝构造函数
传入进来的是一个对象,通过引用的方式进行传入,并的将传进来的对象的m_uiId赋值给本身的m_uiId进而来实现拷贝效果
Student::Student(const Student & student){
m_uiId=student.m_uiId;
}
重载赋值运算符
这个重载赋值和拷贝函数很像,在返回值上有区别,要实现一个链式编程的思想,为了将重载赋值运算符可以链式的使用下去,所以我们需要将其返回一个指针的形式
Student &Student::operator=(const Student &student){
m_uiId=student.m_uiId;
return *this;
}
重载关系运算符
是一个bool类型的函数,判断是否相等,相等则返回true,否则返回false类型
bool Student::operator==(const Student &student)const{
if(student.m_uiId==m_uiId) return true;
return false;
}
bool Student::operator!=(const Student &student)const{
if(student.m_uiId!=m_uiId) return true;
return false;
}
学生集合类
接着创建 学生集合类 在学生集合类里面实现相应函数
我们创建一个Student类型的容器去存放数据
在创建学生集合类时使用了vector容器,需要加入头文件#include<vector>
class StudentSet
{
private:
vector<Student>m_vecData;
public:
StudentSet();
StudentSet(const StudentSet&studentset);
StudentSet& operator=(const StudentSet&studentset);
bool Insert(const Student student);
bool Remove(const int id);
StudentSet Union(const StudentSet&studentset) const;
StudentSet InterSect(const StudentSet&studentset) const;
StudentSet Difference(const StudentSet&studentset) const;
StudentSet Complement() const;
StudentSet SymDifference(const StudentSet&studentset) const;
bool IsEmpty() const;
void Clear();
void Output() const;
};
学生集合类实现
学生集合类的三个构造函数和学生类的一样,在学生集合类中,默认构造函数让其清空
注意在重载赋值函数中,要清空函数,否则会保留上一次的数据
StudentSet::StudentSet(){
m_vecData.clear();
}
StudentSet::StudentSet(const StudentSet &studentset){
int len=studentset.m_vecData.size();
for(int i=0;i<len;i++){
m_vecData.push_back(studentset.m_vecData[i]);
}
}
StudentSet& StudentSet::operator=(const StudentSet & studentset){
m_vecData.clear();//清空防止在下一次的使用时仍含有上一次的值
int len=studentset.m_vecData.size();
for(int i=0;i<len;i++){
m_vecData.push_back(studentset.m_vecData[i]);
}
return *this;
}
插入和删除函数,是bool类型的函数,需要判断该集合中是否有与我们插入的id重复,如果有,则返回false,没有则返回true,同理删除函数一样
插入和删除都用到了vector容器里面的push_back函数和erase函数
判断是否有重复的思路
所使用的方法:我使用了map容器,通过map容器的两个参数值key和value,是键值对,他们之间有着一一对应的关系,同时在map容器中key 值是没有重复的。将m_vecData[i].GetID()
全标记为1,此时m_vecData[i].GetID()
就相当于map容器里的key值,标记的1就是相当于value值,这样在通过判断传进来的id的value值是否是1,如果是1,代表有重复的,之没有,没有重复的我们将其插入并返回true。
删除函数:就是在本身的范围内开始遍历,如果有和传入的id相同的,记录一下当前的遍历的位置,使用m_vecData.erase(m_vecData.begin()+i);
的方法删除重复的那个
注:m_vecData[i].GetID()==id
的要注意私有成员函数只能由该类内部成员函数调用
bool StudentSet::Insert(const Student student){//插入
int len =m_vecData.size();
map<int ,int >mp;
for(int i=0;i<len;i++){
mp[m_vecData[i].GetID()]=1;
}
if(!mp[student.GetID()]){
m_vecData.push_back(student);
return true;
}else {
return false;
}
}
bool StudentSet::Remove(const int id){//删除
int len=m_vecData.size();
for(int i=0;i<len;i++){
if(m_vecData[i].GetID()==id){ ///私有成员函数只能被该类内部成员函数调用
m_vecData.erase(m_vecData.begin()+i);
return true;
}
}
return false;
}
并 交 差 补 对称差
实现方式和插入函数的逻辑类似都是通过map函数的key值和value值进行判断的
并集:在本身这个集合内进行遍历将其全部插入到我们创建的的新的集合st里面,并且我们将map函数的key值为那个本身的学号,并将其的value值标记为1
int len=m_vecData.size(); for(int i=0;i<len;i++){ st.Insert(m_vecData[i]); mp[m_vecData[i].GetID()]=1; }
再在传入进来的集合中进行遍历,如果在这个传入的集合中的id(key值)没有等于1的(value值),就意味着传入集合中的元素和我们本身的元素之间没有重复的,那么我们就将其插入进来 ,这样就可以得到我们这个并集了,
StudentSet StudentSet::Union(const StudentSet&studentset) const{//并集
StudentSet st;
map<int,int>mp;
int len=m_vecData.size();
for(int i=0;i<len;i++){
st.Insert(m_vecData[i]);
mp[m_vecData[i].GetID()]=1;
}
len=studentset.m_vecData.size();
for(int i=0;i<len;i++){
if(!mp[studentset.m_vecData[i].GetID()]){
st.Insert(studentset.m_vecData[i]);
}
}
return st;
}
交集: 同样在本身这个集合中进行遍历并将其标记为1,,然后在传入的集合中进行遍历,如果有一样被标记为1的我们就将其插入到我们所新建的那个集合中
StudentSet StudentSet::InterSect(const StudentSet&studentset) const{//交集
StudentSet st;
map<int,int>mp;
for(int i=0;i<m_vecData.size();i++) {
mp[m_vecData[i].GetID()]=1;
}
for(int i=0;i<studentset.m_vecData.size();i++){
if(mp[studentset.m_vecData[i].GetID()]) {
st.m_vecData.push_back(studentset.m_vecData[i]);
}
}
return st;
}
差集:在一个集合中把含有另一个集合的元素去除,我们这里是如果没有一样的元素我就插入进来
在传入的集合中进行遍历并将其标记为1,再在本身这个集合中进行遍历,如果这里面没有等于1的我们就将其插入到我们创建的新的集合中来
StudentSet StudentSet::Difference(const StudentSet&studentset) const{//差集
StudentSet st;
map<int,int>mp;
int len=studentset.m_vecData.size();
for(int i=0;i<len;i++)
mp[studentset.m_vecData[i].GetID()]=1;
len=m_vecData.size();
for(int i=0;i<len;i++){
if(!mp[m_vecData[i].GetID()])
st.m_vecData.push_back(m_vecData[i]);
}
return st;
}
补集:在全集是:IDMAX是0-20之间,求补集,我们在本身这个集合中遍历,并将其标记为1,再在全集中遍历,如果有不等于1的我们就将其插入到我们创建的新集合中来
StudentSet StudentSet::Complement() const{//补集
StudentSet st;
map<int ,int >mp;
int len=m_vecData.size();
for(int i=0;i<len;i++)
mp[m_vecData[i].GetID()]=1;
for(int i=0;i<=IDMAX;i++){
if(!mp[i]){
Student a(i);
st.m_vecData.push_back(a);
}
}
return st;
}
对称差实际上是两个集合的并集和交集再做一下差集
实现:创建一个新的集合a存放st和传入参数的并集,集合b存放的是st和传入参数的交集,完了再让a和b做差集,这样我们就得到了对称差
StudentSet StudentSet::SymDifference(const StudentSet&studentset) const{//对称差
StudentSet st;
int len=m_vecData.size();
for(int i=0;i<len;i++) st.m_vecData.push_back(m_vecData[i]);
StudentSet a=st.Union(studentset);
StudentSet b=st.InterSect(studentset);
StudentSet res=a.Difference(b);
return res;
}
判断是否为空,清空函数以及输出函数
是否为空就是看vector.size()==0
是否成立
bool StudentSet::IsEmpty() const{
if(m_vecData.size()==0) return true;
return false;
}
void StudentSet::Clear(){
m_vecData.clear();
}
void StudentSet::Output() const{
int len=m_vecData.size();
for(int i=0;i<len;i++)
cout<<m_vecData[i].GetID()<<endl;
}
主函数
int main()
{
srand((unsigned int)time(NULL));
StudentSet set1, set2, set3;
set1.Clear();
set2.Clear();
set3.Clear();
for (unsigned int i = 0; i < 5; i++)
{
Student tmpstudent(i);
set1.Insert(tmpstudent);
}
set1.Output();
system("pause");
Student tmpstudent1(3);
cout << set1.Insert(tmpstudent1) << endl;
system("pause");
Student tmpstudent2(10);
cout << set1.Insert(tmpstudent2) << endl;
system("pause");
for (unsigned int i = 7; i < 12; i++)
{
Student tmpstudent(i);
set2.Insert(tmpstudent);
}
set2.Output();
system("pause");
set3 = set1.Union(set2);
set3.Output();
system("pause");
set3 = set1.InterSect(set2);
set3.Output();
system("pause");
set3 = set1.Difference(set2);
set3.Output();
system("pause");
set3 = set3.Complement();
set3.Output();
system("pause");
set3 = set1.SymDifference(set2);
set3.Output();
system("pause");
return 0;
}
总结
这个实验中主要使用的就是vector容器 插入、删除、清空、容量等一系列函数,运算符重载,以及map函数间的key值和value值之间的一一对应关系,以及我们对集合之间关系的掌握与理解.
注意注意
map里面有一种插入方法:(这里所有map的插入方式全都是这种)
map<int ,int>mp;
mp[1]=10;//key=1;value=10,
map中输出元素:如果是输出该容器内含有的元素,可以正常输出其value值,但是如果输出其中没有的,不会进行报错,会输出是0
更多推荐
所有评论(0)