即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种访问策略: (1)深度优先遍历
(2)广度优先遍历
指的是在搜索时,如果遇到一个结点既有子结点,又有兄弟结点,那么先找子结点,然后找兄弟结点。
很明显,在由于边是没有方向的,所以,如果4和5顶点相连,那么4会出现在5的相邻链表中,5也会出现在4的相邻链表中,那么为了不对顶点进行重复搜索,应该要有相应的标记来表示当前顶点有没有搜索过,可以使用一个布尔类型的数组 boolean[V] marked,索引代表顶点,值代表当前顶点是否已经搜索,如果已经搜索,标记为true,如果没有搜索,标记为false;
类名 | DepthFirstSearch |
构造方法 | DepthFirstSearch(Graph G,int s):构造深度优先搜索对象,使用深度优先搜索找出G图中s顶点的所有相通顶点 |
成员方法 | 1.private void dfs(Graph G, int v):使用深度优先搜索找出G图中v顶点的所有相通顶点 2.public boolean marked(int w):判断w顶点与s顶点是否相通 3.public int count():获取与顶点s相通的所有顶点的总数 |
成员变量 | 1.private boolean[] marked: 索引代表顶点,值表示当前顶点是否已经被搜索 2.private int count:记录有多少个顶点与s顶点相通 |
1、实现图:
package 基本图;
import 队列.Queue;
public class Graph {
//顶点数目
private final int v;
//遍的数目
private int E;
//邻接表
private Queue[] adj;
public Graph(int v) {
//初始化顶点数量
this.v = v;
//初始化边的数量
this.E = 0;
//初始化邻接表
this.adj = new Queue[v];
for (int i = 0; i < adj.length; i++) {
adj[i] = new Queue<>();
}//为邻接表赋值
}
//获取顶点的数目
public int v(){
return v;
}
//获取边的数目
public int E(){
return E;
}
//向图中添加一条边
public void addEdge(int v,int w){
//在无向图中,边是没有方向的,所以该边既可以说是从v到w,也可以是w到v
adj[v].enqueue(w) ;
adj[w].enqueue(v) ;
//边的数量+1
E++;
}
//获取和顶点v相邻的所有顶点
public Queue adj(int v){
return adj[v];
}//返回邻接表里的值
}
2、深度优先搜索处理办法
package 深度优先搜索;
import 基本图.Graph;
public class DepthFirstSearch {
//索引代表顶点,值表示当前顶底是否已经被搜索过
private boolean[] marked;
//记录有多少个顶点与s顶点相通
private int count;
//构造深度优先搜索对象,使用深度优先搜索找出G图中顶点的所有相邻顶点(找兄弟节点)
//s为起点5
public DepthFirstSearch(Graph G, int s){
//初始化marked数组
this.marked = new boolean[G.v()];
//初始化跟顶点s相通的顶点的数量
this.count = 0;
dfs(G,s);
}
//使用深度优先搜索找出G图中v顶点的所有相通的顶点(找子节点)
private void dfs(Graph G,int v){
//把v标识为已搜索
marked[v] = true;
for (Integer w : G.adj(v)) {
//判断当前w顶点有没有被搜索过,如果没有被搜索过 ,则递归调用dfs方法进行深度搜索
if(!marked[w]){
dfs(G,w);
}
}
//相通顶点的数量+1,找到兄弟节点
count++;
}
//判断w顶点与s顶点是否相通
public boolean marked(int w){
return marked[w];
}
//获取与顶点s相通的所有顶点的总数
public int count(){
return count;
}
}
核心代码
//使用深度优先搜索找出G图中v顶点的所有相通的顶点(找子节点)
private void dfs(Graph G,int v){
//把v标识为已搜索
marked[v] = true;
for (Integer w : G.adj(v)) {
//判断当前w顶点有没有被搜索过,如果没有被搜索过 ,则递归调用dfs方法进行深度搜索
if(!marked[w]){
dfs(G,w);
}
}
//相通顶点的数量+1,找到兄弟节点
count++;
}
测试代码(Demo)
package 深度优先搜索;
import 基本图.Graph;
public class DepthFirstSearchTest {
public static void main(String[] args) {
//准备Graph对象
Graph G = new Graph(13);
G.addEdge(0,5);
G.addEdge(0,1);
G.addEdge(0,2);
G.addEdge(0,6);
G.addEdge(5,3);
G.addEdge(5,4);
G.addEdge(3,4);
G.addEdge(4,6);
G.addEdge(7,8);
G.addEdge(9,11);
G.addEdge(9,10);
G.addEdge(9,12);
G.addEdge(11,12);
//准备深度优先搜索对象
DepthFirstSearch search = new DepthFirstSearch(G,0);
//准备深度优先搜索对象
int count = search.count();
System.out.println("与起点0相通的顶点的数量为:" + count);
//测试与某个顶点相通的顶点数量
boolean marked1 = search.marked(5);
System.out.println("顶点5和0是否相通:" + marked1);
//测试某个顶点与起点是否相通
boolean marked2 = search.marked(7);
System.out.println("顶点7和0是否相通:" + marked2);
}
}
导入的包
package 队列;
import java.util.Iterator;
public class Queue implements Iterable{
//记录首结点
private Node head;
//记录最后一个结点
private Node last;
//记录队列中元素的个数
private int N;
private class Node{
public T item;
public Node next;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
public Queue() {
this.head = new Node(null,null);
this.last=null;
this.N=0;
}
//判断队列是否为空
public boolean isEmpty(){
return N==0;
}
//返回队列中元素的个数
public int size(){
return N;
}
//向队列中插入元素t
public void enqueue(T t){
if (last==null){
//当前尾结点last为null
last= new Node(t,null);
head.next=last;
}else {
//当前尾结点last不为null
Node oldLast = last;
last = new Node(t, null);
oldLast.next=last;
}
//元素个数+1
N++;
}
//从队列中拿出一个元素
public T dequeue(){
if (isEmpty()){
return null;
}
Node oldFirst= head.next;
head.next=oldFirst.next;
N--;
//因为出队列其实是在删除元素,因此如果队列中的元素被删除完了,需要重置last=null;
if (isEmpty()){
last=null;
}
return oldFirst.item;
}
@Override
public Iterator iterator() {
return new QIterator();
}
private class QIterator implements Iterator{
private Node n;
public QIterator(){
this.n=head;
}
@Override
public boolean hasNext() {
return n.next!=null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}