今天我们运用之前学过的深度优先算探索来求两点间路径问题,如果没有学习过深度优先探索的,快点点链接去学习吧!
在解决该问题时,我们会使用到队列和栈这种数据结构,所以我们先用代码实现一下
队列:
public class Queue<T> {
private Node head;
private Node last;
int N;
//定义节点内部类
private class Node
{
T item; //节点存储的值
Node next; //下一个节点
public Node(T item,Node next) //构造方法
{
this.item=item;
this.next=next;
}
}
//Queue类的构造方法
public Queue()
{
this.head=new Node(null,null);
this.N=0;
this.last=null;
}
//判断队列是否为空
public boolean isEmpty()
{
return N==0;
}
//返回队列的大小
public int size()
{
return N;
}
//向队列尾部插入元素
public void enqueue(T item)
{
if(this.last==null)
{
this.last=new Node(item,null);
head.next=last;
N++;
return;
}
Node newlast=new Node(item,null);
this.last.next=newlast;
last=newlast;
N++;
}
//弹出队列头部的第一个元素,并返回该元素
public T dequeue()
{
if(isEmpty())
{
return null;
}
Node oldfir = head.next;
head.next=oldfir.next;
N--;
if(isEmpty())
{
this.last=null;
}
return oldfir.item;
}
}
队列按进入队列的顺序弹出元素,先进先出,后进后出
栈:
public class Stack<T> implements Iterable<T>{
private Node head; //首节点
private int N; //栈的大小
//使用链表来实现栈
private class Node {
T item;
Node next;
public Node(T item,Node node)
{
this.next=node;
this.item=item;
}
}
//对栈的初始化
public Stack()
{
this.head=new Node(null,null);
this.N=0;
}
//判断栈是否为空
public boolean isEmpty()
{
return N==0;
}
//返回栈的大小
public int size()
{
return N;
}
//向栈中添加元素(首节点不存储元素)
public void push(T item)
{
Node old = head.next;
Node node = new Node(item, old);
head.next=node;
N++;
}
//弹出栈中元素并返回该元素
public T top()
{
Node top = head.next;
if(top==null)
{
return null;
}
head.next=top.next;
N--;
return top.item;
}
栈是一种存储元素的数据结构,与队列相反,栈先弹出后进入的元素
图的实现
public class Graph {
private final int pointcount; //图中的点的数量
private int linecount; /图中的线的数量
private Queue<Integer>[] adj; //队列数组,用于存储每一个点的相邻点
//构造方法
public Graph(int N) {
this.pointcount = 0;
this.linecount = N;
//初始情况下每个点没有相邻点
this.adj = new Queue[N];
for (int i = 0; i < N; i++) {
adj[i] = new Queue<Integer>();
}
}
//返回图的点的数量
public int pointcount() {
return this.pointcount;
}
//返回图的线的数量
public int linecount() {
return this.linecount;
}
//使图中 v,w两点相连
public void addEdge(int v, int w)
{
adj[v].enqueue(w); //在w的相邻点队列中加入v
adj[w].enqueue(v); //在v的相邻点队列中加入w
this.linecount++; //线数目加1
}
//返回某个点的相邻点的队列
public Queue<Integer> adj(int v)
{
return adj[v];
}
}
好的,万事俱备,只欠东风,我们可以开始对算法的实现了
public class DepthFirstPath {
//布尔数组:用来确认节点是否被遍历过
private boolean [] marked;
//路径的起始点
private int s;
//用来存储路径的数组,每一个索引的值表示该节点,数组中索引处的值指向上一个节点,即确定从哪里来的
private int [] edgeto;
//构造方法
public DepthFirstPath(Graph g,int s)
{
//外界输入确定图和起点
this.s=s;
//初始化布尔数组
this.marked=new boolean[g.V()];
//初始化
this.edgeto=new int[g.V()];
for(int i=0;i<g.V();i++)
{
marked[i]=false;
edgeto[i]=-1;
}
//实现深度优先算法
dfs(g,s);
}
public void dfs(Graph g,int s)
{
//标记节点s已遍历
marked[s]=true;
//获取相邻点的队列
Queue<Integer> q = g.adj(s);
//获取队列长度
int size=g.adj(s).size();
//对节点s的相邻节点遍历
for(int i=0;i<size;i++)
{
//弹出队列中一点
Integer dequeue = q.dequeue();
//判断是遍历过
if(!marked[dequeue])
{
//没有遍历过
//使该点处的值为指向它的点;
edgeto[dequeue]=s;
//再递归调用该方法,直到遍历完所有相通的点
dfs(g,dequeue);
}
}
}
//判断初始点是否可以达到点point,如果marked[point]为真,则证明可以达到
public boolean haspathto(int point)
{
return marked[point];
}
//返回存储到达点k路径的栈
public Stack<Integer> path(int k)
{
//判断路线是否存在,不存在返回空
if(haspathto(k))
{
//存在则创建一个栈存储路径
Stack<Integer> stack=new Stack<>();
//从终点开始遍历,不断向栈中点,由于栈先进后出的特点,最后从栈中弹出的点顺序即为路径
for(int i=k;i!=this.s;i=edgeto[i])
{
stack.push(i);
}
//最后向栈中添加初始点
stack.push(this.s);
return stack;
}
return null;
}
}
下面,让我们来进行测试
public class RoadPathTest {
public static void main(String[] args) throws IOException {
//创建一个有六个点的图
Graph g=new Graph(6);
//在图中建立点的联通关系
g.addEdge(0,2);
g.addEdge(0,1);
g.addEdge(2,1);
g.addEdge(2,3);
g.addEdge(2,4);
g.addEdge(3,5);
g.addEdge(3,4);
g.addEdge(0,5);
DepthFirstPath path=new DepthFirstPath(g,0);
//得到结果
Stack<Integer> path1 = path.path(4);
//遍历栈并输出
while(!path1.isEmpty())
{
System.out.print(path1.top()+" ");
}
}
}
测试用图的结构为
测试结果为
0 2 3 4
这样算法就实现了