有向無環圖的拓撲排序
拓撲排序只能用於無環圖。
// 頂點
class Vertex3 {
char label;
boolean visited;
public Vertex3(char label) {
this.label = label;
visited = false;
}
}
public class Topo {
private final int maxVer = 20;// 最大頂點數
private int[][] adjMat;// 鄰接矩陣
private Vertex3[] vertex;// 頂點陣列
private int curVer;// 當前頂點數
public Topo() {
curVer = 0;
vertex = new Vertex3[maxVer];
adjMat = new int[maxVer][maxVer];
for (int i = 0; i < maxVer; i++)
for (int j = 0; j < maxVer; j++)
adjMat[i][j] = 0;
}
// 新增頂點
public void addVer(char label) {
vertex[curVer++] = new Vertex3(label);
}
// 新增有向邊,不是雙向
public void addAdj(int i, int j) {
if (i == j)
return;
adjMat[i][j] = 1;
}
public void displayVer(int index) {
System.out.print(vertex[index].label);
}
// 拓撲排序:只能用於有向無環圖
// 先找到一個起始點,找後繼點,“刪除”起始點,迴圈進行。該方法效率低,不如直接刪除點好吧。
public void topo() {
int temp = curVer;
while (temp > 0) {
int first = findFirst();
if (first == -1) {
System.out.println("\nloop(s) occur");
return;
}
displayVer(first);
vertex[first].visited = true;
temp--;
}
for(int i=0;i<curVer;i++)
vertex[i].visited=false;
}
//找到一個點,沒有其他點指向它或指向它的點都訪問過了,說明該點是找到的一個新起點
private int findFirst() {
a: for (int i = 0; i < curVer; i++) {
for (int j = 0; j < curVer; j++) {
if (adjMat[j][i] == 1 && vertex[j].visited == false)
continue a;
}
if (vertex[i].visited == false)// 不取重複值
return i;
}
return -1;// 說明有環,沒有環的單向圖是一定有起始點的
}
public static void main(String[] args) {
Topo g = new Topo();
g.addVer('A');
g.addVer('B');
g.addVer('C');
g.addVer('D');
g.addAdj(0, 1);
g.addAdj(0, 2);
g.addAdj(1, 2);
g.addAdj(2, 3);
g.addAdj(3, 1);
g.topo();
}
}
//書上拓撲排序程式碼
// 頂點
class Vertex_1 {
char label;
public Vertex_1(char label) {
this.label = label;
}
}
public class Graph_2 {
char[] sortedArray;
private final int maxVer = 20;// 最大頂點數
private int[][] adjMat;// 鄰接矩陣
private Vertex_1[] vertex;// 頂點陣列
private int curVer;// 當前頂點數
public Graph_2() {
sortedArray = new char[maxVer];
curVer = 0;
vertex = new Vertex_1[maxVer];
adjMat = new int[maxVer][maxVer];
for (int i = 0; i < maxVer; i++)
for (int j = 0; j < maxVer; j++)
adjMat[i][j] = 0;
}
// 新增頂點
public void addVer(char label) {
vertex[curVer++] = new Vertex_1(label);
}
// 新增有向邊
public void addAdj(int i, int j) {
if (i == j)
return;
adjMat[i][j] = 1;
}
public void displayVer(int index) {
System.out.print(vertex[index].label);
}
// 拓撲排序:只能用於有向無環圖
// 先找到一個起始點,找後繼點,刪除起始點,迴圈進行
public void topo() {
int temp = curVer;
while (curVer > 0) {
int first = noSuccessors();
if (first == -1) {
System.out.println("\n graph has cycles");
return;
}
sortedArray[curVer - 1] = vertex[first].label;// 將圖的末端點從後往前放入陣列
deleteVer(first);
}
for (int i = 0; i < temp; i++)
System.out.print(sortedArray[i]);
System.out.println();
}
// 2個操作:第一步將頂點刪除,第二步以要刪除點為開頭和結尾的臨接矩陣元素刪除,即矩陣收縮一維(要用的變少了而已)
private void deleteVer(int index) {
if (index != curVer - 1) {
for (int j = index; j < curVer - 1; j++)
vertex[j] = vertex[j + 1];// 從要刪除的位置開始左移
for (int row = index; row < curVer - 1; row++)
moveRowUp(row, curVer);
for (int col = index; col < curVer - 1; col++)
moveColLeft(col, curVer - 1);// 因為上一個迴圈的原因,此時可以少移動一列
}
curVer--;
}
private void moveColLeft(int col, int length) {
for (int row = 0; row < length; row++)
adjMat[row][col] = adjMat[row][col + 1];
}
private void moveRowUp(int row, int length) {
for (int col = 0; col < length; col++)
adjMat[row][col] = adjMat[row + 1][col];
}
// 返回沒有後繼點的頂點,即圖的末端,插入陣列時正好從陣列後面開始放
private int noSuccessors() {
boolean isEdge;
for (int row = 0; row < curVer; row++) {
isEdge = false;
for (int col = 0; col < curVer; col++) {
if (adjMat[row][col] > 0) {
isEdge = true;
break;
}
}
if (!isEdge)
return row;
}
return -1;
}
//WarShall演算法,將臨接矩陣修改,不論一步或多步,只要一個頂點能到達另一個頂點,相應矩陣元素設為1
//如A到B,B到C,那麼A到C為1
public void WarShall(){
for(int y=0;y<curVer;y++){//行
for(int x=0;x<curVer;x++){//列
if(adjMat[y][x]==1)
for(int z=0;z<curVer;z++){//z代表x那一列
if(adjMat[x][z]==1)
adjMat[y][z]=1;
}
else continue;
}
}
for(int i=0;i<curVer;i++){
for(int j=0;j<curVer;j++)
System.out.print(adjMat[i][j]+" ");
System.out.println();
}
}
public static void main(String[] args) {
Graph_2 g = new Graph_2();
g.addVer('A');
g.addVer('B');
g.addVer('C');
g.addVer('D');
g.addVer('E');
g.addVer('F');
g.addVer('G');
g.addVer('H');
g.addAdj(0, 3);
g.addAdj(0, 4);
g.addAdj(1, 4);
g.addAdj(2, 5);
g.addAdj(3, 6);
g.addAdj(4, 6);
g.addAdj(5, 7);
g.addAdj(6, 7);
//g.topo();// BAEDGCFH
g.WarShall();//對拓撲排序好像無影響
g.topo();// BAEDGCFH
}
}