利用C++编写Warshell算法求传递闭包+复习构造析构函数、运算符重载、继承与派生、new二维数组

离散数学中提及了求传递闭包的warshell算法,我利用c++创建了矩阵类以及子类方阵类,实现了warshell算法的同时,回顾复习了c++的基本语法与操作,同时对二维数组了解有所增长。(全部代码位于文末,首先分块介绍各部分)

  1. 二维数组的构建:
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需要利用循环,相当于把矩阵的每一行的所有列先删除掉,然后再删除掉指向每一行的指针数组。

  1. 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. 复制构造函数、=运算符重载的深拷贝问题:
    要注意,一般的复制构造函数只是完全复制对象的引用内容给创建的对象,这个时候如果存在指针就会出现问题,因为这样原对象和复制构造的对象的指针指向了同一个地址,这样会导致两个问题
    (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];		//复制内容而不复制地址
        }
    }

}

=运算符的重载与其基本没有区别,唯一需要注意的是要判断一下用一个对象给自己赋值的时候,可以直接返回该对象。

  1. 全部程序代码如下:
    该代码还可以继续进行扩充,例如加上求矩阵行列式、求逆的算法,最终可以扩充完整个方阵类以及矩阵类。
#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();
}
  1. 参考文献:
    1. 《Warshall传递闭包算法的学习与实现》:https://www.cnblogs.com/lpshou/archive/2012/04/27/2473109.html
    2. new二维数组的用法:https://blog.csdn.net/qq_41611893/article/details/87910458
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值