傳遞關系閉包算法
開始,先把關系集合轉化為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)。算法與中間元素的遍歷順序沒有關系,因為開始時,路線起始點確定了,遍歷元素只確定傳遞關系。