图的基本实现
/**
* 顶点集合
*/
private char[] vertex;
/**
* 邻接矩阵
*/
private int[][] matrix;
/**
* 最大值,表示两个顶点之间不连通
*/
private static final int INF = Integer.MAX_VALUE;
/**
* 用提供的顶点和邻接矩阵创建图
*
* @param vertex
* @param matrix
*/
public Graph(char[] vertex, int[][] matrix) {
this.vertex = vertex;
this.matrix = matrix;
}
/**
* 返回顶点vertex的第一个邻接顶点的索引,失败返回-1
*
* @param vertex
* @return
*/
public int firstVertex(int vertex) {
if (vertex < 0 || vertex > (this.vertex.length - 1)) {
return -1;
}
for (int i = 0; i < this.vertex.length; i++) {
if (this.matrix[vertex][i] != 0 && this.matrix[vertex][i] != INF) {
return i;
}
}
return -1;
}
/**
* 返回顶点vertex相对于它的一个邻接顶点index的下一个邻接顶点索引
*
* @param vertex
* @return
*/
public int nextVertex(int vertex, int index) {
if (vertex < 0 || vertex > (this.vertex.length - 1) || index < 0 || index > (this.vertex.length - 1)) {
return -1;
}
for (int i = index + 1; i < this.vertex.length; i++) {
if (this.matrix[vertex][i] != 0 && this.matrix[vertex][i] != INF) {
return i;
}
}
return -1;
}
深度优先遍历DFS
思想
类似于树的前序遍历,采用的搜索方法的特点是尽可能先对纵深方向进行搜索。 首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止,这里定义使用的就是递归定义。
递归实现
以纵向优先的方式遍历节点。我们从当前节点curr出发,如果当前节点被访问过,就返回,否则将该节点标记为访问过的节点,然后在递归访问当前节点的所有邻接节点。
/**
* DFS:深度优先遍历递归版
*
* @param i
* @param visited
*/
public void DFS(int i, boolean[] visited) {
//标记当前顶点以访问
visited[i] = true;
System.out.print(vertex[i] + "-->");
//遍历该顶点的邻接顶点,若是没有访问过,继续往下遍历
for (int index = firstVertex(i); index >= 0; index = nextVertex(i, index)) {
if (!visited[index]) {
DFS(index, visited);
}
}
}
非递归实现(栈和回溯法)
首先我们需要一个栈结构来存放需要被访问的节点,当然栈的第一个元素是我们传入的node节点,如果这个栈里面还有节点的话,拿出栈顶节点,访问该节点,然后将这个节点的所有未被访问的邻接节点压入栈中。
/**
* DFS:深度优先遍历非递归版
*/
public void DFS() {
Stack<Integer> stack = new Stack<>();
boolean[] visited = new boolean[this.vertex.length];
//开始顶点入栈,标记已访问
stack.push(0);
visited[0] = true;
while (!stack.isEmpty()) {
int current = stack.pop();
System.out.print(vertex[current] + "-->");
for (int i = 0; i < this.vertex.length; i++) {
if (!visited[i] && matrix[current][i] != INF && matrix[current][i] != 0) {
visited[i] = true;
stack.push(i);
break;
}
}
}
}
广度优先遍历BFS
思想
广度优先遍历是连通图的一种遍历策略,它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较广的区域。也就是从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点。
算法步骤
广度优先指的是从当前节点curr出发,将该节点标记为已经访问过的节点,然后在依次访问curr的没有被访问的邻接节点,然后在依次访问邻接节点的邻接节点,直到所有的节点被访问。
代码实现
/**
* 广度优先遍历算法 Breadth-first search(非递归)
*/
public void BFS() {
// LinkedList实现了Queue接口 FIFO
Queue<Integer> queue = new LinkedList<Integer>();
boolean[] visited=new boolean[vertex.length];
for (int i = 0; i < vertex.length; i++) {
visited[i] = false;
}
//这个循环是为了确保每个顶点都被遍历到
for (int i = 0; i < vertex.length; i++) {
if (!visited[i]) {
queue.add(i);
visited[i] = true;
System.out.print(vertex[i] + "-->");
while (!queue.isEmpty()) {
int row = queue.remove();
for (int k = firstVertex(row); k >= 0; k = nextVertex(row, k)) {
if (!visited[k]) {
queue.add(k);
visited[k] = true;
System.out.print(vertex[k] + "-->");
}
}
}
}
}
}