图的存储方式主要有两种:邻接矩阵和邻接表,零阶矩阵主要是用二维数组的方式来存储点与点之间的关系,而邻接表主要是一维数组加链表的方式来记录点与点之间的关系。下面我们从两个不同的方式来编写代码。
1、邻接矩阵
代码如下:
package graph_arr;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 带权有向图
*
* @author JustGeeker
*
*/
public class Graph {
private List<String> vertexes;// 用来存放结点信息
private int[][] graphEgdes;// 又来记录边
private int numofEdges;// 记录边的个数
private boolean[] visited;
public Graph() {
super();
}
public Graph(int n) {
super();
visited = new boolean[n];
this.vertexes = new ArrayList<>(n);
this.graphEgdes = new int[n][n];
this.numofEdges = 0;
}
public Graph(String[] vertexarr) {
super();
int len = vertexarr.length;
this.vertexes = new ArrayList<>(len);
visited = new boolean[len];
for (String vertex : vertexarr) {
vertexes.add(vertex);
}
this.graphEgdes = new int[len][len];
this.numofEdges = 0;
}
/**
* 插入结点
*
* @param str结点信息
*/
public void addVertex(String str) {
vertexes.add(str);
}
/**
* 根据结点索引添加有向边
*
* @param index1 起始节点结点的索引
* @param index2 终止结点的索引
* @param weight 两点之间权值
*/
public void addEdge(int index1, int index2, int weight) {
int len = graphEgdes.length;
if (index1 > len || index1 < 0 | index2 > len || index2 < 0) {
System.out.println("索引越界");
return;
}
graphEgdes[index1][index2] = weight;
numofEdges++;
}
/**
* 根据两个结点添加有向边
*
* @param index1 起始节点结点
* @param index2 终止结点
* @param weight 两点之间权值
*/
public void addEdge(String vertex1, String vertex2, int weight) {
int index1 = getIndex(vertex1);
int index2 = getIndex(vertex2);
int len = graphEgdes.length;
if (index1 < -1 || index2 < -1) {
System.out.println("结点不存在");
return;
}
graphEgdes[index1][index2] = weight;
numofEdges++;
}
/**
* 根据两个结点添加有向边
*
* @param index1 起始节点结点
* @param index2 终止结点
* @param weight 两点之间权值
*/
public void addEdges(String vertex1, String vertex2, int weight) {
addEdge(vertex1, vertex2, weight);
addEdge(vertex2, vertex1, weight);
}
/**
* 添加两个结点之间的无向边
*
* @param index1 起始节点结点的索引
* @param index2 终止结点的索引
* @param weight 两点之间权值
*/
public void addEdges(int index1, int index2, int weight) {
addEdge(index1, index2, weight);
addEdge(index2, index1, weight);
}
/**
* 返回结点个数
*
* @return
*/
public int getVertexsNum() {
return vertexes.size();
}
/**
* 返回图中边的个数
*
* @return
*/
public int getEdgesNum() {
return numofEdges;
}
/**
* 根据索引返回结点信息
*
* @param i
* @return
*/
public String getVertex(int i) {
return vertexes.get(i);
}
/**
* 根据结点信息返回索引
*
* @param vertex
* @return
*/
public int getIndex(String vertex) {
if (vertexes.contains(vertex)) {
return vertexes.indexOf(vertex);
}
return -1;
}
/**
* 打印临界矩阵
*/
public void showEdge() {
System.out.println(" " + vertexes);
for (int i = 0; i < graphEgdes.length; i++) {
System.out.print(vertexes.get(i));
System.out.println(Arrays.toString(graphEgdes[i]));
}
System.out.println();
}
/**
* 深度遍历
*
* @param index 出发点
*/
public void DFS(int index) {
int num = vertexes.size();
if (index < 0 || index > num) {
return;
}
System.out.println(vertexes.get(index));// 打印出当前结点
visited[index] = true;// 标记访问
for (int i = 0; i < num; i++) {// 遍历其他点和该点的连通关系
if (!visited[i] && graphEgdes[index][i] == 1) {
DFS(i);// 递归遍历
}
}
}
/**
*
* 广度遍历
*
* @param index
*/
public void BFS(int index) {
int num = vertexes.size();
if (index < 0 || index > num) {
return;
}
int front = 0, rear = 0;// 设置前标和后标
int[] arr = new int[num];// 存储队列
System.out.println(vertexes.get(index));// 打印出当前结点
visited[index] = true;// 设置访问过
arr[rear++] = index;// 将当前访问的结点的索引放到存储对列
while (front != rear) {
index = arr[front++];// 取出当前存储队列队头的下表
for (int i = 0; i < num; i++) {// 遍历其他点和该点的连通关系
if (!visited[i] && graphEgdes[index][i] == 1) {
System.out.println(vertexes.get(i));// 打印当前点
visited[i] = true;// 标记访问
arr[rear++] = i;// 将访问后的下标存入队列
}
}
}
}
}
2、邻接表
代码如下:
先是结点和边的代码
package graph_link;
public class Vertex {
String value;// 结点的值
Edge firstEdge;// 表示第一条边
public Vertex(String val) {
super();
this.value = val;
}
public Vertex() {
super();
}
@Override
public String toString() {
return "Vertex [value=" + value + "]";
}
}
public class Edge {
int order;// 下一个结点的序号
int weight;// 权重
Edge next;// 下一条边
public Edge() {
super();
}
public Edge(int order, int weight) {
super();
this.order = order;
this.weight = weight;
}
@Override
public String toString() {
return "Edge [order=" + order + "]";
}
}
下面是邻接表的详细操作,具体的细节我记录在代码中的注释中
import java.util.ArrayList;
import java.util.List;
/**
* 有向的邻接表
*
* @author JustGeeker
*
*/
public class GraphLink {
List<Vertex> vertexes; // 结点集合
private boolean[] visited;// 结点访问标记数组
int numofEdge;// 边的数量
public GraphLink() {
// TODO Auto-generated method stub
super();
}
/**
*
* @param n 结点的个数
*/
public GraphLink(int n) {
super();
this.vertexes = new ArrayList<>(n);
visited = new boolean[n];
this.numofEdge = 0;
}
public void addVertex(String vertex) {
Vertex v = new Vertex(vertex);
vertexes.add(v);
}
/**
*
* @param vertices 结点数组
*/
public GraphLink(String[] vertices) {
super();
this.vertexes = new ArrayList<>(vertices.length);
visited = new boolean[vertices.length];
int len = vertices.length;
for (String vertex : vertices) {
addVertex(vertex);
}
this.numofEdge = 0;
}
/**
* 返回结点个数
*
* @return
*/
public int getVertexsNum() {
return vertexes.size();
}
/**
* 返回图中边的个数
*
* @return
*/
public int getEdgesNum() {
return numofEdge;
}
/**
* 根据索引返回结点信息
*
* @param i
* @return
*/
public Vertex getVertex(int i) {
return vertexes.get(i);
}
/**
* 根据结点信息返回索引
*
* @param vertex
* @return
*/
public int getIndex(String vertex) {
for (int i = 0; i < vertexes.size(); i++) {
if (vertexes.get(i).value.equals(vertex)) {
return i;
}
}
return -1;
}
/**
* 插入边
*
* @param i 起始结点的索引
* @param j 终止结点的索引
* @param weight 该边的权值
*/
public void addEdge(int i, int j, int weight) {
int len = vertexes.size();
if (i < 0 || j < 0 || i > len || j > len) {
System.out.println("索引越界");
return;
}
// System.out.println(vertexes.get(i) + " " + vertexes.get(j));
Edge edge = vertexes.get(i).firstEdge;
if (edge == null) {
vertexes.get(i).firstEdge = new Edge(j, weight);
return;
}
while (edge.next != null) {
edge = edge.next;
}
edge.next = new Edge(j, weight);
}
/**
* 根据点来插入边
*
* @param vertex1 起始结点
* @param vertex2 终止结点
* @param weight 权值
*/
public void addEdge(String vertex1, String vertex2, int weight) {
int i = getIndex(vertex1);
int j = getIndex(vertex2);
if (i < 0 || j < 0) {
System.out.println("图中没有该结点");
return;
}
addEdge(i, j, weight);
}
/**
* 升序遍历
*
* @param index 起始结点的索引
*/
public void DFS(int index) {
int len = vertexes.size();
if (index < 0 || index > len) {
return;
}
System.out.println(vertexes.get(index).value);// 打印出当前结点
visited[index] = true;// 标记当前结点访问记录
Edge edge = vertexes.get(index).firstEdge;// 获取当前结点的第一个边
while (edge != null) {
int order = edge.order;// 获取与当前结点相连的另一个结点
if (!visited[order]) {
DFS(order);// 继续递归下去
}
edge = edge.next;// 继续指向当前结点的下一个边
}
}
public void BFS(int index) {
int len = vertexes.size();
if (index < 0 || index > len) {
return;
}
int rear = 0, front = 0;// 前标和后标
int[] queue = new int[len];// 索引队列
System.out.println(vertexes.get(index).value);
visited[index] = true;
queue[rear++] = index;// 将当前结点的索引放入队列
while (front < rear) {
index = queue[front++];// 取出队列头部的索引
Edge edge = vertexes.get(index).firstEdge;// 找到与它相连的边
while (edge != null) {
int order = edge.order;// 与它相连的结点的索引
if (!visited[order]) {
System.out.println(vertexes.get(order).value);
visited[order] = true;
queue[rear++] = order;// 将遍历完成的结点放入队列
}
edge = edge.next;// 指向下一条边
}
}
}
}