一、图的数据类型
有3个函数必须要:
①构造函数:读取数据并创建邻接数组表
②addEdge函数:添加边的函数
③邻接表迭代器函数
public class Graph{
private final int V;
private final int E;
private Bag<Integer>[] adj;
public Graph(int V,int E){
Scanner cin=new Scanner (System.in);
this.V=V;
this.E=E:
adj=(Bag<Integer>) new Bag [V];
for(int v=0;v<V;v++)//为每个元素创建一个位置Bag
{
adj[v]=new Bag<Integer> ();
}
for(int i=0;i<this.E;i++){
int v=cin.nextInt();
int w=cin.nextInt():
addEdge(v,w);
}
}
public int V(){return this.V;}
public int E() {return this.E;}
public void addEdge(int v,int w)
{
adj[v].add(w);
adj[w].add(v);
E++;
}
public Iterable<Integer> adk(int v){//迭代器函数,有了这个后面才可以用for的简化形式
return adj[v];
}
二、DFS模板思想
其实DFS就是一个递归,每次访问一个,就把这个标记成已访问,然后就继续递归访问它的邻接顶点。
public class DepthFirstSearch
{
private boolean []marked;
private int count=0;
DepthFirstSearch(Graph G,int s)
{
marked =new boolean (G.V);
dfs(G,s);
}
public void dfs(Graph G,int v){
marked[v]=true;
count++;
for(int w:G.adj(v)
{
if(!marked[w]) dfs(G,w);
}
}
public boolean marked(int w){
return marked[w];
}
public int count()
{
return count;
}
}
三、使用深度优先搜索查找图中的路径
这个方法是只能用于连通图,即图内的每个点都可以连到,所以最后dfs结束递归的条件就是所有的都是marked了,然后还要建立edge[]数组用来记录路线。因为每一个点都是可以连接到的,所以edge[a]=b,就表示,到达a这个点的上一个联通点是b
public class DepthFirstPaths
{
private boolean []marked;
private int []edgeTo;
private final s;
public DepthFirstPaths(Graph G,int s){
marked =new boolean [G.V()];
edgeTo= new int [G.V()];
this.s=s;
dfs(G,s);
}
private void dfs(Graph G,int v)
{
marked [v]=true;
for(int w:G.adj(v))
{
if(!marked[w])
{
edgeTo[w]=v;
dfs(G,w);
}
}
public boolean hasPathTo(int v)
{
return marked[v];
}
public Iterable<Integer>pathTo(int v)
{
if(!hasPathTo()) return null;
Stack <Integer> path=new Stack<Integer> ();
for(int x=v;x!=s;x=edgeTo[x])
{
path.push(x);
}
path.push(s);
return path;
}
}
主函数调用如下:
public static void main(String []args)
{
Graph G=new Graph (5,8);//5个顶点,8条边,开始输入
int s=0;//起点为0
DepthFirstPaths search=new DepthFirst(G,s);
for(int v=0;v<G.V();v++)
{
System.out.print(s+"to"+v+" :");
if(search.hasPathTo(v))
{
for(int x:search.PathTo(v))
{
if(x==s) out.print(x);
else out.print(x+"-");
}
}
}
out.()
}
四、使用BFS查找图中的路径
public class BreadFirstPaths{
private boolean []marked;
private int [] edgeTo;
private final int s;
public BreadthFirstPaths(Graph G,int s)
{
marked=new boolean [G.V()];
edgeTo =new int [G.V()];
this.s=s;
bfs(G,s);
}
private void bfs(Graph G,int s)
{
Queue<Integer> queue=new Queue<Integer>();
marked[s]=true;
queue.enqueue(s);
while(!queue.isEmpty)
{
int v=queue.dequeue();
for(int w:G.adj(v))
{
if(!marked[w])
{
edgeTo[w]=v;
marked[w]=true;
queue.enqueue(w);
}
}
}
}
public boolean hasPathTo(int v)
{
return marked[v];
}
public Iterable <Integer>pathTo(int v)
{
//与前面相同
}
}
-----------------------------------------3.27更新------------------------------------------------
①DFS遍历图,用邻接矩阵存储
package Knowledgement;
import java.util.Arrays;
/*/
* 本节利用邻接矩阵存储图,所以需要一个二维数组以及一维的数组代表这个节点是否被访问
*知识点:
*(1)Java除了基本数据类型,其它类型都是引用传递,即传方法会改变值,但是本质上Java都是值传递的
*/
public class _dfs_in_Graph {
int INF=100000000;
static int maxn=1000;int [][]G=new int[maxn][maxn];boolean vist[]=new boolean [maxn];
int nodenumber=0;
void DFS(int u,int depth) {
vist[u]=true;
for(int i=0;i<nodenumber;i++) {
if(G[u][i]!=INF&&vist[i]==false)//有边且没有被访问过
{
DFS(i,depth+1);
}
}
}
void DFSTrave() //遍历整个图,从0号节点开始遍历
{
for(int u=0;u<nodenumber;u++) {
if(vist[u]==false) {
DFS(u,1);//访问u所在的连通块
}
}
}
//P356题目核心代码
static int K;static int []gang=new int [maxn];static int []weight=new int [maxn];
static int head=0,numbernode=0,totalvalue=0;
void DFS1(int node,int head,int numbernode,int totalvalue) {
numbernode++;
vist[node]=true;
if(weight[node]>weight[head]) {
head=node;
}
for(int i=0;i<nodenumber;i++) {
if(G[node][i]!=INF) {
totalvalue=totalvalue+G[node][i];//加上环形边
G[node][i]=G[i][node]=0;//删除这条边,防止回头
if(vist[i]==false) {
DFS1(i,head,numbernode,totalvalue);
}
}
}
}
void DFSTrave1() {
Arrays.fill(gang,-1);
for(int i=0;i<nodenumber;i++) {
if(vist[i]==false) {
int head=i;numbernode=0;totalvalue=0;//这三个要设置成全局变量,因为要把主函数的head也改了,head会变的
DFS1(i,head,numbernode,totalvalue);
if(numbernode>2&&totalvalue>K) {
gang[head]=numbernode;//最后的时候就遍历整个gang数组,不为1的就输出,其实用treemap会更好,直接排好序了
}
}
}
}
public static void main(String []args) {
}
}
②BFS遍历图
package Knowledgement;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
public class _bfs_in_Graph {
static int maxn=1000;static boolean []inq=new boolean[maxn];
static int[][]G=new int [maxn][maxn];
static int nodenumber;static int INF=10000000;
void BFS(int u) {
Arrays.fill(inq,false);
Queue<Integer> q=new LinkedList<Integer>();
q.add(u);
inq[u]=true;//不出现环的图
while(!q.isEmpty()) {
int node=q.poll();
for(int i=0;i<nodenumber;i++) {
if(G[i][node]!=INF&&inq[i]==false) {
q.add(i);
inq[node]=true;
}
}
}
}
void BFSTrave() {
for(int i=0;i<nodenumber;i++) {
if(inq[i]==false) {
BFS(i);
}
}
}
public static void main(String []args) {
}
}