warshall算法

传递关系闭包算法

开始,先把关系集合转化为0,1矩阵,使得方便关系运算。

对于一般算法,通过矩阵点乘的来迭代的方式得到传递关系闭包的集合。

代码如下:

typedef struct matrix{//定义关系矩阵
    int n;
    int a[10][10];
}Matrix;

Matrix getTranstiveClosure(Matrix matrixA,int matrix_n){
    for(int num=1;num<matrix_n;num++){//R^n,迭代n-1次按照C语言,0号位置为数组第一位
        for(int i=0;i<matrix_n;i++){//开始矩阵布尔积运算
            for(int j=0;j<matrix_n;j++){
                for(int k=0;k<matrix_n;k++){
                    if(matrixA.a[i][j]==0)//优化或运算
                    matrixA.a[i][j]=(matrixA.a[i][k]&matrixA.a[k][j]);
                }
            }
        }
    }
    return matrixA;
}//M=getTranstiveClosure(matrixA);来得到传递闭包矩阵

其中矩阵点乘的算法复杂度为O(n^3),迭代次数为n-1次(得到R^n为结果),算法复杂度为O(n^4)。

对于此类算法,特点为为了找到某一关系(a,b),要把其他的元素作为中间元素来判断是否存在传递关系。

例如:a,b,c,d,e属于A集合,R为A的关系集合,为了找到(a,b),需要把c,d,e作为中间元素,如假设(a,c)(c,b)∈R,

(a,c)(c,b)->(a,b)∈R来得到传递关系。简言之,针对所求的关系,去遍历中间元素的关系去判断。

 

下面我们来看看warshall算法。

代码如下:

Matrix warshall(Matrix matrixB,int matrix_n){
    for(int k=0;k<matrix_n;k++){//K值选择中间量的元素来补全传递关系的路线
        for(int i=0;i<matrix_n;i++){//遍历新矩阵
            for(int j=0;j<matrix_n;j++){
                if(matrixB.a[i][j]==0){//优化或运算
                    matrixB.a[i][j]=matrixB.a[i][k]&matrixB.a[k][j];
                }//如(a->b)&(b->c)-->(a->c)的关系
            }
        }
    }
}

warshall算法的算法复杂度为O(n^3),其巧妙之处就在于无需矩阵的迭代,通过固定中间元素来进行判断关系,并对中间元素逐次遍历,

并对传递关系进行迭代,需要遍历的中间元素为n个,所求矩阵遍历操作为n^2,在n规模足够大的时候warshall算法能体现出优越性。

总结一下,对于同样矩阵上的一个所求关系的元素,一般算法需要的操作为n*(n-1),而warshall算法仅仅需要n次!

warshall例子:同样对于a,b,c,d,e∈A,关系集合R,若(a,b)(b,c)(c,d)(d,e)∈R,先把a作为中间元素,关系集合没变,

再是b,多了(a,c)∈R,再c,(a,d),再d,(a,e)。算法与中间元素的遍历顺序没有关系,因为开始时,路线起始点确定了,遍历元素只确定传递关系。

posted @ 2018-09-30 21:24  Jimmy-Home  阅读(5405)  评论(0编辑  收藏  举报