首页 > 代码库 > 图论 邻接链表存储 BFS DFS 拓扑排序

图论 邻接链表存储 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();
    }
}

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