圖的存儲結構(鄰接矩陣方式)
此圖為帶權無向圖
public class MyGraph {
private ArrayList<Object> vertexList; //存放頂點的數組
private int[][] edges; //鄰接矩陣,存放邊集
private int numofEdges; //邊數
private static final int INF = 65535; //權值為65535時表示不可達
private boolean[] visited; //用于深度、廣度遍歷時頂點是否已被訪問的標志
public MyGraph(int n) {
vertexList = new ArrayList<>(n); //根據傳入的頂點數構造頂點數組
edges = new int[n][n]; //構造對應的鄰接矩陣
numofEdges = 0;
visited = new boolean[n];
//初始化鄰接矩陣
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if (i == j) {
edges[i][j] = 0;
}else {
edges[i][j] = INF;
}
}
}
}
//獲取頂點個數
public int getNumOfVertex() {
return vertexList.size();
}
//獲取邊數
public int getNumofEdges() {
return numofEdges;
}
//打印鄰接矩陣
public void printEdges() {
for(int i = 0; i < vertexList.size(); i++) {
for(int j =0; j < vertexList.size(); j++) {
if (j == vertexList.size() - 1) {
System.out.println(edges[i][j]);
}else {
System.out.print(edges[i][j]+" ");
}
}
}
}
//獲取頂點n的值
public Object getValueByIndex(int n) {
return vertexList.get(n);
}
//獲取邊n1-n2的權值
public int getWeight(int n1, int n2) {
return edges[n1][n2];
}
//插入結點
public void insertVertex(Object vertex) {
vertexList.add(vertexList.size(),vertex);
}
//插入頂點以及設置權值
public void insertEdge(int n1, int n2, int weight) {
edges[n1][n2] = weight;
//該圖為無向圖,所以矩陣關于對角線對稱
edges[n2][n1] = weight;
numofEdges++;
}
//刪除邊
public void deleteEdge(int n1, int n2) {
edges[n1][n2] = INF;
//無向圖刪除邊時矩陣依舊對稱
edges[n2][n1] = INF;
numofEdges--;
}
}
測試類
測試圖如圖所示:
圖片.png
測試程序如下:
//頂點數為4
int n = 4;
String[] vertex = {"A","B","C","D"};
MyGraph graph = new MyGraph(n);
for (String string : vertex) {
graph.insertVertex(string);
}
graph.insertEdge(0, 1, 3);
graph.insertEdge(0, 2, 8);
graph.insertEdge(0, 3,10);
graph.insertEdge(1, 2, 6);
System.out.println("結點數:"+graph.getNumOfVertex());
System.out.println("邊數:"+graph.getNumofEdges());
System.out.println("刪除前的鄰接矩陣:");
graph.printEdges();
graph.deleteEdge(1, 2);
System.out.println("刪除邊<B,C>后:");
System.out.println("結點個數為:"+graph.getNumOfVertex());
System.out.println("邊數為:"+graph.getNumofEdges());
System.out.println("刪除后的鄰接矩陣:");
graph.printEdges();
測試結果:
圖片.png
遍歷算法
測試圖(由于權值不影響遍歷結果,所以不標注):
圖片.png
深度優先
//鄰接矩陣的深度遍歷操作
public void DFSTraverse(MyGraph graph) {
for (int i = 0; i < graph.getNumOfVertex(); i++) {
visited[i] = false;
}
for( int i = 0; i < graph.getNumOfVertex(); i++) {
//對未訪問過的結點調用DFS,若是連通圖,只會執行一次,非連通圖的話有多少個子圖則會調用多少次
if (!visited[i]) {
DFS(graph, i);
}
}
}
//鄰接矩陣的深度優先遞歸算法
public void DFS(MyGraph graph, int i) {
//設置訪問標志位為true
visited[i] = true;
System.out.print(getValueByIndex(i)+" ");
for(int j = 0; j < graph.getNumOfVertex(); j++) {
if (edges[i][j] != 0 && edges[i][j] != INF && !visited[j] ) {
//對未訪問的鄰接結點遞歸調用
DFS(graph, j);
}
}
}
廣度優先
//鄰接矩陣的廣度遍歷算法
public void BFSTraverse(MyGraph graph) {
int i,j;
//初始化訪問標志矩陣
for(i = 0; i < graph.getNumOfVertex(); i++) {
visited[i] = false;
}
//使用linkedList模擬隊列的功能
LinkedList<Integer> queue = new LinkedList<>();
for(i = 0; i < graph.getNumOfVertex(); i++) {
//該圖為非連通圖時,第一次廣度遍歷完后還有結點未被訪問時會再次進入這個分支
//該圖為連通圖時,該分支只會執行一次,因為執行一次后所有的結點都被訪問到了
if (!visited[i]) {
visited[i] = true;
System.out.print(getValueByIndex(i)+" ");
//將結點添加到隊尾
queue.addLast(i);
while(!queue.isEmpty()) {
//移除隊頭元素并將其賦值給i
i = ((Integer)queue.removeFirst()).intValue();
for(j = 0; j < graph.getNumOfVertex(); j++) {
if (edges[i][j] != 0 && edges[i][j] != INF && !visited[j] ) {
visited[j] = true;
System.out.print(getValueByIndex(j)+" ");
queue.addLast(j);
}
}
}
}
}
}
廣度優先各結點在隊列中的情況如下
圖片.png
測試程序:
public class GraphTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//頂點數為4
int n = 9;
String[] vertex = {"A","B","C","D","E","F","G","H","I"};
MyGraph graph = new MyGraph(n);
for (String string : vertex) {
graph.insertVertex(string);
}
graph.insertEdge(0, 1, 3);
graph.insertEdge(0, 2, 8);
graph.insertEdge(1, 3,10);
graph.insertEdge(1, 4, 3);
graph.insertEdge(2, 5, 3);
graph.insertEdge(2, 6, 3);
graph.insertEdge(3, 7, 3);
graph.insertEdge(7, 8, 3);
System.out.println("深度優先遍歷結果:");
graph.DFSTraverse(graph);
System.out.println("\n廣度優先遍歷:");
graph.BFSTraverse(graph);
}
}
測試結果:
圖片.png