算法图解(五):散列表、广度优先搜索

本文探讨了散列表的特性,包括一致性、无冲突的散列函数以及性能优化,强调其在平均情况下的O(1)操作时间。同时,介绍了广度优先搜索在图论中的应用,如寻找最短路径,以及如何利用队列实现。文章还通过一个示例展示了如何用广度优先搜索解决实际问题,并分析了其运行时间为O(V+E)。
摘要由CSDN通过智能技术生成
 * <第5章> 散列表 </第5章>
 *  5.1 散列函数
 *    (1)它必须是一致的
 *    (2)它应将不同的输入映射到不同的数字
 *    (3)总是将同样的输入映射到相同的索引
 *    (4)将不同的输入映射到不同的索引
 *    (5)数知道数组有多大,只返回有效的索引
 *  5.2 冲突(Hash碰撞)
 *   (1)给两个键分配的位置相同。如果两个键映射到了同一个位置,就在这个位置存储一个链表
 *   (2)要避免冲突,需要有较低的填装因子和良好的散列函数
 *  5.3 性能
 *   (1)在平均情况下,散列表执行各种操作的时间都为O(1)
 *   5.3.1 填充因子
 *    (1)填装因子度量的是散列表中有多少位置是空的
 *    (2)一个不错的经验规则是:一旦填装因子大于0.7,就调整散列表的长度
* <第6章> 广度优先搜索 </第6章>
 *  6.1 图
 *   (1)图由节点和边组成
 *   (2)用于模拟不同的东西是如何相连的
 *  6.2 广度优先搜索
 *   (1)广度优先搜索是一种用于图的查找算法
 *   6.2.1 查找最短路径
 *    (1)从节点A出发,有前往节点B的路径吗?
 *    (2)从节点A出发,前往节点B的哪条路径最短?
 *   6.2.2 队列
 *    (1)队列是一种先进先出(First In First Out,FIFO)的数据结构
 *    (2)栈是一种后进先出(Last In First Out,LIFO)的数据结构
 *  6.3 实现图
 *   (1)有向图(directed graph),其中的关系是单向的
 *   (2)无向图(undirected graph)没有箭头,直接相连的节点互为邻居
 *   (3)散列表
 *   (4)树是一种特殊的图,其中没有往后指的边
 *   (5)如果任务A依赖于任务B,在列表中任务A就必须在任务B后面。这被称为拓扑排序,使用它可根据图创建一个有序列表
 *  6.4 实现算法 示例:{@link BreadthFirst}
 *  6.5 运行时间
 *   (1)O(V+E),V是顶点(vertices)数,E为边数
 *  6.6 小结
 *   (1)广度优先搜索指出是否有从A到B的路径
 *   (2)如果有,广度优先搜索将找出最短路径
 *   (3)面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题
 *   (4)有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱
 *   (5)无向图中的边不带箭头,其中的关系是双向的,例如,ross - rachel表示“ross与rachel约会,而rachel也与ross约会”
 *   (6)队列是先进先出(FIFO)的,栈是后进先出(LIFO)的
 *   (7)你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必须是队列
 *   (8)对于检查过的人,务必不要再去检查,否则可能导致无限循环

/**
 * 广度优先算法
 */
public class BreadthFirst {
    // 用来表示图的数据结构
    private static final Map<String, String[]> graphMap = new HashMap<>();
    // 搜索队列
    private static final Queue<String> searchQueue = new LinkedBlockingQueue<>();
    // 用于记录被搜索过的人
    private static final List<String> searched = new ArrayList<>();

    /**
     * 查询传入的人名是否满足条件
     *
     * @param name
     * @return
     */
    private static boolean search(String name) {
        searchQueue.clear();
        searched.clear();

        // 获取一度关系
        String[] firstNames = graphMap.get(name);
        // 入队
        Collections.addAll(searchQueue, firstNames);

        // 只要队列还有元素就继续搜索
        while (searchQueue.size() > 0) {
            // 出队
            String person = searchQueue.poll();
            // 如果没有被搜索过
            if (!searched.contains(person)) {
                // 如果满足条件
                if (isSeller(person)) {
                    System.out.println(person + " is a mango seller!");
                    return false;
                } else {
                    // 获取二度或多度关系
                    String[] deepNames = graphMap.get(person);
                    if (deepNames != null) {
                        // 入队
                        Collections.addAll(searchQueue, deepNames);
                        searched.add(person);
                    }
                }
            }
        }

        return true;
    }

    private static boolean isSeller(String person) {
        return person.contains("x");
    }

    public static void main(String[] args) {
        graphMap.put("a", new String[]{"b", "c", "d"});
        graphMap.put("b", new String[]{"b1", "b2"});
        graphMap.put("c", new String[]{"c1", "c2"});
        graphMap.put("d", new String[]{"x"});
        graphMap.put("c1", new String[]{"x"});

        if (search("a")) {
            System.out.println("no mango seller!");
        }
        if (search("b")) {
            System.out.println("no mango seller!");
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值