Python 每日一记265@Java图的优先广度遍历(邻接表实现的图)

广度优先遍历的概念就不多加叙述了,简而言之就是访问一个顶点,然后访问完这个顶点的所有邻接顶点,再访问每一个邻接顶点的所有邻接顶点,为了实现这个方法,必须使用辅助队列,之前对于邻接数组下的遍历已经介绍过,这里是邻接表实现的图,直接上代码了。

java代码实现


package mypackage;
import javax.print.DocFlavor;
import java.util.Iterator;

//队列类,用链表实现,后面有用
class Queue<T> implements Iterable<T>{
    //    节点个数,头节点,尾节点
    private int N;
    private Node head;
    private Node last;
    //节点类
    public class Node {
        public T data;
        public Node next;

        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
    //构造方法,初始化
    public Queue() {
        this.N = 0;
        this.head = new Node(null,null);
        this.last = null;
    }
    //队列长度
    public int size(){
        return N;
    }
    //队列是否为空
    public boolean isEmpty(){
        return N==0;
    }
    //入队列
    public void enqueue(T data){
//        如果队列为空,说明尾节点为空,让新节点为尾节点,头借点指向尾节点
        if (isEmpty()){
            last=new Node(data,null);
            head.next=last;
//            如果队列不为空,让新节点为尾节点,老的尾节点指向新尾节点
        }else {
            Node oldlast=last;
            last=new Node(data,null);
            oldlast.next=last;
        }
//        最后元素+1
        N++;
    }
    //出队列,注意先入先出,每次出的节点就是head指向的第一个节点,然后让head只想第二个节点即可
//    且注意,如果队列为空,要将last=null
    public T dequeue(){
//        如果为空,返回null
        if (isEmpty()){
            return null;
//            如果不为空,让head只想第二个节点,元素-1,且如果队列为空,要将last=null
        }else {
            Node oldfirst=head.next;
            head.next=oldfirst.next;
            N--;

            if (isEmpty()){
                last=null;
            }
//            返回弹出的元素
            return oldfirst.data;
        }
    }

    //    遍历
    @Override
    public Iterator iterator() {
        return new QIterator();
    }
    //    创建一个内部类实现Iterator接口
    public class QIterator implements Iterator {
        //        定义一个遍历的节点
        private Node n;

        public QIterator() {
//            初始化为0索引位置
            this.n = head;
        }

        //重写两个方法
        @Override
        public boolean hasNext() {
//            这个方法判断是否超出最大索引,如果超出会停止遍历
            return n.next != null;
        }

        @Override
        public Object next() {
//            这个方法会遍历得每个节点
            n = n.next;
            return n.data;
        }
    }
}

class Graph<T> {
    private int V;//顶点数
    private int E;//边数
    private Queue<T>[] adj;//邻接表,用于装每个顶点的相连的顶点组成的队列,注意索引是每个顶点,这个索引对应的值是相连的顶点组成的队列
    //adj中索引是每个顶点,为了在图中可以添加任意类型的数据,比如城市名字,字母等,因此使用一个数组将索引映射为其他数据
    //比如讲索引0,映射为A
    private T[] mapArr;
    private boolean[] isVisited;//是否被访问过
    private Queue<T> temp;
    //构造方法,传入顶点个数,初始化边数为0,
    public Graph(int v) {
        this.V = v;
        this.E = 0;
        this.adj = new Queue[v];//初始化队列数组,大小为顶点的个数
        for (int i = 0; i < adj.length; i++) {
            adj[i] = new Queue<T>();//初始化数组的每个队列
        }
        //初始化mapArr,在初始情况下,每个索引对应的顶点元素为null
        this.mapArr = (T[]) new Object[v];//注意不能new T[v]
        for (int i = 0; i < mapArr.length; i++) {
            mapArr[i] = null;
        }
    }

    //添加顶点,和索引对应
    public void addV(int i, T v) {
        mapArr[i] = v;
    }

    //获得顶点的个数
    public int getV() {
        return V;
    }

    //获取顶点在邻接表内所对应的索引
    public int getIndex(T v) {
        for (int i = 0; i < mapArr.length; i++) {
            if (mapArr[i] == v) {
                return i;
            }
        }
        return -1;
    }

    //添加边,即将顶点v,w连接起来形成图,注意是无向的因此不仅要adj[getIndex(v)].enqueue(w);还要adj[getIndex(w)].enqueue(v);
    public void addEdge(T v, T w) {
        adj[getIndex(v)].enqueue(w);
        adj[getIndex(w)].enqueue(v);
        E++;//边数+1
    }

    //    获取边的个数
    public int getE() {
        return E;
    }

    //获取某个顶点相邻的所有顶点,返回这个队列即可
    public Queue<T> getAdj(T v) {
        return adj[getIndex(v)];
    }

    //广度优先遍历对外调用方法
    public void wideSerch() {
        temp=new Queue<T>();
        //初始化均为没有被访问过
        isVisited = new boolean[getV()];
        for (int i = 0; i < isVisited.length; i++) {
            isVisited[i] = false;
        }
        //对每一个顶点都优先广度遍历
        for (int i = 0; i < getV(); i++) {
            if (isVisited[i] == false) {
                wideSerch(mapArr[i]);
            }
        }
    }

    //广度优先遍历重载方法,让第一个顶点入队列,标记为已经访问,打印出来
    //循环队列,先弹出一个顶点,以这个顶点为基础,访问他的邻接表,并且把这些顶点装入队列,以此类推
    //总之,核心思想是,先访问一个顶点的所有相邻顶点,然后再访问每个相邻顶点的相邻顶点
    public void wideSerch(T v) {
        isVisited[getIndex(v)] = true;
        temp.enqueue(v);
        System.out.print(v + "-->");

        while (!temp.isEmpty()){
            T out=temp.dequeue();
            for (T q : adj[getIndex(out)]) {
                if (isVisited[getIndex(q)] == false) {
                    isVisited[getIndex(q)] = true;
                    temp.enqueue(q);
                    System.out.print(q + "-->");
                }
            }
        }
    }
}
//测试
public class MyJava {

    public static void main(String[] args) {
        Graph <String>graph=new Graph(7);
        //添加顶点
        graph.addV(0,"A");
        graph.addV(1,"B");
        graph.addV(2,"C");
        graph.addV(3,"D");
        graph.addV(4,"E");
        graph.addV(5,"F");
        graph.addV(6,"G");

        //添加边
        graph.addEdge("A","E");
        graph.addEdge("A","F");
        graph.addEdge("A","G");
        graph.addEdge("E","B");
        graph.addEdge("F","C");
        graph.addEdge("G","D");

        System.out.println("顶点个数:"+graph.getV());
        System.out.println("边条数:"+graph.getE());
        System.out.print("顶点A相邻元素包括:");
        Queue vs=graph.getAdj("A");
        for (Object v : vs){
            System.out.print(v+" ");
        }
        System.out.println();
        System.out.println("广度优先遍历图:");
        graph.wideSerch();
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值