广度优先搜索是图的另外一种遍历方法,该算法的实现需要附设标志数组和辅助队列 ;
算法思路:假设图中所有顶点均未被访问,从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问他们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中已被访问的顶点的邻接点都被访问到。若此时图中尚有未被访问的顶点,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程。
下面给出广度度优先搜索的Java实现及其测试代码:
1. 广度优先搜索算法实现
package org.sky.graph;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingDeque;
/**
* @description 广度优先搜索
* @author sky
* @date 2017/1/3
*/
public class BreadthFirstSearch {
//表结点,包含边的相关信息
@SuppressWarnings("unused")
private static class ArcNode{
int adjVex; //该弧或边所指向的顶点的位置
int value; //与弧或边相关的信息,如权值
ArcNode nextArc; //指向下一条弧或边的指针
public ArcNode(int adjVex, int value) {
super();
this.adjVex = adjVex;
this.value = value;
}
ArcNode(int adjvex, int value, ArcNode nextArc) {
super();
this.adjVex = adjvex;
this.value = value;
this.nextArc = nextArc;
}
public int getAdjVex() {
return adjVex;
}
public void setAdjVex(int adjVex) {
this.adjVex = adjVex;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public ArcNode getNextArc() {
return nextArc;
}
public void setNextArc(ArcNode nextArc) {
this.nextArc = nextArc;
}
}
//头结点,对应图中的顶点
@SuppressWarnings("unused")
private static class VNode{
Object data; //顶点信息
ArcNode firstArc; //指向第一条依附该顶点的弧或边的指针
public VNode(Object data) {
super();
this.data = data;
}
public VNode(Object data, ArcNode firstArc) {
super();
this.data = data;
this.firstArc = firstArc;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public ArcNode getFirstArc() {
return firstArc;
}
public void setFirstArc(ArcNode firstArc) {
this.firstArc = firstArc;
}
}
private int numVex; //图的当前顶点数
private int numArc; //图的当前边数或弧数
private VNode[] vexs; //存储表头结点,通常采用顺序存储结构
public BreadthFirstSearch() {
super();
}
public BreadthFirstSearch(int numVex, int numArc, VNode[] vexs) {
super();
this.numVex = numVex;
this.numArc = numArc;
this.vexs = vexs;
}
/**
* @Desciption 创建有向网
*/
public void createDN(){
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入图的顶点数及边数");
numVex = sc.nextInt();
numArc = sc.nextInt();
vexs = new VNode[numVex];
System.out.println("请分别输入图的各个顶点:");
for(int v = 0; v < numVex; v++){
vexs[v] = new VNode(sc.next());
}
System.out.println("请输入各个边的来给你个顶点及其权值");
for(int k = 0; k < numArc; k++){
int v = locateVex(sc.next());
int u = locateVex(sc.next());
int value = sc.nextInt();
addArc(v,u,value);
}
sc.close();
}
/**
* @Desciption 创建无向网
*/
public void createUDN(){
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入图的顶点数及边数");
numVex = sc.nextInt();
numArc = sc.nextInt();
vexs = new VNode[numVex];
visited = new boolean[numVex];
System.out.println("请分别输入图的各个顶点:");
for(int v = 0; v < numVex; v++){
vexs[v] = new VNode(sc.next());
visited[v] = false;
}
System.out.println("请输入各个边的来给你个顶点及其权值");
for(int k = 0; k < numArc; k++){
int v = locateVex(sc.next());
int u = locateVex(sc.next());
int value = sc.nextInt();
addArc(v,u,value);
addArc(u,v,value);
}
sc.close();
}
/**
* @Desciption 返回与传入值相对应的定点位置
*/
public int locateVex(Object vex){
for(int v = 0; v < numVex; v++){
if(vexs[v].getData().equals(vex)){
return v;
}
}
return -1;
}
/**
* @Desciption 在位置v和u间添加边,并赋权值
*/
private void addArc(int v, int u, int value){
ArcNode arc = new ArcNode(u,value);
arc.setNextArc(vexs[v].getFirstArc());
vexs[v].setFirstArc(arc);
}
///广度优先搜索//
private boolean[] visited; //访问标志数组
/**
* 广度优先遍历
*/
public void BFSTraverse(){
LinkedBlockingDeque<Integer> queue = new LinkedBlockingDeque<Integer>(); //辅助队列
for(int v = 0; v < numVex; v++){
if(!visited[v]){ //v尚未访问
visited[v] = true;
System.out.println(vexs[v].getData()); //输出访问的结点
queue.putLast(v);
while(!queue.isEmpty()){
int u = queue.pollFirst(); //队头元素出队并设置为u
for(int w = getFirstAdjVex(u); w >= 0; w = getNextAdjVex(u , w)){
if(!visited[w]){ //w为u的尚未访问的邻接顶点
visited[w] = true;
System.out.println(vexs[w].getData()); //输出访问的结点
queue.putLast(w);
}
}
}
}
}
}
/**
* 获取vexs[v]的第一个邻接弧的顶点位置
* @param vexs
* @param v
* @return vexs[v]的第一个邻接弧的顶点位置;若不存在,则返回-1
*/
public int getFirstAdjVex(int v){
if(vexs[v].firstArc != null){ //第一个邻接弧是否存在
return vexs[v].firstArc.adjVex;
}
return -1;
}
/**
* 获取vexs[v]的相对第一个邻接弧的下一个邻接弧的顶点位置
* @param v
* @param w
* @return vexs[v]的相对第一个邻接弧的下一个邻接弧的顶点位置;若不存在,则返回-1
*/
public int getNextAdjVex(int v, int w){
ArcNode temp = vexs[v].firstArc;
int tempTail = -1;
while(temp != null){
if(temp.adjVex == w){
temp = temp.nextArc;
if(temp != null){
tempTail = temp.adjVex;
break;
}
}else{
temp = temp.nextArc;
}
}
return tempTail;
}
}
2. 测试代码
package org.sky.graph;
public class TestGragh {
public static void main(String[] args){
BreadthFirstSearch bfs = new BreadthFirstSearch();
bfs.createUDN();
bfs.BFSTraverse();
}
}