一、概念
- 一种非线性表数据结构
如上所示:图片中A、B、C、D等称之为图的定点,一条条竖线称为图的边,如顶点A有三条边
二、图的存储方法
1、邻接矩阵
- 依赖二维数组存储
- 如果a[i][j]之间有边,就标为1,本身标为0,如下所示,a[1][1] = 0,a[1][2] = 1,a[1][3] = 1,a[1][4] = 0
使用邻接矩阵存储比较浪费空间,如a[i][j]和a[j][i]存储的是一样的,只需存储一次就行了,用矩阵需要存储两次
2、邻接表
-
依赖链表存储
-
维护一条链表,每个链表的节点又各自维护一条链表,如图所示,顶点1指向2,对应的链表中存储2,也就是说,每个顶点的链表中存储的是与这个顶点有边的顶点
-
邻接表存储是一种空间换时间的方式,如果链表过长,遍历起来的时间复杂度比较高
-
可以对链表存储的方式进行改造,比如每个顶点可以用散列表存储,每个顶点对应的链表可以用平衡二叉查找树存储来提高查找效率
三、代码实现
package Graph;
import java.util.LinkedList;
import java.util.Queue;
public class graph_nie {
private int v; //顶点个数
private LinkedList<Integer>[] adj; //使用邻接表数据结构来存储链表
public graph_nie(int v){
this.v = v;
this.adj = new LinkedList[v];
for (int i = 0; i < v; i++){
adj[i] = new LinkedList<>();
}
; }
public void addedge(int s,int t){
adj[s].add(t);
adj[t].add(s);
}
public void bfs(int s,int t){
//广度优先遍历
if (s == t){
return;
}
boolean[] visited = new boolean[v];
Queue<Integer> queue = new LinkedList<>();
queue.add(s);
int[] prev = new int[v];
for (int i = 0;i < v;i++){
prev[i] = -1;
}
while (queue.size() != 0){
int w = queue.poll();
for (int i = 0; i < adj[w].size(); i++){
int q = adj[w].get(i);
if (!visited[q]){
visited[q] = true;
prev[q] = w;
if (t == q){
print(prev,s,t);
return;
}
queue.add(q);
}
}
}
}
boolean found = false;
public void dfs(int s,int t){
found = false;
int[] prev = new int[v];
boolean[] visited = new boolean[v];
for (int i = 0; i < v; i++){
prev[i] = -1;
}
reducerDFS(prev,visited,s,t);
print(prev,s,t);
}
private void reducerDFS(int[] prev,boolean[] visited,int s,int t){
if (found == true){
return;
}
if (s == t){
found = true;
return;
}
for (int i = 0;i < adj[s].size();i++){
int q = adj[s].get(i);
if (!visited[q]){
visited[q] = true;
prev[q] = s;
reducerDFS(prev,visited,q,t);
}
}
}
private void print(int[] prev,int s,int t){
if (prev[t] != -1 && t != s){
print(prev,s,prev[t]);
}
System.out.println(t + " ");
}
}