目录

题目

前言

集合的实现的两种方法:

枚举类型:

方式一

总体实现原理

各函数实现

构造函数

拷贝构造函数和赋值运算符重载

“>>”的 重载

“<<”的重载

集合运算符重载​​​​​​​

总体实现代码​​​​​​​​​​​​​​

方式二

总体实现原理

各函数实现

“>>”的 重载

“<<”的重载

集合运算符重载

总体实现代码​​​​​​​

测试主函数

测试用例与结果



题目

定义一个集合类setColour,要求元素为枚举类型值。例如,
enum colour { red, yellow, blue, white, black };
集合类实现交、并、差、属于、蕴含、输入、输出等各种基本运算。设计main函数测试setColour类的功能。

前言

集合的实现的两种方法:

1.用bool数组每个数组元素存储一种集合元素

2.用一个unsigned int存储,每一个二进制位代表一个集合元素

从实现上,方法一更好理解,但无论是从时间角度、空间角度还是代码量(行数足足有二倍之差)方法二都有明显优势。

下文将分别对两种方法进行讲解,除集合的实现原理不同,在方式二的实现过程中,还进行了实现方式的优化和代码拓展性的延申,可以在宏变量增加元素。

枚举类型:

在枚举类型中,共五种颜色,若不进行初始化,其默认从0开始向后累加1,如下测试:

方式一

总体实现原理

1.我们定义一个bool型数组作为成员变量,长度为4,每个位置作为以一种颜色,此颜色在集合中,就置1,否则为0,如下:

2.接下来,各种集合运算就可以通过遍历数组,对每一个元素进行逻辑运算操作而实现。

各函数实现

class setColour
{
public:setColour();//构造函数setColour(const setColour& c);//拷贝构造函数setColour& operator=(const setColour& c);//赋值运算符重载setColour operator+(setColour& c2);//并集setColour operator*(setColour& c2);//交集setColour operator-(setColour& c2);//差集friend bool operator<(colour c, setColour& c2);//属于bool operator<=(setColour& c2);//包含于friend ostream& operator<<(ostream& output, const setColour& c);//流插入运算符重载friend istream& operator>>(istream& input, setColour& c);//流提取运算符重载
private:bool* _colourStatus;
};

为使集合的运算更直观,我们对“ * + - <= < ”等符号进行重载,用来代表交、并、差、蕴含、属于等集合运算。

 * + - <= <

交集(两个集合同时存在的元素集合)

并集(两个集合的所有元素集合) 差集(前一个集合有后一个集合没有的元素集合) 蕴含(右蕴含左) 属于(左侧元素属于右侧集合)

构造函数

构造数组,并将每个元素初始化为0:

setColour::setColour()
{_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = 0;}
}

拷贝构造函数和赋值运算符重载

由于我们的成员变量是动态开辟的,但编译器给的默认拷贝构造函数和赋值重载只会进行浅拷贝,在对象析构的时候,会出现两个对象delete同一块内存的情况,而引发报错,所以我们要自己写两个深拷贝的,保证复制出的数组和原来的数组不是同一块空间:

setColour::setColour(const setColour& c)
{_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = c._colourStatus[i];}
}
setColour& setColour::operator=(const setColour& c)
{if (this != &c){_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = c._colourStatus[i];}return *this;}
}

“>>”的 重载

在输入时,我们会输入一个字符串来表示这个集合,或添加某个元素,所以我们要用到strstr()这个函数进行颜色元素的检索,再进行数组写入:

istream& operator>>(istream& input, setColour& c)
{char inColour[30] = { 0 };cin.getline(inColour, 30);if (strstr(inColour, "red")){c._colourStatus[(int)red] = 1;}if (strstr(inColour, "yellow")){c._colourStatus[(int)yellow] = 1;}if (strstr(inColour, "blue")){c._colourStatus[(int)blue] = 1;}if (strstr(inColour, "white")){c._colourStatus[(int)white] = 1;}if (strstr(inColour, "black")){c._colourStatus[(int)black] = 1;}return input;
}

“<<”的重载

循环数组每一个元素,若此元素为1,则对这个下标表示的颜色进行输出(counter是用于格式控制的)

ostream& operator<<(ostream& output, const setColour& c)
{cout << "{ ";int counter = 0;for (int i = 0; i < 5; i++){if (c._colourStatus[i]){switch (i){case 0:cout << "red, ";break;case 1:cout << "yellow, ";break;case 2:cout << "blue, ";break;case 3:cout << "white, ";break;case 4:cout << "black, ";break;default:break;}counter++;}}if (counter > 0){cout << "\b\b }";}else{cout << "\b}";}return output;
}

集合运算符重载

实现大致相同,都是遍历每一个元素进行逻辑运算:

setColour setColour::operator*(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] && c2._colourStatus[i];}return newSet;
}
setColour setColour::operator+(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] || c2._colourStatus[i];}return newSet;
}
setColour setColour::operator-(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] && !c2._colourStatus[i];}return newSet;
}
bool operator<(colour c, setColour& c2)
{if (c2._colourStatus[(int)c])return 1;elsereturn 0;
}
bool setColour::operator<=(setColour& c2)
{for (int i = 0; i < 5; i++){if (_colourStatus[i] && !c2._colourStatus[i]){return 0;}}return 1;
}

​​​​​​​

总体实现代码​​​​​​​

#include <assert.h>
#include <string.h>
#include <iostream>
using namespace std;
enum colour { red, yellow, blue, white, black };
class setColour
{
public:setColour();setColour(const setColour& c);setColour& operator=(const setColour& c);//赋值setColour operator+(setColour& c2);//并集setColour operator*(setColour& c2);//交集setColour operator-(setColour& c2);//差集friend bool operator<(colour c, setColour& c2);//属于bool operator<=(setColour& c2);//包含于friend ostream& operator<<(ostream& output, const setColour& c);friend istream& operator>>(istream& input, setColour& c);
private:bool* _colourStatus;
};
setColour::setColour()
{_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = 0;}
}
setColour::setColour(const setColour& c)
{_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = c._colourStatus[i];}
}
setColour& setColour::operator=(const setColour& c)
{if (this != &c){_colourStatus = new bool[5];for (int i = 0; i < 5; i++){_colourStatus[i] = c._colourStatus[i];}return *this;}
}
setColour setColour::operator*(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] && c2._colourStatus[i];}return newSet;
}
setColour setColour::operator+(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] || c2._colourStatus[i];}return newSet;
}
setColour setColour::operator-(setColour& c2)
{setColour newSet;for (int i = 0; i < 5; i++){newSet._colourStatus[i] = _colourStatus[i] && !c2._colourStatus[i];}return newSet;
}
bool operator<(colour c, setColour& c2)
{if (c2._colourStatus[(int)c])return 1;elsereturn 0;
}
bool setColour::operator<=(setColour& c2)
{for (int i = 0; i < 5; i++){if (_colourStatus[i] && !c2._colourStatus[i]){return 0;}}return 1;
}
ostream& operator<<(ostream& output, const setColour& c)
{cout << "{ ";int counter = 0;for (int i = 0; i < 5; i++){if (c._colourStatus[i]){switch (i){case 0:cout << "red, ";break;case 1:cout << "yellow, ";break;case 2:cout << "blue, ";break;case 3:cout << "white, ";break;case 4:cout << "black, ";break;default:break;}counter++;}}if (counter > 0){cout << "\b\b }";}else{cout << "\b}";}return output;
}
istream& operator>>(istream& input, setColour& c)
{char inColour[30] = { 0 };cin.getline(inColour, 30);if (strstr(inColour, "red")){c._colourStatus[(int)red] = 1;}if (strstr(inColour, "yellow")){c._colourStatus[(int)yellow] = 1;}if (strstr(inColour, "blue")){c._colourStatus[(int)blue] = 1;}if (strstr(inColour, "white")){c._colourStatus[(int)white] = 1;}if (strstr(inColour, "black")){c._colourStatus[(int)black] = 1;}return input;
}

方式二

总体实现原理

1.这里我们只定义了一个unsigned int(这里size_t就是unsigned int)类型,用它的32个二进制位进行集合元素的存储。(此时这种方式的劣势也显现出来,定义的集合只能有32种元素,其实也可以申请一块连续空间(数组)拓展元素个数,实现了“站着挣钱”,但后续将不能直接对一个int直接进行位运算,还需进行额外实现,各位大神如果想进行实现或有任何见解欢迎评论区一起探讨)。

2.接下类的集合运算就可以通过对这个整形进行位运算而实现。

各函数实现

1. 前面的两个宏用来进行元素扩充,COLOUR_NUM用来更改元素个数,COLOUR_STR是元素对应的字符串,在后面cin/cout会用到,再对枚举类型进行元素添加即可实现集合元素扩充

2.由于没有动态开辟空间,这里将不再需要自己写拷贝构造,赋值重载。

“>>”的 重载

1.在输入时,我们会输入一个字符串来表示这个集合,或添加某个元素,所以我们要用到strstr()这个函数进行颜色元素的检索,再进行数组写入:

2.很明显,相较方法一,这里的输入重载明显变短,那么是怎么做到的的呢?

我们定义一个字符串数组,用输入的字符串循环对这个数组进行匹配判断,从而对集合进行写入

3.如果匹配成功,这时的“ i ”就代表字符串数组的元素下标,同时也是这个颜色对应的enum赋值,也就是i代表了对应的颜色,这时我们将数字1进行左移 i 位,使它只有第 i 个二进制位是1,其他位都是0,再将这个数与原集合数字进行按位或,就可以将这一位赋值位真。

istream& operator>>(istream& input, setColour& c)
{const char* colourIn[COLOUR_NUM] = { COLOUR_STR };char inColour[30] = { 0 };cin.getline(inColour, 30);for (int i = 0; i < COLOUR_NUM; i++){if (strstr(inColour, colourIn[i])){c._colourStatus |= (1 << i);}}return input;
}

“<<”的重载

输出函数原理大致与输入函数相同,只不过这次是循环检查哪一位是1,并打印第i位对应的字符串。

ostream& operator<<(ostream& output, const setColour& c)
{const char* colourOut[COLOUR_NUM] = { COLOUR_STR };cout << "{ ";int counter = 0;size_t colour_test = 1;for (int i = 0; i < COLOUR_NUM; i++){if (c._colourStatus & colour_test){cout << colourOut[i] << ", ";counter++;}colour_test <<= 1;}if (counter > 0){cout << "\b\b }";}else{cout << "\b}";}return output;
}

集合运算符重载

实现大致相同,都是对元素进行位运算。

其他都好理解,这里差集要进行着重解释一下,差集就是被减集合减去交集,即:a & ~(a & b),但为什么写了a & ~b呢?这里就需要大家有一点位运算或者离散数学的知识了,运算过程如下:

a & ~(a & b) <==> a&(~a | ~b) <==> (a & ~a) | (a & ~b) <==> 1 | (a & ~b) <==> a & ~b

setColour setColour::operator*(setColour& c2)
{return setColour(_colourStatus & c2._colourStatus);
}
setColour setColour::operator+(setColour& c2)
{return setColour(_colourStatus | c2._colourStatus);
}
setColour setColour::operator-(setColour& c2)
{return setColour(_colourStatus & ~c2._colourStatus);
}
bool operator<(colour c, setColour& c2)
{return c2._colourStatus & (1 << c);
}
bool setColour::setColour::operator<=(setColour& c2)
{return (_colourStatus | c2._colourStatus) == c2._colourStatus;
}

总体实现代码​​​​​​​

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include <iostream>
using namespace std;
#define COLOUR_NUM 5
#define COLOUR_STR "red","yellow","blue","white","black"
enum colour { red, yellow, blue, white, black };
class setColour
{
public:setColour(size_t cS = 0);setColour operator+(setColour& c2);//并集setColour operator*(setColour& c2);//交集setColour operator-(setColour& c2);//差集friend bool operator<(colour c, setColour& c2);//属于bool operator<=(setColour& c2);//包含于friend ostream& operator<<(ostream& output, const setColour& c);friend istream& operator>>(istream& input, setColour& c);
private:size_t _colourStatus;
};
setColour::setColour(size_t cS)
{_colourStatus = cS;
}
setColour setColour::operator*(setColour& c2)
{return setColour(_colourStatus & c2._colourStatus);
}
setColour setColour::operator+(setColour& c2)
{return setColour(_colourStatus | c2._colourStatus);
}
setColour setColour::operator-(setColour& c2)
{return setColour(_colourStatus & ~c2._colourStatus);
}
bool operator<(colour c, setColour& c2)
{return c2._colourStatus & (1 << c);
}
bool setColour::setColour::operator<=(setColour& c2)
{return (_colourStatus | c2._colourStatus) == c2._colourStatus;
}
ostream& operator<<(ostream& output, const setColour& c)
{const char* colourOut[COLOUR_NUM] = { COLOUR_STR };cout << "{ ";int counter = 0;size_t colour_test = 1;for (int i = 0; i < COLOUR_NUM; i++){if (c._colourStatus & colour_test){cout << colourOut[i] << ", ";counter++;}colour_test <<= 1;}if (counter > 0){cout << "\b\b }";}else{cout << "\b}";}return output;
}
istream& operator>>(istream& input, setColour& c)
{const char* colourIn[COLOUR_NUM] = { COLOUR_STR };char inColour[30] = { 0 };cin.getline(inColour, 30);for (int i = 0; i < COLOUR_NUM; i++){if (strstr(inColour, colourIn[i])){c._colourStatus |= (1 << i);}}return input;
}

测试主函数

void test1()
{setColour colour1;setColour colour2 = colour1;cout << "请输入两行颜色集合:(如:{red, yellow, blue})" << endl;cin >> colour1;cin >> colour2;setColour colour3 = colour1 * colour2;cout << "交集:" << colour3 << endl;colour3 = colour1 + colour2;cout << "并集:" << colour3 << endl;colour3 = colour1 - colour2;cout << "差集:" << colour3 << endl;if (red < colour1){cout << "red属于第一个集合" << endl;}else{cout << "red不属于第一个集合" << endl;}if (colour1 <= colour2){cout << "集合一包含于集合二" << endl;}else{cout << "集合一不包含于集合二" << endl;}
}
int main()
{test1();return 0;
}

测试用例与结果

定义一个集合类setColour,要求元素为枚举类型值相关推荐

  1. 12.定义一个集合类SET,处理整型数组。

    12.定义一个集合类SET,处理整型数组.通过成员函数重载运算符"==",判断一个数是否属于集合;通 过友元重载运算符"==",判断两个集合是否相同,即集合中的 ...

  2. java 整型数组定义_在Java中定义一个具有10个元素的整型数组a的语句是:___

    在Java中定义一个具有10个元素的整型数组a的语句是:___ 答: int [] arr = new int[10] 在借贷记账法下() 答:在账户结构上,"借"和"贷 ...

  3. cpp课程设计实验题:定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name)、学号(num)、数学成绩(mathScore)、英语成绩(englishScore)、人数(coun

    CPP实验题:定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name).学号(num).数学成绩(mathScore).英语成绩(englishScore).人数(count).数 ...

  4. C++实验编程题:.定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name)、学号(num)、数学成绩(mathScore)、英语成绩(englishScore)、人数(count

    题目描述: *6.定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name).学号(num).数学成绩(mathScore).英语成绩(englishScore).人数(count) ...

  5. 类与对象实验:定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name)、学号(num)、数学成绩(mathScore)、英语成绩(englishScore)、人数(count)……

    定义一个描述学生(Student)基本情况的类,数据成员包括姓名(name).学号(num).数学成绩(mathScore).英语成绩(englishScore).人数(count).数学总成绩(ma ...

  6. 定义一个集合类Set,(考察动态数组的建立)

    完整题目 定义一个整形数集合类Set,请通过创建动态分配的整数数组(使用new运算符)存放整数值,且数组的大小要能够根据包含元素的个数动态的变化.集合中,元素的顺序无关紧要,每个元素至多出现一次.实现 ...

  7. 7.定义一个有80个元素的字符数组,从键盘输入一串字符,将其中的大写字母转换为小写字母,而将原来为小写的字母转换为大写字母,其他字符不变。

    #include<stdio.h> #define N 80 void main(void) {int i=0;char a[N],b;printf("输入字符串:") ...

  8. 3.定义一个有10个元素的数组,用其代表10个学生的考试成绩,从键盘输入10个成绩,统计平均成绩。

    #include<stdio.h> #define N 10 void main(void) {int i;float a[N],ave;ave=0;for(i=0;i<N;i++) ...

  9. python定义一个1xn矩阵_Python实现的矩阵类实例

    本文实例讲述了Python实现的矩阵类.分享给大家供大家参考,具体如下: 科学计算离不开矩阵的运算.当然,python已经有非常好的现成的库: 我写这个矩阵类,并不是打算重新造一个轮子,只是作为一个练 ...

最新文章

  1. 论如何优雅的处理回文串 - 回文自动机详解
  2. Max retries exceeded with url 解决方案
  3. java日期用什么属性_java日期以及使用Java反射机制遍历实体类的属性和类型
  4. datasnap——动态注册服务类
  5. 教你打开线程、进程和协程的大门!
  6. java怎么把弹框设置为圆角_自定义圆角Dialog
  7. 迭代器java.util.Iterator接口
  8. 万字超详细图文教程:联想G510加装内存条、固态,机械移至光驱位
  9. The second sprint
  10. 再现隐私之争_反谷歌FLoC联盟: selenium谷歌浏览器报错: Error with Permissions-Policy header
  11. 关于行人重识别方法PCB《Beyond Part Models: Person Retrieval with Refined Part Pooling 》及代码实现解读
  12. 风格化半调效果如何制作?教程来了
  13. (一)Python基础语法
  14. 机器学习中的数学——常用概率分布(九):经验分布(Empirical分布)
  15. 独孤思维:没有复盘的项目,不会赚钱
  16. 贪心算法--加勒比海盗船--最优装载问题
  17. [Luogu P3960] [UOJ 334] [NOIP 2017 tg]列队
  18. 1到100之间所有奇(偶)数的和,奇(偶)数的个数,奇(偶)数的平均数
  19. 计算机硬件音频,浅析计算机硬件基础 第9章(音频和视频设备).ppt
  20. 大学生程序设计大赛官网

热门文章

  1. 计算机作业ppt能用wps吗,WPS演示怎么设置PPT可以在未安装WPS的电脑上打开?
  2. html5在线俄罗斯方块,HTML5最新经典俄罗斯方块游戏插件
  3. 抖音群控软件教你如何玩转短视频营销
  4. 一本通OJ 1376
  5. win10本地安装redis教程
  6. gromacs PCA 做自由能景观图
  7. 人工智能下一个风口在哪里?专家大咖这样说
  8. 第8组 团队展示(组长)
  9. 2种解法:分数转化为小数形式
  10. python儿童编程培训班-北京哪有儿童python编程培训班