网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 |
---|
如果右边没有就找找左边 |
- 线性表和树,线性表局限于一个直接前驱和一个直接后继,树只有一个直接前驱(父结点)
- 当我们需要多对多的关系时,就需要图这种数据结构
- 边是两个结点之间的连接
- 顶点就是结点
- 无向图,顶点之间的连接没有方向,A-B,既可以从A到B,又可以从B到A,而有向图,只能一个方向
- 路径,一个顶点到另一个顶点的路径,比如D->C的路径有D-B-C和D-A-B-C
- 有向图,顶点之间连接有方向
- 带权图,顶点直接的连接带有权值,这种图又名网
- 邻接矩阵(二维数组表示)
- 通过1和0表示两个顶点,是否存在直接连接,比如arr[0][1]=1,那么表示0这个顶点和1这个顶点相互连接
- 邻接表(链表)
一、代码实现
1. 创建图
- 思路
- 通过一个List保存顶点,
- 通过二维数组,也就是用邻接矩阵的方式表示顶点间的连接关系
- 运行效果
3.代码
import java.util.ArrayList;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
String[] arr = {"0","1","2","3","4","5"};
Graph graph = new Graph(arr.length);
graph.insertVertexs(arr);
graph.insetEdge(0,1);
graph.insetEdge(0,4);
graph.insetEdge(0,3);
graph.insetEdge(0,2);
graph.insetEdge(1,4);
graph.insetEdge(2,4);
graph.insetEdge(2,5);
graph.insetEdge(3,5);
graph.insetEdge(4,5);
graph.showGraph();
}
}
class Graph{
private ArrayList<String> vertexList;
private int[][] edges;
private int numOfEdges;
public Graph(int n){
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;
}
public int getNumOfVertex(){
return vertexList.size();
}
public int getNumOfEdges(){
return numOfEdges;
}
public String getValueByIndex(int i){
return vertexList.get(i);
}
public int getFlag(int v1,int v2){
return edges[v1][v2];
}
public void insertVertex(String vertex){
vertexList.add(vertex);
}
public void insertVertexs(String[] vertexs){
for (String s : vertexs){
vertexList.add(s);
}
}
public void insertEdge(int v1,int v2,int flag){
edges[v1][v2]=flag;
edges[v2][v1]=flag;
numOfEdges++;
}
public void insetEdge(int v1,int v2){
insertEdge(v1,v2,1);
}
public void showGraph(){
System.out.println("图的领接矩阵为:");
for (int[] row : edges){
System.out.println(Arrays.toString(row));
}
}
}
2. 图的遍历
- 图有两种遍历方式,深度优先(DFS)遍历和广度优先(BFS)遍历
1. 深度优先遍历
- 深度优先搜索(Depth First Search)
- 深度优先遍历,从初始结点出发,访问邻接的第一个结点,然后以被访问的结点,访问邻接它的下一个结点,每次访问完当前结点后,标记此结点已经访问过,然后访问当前结点的第一个邻接结点
- 此种访问策略,是优先向下挖掘深入,不是对一个结点的所有邻接结点横向访问,显然,深度优先搜索是一个递归的过程
- 运行结果
- 代码
private boolean[] vertexVisited;
public Graph(int n){
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;
vertexVisited = new boolean[n];
}
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(){
for (int i = 0;i<getNumOfVertex();i++){
if(!vertexVisited[i]){
dfs(vertexVisited,i);
}
}
}
public void dfs(boolean[] isVisited,int i){
System.out.println(getValueByIndex(i));
isVisited[i] = true;
int w = getFirstNeighbor(i);
while(w != -1){
if(!isVisited[w]){
dfs(isVisited,w);
}
w = getNextNeighbor(i,w);
}
}
2. 广度优先遍历
- 广度优先搜索(Broad First Search):类似分层搜索,需要使用队列以保证访问过结点的顺序,以便按顺序访问这些结点的邻接结点
- 访问初始结点,标记为已访问,入队列。
- 然后出队列,直到队列为空,算法结束
- 当一个结点出队列后,找到第一个邻接结点,不存在继续出队列,存在,就访问这个邻接结点,然后标记为已访问,入队列
- 然后继续查找刚刚出队列的内个结点的下一个邻接结点,如果没有了就继续出队列
- 运行结果
- 代码(用到的数组和一些方法,在深度优先遍历的代码块中)
public void bfs(){
for (int i = 0;i<getNumOfVertex();i++){
if(!vertexVisited[i]){
bfs(vertexVisited,i);
}
}
vertexVisitedInit();
}
public void bfs(boolean[] isVisited,int i){
int u;
int w;
LinkedList queue = new LinkedList<>();
System.out.print(getValueByIndex(i)+"=>");
isVisited[i] = true;
queue.addLast(i);
while(!queue.isEmpty()){
u = (Integer)queue.removeFirst();
w = getFirstNeighbor(u);
while(w!=-1){
if(!isVisited[w]){
System.out.print(getValueByIndex(w)+"=>");
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u,w);
}
}
}