生成森林是指由非连通图的连通分量的生成树所组成的森林,而深度优先生成森林则指由图的深度优先遍历算法获得的生成森林。
下面给出非连通图的深度优先生成森林算法的Java实现,其中生成森林采用孩子兄弟链表存储结构。
1. 深度优先生成森林算法实现
package org.sky.graph;
import java.util.Scanner;
public class DeepFirstSearchForest {
//表结点,包含边的相关信息
@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 DeepFirstSearchForest() {
super();
}
public DeepFirstSearchForest(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);
}
///深度优先生成森林(以孩子兄弟链表作生成森林的存储结构)//
//孩子兄弟链表内部类
public class CSNode{
Object data;
CSNode firstChild;
CSNode nextSibling;
public CSNode(Object data, CSNode firstChild, CSNode nextSibling) {
super();
this.data = data;
this.firstChild = firstChild;
this.nextSibling = nextSibling;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public CSNode getFirstChild() {
return firstChild;
}
public void setFirstChild(CSNode firstChild) {
this.firstChild = firstChild;
}
public CSNode getNextSibling() {
return nextSibling;
}
public void setNextSibling(CSNode nextSibling) {
this.nextSibling = nextSibling;
}
}
private boolean[] visited; //访问标志数组
private CSNode T = null; //孩子兄弟链表
/**
* 深度优先遍历建立无向图的深度优先生成森林
*/
public void DFSTraverse(){
CSNode q = null; //指向当前生成树的根
for(int v = 0; v < numVex; v++){
if(!visited[v]){
CSNode p = new CSNode(vexs[v].getData(), null, null);
if(T == null){
T = p; //第一棵生成树的根
}else{
q.setNextSibling(p); //其他生成树的根
}
q = p; //指向当前生成树的根
DFSTree(vexs, v, p); //对尚未访问的顶点调用DFS
}
}
}
/**
* 从第v个顶点出发递归地深度优先遍历图
* @param vexs
* @param v
*/
public void DFSTree(VNode[] vexs, int v, CSNode T){
visited[v] = true;
System.out.println(vexs[v].getData()); //输出访问的结点
boolean first = true;
CSNode q = null; //指向当前生成树的根
for(int w = getFirstAdjVex(v); w >= 0; w = getNextAdjVex(v , w)){
if(!visited[w]){
CSNode p = new CSNode(vexs[w].getData(), null, null);
if(first){ //w是v的第一个未被访问的邻接顶点
T.setFirstChild(p); //根的左孩子结点
first = false;
}else{ //w是v的其他未被访问的邻接顶点
q.setNextSibling(p);//上一个邻接顶点的右兄弟结点
}
q = p;
DFSTree(vexs, w, q); //对尚未访问的顶点调用DFS
}
}
}
/**
* 获取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){
DeepFirstSearchForest dfsForest = new DeepFirstSearchForest();
dfsForest.createUDN();
dfsForest.DFSTraverse();
}
}