剑指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. bzoj 2594: [Wc2006]水管局长数据加强版

    Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...

  2. 软件测试人员在工作中如何运用Linux

    从事过软件测试的小伙们就会明白会使用Linux是多么重要的一件事,工作时需要用到,面试时会被问到,简历中需要写到. 对于软件测试人员来说,不需要你多么熟练使用Linux所有命令,也不需要你对Linux ...

  3. Dynamics 365中使用Web API将查找字段的值设置为空值的方法。

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复270或者20180424可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  4. 简易js进度条

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. 第四周小组作业:Wordcount优化

    1.小组github地址 https://github.com/muzhailong/wcPro 2.PSP表格 PSP2.1 PSP阶段 预计耗时(分钟) 实际耗时(分钟) Planning 计划 ...

  6. vue环境搭建过程中,遇到的坑爹的问题

    1,在配置package.json下载node依赖包时,执行$cnpm install过程中,这个过程是比较漫长的,尤其的这种core i5配置的电脑,简直有点卡的人怀疑人生,后来动了下有消息输出,我 ...

  7. 螺旋打印2D数组

    //一破题付出血的代价 多思考!public static void offer(int [][]a){ ,right=a.length-,low=,high=a[].length-; while(l ...

  8. AleNet模型笔记

    谁创造了AlexNet? AlexNet是有Hinton大神的弟子Alex Krizhevsky提出的深度卷积神经网络.它可视为LeNet的更深更宽的版本. AlexNet主要用到的技术 成功使用Re ...

  9. scan函数用法详解

    scan函数: scan(s,n,"char")表示从字串string中以char为分隔符提取第n个字串 功能(function):从字符表达式s中搜取给定的n个单词语法(synt ...

  10. dephi FillChar 的几种写法

    //在 delphi 新版中, char 已经是双字节了.故应该重新自己写一个函数,取名为 FillByte ,才无歧义. procedure TForm1.Button2Click(Sender: ...