今天介绍图(森林)的深度优先历遍和广度优先历遍
1、以下算法是用java实现的,但核心的步骤跟C语言差不多,先介绍必要的数据结构
1.1、图(当取定图中某个顶点为树根时,可依次把图划分为一棵树或若干棵树即森林
import java.util.ArrayList;
/*
* 图的数据结构,由顶点数组和图的类型组成
*/
public class Graph
{
ArrayList<Point> points = new ArrayList(); //顶点数组
String graphKind; //图的类型,此处没用到,一概假定为无向图
//添加顶点
public void addPoint(Point p){
points.add(p);
}
//移除顶点,连与顶点有关的边都移除
public void removePoint(Point removePoint){
for(Point p : points)
for(AdjacentEdge edge : p.adjcentEdges){
if(edge.adjacentPointIndex == removePoint.pointIndex)
p.adjcentEdges.remove(edge);
}
points.remove(removePoint);
}
}
1.2、点
import java.util.LinkedList;
/*
* 点的数据结构
*/
public class Point
{
boolean isVisited = false; //该点是否被访问过
int pointIndex; //点的下标
String data; //点代表的数据
LinkedList<AdjacentEdge> adjcentEdges = new LinkedList(); //点的邻接边数组
public Point(int pointIndex, String data){
this.pointIndex = pointIndex;
this.data = data;
}
//添加邻接边
public void addAdjacentEdge(AdjacentEdge adjacentEdge){
adjcentEdges.add(adjacentEdge);
}
//删除邻接边
public void removeAdjacentEdge(AdjacentEdge adjacentEdge){
adjcentEdges.remove(adjacentEdge);
}
@Override
public String toString()
{
// TODO Auto-generated method stub
return "[" + pointIndex + "]" + data + " ";
}
}
1.3、邻接边
/*
* 此类代表邻接边的信息
*/
public class AdjacentEdge
{
int adjacentPointIndex; //邻接边顶点的编号,此处的编号是顶点数组中对应的下标
int edgeInfo;//邻接边的信息,即权值,若无则为0
public AdjacentEdge(int adjacentPointIndex,int edgeInfo){
this.adjacentPointIndex = adjacentPointIndex;
this.edgeInfo = edgeInfo;
}
public AdjacentEdge(int adjacentPointIndex){
this(adjacentPointIndex, 0);
}
}
2、深度优先历遍
2.1、思路:
1)假定图的顶点数组中某顶点(第一次假定为第一个顶点)为树的根,进行访问
2)访问点后,看点是否有邻接边,有则对每一邻接边进行递归深度优先历遍
3)查看顶点数组中有没有没被访问的顶点,若有,则返回
2.2、算法实现:
public class DepthFirstSerch
{
/* 采用递归的思想 */
//对图中某个点的访问
public static void dfsOne(Graph graph, Point startPoint){
System.out.print(startPoint);
startPoint.isVisited = true;
//访问顶点有无邻接边,有则进行递归,深度优先的思想,一直深入到尽头
for(AdjacentEdge edge : startPoint.adjcentEdges)
if(!graph.points.get(edge.adjacentPointIndex).isVisited)
dfsOne(graph, graph.points.get(edge.adjacentPointIndex));
}
//对整个图进行深度优先历遍,对没访问过的结点逐一进行深度历遍
public static void dfsAll(Graph graph){
for(Point p : graph.points)
if(!p.isVisited)
dfsOne(graph, p);
}
//测试算法正确性
public static void main(String[] args){
Graph graph = new Graph(); //创建图
//初始化顶点数组
for(int i = 0 ; i < 10 ; i++){
graph.addPoint(new Point(i, "point" + i));
}
//给顶点添加邻接边
graph.points.get(0).addAdjacentEdge(new AdjacentEdge(1));
graph.points.get(0).addAdjacentEdge(new AdjacentEdge(2));
graph.points.get(1).addAdjacentEdge(new AdjacentEdge(3));
graph.points.get(3).addAdjacentEdge(new AdjacentEdge(4));
graph.points.get(2).addAdjacentEdge(new AdjacentEdge(5));
//进行深度优先历遍
dfsAll(graph);
}
}
3.1、思路:
1)假定图的顶点数组中某顶点(第一次假定为第一个顶点)为树的根,该顶点未被访问,则访问后入队
2)从队列中出队一个顶点进行访问,有邻接边则且邻接边顶点未被访问,则对邻接顶点逐一访问(不递归),并按序入队
3)查看顶点数组中有没有没被访问的顶点,若有,则返回 1)
3.2、算法实现:
import java.util.LinkedList;
import java.util.Queue;
/*
* 广度优先历遍
*/
public class BreadthFirstSearch
{
//广度优先历遍步骤:从队列中出队一个顶点进行访问,有邻接边则对邻接边顶点逐一访问(不递归),并按序入队
public static void bfs(Graph graph){
Queue<Point> queue = new LinkedList<Point>(); //定义顶点队列
Point temp; //队列出队顶点
for(Point p : graph.points){
//若顶点未被访问,则访问并入队
if(!p.isVisited){
System.out.print(p);
p.isVisited = true;
queue.offer(p); //入队
}
//对出队顶点进行邻接顶点的访问,有未被访问到的则访问并入队
while((temp = queue.poll()) != null)
for(AdjacentEdge edge : temp.adjcentEdges){
Point adjacentPoint = graph.points.get(edge.adjacentPointIndex);
if(!adjacentPoint.isVisited){
System.out.print(adjacentPoint);
adjacentPoint.isVisited = true;
queue.offer(adjacentPoint); //入队
}
}
}
}
//对算法进行测试
public static void main(String[] args){
Graph graph = new Graph(); //初始化图
//初始化图的顶点数组
for(int i = 0 ; i < 10 ; i++){
graph.addPoint(new Point(i, "point" + i));
}
//为顶点添加邻接边
graph.points.get(0).addAdjacentEdge(new AdjacentEdge(9));
graph.points.get(0).addAdjacentEdge(new AdjacentEdge(2));
graph.points.get(9).addAdjacentEdge(new AdjacentEdge(3));
graph.points.get(3).addAdjacentEdge(new AdjacentEdge(4));
graph.points.get(2).addAdjacentEdge(new AdjacentEdge(5));
//广度优先历遍
bfs(graph);
}
}