1. 概述

搜索是计算机科学中的一个基础问题,因此也衍生出大量用于寻找最优解的算法。爬山算法(Hill Climbing)最佳优先搜索(Best First Search, BeFS) 是两种常见的搜索算法。尽管它们在某些方面相似,但也有明显差异。

本文将分别介绍 Hill Climbing 和 BeFS 的基本原理,并从多个维度进行对比分析,帮助你根据实际场景选择合适的算法。

2. 爬山搜索(Hill Climbing)

爬山算法是一种简单的启发式搜索算法。其核心思想是:从一个随机初始状态出发,不断查看其邻近状态,若发现更优状态则移动过去,直到无法找到更优状态为止。

✅ 优点:

  • 简单直观
  • 内存消耗低

❌ 缺点:

  • 容易陷入局部最优(local optima)
  • 遇到平台(plateau)或山脊(ridge)时表现不佳

举个例子,爬山算法就像你在雾中爬山,只能看到脚下的路,每次只向上走一步,但可能只爬到了一个小山头就停下了。

以下是其伪代码实现:

algorithm HillClimbing(ss, f):
    // INPUT
    //    ss = 一个任意的搜索空间
    //    f = 评估函数,值越大表示状态越优
    // OUTPUT
    //    s = 一个局部最优状态

    s <- 从 ss 中随机选取一个状态

    while true:
        N <- s 的所有邻接状态

        if N 为空:
            return s

        for 每个 n in N:
            if f(n) >= f(s):
                s <- n

    return s

3. 最佳优先搜索(Best First Search)

最佳优先搜索(BeFS)是一类启发式搜索算法的统称,A*B* 等算法都属于这一类。它结合了广度优先搜索(BFS)和深度优先搜索(DFS)的优点,通过启发式函数评估节点的优先级,优先扩展最有希望到达目标的节点。

BeFS 通常维护两个列表:

  • openList:待扩展的节点集合
  • closedList:已扩展过的节点集合

每次从 openList 中选择启发值最小的节点进行扩展,直到找到目标节点为止。

以下是 BeFS 的伪代码:

algorithm BestFirstSearch(G, s, g):
    // INPUT
    //    G = 图结构
    //    s = 起始节点
    //    g = 目标节点
    // OUTPUT
    //    返回从 s 到 g 的最优路径

    openList <- { s }
    closedList <- 空列表
    path <- 空列表

    while openList 不为空:
        b <- openList 中启发函数值最小的节点

        openList.remove(b)
        closedList.add(b)

        if b == g:
            path.add(b)
            return path

        N <- b 的所有邻居节点

        for n in N:
            if n 未在 closedList 或 openList 中:
                openList.add(n)
            else if n 在 openList 中:
                if 当前路径代价 <= 旧路径代价:
                    替换父节点
            else if n 不在 closedList 中:
                openList.add(n)

    return path

4. 爬山算法 vs 最佳优先搜索对比

维度 爬山算法 最佳优先搜索
✅ 优点 内存占用低,实现简单 可从多个候选中选择最优路径
❌ 缺点 易陷入局部最优、平台、山脊 内存开销大,可能陷入循环
启发式 仅比较当前与邻接节点 使用全局启发函数排序候选节点
搜索策略 局部贪心 全局贪心
内存使用 极低(仅保存当前状态) 较高(需保存 openList 和 closedList)
适用场景 快速近似解,对精度要求不高 需要较优路径,如路径规划、图搜索

4.1 局部最优问题

  • 爬山算法容易陷入局部最优,解决办法之一是多次运行算法,每次从不同起点开始(类似多起点爬山)。
  • Best First Search 可能陷入循环,比如访问一个节点后又回到父节点。可通过优化启发函数或加入循环检测机制避免。

4.2 平台与山脊问题

  • 平台(plateau):周围节点与当前节点评估值相同,算法无法判断下一步方向。
  • 山脊(ridge):梯度变化方向受限,只能通过“之”字形路径前进,效率低下。

4.3 内存消耗对比

  • 爬山算法只需保存当前状态和目标状态,内存极低。
  • Best First Search 需要维护两个列表(openList 和 closedList),内存消耗较高。

4.4 搜索策略对比

  • 爬山算法一旦找到比当前更优的邻接节点就立即移动。
  • Best First Search会评估所有邻接节点,并通过启发函数选出最优节点进行扩展。

5. 总结

特性 爬山算法 最佳优先搜索
是否全局最优 ❌(可能陷入局部最优) ✅(取决于启发函数)
内存占用 ✅ 极低 ❌ 较高
实现复杂度 ✅ 简单 ❌ 稍复杂
是否适合复杂搜索空间 ❌(易陷入平台或山脊) ✅(启发式排序更灵活)

✅ 建议使用场景

  • 爬山算法适用于对速度要求高、内存有限、且可接受局部最优解的场景,如快速优化问题。
  • Best First Search 更适合需要在复杂图结构中找到较优路径的问题,比如路径规划、游戏 AI 等。

⚠️ 踩坑提醒

  • 使用 Hill Climbing 时,记得多试几个起点,避免陷入局部最优。
  • 使用 BeFS 时,务必选择一个合适的启发函数(如 A* 的 h(n)),否则效率可能大打折扣。
  • 如果搜索空间存在循环路径,记得加入循环检测机制。

如你所见,两种算法各有优劣,关键在于根据具体问题选择合适的方法。希望这篇文章能帮你更清晰地理解它们的差异,并在实际项目中做出明智选择。


原始标题:Hill Climbing Search vs. Best First Search