本文大部分参考:数据结构与算法java 作者:周鹏
pdf版下载地址
邻接矩阵法
图的邻接矩阵( adjacent matrix) 表示法是使用数组来存储图结构的方法,也被称为数组表示法。它采用两个数组来表示图:一个是用于存储所有顶点信息的一维数组,另一个是用于存储图中顶点之间关联关系的二维数组,这个关联关系数组也被称为邻接矩阵。
假设图G=(V , E)有n个顶点,即V={v0,v1,…,vn-1},则表示G中各顶点关联关系的为一个n×n的矩阵A,当两个顶点之间有边连接时,对应的元素表示边的权值,否则表示为无穷。
优点:
1. 表示方法非常直观简单,很容易确定两个顶点之间是否有边。
缺点
1. 空间需求为n^2。一般来说,图的边远远达不到n^2。造成空间的浪费
2. 二维数组静态分配,不够灵活
邻接表
邻接表是图的一种链式存储方法,在邻接表中对于图G中的每个顶点vi建立一个单链表,将所有邻接于vi的顶点vj链成一个单链表。在无向图的邻接表中,顶点vi的度恰为顶点vi的邻接表中结点的个数;而在有向图中,顶点vi的邻接表中边表结点的个数仅为顶点vi的出度,为求顶点vi的入度必须遍历整个邻接表,在所有链表中其邻接点域的值指向vi的位置的结点个数是顶点vi的入度。为了方便求得有向图中顶点的入度,可以建立一个有向图的逆邻接表。将指向vi顶点的边也链接到顶点vi,这样便可方便求得入度。
在邻接表中容易找到一个顶点的邻接点,但是要判定两个顶点vi和vj之间是否有边,则需要搜索顶点vi或顶点vj的邻接表,与邻接矩阵相比不如邻接矩阵方便。
示例
leetcode朋友圈问题
邻接矩阵表示法:
package dataStructureAndAlgorithms;
import java.util.LinkedList;
import java.util.Queue;
public class FriendCircleProblemByAdjacencyMatrix {
/*
* M 邻接矩阵
* visit 是否被访问
* i 从i出发
*/
public static void dfs(int[][] M, boolean[] visit,int i){
for(int j=0;j<M[0].length;j++){
if(M[i][j] != 0 && !visit[j]){
visit[j] = true;
dfs(M,visit,j);
}
}
}
public static void bfs(int[][] M, boolean[] visit,int i){
Queue<Integer> toVisitQueue = new LinkedList<Integer>();
toVisitQueue.add(i);
while(!toVisitQueue.isEmpty()){
int temp = toVisitQueue.poll();
visit[temp] = true;
for(int j=0;j<M[0].length;j++ ){
if(M[temp][j] != 0 && !visit[j]){
toVisitQueue.add(j);
}
}
}
}
public static int findCircleNum(int[][] M){
boolean[] visit = new boolean[M[0].length];
int circle = 0;
for(int i=0;i<M[0].length;i++){
if(!visit[i]){
//bfs(M, visit, i);
dfs(M, visit, i);
circle ++;
}
}
return circle;
}
public static void main(String[] args) {
int[][] M1 = {{1,1,0},{1,1,0},{0,0,1}};
System.out.println(findCircleNum(M1));
int[][] M2 = {{1,1,0},{1,1,1},{0,1,1}};
System.out.println(findCircleNum(M2));
}
}
邻接表表示法:
package dataStructureAndAlgorithms;
import java.util.LinkedList;
import java.util.Queue;
public class FriendCircleProblemByAdjacencyList {
public static void dfs(Vertex vertex){
Neighbor neighbor = vertex.getNeighbor();
while(neighbor != null){
if(!neighbor.getV().visited){
neighbor.getV().setVisited(true);
dfs(neighbor.getV());
}
neighbor = neighbor.getNext();
}
}
public static void bfs(Vertex vertex){
Queue<Vertex> toVisitQueue = new LinkedList<Vertex>();
toVisitQueue.add(vertex);
while(!toVisitQueue.isEmpty()){
Vertex temp = toVisitQueue.poll();
temp.setVisited(true);
Neighbor neighbor = temp.getNeighbor();
while(neighbor != null){
if(!neighbor.getV().isVisited()){
toVisitQueue.add(neighbor.getV());
}
neighbor = neighbor.getNext();
}
}
}
public static int findCircleNum(Vertex[] vertexs, boolean useDfs){
int circle = 0;
for(int i=0;i<vertexs.length;i++){
if(!vertexs[i].isVisited()){
if(useDfs){
dfs(vertexs[i]);
}else{
bfs(vertexs[i]);
}
circle ++;
}
}
return circle;
}
public static void main(String[] args) {
//顶点
Vertex vertex0 = new Vertex();
vertex0.setNumber(0);
Vertex vertex1 = new Vertex();
vertex1.setNumber(1);
Vertex vertex2 = new Vertex();
vertex2.setNumber(2);
Vertex[] vertexs = {vertex0,vertex1,vertex2};
//test1 构造邻接表
vertex0.setNeighbor(new Neighbor(vertex1));
vertex1.setNeighbor(new Neighbor(vertex0));
System.out.println(findCircleNum(vertexs,true));
vertex0.setVisited(false);
vertex1.setVisited(false);
vertex2.setVisited(false);
System.out.println(findCircleNum(vertexs,false));
//test2
vertex0.setNeighbor(null);
vertex1.setNeighbor(null);
vertex2.setNeighbor(null);
vertex0.setNeighbor(new Neighbor(vertex1));
vertex1.setNeighbor(new Neighbor(vertex0));
vertex1.setNeighbor(new Neighbor(vertex2));
vertex2.setNeighbor(new Neighbor(vertex1));
vertex0.setVisited(false);
vertex1.setVisited(false);
vertex2.setVisited(false);
System.out.println(findCircleNum(vertexs,true));
vertex0.setVisited(false);
vertex1.setVisited(false);
vertex2.setVisited(false);
System.out.println(findCircleNum(vertexs,false));
}
static class Neighbor{
public Neighbor(Vertex vertex){
this.v = vertex;
}
private Vertex v = null;
private Neighbor next = null;
public Vertex getV() {
return v;
}
public void setV(Vertex v) {
this.v = v;
}
public Neighbor getNext() {
return next;
}
public void setNext(Neighbor next) {
this.next = next;
}
}
static class Vertex{
private int number;
private Neighbor neighbor;
private Vertex nextVertex;
private boolean visited = false;
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
public Vertex getNextVertex() {
return nextVertex;
}
public void setNextVertex(Vertex nextVertex) {
this.nextVertex = nextVertex;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Neighbor getNeighbor() {
return neighbor;
}
public void setNeighbor(Neighbor neighbor) {
if(neighbor == null){
this.neighbor = null;
return;
}
neighbor.next = this.neighbor;
this.neighbor = neighbor;
}
}
}