图的表示有三种,邻接表,邻接矩阵和十字链表
我使用邻接矩阵表示图
邻接矩阵中[i][j]表示i节点指向j节点,大小为[i][j]的值
比如这样
若是无向图,矩阵则是按照对角线对称的。
首先是深度遍历,深度遍历是沿着一个节点往下走,当某个节点的下一个节点被访问过,或者就没有下一个节点时,返回。
和二叉树的深度遍历类似,使用递归
/**
* 深度遍历
*/
@Override
public void dfsGraph() {
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int i = 0; i < nodeNumbers; i++) {
if (visit[i] != 1)
dfs(i);
}
}
public void dfs(int i) {
visit[i] = 1;
System.out.println(i);
for (int j = 0; j < nodeNumbers; j++) {
if (graphMatrix[i][j] != 0 && visit[j] != 1) {
dfs(j);
}
}
}
广度遍历
广度遍历也和二叉树的类似,把一个节点的出度节点都访问完,再访问下一个节点的,使用队列
/**
* 广度优先遍历
*/
@Override
public void bfsGraph() {
ArrayDeque<Integer> bfs = new ArrayDeque<>();
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int i = 0; i < nodeNumbers; i++) {
if (visit[i] == 0) {
bfs.addFirst(i);
visit[i] = 1;
while (!bfs.isEmpty()) {
int j = bfs.removeLast();
System.out.println(j);
for (int m = 0; m < nodeNumbers; m++) {
if (visit[m] != 1 && graphMatrix[j][m] != 0) {
bfs.addFirst(m);
visit[m] = 1;
}
}
}
}
}
}
拓扑排序
会问到的还有拓扑排序,拓扑排序可以解决有向图中是否存在环的问题
其基本思想:
拓扑排序的基本操作为:
1.从图中选择一个入度为0的顶点并且输出它;
2.从图中删除此顶点及所有由它发出的边;
3.重复上述过程,直到图中没有入度为0的边。
因此,当有向图中存在环的时候,几个节点会相互存在出度,会删除不掉,所以拓扑排序可以判断是否有环
/**
* 拓扑排序
*/
@Override
public void TopologicalGraph() {
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int n = 0; n < nodeNumbers; n++) {
for (int i = 0; i < nodeNumbers; i++) {
boolean haveOut = true;
for (int j = 0; j < nodeNumbers; j++) {
if (graphMatrix[j][i] != 0) {
haveOut = false;
break;
}
}
if (visit[i] == 0 && haveOut) {
visit[i] = 1;
System.out.println(i);
for (int m = 0; m < nodeNumbers; m++) {
graphMatrix[i][m] = 0;
graphMatrix[m][i] = 0;
}
break;
}
}
}
}
图的构建:
public class GraphMatrixImpl implements GraphMatrix {
private int nodeNumbers;
private int[][] graphMatrix;
private int[] visit;
public GraphMatrixImpl(int nodeNumbers) {
graphMatrix = new int[nodeNumbers][nodeNumbers];
this.nodeNumbers = nodeNumbers;
}
@Override
public void addBrim(int firstNode, int secondNode, int value) {
if (firstNode >= nodeNumbers && secondNode >= nodeNumbers) return;
graphMatrix[firstNode][secondNode] = value;
//graphMatrix[secondNode][firstNode] = value;
}
@Override
public void deleteBrim(int firstNode, int secondNode, int value) {
if (firstNode >= nodeNumbers && secondNode >= nodeNumbers) return;
graphMatrix[firstNode][secondNode] = 0;
graphMatrix[secondNode][firstNode] = 0;
}
@Override
public void display() {
for (int i = 0; i < nodeNumbers; i++) {
for (int j = 0; j < nodeNumbers; j++) {
System.out.print(graphMatrix[i][j] + " ");
}
System.out.println("");
}
}
/**
* 深度遍历
*/
@Override
public void dfsGraph() {
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int i = 0; i < nodeNumbers; i++) {
if (visit[i] != 1)
dfs(i);
}
}
public void dfs(int i) {
visit[i] = 1;
System.out.println(i);
for (int j = 0; j < nodeNumbers; j++) {
if (graphMatrix[i][j] != 0 && visit[j] != 1) {
dfs(j);
}
}
}
/**
* 广度优先遍历
*/
@Override
public void bfsGraph() {
ArrayDeque<Integer> bfs = new ArrayDeque<>();
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int i = 0; i < nodeNumbers; i++) {
if (visit[i] == 0) {
bfs.addFirst(i);
visit[i] = 1;
while (!bfs.isEmpty()) {
int j = bfs.removeLast();
System.out.println(j);
for (int m = 0; m < nodeNumbers; m++) {
if (visit[m] != 1 && graphMatrix[j][m] != 0) {
bfs.addFirst(m);
visit[m] = 1;
}
}
}
}
}
}
/**
* 拓扑排序
*/
@Override
public void TopologicalGraph() {
visit = new int[nodeNumbers];
for (int i = 0; i < nodeNumbers; i++) {
visit[i] = 0;
}
for (int n = 0; n < nodeNumbers; n++) {
for (int i = 0; i < nodeNumbers; i++) {
boolean haveOut = true;
for (int j = 0; j < nodeNumbers; j++) {
if (graphMatrix[j][i] != 0) {
haveOut = false;
break;
}
}
if (visit[i] == 0 && haveOut) {
visit[i] = 1;
System.out.println(i);
for (int m = 0; m < nodeNumbers; m++) {
graphMatrix[i][m] = 0;
graphMatrix[m][i] = 0;
}
break;
}
}
}
}
}
参考: