剑指Offer–图的操作

前言

  企业笔试过程中会涉及到数据结构的方方面面,现将有关图的深度优先搜索与广度优先搜索进行整理归纳,方便日后查阅。

  在已做过的笔试题目中,可用DFS解决的题目有:

  1. 地牢逃脱”–网易
  2. 遍历最短路径长度”–携程
  3. 小青蛙走迷宫”–滴滴

  三道题目都是DFS的经典应用,主要采用递归+回溯的方式。

  下面主要讲解一下DFS与BFS的具体实现。

深度优先搜索(DFS) && 广度优先搜索(BFS)

package cn.edu.ujn.graph;
import java.util.ArrayList;
import java.util.LinkedList;
/**
 * @description 邻接矩阵模型类
 * @author SHQ
 * @time 2016.09.12
 */
public class DFS_BFS {
    private ArrayList<Object> vertexList;// 存储点的链表
    private int[][] edges;       // 邻接矩阵,用来存储边
    private int numOfEdges;      // 边的数目
    boolean[] isVisited;         // 遍历标志位

    public DFS_BFS(int n) {
        //初始化矩阵,二维数组,和边的数目
        edges = new int[n][n];
        vertexList = new ArrayList<Object>(n);
        numOfEdges = 0;
        // 将所有节点访问标志位均置为未访问
        isVisited = new boolean[n];
        for(int i = 0; i < n; i++){
            isVisited[i] = false;
        }
    }

    // 得到结点的个数
    public int getNumOfVertex() {
        return vertexList.size();
    }

    // 得到边的数目
    public int getNumOfEdges() {
        return numOfEdges;
    }

    // 返回结点i的数据
    public Object getValueByIndex(int i) {
        return vertexList.get(i);
    }

    // 返回v1,v2的权值
    public int getWeight(int v1,int v2) {
        return edges[v1][v2];
    }

    //插入结点
    public void insertVertex(Object vertex) {
        vertexList.add(vertexList.size(),vertex);
    }

    //插入结点
    public void insertEdge(int v1,int v2,int weight) {
        edges[v1][v2]=weight;
        numOfEdges++;
    }

    //删除结点
    public void deleteEdge(int v1,int v2) {
        edges[v1][v2] = 0;
        numOfEdges--;
    }

    // 得到第一个邻接结点的下标
    public int getFirstNeighbor(int index) {
        for(int j = 0; j < vertexList.size(); j++) {
            if (edges[index][j] > 0) {
                return j;
            }
        }
        return -1;
    }

    // 根据前一个邻接结点的下标来取得下一个邻接结点
    public int getNextNeighbor(int v1, int v2) {
        for (int j = v2+1; j < vertexList.size(); j++) {
            if (edges[v1][j]>0) {
                return j;
            }
        }
        return -1;
}
    // 私有函数,深度优先遍历
    private void depthFirstSearch(boolean[] isVisited,int  i) {
        // 首先访问该结点,在控制台打印出来
        System.out.print(getValueByIndex(i) + "  ");
        // 置该结点为已访问
        isVisited[i] = true;

        int w = getFirstNeighbor(i);
        while (w != -1) {
            if (!isVisited[w]) {
                depthFirstSearch(isVisited,w);
            }
            w = getNextNeighbor(i, w);
        }
    }

    // 对外公开函数,深度优先遍历,与其同名私有函数属于方法重载
    public void depthFirstSearch() {
        for(int i = 0; i < getNumOfVertex(); i++) {
            //因为对于非连通图来说,并不是通过一个结点就一定可以遍历所有结点的。
            if (!isVisited[i]) {
                depthFirstSearch(isVisited,i);
            }
        }
}
    /**
     * 私有函数,广度优先遍历
     * 遍历步骤:
     *  1.访问初始结点v并标记结点v为已访问。
     *  2.结点v入队列
     *  3.当队列非空时,继续执行,否则算法结束。
     *  4.出队列,取得队头结点u。
     *  5.查找结点u的第一个邻接结点w。
     *  6.若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
     *      1)若结点w尚未被访问,则访问结点w并标记为已访问。
     *      2)结点w入队列
     *      3)查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。
     * @param isVisited
     * @param i
     */
    private void broadFirstSearch(boolean[] isVisited, int i) {
        int u, w;
        // 借助辅助队列,记录访问顺序
        LinkedList<Object> queue = new LinkedList<Object>();
        // 访问结点i
        System.out.print(getValueByIndex(i) + "  ");
        isVisited[i] = true;
        // 结点入队列
        queue.addLast(i);
        while (!queue.isEmpty()) {
            u = ((Integer)queue.removeFirst()).intValue();
            w = getFirstNeighbor(u);
            while(w != -1) {
                if(!isVisited[w]) {
                        //访问该结点
                        System.out.print(getValueByIndex(w)+"  ");
                        //标记已被访问
                        isVisited[w] = true;
                        //入队列
                        queue.addLast(w);
                }
                //寻找下一个邻接结点
                w = getNextNeighbor(u, w);
            }
        }
    }

    //对外公开函数,广度优先遍历
    public void broadFirstSearch() {
        for(int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]) {
                broadFirstSearch(isVisited, i);
            }
        }
    }
}

Main.java

package cn.edu.ujn.graph;

public class Main {
    public static void main(String args[]) {
        int n = 8, e = 9;   // 分别代表结点个数和边的数目
        String labels[]={"1","2","3","4","5","6","7","8"};  // 结点的标识
        DFS_BFS graph = new DFS_BFS(n);
        for(String label : labels) {
            graph.insertVertex(label);  // 插入结点
        }
        //插入九条边
        graph.insertEdge(0, 1, 1);
        graph.insertEdge(0, 2, 1);
        graph.insertEdge(1, 3, 1);
        graph.insertEdge(1, 4, 1);
        graph.insertEdge(3, 7, 1);
        graph.insertEdge(4, 7, 1);
        graph.insertEdge(2, 5, 1);
        graph.insertEdge(2, 6, 1);
        graph.insertEdge(5, 6, 1);
        graph.insertEdge(1, 0, 1);
        graph.insertEdge(2, 0, 1);
        graph.insertEdge(3, 1, 1);
        graph.insertEdge(4, 1, 1);
        graph.insertEdge(7, 3, 1);
        graph.insertEdge(7, 4, 1);
        graph.insertEdge(6, 2, 1);
        graph.insertEdge(5, 2, 1);
        graph.insertEdge(6, 5, 1);

/*        System.out.println("深度优先搜索序列为:");
        graph.depthFirstSearch();
        System.out.println();*/
        System.out.println("广度优先搜索序列为:");
        graph.broadFirstSearch();
    }
}


剑指Offer--图的操作的更多相关文章

  1. 剑指Offer——Java实现栈和队列的互模拟操作

    剑指Offer--Java实现栈和队列的互模拟操作 栈模拟队列   题目:JAVA实现用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型.   思路:其实就是把队列正常入 ...

  2. [剑指offer]09用两个栈实现队列插入和删除操作,C++实现

    原创博文,转载请注明出处! # 本文为牛客网<剑指offer>刷题笔记 1.题目 # 用两个栈实现队列的插入和删除操作 2.思路 栈服从先入后出的原则处理数据,队列服从先入先出的原则处理数 ...

  3. 面试经典算法题集锦——《剑指 offer》小结

    从今年 3 月份开始准备找实习,到现在校招结束,申请的工作均为机器学习/数据挖掘算法相关职位,也拿到了几个 sp offer.经历这半年的洗礼,自己的综合能力和素质都得到了一个质的提升. 实话说对于未 ...

  4. 剑指Offer——知识点储备--Linux基本命令+Makefile

    剑指Offer--知识点储备–Linux基本命令 1.linux下查看进程占用cpu的情况(top): 格式 top [-] [d delay] [q] [c] [S] [s] [i] [n] 主要参 ...

  5. 剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制

    剑指Offer--知识点储备-故障检测.性能调优与Java类加载机制 故障检测.性能调优 用什么工具可以查出内存泄露 (1)MerroyAnalyzer:一个功能丰富的java堆转储文件分析工具,可以 ...

  6. 剑指Offer——知识点储备-J2EE基础

    剑指Offer--知识点储备-J2EE基础 9.2 jdk 1.8的新特性(核心是Lambda 表达式) 参考链接:http://www.bubuko.com/infodetail-690646.ht ...

  7. 剑指Offer——迅雷笔试题+知识点总结

    剑指Offer--迅雷笔试题+知识点总结 情景回顾 时间:2016.9.19 19:00-21:00 地点:山东省网络环境智能计算技术重点实验室 事件:迅雷笔试 总体来说,迅雷笔试内容体量不算多,主要 ...

  8. 剑指Offer——携程笔试题+知识点总结

    剑指Offer--携程笔试题+知识点总结 情景回顾 时间:2016.9.17 19:10-21:10 地点:山东省网络环境智能计算技术重点实验室 事件:携程笔试 总体来说,携程笔试内容与其它企业笔试题 ...

  9. 剑指Offer——归并排序思想应用

    剑指Offer--归并排序思想应用 前言 在学习排序算法时,初识归并排序,从其代码量上感觉这个排序怎么这么难啊.其实归并排序的思想很简单:将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列 ...

  10. 剑指Offer——巧妙使用sort(List<T>,Comparator<? super T>)比较器

    剑指Offer--巧妙使用sort(List<T>,Comparator<? super T>)比较器 先入为主 package cn.edu.ujn.offersword; ...

随机推荐

  1. hdu 3065 AC自动机(各子串出现的次数)

    病毒侵袭持续中 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  2. SpringCloud学习之快速搭建分布式配置

    一. 关于spring-cloud中的分布式配置 Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持.使用Config Server,您可以在所有环境中管理应用程序的 ...

  3. 常用Markdown语法

    个人常用的Markdown语法 前言 初次使用Markdown编辑器,将自己最常用的几个语法记录一下,如有错误或是更方便的使用方式还请指出. 多级标题 一个"#"到六个" ...

  4. 《Java技术》第三次作业

    (一)学习总结 1.阅读下面程序,分析是否能编译通过?如果不能,说明原因.应该如何修改?程序的运行结果是什么?为什么子类的构造方法在运行之前,必须调用父 类的构造方法?能不能反过来? class Gr ...

  5. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  6. IOS UITextView支持输入、复制、粘贴、剪切自定义表情

    UITextView是ios的富文本编辑控件,除了文字还可以插入图片等.今天主要介绍一下UITextView对自定义表情的处理. 1.首先识别出文本中的表情文本,然后在对应的位置插入NSTextAtt ...

  7. a标签href无值 onclick事件跳转

    <a href='#'  onclick='gomore()'>更多>></a>  单击无反应 <a href='javascript:void(0)'  o ...

  8. Java8——快速入门手册(学习笔记)

    github博文传送门 Java8特性学习笔记 Java8中新增了许多的新特性,在这里本人研究学习了几个较为常用的特性,在这里与大家进行分享.(这里推荐深入理解Java 8用于理解基础知识)本文分为以 ...

  9. 自定义alert窗口样式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. idea-JSP out.println报错问题

    <%! out.println("xxxx");%> 上面是错误的,<%!%>是声明变量是使用,而不是进行逻辑输出! <% out.println(x ...