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)。算法与中间元素的遍历顺序没有关系,因为开始时,路线起始点确定了,遍历元素只确定传递关系。