深度優先dfs求解兩點間所有路徑
阿新 • • 發佈:2018-12-09
鄰接表:
dfs4(a,start,end,visited,stack,-1)//遞迴
dfs5(a,start,end);//非遞迴
鄰接矩陣:(可以直接用矩陣資料計算路徑長度)
dfs6(m,start,end,visited,stack,-1);//遞迴
dfs7(m,start,end);//非遞迴
遞迴的思路來自https://blog.csdn.net/hackersuye/article/details/79044555
非遞迴是自己做的
大家可以試試。
鄰接表和鄰接矩陣的寫法是來自《天勤高分筆記資料結構》。
鄰接表
package dfs;
class AGraph{
int n;
int e=0;
VNode adjlist[];
public AGraph(int n) {
super();
this.n = n;
adjlist=new VNode[n];
}
}
package dfs;
class ArcNode{
int adjvex; ArcNode nextarc;
int weight;//weight就是adjlist[i]->adjvex的權重
//對應於鄰接矩陣的權重m[i][adjvex]
AGraph a;//記錄邊數時,需要圖a
int edge_type=0;//初始化為回邊(P99.8)
public ArcNode(int adjvex, AGraph a) {
super();
this.adjvex = adjvex;
this.a = a;
a.e+=1;
}
public ArcNode() {
}
public ArcNode (int adjvex){
this.adjvex=adjvex;
};
}
package dfs;
class VNode{//鄰接矩陣的頂點也可以用這個
ArcNode firstarc;
char info;
int level;//對應於99.8,對每個點,都要有層級
public VNode(char info) {
this.info = info;
}
int ini=1;//用於利用鄰接表非遞迴輸出全部路徑的DFS
//在該次應該指向連結表的哪一個arc
//初始值為1,即firstarc;若大於1,不停地取nextarc,
//直到找到對應的 第ini邊
}
鄰接矩陣
package dfs;
public class VertexType {
int no;
int ini=0;//用於利用鄰接矩陣非遞迴輸出全部路徑的DFS
//這裡的ini是指向的頂點數字(因為用鄰接矩陣總要從後向前遍歷)
//不是VNode裡面的第幾個
}
package dfs;
public class MGraph {
int n;
int e=0;//n為頂點數,e為邊數
//int edges[][];
VertexType vex[];
int edges[][];
public MGraph(int n) {
this.n = n;
edges=new int[n][n];
vex=new VertexType[n];
for(int i=0;i<vex.length;i++)
vex[i]=new VertexType();
}
public void set(int i,int j)
{
edges[i][j]=1;
//如果是無向圖的話
edges[j][i]=1;
e+=2;
}
}
4個方法
public static void dfs4(AGraph a,int start,int end,
int visited[],int stack[],int top)
{ visited[start]=1;
stack[++top]=start;
if(start==end) {
System.out.println("成功");
for(int i=0;i<=top;i++)
System.out.print(stack[i]+" ");
System.out.println("");//出棧
top--;
visited[end]=0;
//visited[stack[top]]=0;top--;
return;
}
ArcNode arc=a.adjlist[start].firstarc;
while(arc!=null)
{if(visited[arc.adjvex]==0)
dfs4(a,arc.adjvex,end,visited,stack,top);
arc=arc.nextarc;
}
if(arc==null) {
top--;visited[start]=0;
//visited[stack[top]]=0;top--;
}
}
public static void dfs5(AGraph a,int start,int end)
{//每次進棧一個元素或出棧一個元素
int visited[]=new int[a.n];//初始化為0
int stack[]=new int[a.n];
int top=-1;
stack[++top]=start;
//stack存放的是adjlist中某一個的位置
visited[start]=1;
while(top!=-1)
{
ArcNode arc=null;
int x=stack[top];
//在if else下面統一出棧,設定為未訪問
if(x==end) //棧輸出 //9在這裡是終點
{ System.out.println("成功");
for(int i=0;i<=top;i++)
System.out.print(stack[i]+" ");
System.out.println("");
}
else
//m是指明arc是x指向的第幾個頂點
//這個頂點必須滿足:
//①未被訪問
//②m必須大於等於ini(小於ini的都已經出棧或不行了,不用考慮)
{arc=a.adjlist[x].firstarc;
int m=1;
while(arc!=null)
{if(visited[arc.adjvex]==0&&m>=a.adjlist[x].ini)
{stack[++top]=arc.adjvex;
visited[arc.adjvex]=1;break;}
else {
arc=arc.nextarc;m++;}}
}
if(arc==null)
//此處邏輯為先出棧,出棧的元素指向的邊還原為firstarc
//出棧的元素b一定是出棧後棧頂元素a指向的某一個頂點
//我們找到b是a的第m個頂點,把a的ini設定為m+1
//使其不要重複搜尋前m個
//(前面的做法一定是按順序的,說明前m個已經搜過)
{ int y=stack[top--];//出棧
visited[y]=0;
a.adjlist[y].ini=1;
if(top>=0)
{ ArcNode ar=a.adjlist[stack[top]].firstarc;
int count=1;
//由上面,我們知道進棧的一定>=ini
//所以首先ar要變成ini
while(count<a.adjlist[stack[top]].ini)
{ar=ar.nextarc;
count++;}
//再往下找
int number=ar.adjvex;
while(number!=y)
{a.adjlist[stack[top]].ini++;
ar=ar.nextarc;
number=ar.adjvex;
}
a.adjlist[stack[top]].ini++;
}
}
}
}
public static void dfs6(MGraph m,int start,int end,
int visited[],int stack[],int top)
{ visited[start]=1;
stack[++top]=start;
if(start==end) {
System.out.println("成功");
for(int i=0;i<=top;i++)
System.out.print(stack[i]+" ");
System.out.println("");//出棧
top--;
visited[end]=0;
//visited[stack[top]]=0;top--;
return;
}
for(int i=0;i<m.n;i++)
if(m.edges[start][i]==1&&visited[i]==0)
{
dfs6(m,i,end,visited,stack,top);
}
top--;
visited[start]=0;
}
public static void dfs7(MGraph m,int start,int end)
{//每次進棧一個元素或出棧一個元素
int visited[]=new int[m.n];//初始化為0
int stack[]=new int[m.n];
int top=-1;
stack[++top]=start;
//stack存放的是vex中某一個的位置
visited[start]=1;
while(top!=-1)
{
int x=stack[top];
int ii=m.n;//ii為條件
//在if以及else下面統一出棧
if(x==end) //棧輸出
{ System.out.println("成功");
for(int i=0;i<=top;i++)
System.out.print(stack[i]+" ");
System.out.println("");
}
else
//m是指明arc是x指向的第幾個頂點
//這個頂點必須滿足:
//①未被訪問
//②ii必須大於等於x的ini(小於ini的都已經出棧或不行了,不用考慮)
//③ii必須與x有邊
{
for(ii=m.vex[x].ini;ii<m.n;ii++)
if(visited[ii]==0&&m.edges[x][ii]!=0)
{stack[++top]=ii;
visited[ii]=1;break;}
}
if(ii==m.n)
//此處邏輯為先出棧,出棧的元素指向的邊還原為0
//出棧的元素y一定是出棧後棧頂元素a指向的某一個頂點
//把a的ini設定為y+1
//使其不要重複搜尋前y個頂點
//(前面的做法一定是按順序的,說明前y個已經搜過或者根本不滿足條件)
{ int y=stack[top--];//出棧
visited[y]=0;
m.vex[y].ini=0;
if(top>=0)
m.vex[stack[top]].ini=y+1;
}
}
}