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

目录

题目

前言

集合的实现的两种方法:

枚举类型:

方式一

总体实现原理

各函数实现

构造函数

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

“>>”的 重载

“<<”的重载 

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

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

方式二

总体实现原理

各函数实现

“>>”的 重载

“<<”的重载 

集合运算符重载

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

测试主函数

测试用例与结果



题目

定义一个集合类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;
	else
		return 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;
	else
		return 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;
}

测试用例与结果

 

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值