圖:
一種多對多的數據結構,可以使用鄰接矩陣來存儲數據(鄰接矩陣:假如有M個點,則創建 M * M 的鄰接矩陣,【0,1】點表示0到1的點,如果其值不爲0,則表示0到1的權值),如果邊比較少,矩陣稀疏此方式比較浪費內存;這時候可以使用鄰接表來存儲數據(鄰接表: 創建一個長度爲M的數組a[M], 其中a[0]表示第0個節點,其值爲一個鏈表,鏈表立裏保存的是與第0個節點相鏈接的點),鄰接表相對省內存,但是操作沒有鄰接矩陣方便。一般途中用v表示點,u表示邊;圖可以分爲有向圖和無向圖,無向圖——A可以到B,則默認的B可以到A,點到點之間沒有方向;有向圖——A可以到B,但是B不一定可以到A,點到點之間是有方向的。加權圖——點到點之間的距離不一樣,它們之間不同的距離用不同的權來表示,還可以稱爲網。
圖的廣度優先遍歷與深度優先遍歷:
public class MapDemo {
private ArrayList<String> vertexList; //存儲頂點集合
private int[][] edges; //
private int numOfedges; //表示邊的數目
//定義一個數組用來記錄某個頂點是否被訪問過
private boolean[] isVisited;
public static void main(String[] args) {
//測試
int n = 8;
// String VertexVal[] = {"A", "B","C","D","E"} ;
String VertexVal[] = {"1", "2","3","4","5","6","7","8"} ;
//創建圖對象
MapDemo mapDemo = new MapDemo(n);
for (String val : VertexVal) {
mapDemo.insertVertex(val);
}
//添加邊
mapDemo.insertEdge(0,1,1);
mapDemo.insertEdge(0,2,1);
mapDemo.insertEdge(1,3,1);
mapDemo.insertEdge(1,4,1);
mapDemo.insertEdge(3,7,1);
mapDemo.insertEdge(4,7,1);
mapDemo.insertEdge(2,5,1);
mapDemo.insertEdge(2,6,1);
mapDemo.insertEdge(5,6,1);
mapDemo.showMap();
System.out.println("深度優先遍歷");
mapDemo.dfs();
// mapDemo.bfs();
}
//構造器
public MapDemo(int n) {
//初始化矩陣和vertexList
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfedges = 0;
isVisited = new boolean[n];
}
//得到第一個鄰接節點的下標w
public int getFirstNeighbor(int index) {
for (int j = 0; j < vertexList.size(); j++) {
if (edges[index][j] > 0) {
return j;
}
}
return -1;
}
//根據前一個鄰接節點的下標,獲取下一個鄰接節點
public int getNextNeighbor(int v1, int v2) {
for (int j = v2+1; j < vertexList.size(); j++) {
if (edges[v1][j] > 0) {
return j;
}
}
return -1;
}
//深度優先遍歷
public void dfs(boolean[] isVisited, int i) {
//訪問該節點
System.out.print(getValueByIndex(i) + "->");
isVisited[i] = true;
int w = getFirstNeighbor(i);
while (w != -1) {
if (!isVisited[w]) {
dfs(isVisited, w);
}
w = getNextNeighbor(i, w);
}
}
//
public void dfs() {
//遍歷所有的節點
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i] ) {
dfs(isVisited, i);
}
}
}
//廣度優先算法
private void bfs() {
int u; //表示隊列的頭結點對應的下標
int w; //鄰接節點w
int i = 0;
//隊列
LinkedList<Integer> queue = new LinkedList<>();
queue.addLast(i);
isVisited[i] = true;
while (!queue.isEmpty()) {
//取出隊列的頭
Integer integer = queue.removeFirst();
u = integer;
w = getFirstNeighbor(u);
while (w != -1) {
if (!isVisited[w]) {
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u, w);
}
System.out.print(getValueByIndex(u) + "=>");
}
}
//返回節點的個數
public int getNumOfVertex() {
return vertexList.size();
}
//得到邊的數目
public int getNumOfedges() {
return numOfedges;
}
//返回i下標對應的數據: 0 -> A, 1 -> B, 2->C
public String getValueByIndex(int i) {
return vertexList.get(i);
}
//返回v1和v2的權值
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
//插入節點
public void insertVertex(String vertex) {
vertexList.add(vertex);
}
//顯示圖對應的矩陣
public void showMap() {
for (int i = 0; i < edges.length; i++) {
System.err.println(Arrays.toString(edges[i]));
}
}
//添加邊
/**
*
* @param v1 表示點的下標,即第幾個頂點
* @param v2 表示點的下標,
* @param weight 路徑上的權值
*/
public void insertEdge(int v1, int v2, int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfedges++;
}
}