图论 邻接链表存储 BFS DFS 拓扑排序


package Algorithms;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.LinkedList;

import java.util.Stack;

public class Graphic {

public static class Vertex{

public int num;//节点编号

public int weight;//边的权重

public Vertex next;//指向顶点的下一个弧尾,即下一条边

public Vertex(int num,int weight,Vertex next)

{

this.num=num;

this.weight=weight;

this.next=next;

}

}

private int size;//图的顶点数

private boolean isDirection;//是否为有向图true,

private boolean visit[];

private Vertex  p[];//存放每个顶点的前驱

private int distance[];//广度优先遍历时存放与根节点的距离

private Vertex adj[];

public int startT[];//深度优先遍历的开始时间

public int endT[];//深度优先遍历的结束时间  用于拓扑排序

int time;//深度优先遍历时记录每个节点的开始和结束时间的计时器

LinkedList<Vertex>topologicalSort=new LinkedList<Vertex>();//存放拓扑排序的数组

public Graphic(int verNum,boolean isDirection){

adj=new Vertex[verNum];

p=new Vertex[verNum];

size=verNum;

this.isDirection=isDirection;

visit=new boolean[verNum];

distance=new int [verNum];

endT=new int [size];

startT=new int [size];

//构造顶点,防止下面的有向图中顶点不是弧头,从而顶点数组会为空指针

for(int i=0;i<size;i++)

{

adj[i]=new Vertex(i, 0, null);

}

}

/**

* 创建图  只插入所有节点即可创建 图的连接表表示

* x y分别表示弧头,和 弧尾

*/

public void insertE(int x,int y)

{

Vertex temp=adj[x];

while(temp.next!=null)

temp=temp.next;

temp.next=new Vertex(y, 0, null);

if(isDirection==false)

{

if(adj[y]==null)

adj[y]=new Vertex(y, 0, null);

Vertex temp1=adj[y];

while(temp1.next!=null)

temp1=temp1.next;

temp1.next=new Vertex(x, 0, null);

}

}

/**   广度优先遍历

* @param x:图的根节点 开始遍历

* 存放在队列中的节点都是将要访问的所以设置为true ,以免重复添加

*/

public void BFS(int x)

{

//初始化

Arrays.fill(visit, false);

Arrays.fill(distance, -1);

Arrays.fill(p, null);

java.util.Queue<Integer> q=new LinkedList<Integer>();

distance[x]=0;//初始化距离根节点的深度

visit[x]=true;

q.add(x);

while(!q.isEmpty())

{

//这里遍历顶点的边,要找到定点数组中的引用,才能找到相应的邻接表,否则

//只在一个顶点的边上乱转,所以 使用顶点的编号 在队列中表示 不要用引用

//使用引用,还要找到相应的定点数组上的引用

Vertex parent=adj[q.poll()];

System.out.print(parent.num+" ");

Vertex temp=parent.next;

while(temp!=null)//在向队列中添加节点时就把此节点的前驱和深度进行赋值

{

if(visit[temp.num]==false)

{

p[temp.num]=parent;

visit[temp.num]=true;//添加访问标志进入队列之后就要添加标志防止

//重复进入 重复访问

distance[temp.num]=distance[p[temp.num].num]+1;

q.add(temp.num);

}

temp=temp.next;

}

}

}

/**

* 深度优先遍历 与拓扑排序

*/

public void DFS()

{

//初始化

Arrays.fill(visit, false);

Arrays.fill(distance, -1);

Arrays.fill(p, null);

Arrays.fill(endT, 0);

Arrays.fill(startT, 0);

time=0;

for(int i=0;i<size;i++)//避免有的图为不强连通的

{

if(visit[i]==false)//注意不能把这个条件写到for循环中,因为遇到2

//已经访问退出循环不再迭代,应该放在循环体中

DFSvisit3(i);

}

}

//递归实现

public void DFSvisit(int i)

{

time++;//开始访问的时间

startT[i]=time;

visit[i]=true;

System.out.print(i+" ");

Vertex temp=adj[i].next;

while(temp!=null)

{

if(visit[temp.num]==false)

DFSvisit(temp.num);

temp=temp.next;

}

time++;//访问完成+1 ,记录 结束的时间  如果不加就和开始的时间一样了

endT[i]=time;

topologicalSort.addFirst(adj[i]);

}

//使用栈实现

public void DFSvisit2(int i)

{

Stack<Integer> s=new Stack<Integer>();

s.push(i);

while(!s.isEmpty())

{

time++;

int num=s.pop();

visit[num]=true;

System.out.print(num+" ");

Vertex temp=adj[num].next;

while(temp!=null)

{

if(visit[temp.num]==false)

s.push(temp.num);

temp=temp.next;

}

}

}

//使用栈实现 拓扑排序

public void DFSvisit3(int i)

{

Stack<Integer> s=new Stack<Integer>();

s.push(i);

while(!s.isEmpty())

{

time++;

int num=s.peek();

if(visit[num]==false)

{

visit[num]=true;

startT[num]=time;

System.out.print(num+" ");

Vertex temp=adj[num].next;

while(temp!=null)

{

if(visit[temp.num]==false)

s.push(temp.num);

temp=temp.next;

}

}

else

{

endT[num]=time;

s.pop();

topologicalSort.addFirst(adj[num]);

}

}

}

/**

* 拓扑排序(对于无环图)

* 深度优先遍历的按 结束时间从大到小排序

* 结束时间大的表示  为最前面的节点

*/

public void topologicalSort()

{

DFS();

for(int i=0;i<topologicalSort.size();i++)

{

int num=topologicalSort.get(i).num;

System.out.println("第"+i+"执行的"+"节点"+num+": "+startT[num]+"/"+endT[num]);

}

}

public static void main(String []args)

{

Graphic g=new Graphic(9, true);

g.insertE(0, 1);

g.insertE(0, 6);

g.insertE(1, 6);

g.insertE(1, 2);

g.insertE(7, 6);

g.insertE(5, 2);

g.insertE(5, 4);

g.insertE(4, 3);

g.insertE(2, 3);

g.insertE(8, 8);

//g.DFS();

g.topologicalSort();

}

}

时间: 2024-10-17 19:29:00

图论 邻接链表存储 BFS DFS 拓扑排序的相关文章

图论知识整理(2) 拓扑排序、最短路、最小生成树

===================================== 发现以前图论学的很不好,什么都不会,现在开始整理图论知识了 作者就是个蒟蒻,ORZ各位大神们 ===================================== 定义:对一个有向无环图(Directed Acyclic Graph,简称DAG)进行拓扑排序,将图中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前. 说的好像很有道理,然而我并没有看懂它在

HDU3342有向图判圈DFS&amp;&amp;拓扑排序法

HDU3342 Legal or Not 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3342 题目意思:一群大牛互相问问题,大牛有不会的,会被更厉害的大牛解答,更厉害的大牛是会的东西比大牛多,但是有的时候更厉害的大牛会装弱,出来问问题,这样就被大牛解答了.这样就形成了一个圈.题目的意思就是让你在一个有向图里面判断是否存在环.我们可以通过dfs和拓扑排序两种方法. DFS的代码: //Author: xiaowuga #include <bits

对邻接链表的深度优先(DFS)遍历

深度优先搜索算法在搜索过程中对节点进行涂色来指明节点的当前状态. 每个节点的初始颜色都是白色. 在节点被发现后变成灰色. 在其邻接链表被扫描完成之后变成黑色. 该方法可以保证每个节点只在一棵深度优先树中出现, 因此, 所有的深度优先树是不相交(disjoint)的. 除了创建深度优先搜索森林之外, 该方法还在每个节点盖上两个时间戳. 一个是被发现的时间(涂上灰色的时间), 另一个是完成对v的邻接链表扫描的时间(涂上黑色的时间). 这些时间戳提供了图的结构的重要信息. 当DFS算法返回时, 每个顶

hihoCoder#1185 : 连通性&#183;三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

题目链接: http://hihocoder.com/problemset/problem/1185# 题意: n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了.求最多可以吃掉多少草. 思路: 提示里面讲的挺好的 如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点.所以把强联通块缩成一个点 因为一个强连通块会被缩成一个点,那么我们可

[poj 1691] Painting A Board dfs+拓扑排序

Painting A Board Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 3611 Accepted: 1795 Description The CE digital company has built an Automatic Painting Machine (APM) to paint a flat board fully covered by adjacent non-overlapping rectangle

(番外)使用DFS和BFS实现拓扑排序

1.BFS实现 public class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { int[] incLinkCounts = new int[numCourses]; List<List<Integer>> adjs = new ArrayList<>(numCourses); initialiseGraph(incLinkCounts, adjs, prere

leetcode_课程表(BFS、拓扑排序)

题目描述: 你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 .在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习? 最近打华为软挑有用到拓扑剪枝,顺便刷了这题.题目要求翻译过来就是要在一个有向图中找环:使用拓扑算法把入度为零的点去掉,再更新入度表,使用bfs循环往复,如果图中没有环,那最后不会有点留下来.返回值很简洁,若

图的邻接链表存储

//输入样例 /* 5 0 AB AD AC CD BE DE */ //输出 /* Please Input the edge x-->y:AB AD AC CD BE DE A 1 2 3 B 0 4 C 0 3 D 0 2 4 E 1 3 */ #include<iostream> #include<cstdio> using namespace std; #define MAXVER 10 typedef char Elemtype; //接下来要连的结点 typed

拓扑排序-图论

如果我们有一组任务完成,而有些任务人才的其他任务结束后开始.因此,我们必须非常小心,这些任务的运行顺序. 假设这些任务很简单的字的运行顺序,我们可以用它们来存储列表,这是一个非常好的方案,这样我们就可以知道运行秩序完全任务. 间的关系是非常复杂的.有些任务依赖于两个甚至很多其它的任务,或者反过来非常多任务依赖自己. 因此我们不能通过链表或者树的数据结构来对这个问题建模.对这类问题唯一合理的数据结构就是图.我们须要哪种图呢?非常显然,我们须要有向图来描写叙述这样的关系,并且是不能循环的有向图,我们