离散数学中提及了求传递闭包的warshell算法,我利用c++创建了矩阵类以及子类方阵类,实现了warshell算法的同时,回顾复习了c++的基本语法与操作,同时对二维数组了解有所增长。(全部代码位于文末,首先分块介绍各部分)
- 二维数组的构建:
Matrix::Matrix(int n, int k):row(n), column(k) {
ptr = new int *[row];
for (int i = 0; i < row; i++) {
ptr[i] = new int [column];
memset(ptr[i], 0, sizeof(int)*column);
}
}
二维数组构建有不同方式,该方式是比较好理解的,**即创建一个二维指针,指向new出的一个指针数组,这些指针数组就代表着矩阵的行首,然后再让指针数组里面的每个指针指向new出的数组,这些数组对应的就是每一列。**此处我给整个二维数组赋了初值,只是为了用着方便。不过在此处如果想对数组进行初始化,最好使用这种方式,如果对其整体赋值的话,容易出现地址上的错误。
for (int i = 0; i < row; i++) {
delete [] ptr[i];
}
delete [] ptr;
二维数组的删除位于类的析构函数中,delete需要利用循环,相当于把矩阵的每一行的所有列先删除掉,然后再删除掉指向每一行的指针数组。
- Warshell算法求传递闭包的实现:
首先对于传递闭包,其原理为:将最初的关系记为R0,将关系矩阵对应关系图中的每个点标为v1,v2…vn,然后从R0出发,寻找R1,R1即为在R0的基础上+以v1作为内点的路径,以v1为内点的两步到达的路径可以通过一步到达,此时需要加上这只用一步就到达的路径。
例如:a,b,c三个点,R0对应关系图中只有a->b,b->c两条一步到达的路,此时b点就是a->b->c这条两步到达的路的内点,那么R1中就要加上a->c这条一步到达的路。
以此类推:R2需要在R1的基础上+v1,v2共同为内点或者v2单独为内点的路。(此时注意,由于R1已经包括了v1为内点的路,所以在v1,v2为内点的路线中,实际上等同于v2单独为内点的路,也就是说实现了递推)
这样我们可以得到Rn的公式,即Rn矩阵的(i,j)处为1,要么Rn-1的(i,j)位置为1,要么Rn-1的(i,k)位置和(k,j)位置同时为1。
程序代码如下:
for (int InPoint = 0; InPoint < num; InPoint++) { //此处为设置内点,对每一个点做内点都进行检验筛选
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
ptr_t[i][j] = (ptr[i][j]) || (ptr[i][InPoint] && ptr[InPoint][j]); //此处为关键,此处实现了Rn的公式,每次循环ptr_t都是更新过的
}
}
}
- 复制构造函数、=运算符重载的深拷贝问题:
要注意,一般的复制构造函数只是完全复制对象的引用内容给创建的对象,这个时候如果存在指针就会出现问题,因为这样原对象和复制构造的对象的指针指向了同一个地址,这样会导致两个问题:
(1)两个对象交缠严重,改变一个等同于改变了另一个,和一个对象没什么区别
(2)对象消亡再调用析构函数的时候,同一片地址被delete了两次,这样对内存的操作会出现错误。
因此我们需要进行深拷贝,所谓深拷贝,也就是在复制构造函数里进行操作和对=运算符进行重载,从而实现仅仅复制内容,而不复制地址。
Matrix::Matrix(const Matrix & m1) {
if (m1.ptr == ptr) return;
row = m1.row;
column = m1.column;
ptr = new int *[row]; //请求一片新的空间,存放新数组
for (int i = 0; i < row; i++) {
ptr[i] = new int [column];
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
ptr[i][j] = m1.ptr[i][j]; //复制内容而不复制地址
}
}
}
=运算符的重载与其基本没有区别,唯一需要注意的是要判断一下用一个对象给自己赋值的时候,可以直接返回该对象。
- 全部程序代码如下:
该代码还可以继续进行扩充,例如加上求矩阵行列式、求逆的算法,最终可以扩充完整个方阵类以及矩阵类。
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
class Matrix { //基类,通用的矩阵
int row;
int column;
protected:
int ** ptr;
public:
Matrix(int, int);
Matrix(const Matrix &);
Matrix & operator=(const Matrix &);
~Matrix();
void SetInfo();
void PrintInfo();
};
class sMatrix:public Matrix{ //子类,方阵
int num;
int ** ptr_t;
bool op_t; //记录操作与否
public:
sMatrix(int);
sMatrix(const sMatrix &);
sMatrix & operator=(const sMatrix &);
~sMatrix();
void Do_Tr_Warshell(); //沃舍尔算法求传递闭包
void PrintInfo_t();
};
Matrix::Matrix(int n, int k):row(n), column(k) {
ptr = new int *[row];
for (int i = 0; i < row; i++) {
ptr[i] = new int [column];
memset(ptr[i], 0, sizeof(int)*column);
}
}
Matrix::Matrix(const Matrix & m1) {
if (m1.ptr == ptr) return;
row = m1.row;
column = m1.column;
ptr = new int *[row];
for (int i = 0; i < row; i++) {
ptr[i] = new int [column];
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
ptr[i][j] = m1.ptr[i][j];
}
}
}
Matrix & Matrix::operator=(const Matrix & m1) {
if (m1.ptr == ptr) return *this;
row = m1.row;
column = m1.column;
ptr = new int *[row];
for (int i = 0; i < row; i++) {
ptr[i] = new int [column];
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
ptr[i][j] = m1.ptr[i][j];
}
}
return *this;
}
Matrix::~Matrix() {
for (int i = 0; i < row; i++) {
delete [] ptr[i];
}
delete [] ptr;
}
void Matrix::SetInfo() {
cout << "Set the matrix by inputing 0/1 numbers." << endl;
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
cin >> ptr[i][j];
}
}
cout << "Set compelete." << endl;
}
void Matrix::PrintInfo() {
cout << "The matrix is :" << endl;
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
cout << setw(4) << ptr[i][j];
}
cout << endl;
}
}
sMatrix::sMatrix(int n):Matrix(n, n), num(n) { //派生类构造函数
op_t = false;
ptr_t = new int *[num];
for (int i = 0; i < num; i++) {
ptr_t[i] = new int [num];
memset(ptr_t[i], 0, sizeof(int)*num);
}
}
sMatrix::sMatrix(const sMatrix & m1):Matrix(m1) { //派生类复制构造函数
if (m1.ptr_t == ptr_t) return;
num = m1.num;
op_t = m1.op_t;
ptr_t = new int *[num];
for (int i = 0; i < num; i++) {
ptr_t[i] = new int [num];
}
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
ptr_t[i][j] = m1.ptr_t[i][j];
}
}
}
sMatrix & sMatrix::operator=(const sMatrix & m1) {
Matrix::operator=(m1);
if (m1.ptr_t == ptr_t) return *this;
num = m1.num;
op_t = m1.op_t;
ptr_t = new int *[num];
for (int i = 0; i < num; i++) {
ptr_t[i] = new int [num];
}
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
ptr_t[i][j] = m1.ptr_t[i][j];
}
}
return *this;
}
sMatrix::~sMatrix() {
for (int i = 0; i < num; i++) {
delete [] ptr_t[i];
}
delete [] ptr_t;
}
void sMatrix::PrintInfo_t() {
if (!op_t) {
cout << "Haven't done warshell algorithm." << endl;
return;
}
cout << "The transitive matrix is :" << endl;
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
cout << setw(4) << ptr_t[i][j];
}
cout << endl;
}
}
void sMatrix::Do_Tr_Warshell() {
for (int InPoint = 0; InPoint < num; InPoint++) {
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
ptr_t[i][j] = (ptr[i][j]) || (ptr[i][InPoint] && ptr[InPoint][j]);
}
}
}
op_t = true;
}
int main() {
int n = 0;
cout << "Set the order of a square matrix by inputing n = ";
cin >> n;
sMatrix m1(n);
m1.SetInfo();
m1.PrintInfo();
m1.Do_Tr_Warshell();
m1.PrintInfo_t();
}
- 参考文献:
- 《Warshall传递闭包算法的学习与实现》:https://www.cnblogs.com/lpshou/archive/2012/04/27/2473109.html
- new二维数组的用法:https://blog.csdn.net/qq_41611893/article/details/87910458