序:
上学期离散数学由于疫情原因在家中进行网络授课,实验要求也因此产生了一些变化,本来是需要完成书上的八个实验并进行现场验收,调整为每人五道实验题并上传教学系统直接让助教批阅的形式。笔者完成了所有十道实验但是由于前五道不需要提交因此写得不算认真就不拿出来献丑了。
下面就展示一下后五道的实验代码,仅供参考不建议直接copy,每一题都有详尽的注释并标明了修改之处方便读者阅读。
代码:
关系运算:
/*
采用C++编写
函数声明注释规则:
'//'的表示为新增功能
'/*'形式的为解释说明
*/
#include<map>
#include<set>
#include<sstream>
#include<cstring>
#include<iomanip>
#include<iostream>
#define N 100
using namespace std;
//新增结构体存储关系
struct node {
int size; //存储序偶的个数
int M[N][N]; //存储关系矩阵
char pair[N*N][2]; //存储序偶对
node() {
//初始化为空
size=0;
memset(M,0,sizeof(M));
}
};
//新增分割元素函数
/*
此函数将非法字符替换为空格方便之后转为输入流
*/
string divideItem(string s) {
for(int i=0; i<s.size(); i++) {
//采用isdigit以及isalpha函数,简化代码
if(!isdigit(s[i]) && !isalpha(s[i]))
s[i]=' ';
}
return s;
}
//新增判断元素重复函数
/*
在进行序偶计算时常需要进行重复性判断
此处将其单独列为一个函数以便复用
*/
bool isRepeat(char s1, char s2, node R) {
for(int i=0; i<R.size; i++) {
if(s1==R.pair[i][0] && s2==R.pair[i][1])
return true;
}
return false;
}
/*
采取迭代器方式进行集合输出
*/
void printYsh(set<char> a) {
set<char>::iterator it; //迭代器it
for(it=a.begin(); it!=a.end(); it++) {
//处理特殊情况,不需要单独输出第一个元素
if(it!=a.begin())
cout<<',';
cout<<*it;
}
cout<<endl;
}
void printRelation(node R) {
for(int i=0; i<R.size; i++) {
//处理特殊情况,不需要单独输出第一个元素
if(i!=0)
cout<<',';
cout<<"<"<<R.pair[i][0]<<","<<R.pair[i][1]<<">";
}
cout<<endl;
}
void printRelationMatrix(node R, int n) {
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) //采取setw函数进行格式化输出
cout<<setiosflags(ios::left)<<setw(4)<<R.M[i][j];
cout<<endl;
}
}
/*
采取set容器读入元素数据,避免了查重操作
集合输入完毕后构造元素表以及位置表,方便之后序偶与关系矩阵的互换
*/
void inputYsh(set<char>& a, map<char,int>& pos, map<int,char>& item) {
cout<<"集合元素只能是A-Za-z0-9,其他字符被当作分隔符而去掉:"<<endl;
int cnt=0;
string s,temps;
getline(cin,s);
//处理后的字符串转换为输入流
istringstream ss(divideItem(s));
while(ss>>temps) {
//输入流读取
//若当前读取字符串非单个字符则视为不合法
if(temps.size()==1)
a.insert(temps[0]);
}
set<char>::iterator it; //迭代器it
for(it=a.begin(); it!=a.end(); it++) {
item[cnt]=(*it); //生成位置->元素的元素表
pos[(*it)]=cnt++; //生成元素->位置的位置表
}
}
/*
1、可复用的isRepeat函数有效缩短了代码长度
2、存储序偶的同时调用位置表生成关系矩阵
避免了低效率的"rela2matrix"矩阵生成函数
*/
void inputRelation(set<char> a, map<char,int> pos, node &R) {
cout<<"序偶只能是A-Za-z0-9,其他字符被当作分隔符而去掉,形如<a,b>:"<<endl;
string s;
getline(cin,s);
string temps1,temps2;
set<char>::iterator it; //迭代器it
//处理后的字符串转换为输入流
istringstream ss(divideItem(s));
while(ss>>temps1>>temps2) {
//序偶对中存在不合法字符串则直接舍弃整个序偶
if(temps1.size()!=1 || temps2.size()!=1)
continue;
//if语句判断序偶的元素是否存在于集合中
if(a.find(temps1[0])!=a.end() && a.find(temps2[0])!=a.end()) {
//调用isRepeat函数进行查重
if(!isRepeat(temps1[0],temps2[0],R)) {
R.pair[R.size][0]=temps1[0]; //存储序偶
R.pair[R.size++][1]=temps2[0]; //存储序偶同时size++
R.M[pos[temps1[0]]][pos[temps2[0]]]=1; //调用位置表构造关系矩阵
}
}
}
}
/*
可复用的isRepeat函数有效缩短了代码长度
*/
void Compose(node R1, node R2, node &T) {
for(int i=0; i<R1.size; i++) {
for(int j=0; j<R2.size; j++) {
if(R1.pair[i][1]==R2.pair[j][0]) {
//满足复合条件
//进行查重操作
if(!isRepeat(R1.pair[i][0],R2.pair[j][1],T)) {
T.pair[T.size][0]=R1.pair[i][0]; //存储序偶
T.pair[T.size++][1]=R2.pair[j][1]; //存储序偶同时size++
}
}
}
}
}
/*
1、结构体直接进行赋值不需要循环操作
2、可复用的isRepeat函数有效缩短了代码长度
*/
void Self(set<char> a, node R, node &T) {
T=R; //结构体重载等号
set<char>::iterator it; //迭代器it
for(it=a.begin(); it!=a.end(); it++) {
//对自反序偶进行查重操作
if(!isRepeat((*it),(*it),T)) {
T.pair[T.size][0]=(*it); //存储序偶
T.pair[T.size++][1]=(*it); //存储序偶同时size++
}
}
}
/*
1、结构体直接进行赋值不需要循环操作
2、可复用的isRepeat函数有效缩短了代码长度
*/
void Symmetry(node R, node &T) {
T=R; //结构体重载等号
set<char>::iterator it; //迭代器it
for(int i=0; i<R.size; i++) {
//对当前序偶的对称序偶进行查重操作
if(!isRepeat(R.pair[i][1],R.pair[i][0],T)) {
T.pair[T.size][0]=R.pair[i][1]; //存储序偶
T.pair[T.size++][1]=R.pair[i][0]; //存储序偶同时size++
}
}
}
/*
1、使用与运算生成关系矩阵,避免了求和操作以及之后的>1判断
2、调用元素表构造序偶,避免了低效率的"matrix2rela"序偶生成函数
*/
void Multiply(node R1, node R2, node &T, map<int,char> item, int n) {
//此处矩阵规模不大,直接使用三重循环进行计算
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
for(int k=0; k<n; k++) {
//采取与运算直接得到01结果
T.M[i][j]=R1.M[i][k]&&R2.M[k][j];
if(T.M[i][j]) {
//当前位置为1
T.pair[T.size][0]=item[i]; //调用元素表生成序偶
T.pair[T.size++][1]=item[j];//调用元素表生成序偶同时size++
break; //当前位置有效,直接break以防被0覆盖
}
}
}
}
}
/*
1、结构体直接进行赋值不需要循环操作
2、可复用的isRepeat函数有效缩短了代码长度
3、调用位置表直接生成关系矩阵,避免了低效率的"rela2matrix"矩阵生成函数
*/
void transOrder(node R, node &T, map<char,int> pos, int n) {
T=R; //结构体重载等号
node tempR=R; //结构体重载等号
for(int i=0; i<n-1; i++) {
node tempT;
printRelation(tempR); //输出复合序偶
printRelation(R); //输出原始序偶
Compose(tempR,R,tempT); //序偶复合运算
printRelation(tempT); //输出复合后的序偶
cout<<endl;
for(int j=0; j<tempT.size; j++) {
//查重,若不重复则加入传递闭包
if(!isRepeat(tempT.pair[j][0],tempT.pair[j][1],T)) {
T.pair[T.size][0]=tempT.pair[j][0]; //生成序偶
T.pair[T.size++][1]=tempT.pair[j][1]; //生成序偶同时size++
}
}
tempR=tempT;//结构体重载等号
}
//调用位置表直接生成关系矩阵
for(int i=0; i<T.size; i++)
T.M[pos[T.pair[i][0]]][pos[T.pair[i][1]]]=1;
}
/*
1、使用或运算进行矩阵的行相加,避免了求和操作以及之后的>1判断
2、调用元素表构造序偶,避免了低效率的"matrix2rela"序偶生成函数
*/
void transMatrix(node R, node &T, map<int,char> item, int n) {
//warshall算法,M[i][j]=1则j行加到i行
for (int j=0; j<n; j++) {
for (int i=0; i<n; i++) {
if (T.M[i][j]==1) {
for (int k=0; k<n; k++)
T.M[i][k]=T.M[i][k]||T.M[j][k];
}
}
}
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
if(T.M[i][j]) {
//当前位置有效
T.pair[T.size][0]=item[i]; //元素表生成序偶
T.pair[T.size++][1]=item[j];//元素表生成序偶同时size++
}
}
}
}
//文本说明表示为text函数,避免主函数的冗长
void text();
int main() {
node R1,R2; //结构体存储关系,同时包含序偶以及关系矩阵
set<char> a; //set容器存储集合元素,使用迭代器遍历
int nChoice; //nChoice进行操作选择
string sChoice; //sChoice直接读入一行
map<char,int> pos; //map容器构造元素->位置的位置表
map<int,char> item; //map容器构造位置->元素的元素表
while (1) {
text(); //输出文本提示
//读取字符串,以第