准备工作
图的创建
class Graph {
//表示顶点数量
private int V;
//表示边的数量
private int E;
private Queue<Integer>[] adj;
private boolean[] marked;
//初始化图
public Graph(int n) {
V = n;
E = 0;
adj = new LinkedList[V];
for (int i = 0; i < n; i++) {
adj[i] = new LinkedList<>();
}
}
//获取图的顶点
public int V() {
return V;
}
//获取图的边
public int E() {
return E;
}
/**
* 添加边的方法
*
* @param x
* @param y
*/
public void add(int x, int y) {
adj[x].offer(y);
adj[y].offer(x);
E++;
}
/**
* 获取顶点对应的其他顶点队列
*
* @return
*/
public Queue<Integer> adj(int v) {
//直接用索引取就可以了
return adj[v];
}
}
广度优先遍历
看图
类似于二叉树的层序遍历
如果从0开始 那就是0→1→3→5→2→4
如果从1开始 那就是1→0→5→3→4→2
如果从2开始 那就是2→3→4→0→5→1
如果从3开始 那就是3→0→5→2→1→4
也就是说 先从顶点开始访问子节点 再访问子节点的兄弟节点 直到没有兄弟节点了
就展开 顶点第一次访问的子节点
然后再访问兄弟节点 直到遍历完毕
所以我们需要在使用图的基础上
新增一个标记哪个节点被访问过的marked布尔数组
维护一个队列来存放进出的元素
思维导图大纲
看下大纲吧
核心思路截取一下
/**
* 与深度遍历不同的是 广度优先需要维护一个队列
*/
class GraphRangeSearch {
int count;
boolean[] marked;
Queue<Integer> queue;
public GraphRangeSearch(Graph G, int s) {
marked = new boolean[G.V()];
//这里使用的是链表当队列
queue=new LinkedList<>();
//初始化完毕 打印遍历顺序
bfs(G,s);
}
private void bfs(Graph G, int v) {
//先标记该顶点 表示已搜索过
marked[v]=true;
//队列中加入该元素
queue.offer(v);
while (!queue.isEmpty()) {
//取出队列的第一个元素
Integer first = queue.poll();
//取出一个元素 数量++
count++;
//遍历first的领接表 w为邻接表的第一个元素 然后是第二个 直到遍历完毕
for (Integer w : G.adj(first)) {
//若w没有被搜索过
if (!marked[w]) {
//将该元素也放入队列
queue.offer(w);
//同时标记该元素
marked[w]=true;
}
}
//顺便打印出元素遍历的顺序
System.out.print(first+" ");
}
}
//返回被搜索过的顶点标记
public boolean marked(int s) {
return marked[s];
}
//获取相连的数量
public int getCount() {
return count;
}
}
测试
public static void main(String[] args) {
//准备Graph对象
Graph G = new Graph(6);
G.add(0,1);
G.add(0,3);
G.add(1,5);
G.add(3,5);
G.add(3,2);
G.add(5,4);
G.add(2,4);
GraphRangeSearch search = new GraphRangeSearch(G, 0);
System.out.println();
System.out.println("总数为"+search.count);
}
对照一下
深度优先遍历
与广度优先不同的是 他是一个节点走到底 走不动了 再回去走其他路线
比如从0开始走 那就是0→1→5→4→2→3
但是注意 深度优先的走法有很多种 不一定是我这种走法
明白思路就可以了
思维导图大纲
只要把栈换成是队列 就可以完成了
class GraphDeepSearch {
int count;
boolean[] marked;
Stack<Integer> stack;
public GraphDeepSearch(Graph G, int s) {
marked = new boolean[G.V()];
stack=new Stack<>();
dfs(G, s);
}
/**
* 深度遍历
* @param G
* @param s
*/
private void dfs(Graph G, int s) {
//标记为已搜索
marked[s]=true;
//顶点加入栈中
stack.push(s);
//当栈不为空
while (!stack.isEmpty()) {
//弹出第一个元素
Integer first = stack.pop();
//相连数量++
count++;
//遍历first的领接表
for (Integer w : G.adj(first)) {
//标记w为已搜索
if (!marked[w]) {
//弹出元素
stack.push(w);
//w标记为已搜索
marked[w] = true;
}
}
System.out.print(first+" ");
}
}
public boolean marked(int v) {
return marked[v];
}
public int count() {
return count;
}
}
测试
public static void main(String[] args) {
//准备Graph对象
Graph G = new Graph(6);
G.add(0,1);
G.add(0,3);
G.add(1,5);
G.add(3,5);
G.add(3,2);
G.add(5,4);
G.add(2,4);
GraphDeepSearch search = new GraphDeepSearch(G, 0);
System.out.println();
System.out.println("总数为"+search.count);
}
完整代码放上
public class Test {
public static void main(String[] args) {
//准备Graph对象
Graph G = new Graph(6);
G.add(0,1);
G.add(0,3);
G.add(1,5);
G.add(3,5);
G.add(3,2);
G.add(5,4);
G.add(2,4);
GraphDeepSearch search = new GraphDeepSearch(G, 0);
System.out.println();
System.out.println("总数为"+search.count);
}
}
class Graph {
//表示顶点数量
private int V;
//表示边的数量
private int E;
private Queue<Integer>[] adj;
private boolean[] marked;
//初始化图
public Graph(int n) {
V = n;
E = 0;
adj = new LinkedList[V];
for (int i = 0; i < n; i++) {
adj[i] = new LinkedList<>();
}
}
//获取图的顶点
public int V() {
return V;
}
//获取图的边
public int E() {
return E;
}
/**
* 添加边的方法
*
* @param x
* @param y
*/
public void add(int x, int y) {
adj[x].offer(y);
adj[y].offer(x);
E++;
}
/**
* 获取顶点对应的其他顶点队列
*
* @return
*/
public Queue<Integer> adj(int v) {
//直接用索引取就可以了
return adj[v];
}
}
/**
* 与深度遍历不同的是 广度优先需要维护一个队列
*/
class GraphRangeSearch {
int count;
boolean[] marked;
Queue<Integer> queue;
public GraphRangeSearch(Graph G, int s) {
marked = new boolean[G.V()];
queue=new LinkedList<>();
bfs(G,s);
}
private void bfs(Graph G, int v) {
//先标记该顶点 表示已搜索过
marked[v]=true;
//队列中加入该元素
queue.offer(v);
while (!queue.isEmpty()) {
//取出队列的第一个元素
Integer first = queue.poll();
//取出一个元素 数量++
count++;
//遍历first的领接表 w为邻接表的第一个元素 然后是第二个 直到遍历完毕
for (Integer w : G.adj(first)) {
//若w没有被搜索过
if (!marked[w]) {
//将该元素也放入队列
queue.offer(w);
//同时标记该元素
marked[w]=true;
}
}
//顺便打印出元素遍历的顺序
System.out.print(first+" ");
}
}
//返回被搜索过的顶点标记
public boolean marked(int s) {
return marked[s];
}
//获取相连的数量
public int getCount() {
return count;
}
}
class GraphDeepSearch {
int count;
boolean[] marked;
Stack<Integer> stack;
public GraphDeepSearch(Graph G, int s) {
marked = new boolean[G.V()];
stack=new Stack<>();
dfs(G, s);
}
/**
* 深度遍历
* @param G
* @param s
*/
private void dfs(Graph G, int s) {
//标记为已搜索
marked[s]=true;
//顶点加入栈中
stack.push(s);
//当栈不为空
while (!stack.isEmpty()) {
//弹出第一个元素
Integer first = stack.pop();
//相连数量++
count++;
//遍历first的领接表
for (Integer w : G.adj(first)) {
//标记w为已搜索
if (!marked[w]) {
//弹出元素
stack.push(w);
//w标记为已搜索
marked[w] = true;
}
}
System.out.print(first+" ");
}
}
public boolean marked(int v) {
return marked[v];
}
public int count() {
return count;
}
}
ps:大海上最自由的才是海贼王 -----王路飞