图:
一种多对多的数据结构,可以使用邻接矩阵来存储数据(邻接矩阵:假如有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++;
}
}