邻接表只关心存在的边,相较于邻接矩阵而言不关心不存在的边,因此没有空间的浪费,邻接表由数组和链表组成。
使用邻接矩阵表示图。
思路:
import java.util.ArrayList;
import java.util.Arrays;
public class Graph {
private ArrayList<String> vertexList;
private int[][] edge;
private int edgesNum;
public static void main(String[] args) {
String[] vertex = {"A","B","C","D","E"};
Graph graph = new Graph(vertex.length);
for(String i:vertex){
graph.insertVertex(i);
}
graph.insertEdge(0,1,1);
graph.insertEdge(0,2,1);
graph.insertEdge(1,2,1);
graph.insertEdge(1,3,1);
graph.insertEdge(1,4,1);
graph.getGraph();
}
/**
* 有参构造函数
* @param n 为图的节点数
*/
public Graph(int n){
vertexList = new ArrayList<String>(n);
edge = new int[n][n];
edgesNum =0;
}
public void insertVertex(String vertex){
vertexList.add(vertex);
}
public void insertEdge(int v1,int v2,int weight){
edge[v1][v2]=weight;
edge[v2][v1]=weight;
edgesNum++;
}
public int getVertexNum(){
return vertexList.size();
}
public int getEdgesNum(){
return edgesNum;
}
/**
*
* @param i 节点的索引
* @return 索引节点的值
*/
public String getVertex(int i){
return vertexList.get(i);
}
/**
*
* @param v1 节点v1的索引
* @param v2 节点V2的索引
* @return 两个节点相连边的权值
*/
public int getWeight(int v1,int v2){
return edge[v1][v2];
}
//打印图的邻接矩阵
public void getGraph(){
for(int[] i :edge){
System.out.println(Arrays.toString(i));
}
}
}
深度优先遍历策略是一个往纵向挖掘的过程,其访问节点的过程是:首相访问初始节点,在访问初始节点的一个邻接节点,然后将次节点作为初始节点,再访问它的下一个邻接节点。深度优先遍历是一个递归的过程。
import java.util.ArrayList;
import java.util.Arrays;
public class Graph {
private ArrayList<String> vertexList;
private int[][] edge;
private int edgesNum;
private boolean[] isVisted;
//得到第一个邻接节点的下标
public int getFirstneighbour(int i){
for(int j = 0;j<vertexList.size();j++){
if(edge[i][j]>0){ //两个节点的边大于0说明相连
return j;
}
}
return -1; //没有邻接节点
}
/**
*
* @param v1 为初始节点
* @param v2 为初始节点的下一个邻接点但是被访问过了
* @return 返回一个初始节点没有被访问过的邻接点
*/
public int getNextneighbour(int v1,int v2){
for(int j=v2+1;j<vertexList.size();j++){
if(edge[v1][j]>0){
return j;
}
}
return -1;
}
/**
*
* @param isVisted 节点是否访问数组
* @param i 初始节点
*/
private void dfs(boolean[] isVisted,int i){
//访问入口的节点
System.out.print(vertexList.get(i)+"-->");
isVisted[i] =true;
int neighbour = getFirstneighbour(i);
while (neighbour!=-1){ //下一个邻接点存在
if(isVisted[neighbour]==false){ //下一个邻接点没访问过
dfs(isVisted,neighbour);
}else { //下一个邻接点访问过了
neighbour = getNextneighbour(i,neighbour);
}
}
}
public void dfs(){
for(int i =0;i<vertexList.size();i++){
if(isVisted[i]==false){
dfs(isVisted,i);
}
}
}
广度优先遍历类似于分层搜索的过程,需要使用一个队列存储访问的节点。
/**
*
* @param isVisted 节点是否访问数组
* @param i 初始节点
*/
private void bfs(boolean[] isVisted,int i){
System.out.print(getVertex(i)+"-->"); //取出初始节点
isVisted[i] =true; //将初始节点标记为以访问
Queue<Integer> vertexQueue = new LinkedList<>();
vertexQueue.add(i); //将访问的初始节点加入队列
while (!vertexQueue.isEmpty()) { //队列不为空
int intial = vertexQueue.poll(); //删除队列头元素
int neighbour = getFirstneighbour(i); // 获取初始节点的第一个邻接点
while (neighbour != -1) { //邻接点存在
if (isVisted[neighbour] == false) { //邻接点没有访问过
System.out.print(getVertex(neighbour)+"-->"); //打印邻接点
isVisted[neighbour] = true; //标记邻接点访问过
vertexQueue.add(neighbour);//将邻接点加入队列
} else {
neighbour = getNextneighbour(intial,neighbour);
}
}
}
}
public void bfs(){
for(int i=0;i<getVertexNum();i++){
if(isVisted[i]==false){
bfs(isVisted,i);
}
}
}
图的广度优先遍历思路: