两种实现都是基于邻接表
深度优先遍历是一种优先走到底、无路可走再回头的遍历方式。具体地,从某个顶点出发,访问当前顶点的某个邻接顶点,直到走到尽头时返回,再继续走到尽头并返回,以此类推,直至所有顶点遍历完成。
这种算法一般我们可以用递归实现 ,也可以用栈实现。同样的, 我们需要接著一个辅助数组来记录我们已经访问过的顶点。
public class Graph {
// 邻接表,key: 顶点,value:该顶点的所有邻接顶点
Map<Vertex, List<Vertex>> adjList;
/**
* 初始化邻接表
* @param edges 两顶点之间的边的关系, edges中的数代表顶点上的数
*/
public Graph(Vertex[][] edges){
this.adjList = new HashMap<>();
//添加顶点
for (Vertex[] edge : edges){
addVertex(edge[0]);
addVertex(edge[1]);
//添加边
addAdjMat(edge[0],edge[1]);
}
}
/**
* 添加两个顶点之间的关系, 也就是添加边的关系
* @param item0 顶点0
* @param item1 顶点1
*/
private void addAdjMat(Vertex item0, Vertex item1) {
//首先判断两个顶点是否存在, 如果不存在就不能添加边的关系
if (!adjList.containsKey(item0) || !adjList.containsKey(item1) || item0 == item1){
throw new IndexOutOfBoundsException("其中一个顶点不存在!");
}
if (!adjList.get(item0).contains(item1)){
adjList.get(item0).add(item1);
}
if (!adjList.get(item1).contains(item0)){
adjList.get(item1).add(item0);
}
}
/**
* 添加点 ,并且需要将扩展顶点
* @param item 顶点val
*/
private void addVertex(Vertex item) {
//先判断顶点是否存在
if(adjList.containsKey(item)){
return;
}
adjList.put(item,new ArrayList<>());
}
/**
* 删除顶点 ,同时需要删除所有有关它的边的关系
* @param val 顶点的所有边的关系
*/
public void removeVertex(Vertex val){
//先判断顶点是否存在
if(!adjList.containsKey(val)){
throw new IndexOutOfBoundsException("顶点不存在");
}
adjList.remove(val);
//先遍历每个顶点,然后看他里面是否存在val顶点, 存在就删除
for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
item.getValue().remove(val);
}
}
//todo 打印邻接表
public void list(){
for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
System.out.print("key : " + item.getKey() + " value : ");
List<Vertex> value = item.getValue();
for (Vertex vertex : value){
System.out.print(vertex + "—>");
}
System.out.println();
}
}
/**
* 深度优先搜索
* @param adjList 存储元素的邻接表
* @param vertex 传入遍历的节点
* @param visited 记录当前节点地日志数组
*/
public static void DFS(Map<Vertex, List<Vertex>> adjList,Vertex vertex,int[] visited){
visited[vertex.val] = 1;
System.out.print(vertex + "\t");
List<Vertex> vertices = adjList.get(vertex);
Iterator<Vertex> iterator = vertices.iterator();
while(iterator.hasNext()){
Vertex v = iterator.next();
if(visited[v.val] == 0){
DFS(adjList,v,visited);
}
}
}
public static void main(String[] args) {
Vertex vertex1 = new Vertex(1);
Vertex vertex3 = new Vertex(3);
Vertex vertex2 = new Vertex(2);
Vertex vertex5 = new Vertex(0);
Vertex vertex4 = new Vertex(4);
Vertex[][] vertices = new Vertex[][]{
{vertex1,vertex3},
{vertex3,vertex1},
{vertex2,vertex3},
{vertex5,vertex1},
{vertex4,vertex2},
};
Graph graph = new Graph(vertices);
graph.addAdjMat(vertex1, vertex5);
graph.addAdjMat(vertex3, vertex2);
graph.addAdjMat(vertex2, vertex5);
graph.addAdjMat(vertex2, vertex4);
graph.addAdjMat(vertex5, vertex2);
graph.addAdjMat(vertex5, vertex4);
graph.addAdjMat(vertex4, vertex5);
graph.list();
BFS(graph.adjList,vertex1);
System.out.println();
DFS(graph.adjList,vertex1);
}
}
广度优先遍历是一种由近及远的遍历方式,从距离最近的顶点开始访问,并一层层向外扩张。具体来说,从某个顶点出发,先遍历该顶点的所有邻接顶点,然后遍历下一个顶点的所有邻接顶点,以此类推,直至所有顶点访问完毕。
广度优先搜索,我们使用的是队列来实现。先进先出 ,我们先将一个顶点加入队列, 然后当他出队列的时候,再将他身边的顶点加入队列。 ,循环往复,直到队列为空, 那么就是将所有的顶点遍历完成。
同时,我们这里也需要一个辅助数组, 用来记录已经加入队列遍历过的顶点。
package tu;
import org.omg.CORBA.MARSHAL;
import java.util.*;
/**
* 基于邻接表实现图
* 将顶点用顶点类Vertex 进行封装
*/
public class Graph {
// 邻接表,key: 顶点,value:该顶点的所有邻接顶点
Map<Vertex, List<Vertex>> adjList;
/**
* 初始化邻接表
* @param edges 两顶点之间的边的关系, edges中的数代表顶点上的数
*/
public Graph(Vertex[][] edges){
this.adjList = new HashMap<>();
//添加顶点
for (Vertex[] edge : edges){
addVertex(edge[0]);
addVertex(edge[1]);
//添加边
addAdjMat(edge[0],edge[1]);
}
}
/**
* 添加两个顶点之间的关系, 也就是添加边的关系
* @param item0 顶点0
* @param item1 顶点1
*/
private void addAdjMat(Vertex item0, Vertex item1) {
//首先判断两个顶点是否存在, 如果不存在就不能添加边的关系
if (!adjList.containsKey(item0) || !adjList.containsKey(item1) || item0 == item1){
throw new IndexOutOfBoundsException("其中一个顶点不存在!");
}
if (!adjList.get(item0).contains(item1)){
adjList.get(item0).add(item1);
}
if (!adjList.get(item1).contains(item0)){
adjList.get(item1).add(item0);
}
}
/**
* 添加点 ,并且需要将扩展顶点
* @param item 顶点val
*/
private void addVertex(Vertex item) {
//先判断顶点是否存在
if(adjList.containsKey(item)){
return;
}
adjList.put(item,new ArrayList<>());
}
/**
* 删除顶点 ,同时需要删除所有有关它的边的关系
* @param val 顶点的所有边的关系
*/
public void removeVertex(Vertex val){
//先判断顶点是否存在
if(!adjList.containsKey(val)){
throw new IndexOutOfBoundsException("顶点不存在");
}
adjList.remove(val);
//先遍历每个顶点,然后看他里面是否存在val顶点, 存在就删除
for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
item.getValue().remove(val);
}
}
//todo 打印邻接表
public void list(){
for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
System.out.print("key : " + item.getKey() + " value : ");
List<Vertex> value = item.getValue();
for (Vertex vertex : value){
System.out.print(vertex + "—>");
}
System.out.println();
}
}
/**
* 实现广度优先搜索 暂时规定
* @param adjList 存储元素的邻接表
* @param vertex 传入遍历的头节点
*/
public static void BFS(Map<Vertex, List<Vertex>> adjList,Vertex vertex){
Deque<Vertex> deque = new LinkedList<>();
int size = adjList.size();
int[] visited = new int[size];
Arrays.fill(visited,0);
//将入队列元素标记。 然后让元素入队列
visited[vertex.val] = 1;
deque.push(vertex);
while (!deque.isEmpty()){
Vertex poll = deque.poll();
/*处理方法 */
System.out.print(poll + "\t");
List<Vertex> vertices = adjList.get(poll);
for (Vertex v : vertices){
if (visited[v.val] != 1){
deque.push(v);
visited[v.val] = 1;
}
}
}
}
public static void main(String[] args) {
Vertex vertex1 = new Vertex(1);
Vertex vertex3 = new Vertex(3);
Vertex vertex2 = new Vertex(2);
Vertex vertex5 = new Vertex(0);
Vertex vertex4 = new Vertex(4);
Vertex[][] vertices = new Vertex[][]{
{vertex1,vertex3},
{vertex3,vertex1},
{vertex2,vertex3},
{vertex5,vertex1},
{vertex4,vertex2},
};
Graph graph = new Graph(vertices);
graph.addAdjMat(vertex1, vertex5);
graph.addAdjMat(vertex3, vertex2);
graph.addAdjMat(vertex2, vertex5);
graph.addAdjMat(vertex2, vertex4);
graph.addAdjMat(vertex5, vertex2);
graph.addAdjMat(vertex5, vertex4);
graph.addAdjMat(vertex4, vertex5);
graph.list();
BFS(graph.adjList,vertex1);
System.out.println();
DFS(graph.adjList,vertex1);
}
}