BFS (Level Order Traversal)

本文详细介绍了广度优先搜索算法的基本原理、特性、应用以及算法描述,包括如何通过队列实现广度优先搜索,以及在图论中的应用如寻找连接元件、最短路径、测试二分图等。并通过实例展示了广度优先搜索在节点遍历和有权最短路径计算中的应用。

广度优先搜索算法(Breadth-First-Search),又译作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索的实现一般采用open-closed表。

特性

 

空间复杂度

因为所有节点都必须被储存,因此BFS的空间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。注:另一种说法称BFS的空间复杂度为 O(BM),其中 B 是最大分支系数,而 M 是树的最长路径长度。由于对空间的大量需求,因此BFS并不适合解非常大的问题。

时间复杂度

最差情形下,BFS必须寻找所有到可能节点的所有路径,因此其时间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。

最佳解

若所有边的长度相等,广度优先搜索算法是最佳解——亦即它找到的第一个解,距离根节点的边数目一定最少;但对一般的图来说,BFS并不一定回传最佳解。这是因为当图形为加权图(亦即各边长度不同)时,BFS仍然回传从根节点开始,经过边数目最少的解;而这个解距离根节点的距离不一定最短。这个问题可以使用考虑各边权值,BFS的改良算法成本一致搜寻法en:uniform-cost search)来解决。然而,若非加权图形,则所有边的长度相等,BFS就能找到最近的最佳解。

广度优先搜索算法的应用

 

广度优先搜索算法能用来解决图论中的许多问题,例如:

  • 寻找图中所有连接元件(Connected Component)。一个连接元件是图中的最大相连子图。 
  • 寻找连接元件中的所有节点。 
  • 寻找非加权图中任两点的最短路径。 
  • 测试一图是否为二分图。 
  • (Reverse) Cuthill–McKee算法

 

寻找连接元件

由起点开始,执行广度优先搜索算法后所经过的所有节点,即为包含起点的一个连接元件。

广度优先搜索,即BFS(Breadth First Search),是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的邻近节点加入搜索队列,循环搜索过程直到队列为空。

        算法描述如下:

        (1)将起始节点放入队列尾部

         (2)While(队列不为空)

取得删除队列首节点Node

                          处理该节点Node

                          把Node的未处理相邻节点加入队列尾部

         使用该算法注意的问题:

        (1)使用该算法关键的数据结构为:队列,队列保证了广度渡优先,并且每个节点都被处理到

         (2)新加入的节点一般要是未处理过的,所以某些情况下最初要对所有节点进行标记

         (3)广度优先在实际使用时,很对情况已超出图论的范围,将新节点加入队列的条件不再局限于

相邻节点这个概念。例如,使用广度优先的网络爬虫在抓取网页时,会把一个链接指向的网页中的所有

URL加入队列供后续处理。

         典型实例:

        1.图的遍历(VC6.0/VS2005)

////////////////////////////////// 
//广度优先之节点遍历 
//1-----5----------9 
//|        |              | 
//|        |              |   
//2-----4----6-----8 
//|               |         | 
//|             |         | 
//3----------7-----10 
// 1 2 3 4 5 6 7 8 
//1 0 1 0 0 1 0 0 0 
//2 1 0 1 1 0 0 0 0 
//3 0 1 0 0 0 0 1 0 
//4 0 1 0 0 1 1 0 0 
//5 1 0 0 1 0 0 0 0 
//6 0 0 0 1 0 0 1 1 
//7 0 0 1 0 0 1 0 0 
//8 0 0 0 0 0 1 0 0

#include 
#include 
using namespace std;

//节点数 
#define M 10

//图的矩阵表示 
int matrix[M][M] = 
{ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 
0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 
1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 
0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 
0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 
0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 
0, 0, 0, 0, 0, 0, 1, 1, 0, 0

}; 
//访问标记,初始化为0, 
int visited[M + 1];

//graph traverse 
void GT_BFS() 

visited[1] = 1; 
queue q; 
q.push(1); 
while(!q.empty()) 

   int top = q.front(); 
   cout << top<<" ";//输出 
   q.pop(); 
   int i ; 
   for(i = 1; i <= M; ++i) 
   { 
    if(visited[i] == 0 && matrix[top - 1][i - 1 ] == 1) 
    { 
     visited[i] = 1; 
     q.push(i); 
    } 
   } 

}

int main() 

GT_BFS();//输出结果为1 2 5 3 4 9 7 6 8 10 
system("pause"); 
return 0; 
}

      2.有权最短路径,Dijkstra

/////////////////////////////////////////// 
//广度优先搜索之有权最短路径,Dijkstra算法 
// 1---(1)-->5 
// |     | 
//(2)      (12) 
// |        | 
// 2--(13)---4---(2)--6--(2)--8 
// |                  | 
//(4)               (5) 
// |                 | 
// 3----(1)----------7 
// 1 2 3 4 5 6 7 8 
//1 0 2 0 0 1 0 0 0 
//2 2 0 4 7 0 0 0 0 
//3 0 4 0 0 0 0 1 0 
//4 0 7 0 0 12 2 0 0 
//5 1 0 0 12 0 0 0 0 
//6 0 0 0 2 0 0 5 2 
//7 0 0 1 0 0 5 0 0 
//8 0 0 0 0 0 2 0 0

#include 
#include 
using namespace std;

//节点数 
#define M 8

//图的矩阵表示 
int matrix[M][M] = 
{ 0, 2, 0, 0, 1, 0, 0, 0, 
2, 0, 4, 13, 0, 0, 0, 0, 
0, 4, 0, 0, 0, 0, 1, 0, 
0, 13, 0, 0, 12, 2, 0, 0, 
1, 0, 0, 12, 0, 0, 0, 0, 
0, 0, 0, 2, 0, 0, 5, 2, 
0, 0, 1, 0, 0, 5, 0, 0, 
0, 0, 0, 0, 0, 2, 0, 0

};

//保存每个节点的最短路径,初始化为0xFFFF 
int dist[M + 1] ={0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}; 
//calculate the distance 
void Dijkstra_BFS(int startNodeNum) 

dist[startNodeNum] = 0; 
queue q; 
q.push(startNodeNum); 
while(!q.empty()) 

   int top = q.front(); 
   q.pop(); 
   cout<   int i ; 
   for(i = 1; i <= M; ++i) 
   { 
    if(matrix[top - 1][i - 1 ] != 0 && (dist[top] + matrix[top - 1][i -1]) < dist[i] ) 
    { 
     dist[i] = dist[top] + matrix[top - 1][i -1]; 
     q.push(i); 
    } 
   } 


void PrintDist() 
{

for(int i = 1; i <= M; ++i) 
   cout<}

int main() 

Dijkstra_BFS(1); 
PrintDist(); 
system("pause"); 
return 0; 
}

<think>我们正在讨论二叉树的相关知识点。用户之前已经询问了二叉树的核心概念和专业名词,现在用户提出了几个具体问题: 1. 满二叉树和完全二叉树的区别 2. BFS path的含义 3. Pre-order traversal和In-order traversal的定义 根据用户提供的引用,我们可以参考以下信息: 引用[1]提到了二叉树的遍历方式,包括前序、中序、后序和层序。 引用[2]进一步解释了前序遍历、中序遍历和后序遍历,以及广度优先搜索(BFS)。 引用[3]和[4]则提供了层序遍历的代码示例。 因此,我们将针对这三个问题逐一解答。 1. 满二叉树(Full Binary Tree)和完全二叉树(Complete Binary Tree)的区别: - 满二叉树:每个结点都有0个或2个子结点,也就是说,除了叶子结点外,每个结点都有两个子结点。而且,所有叶子结点都在同一层上。满二叉树的层数$h$与结点总数$n$的关系为:$n = 2^h - 1$。 - 完全二叉树:除了最后一层外,其他层的结点数都达到最大值,并且最后一层的结点都连续集中在最左边。也就是说,完全二叉树是满二叉树在最后一层从右向左连续缺失若干个结点而形成的。完全二叉树常用于数组存储(堆结构)。 2. BFS path的含义: - BFS(Breadth-First Search,广度优先搜索)是一种按层次遍历树的方法,从根结点开始,一层一层地向下遍历。在二叉树中,BFS通常指层序遍历(Level Order Traversal)。 - BFS path通常指的是从根结点到目标结点所经过的结点序列,且这个序列是按照BFS遍历的顺序得到的。但更常见的,BFS用于寻找最短路径(在树中,根到叶子的最短路径就是层数最小的路径)。例如,在无权图中,BFS可以找到两点之间的最短路径,而在二叉树中,BFS遍历的路径就是按层展开的结点序列。 3. Pre-order traversal(前序遍历)和In-order traversal(中序遍历)的定义: - 前序遍历(Pre-order traversal):按照“根结点-左子树-右子树”的顺序遍历二叉树。即先访问根结点,然后递归地前序遍历左子树,最后递归地前序遍历右子树[^1][^2]。 - 中序遍历(In-order traversal):按照“左子树-根结点-右子树”的顺序遍历二叉树。即先递归地中序遍历左子树,然后访问根结点,最后递归地中序遍历右子树[^1][^2]。 另外,我们可以通过一个例子来展示这两种遍历方式: 1 / \ 2 3 / \ 4 5 前序遍历:1 -> 2 -> 4 -> 5 -> 3 中序遍历:4 -> 2 -> 5 -> 1 -> 3 根据用户要求,我们将在回答中使用数学公式的LaTeX格式,并生成相关问题。 注意:用户提供的引用中并没有直接定义“BFS path”,所以我们根据图论中的常规用法进行解释。在树中,BFS遍历得到的路径序列实际上是按层访问的序列,而最短路径指的是层数最少的路径(因为树是无环的,所以从根到任意结点的路径是唯一的,但BFS可以保证我们按层数递增的顺序访问结点,因此最先访问到目标结点的路径就是最短路径)。 最后,按照要求生成相关问题。 </think>### 二叉树核心概念解析 #### 一、满二叉树 vs 完全二叉树 | **特性** | 满二叉树 (Full Binary Tree) | 完全二叉树 (Complete Binary Tree) | |----------------|------------------------------------------|-------------------------------------------| | **定义** | 所有非叶子结点都有两个子结点 | 除最后一层外完全填充,最后一层左对齐填充[^1] | | **数学关系** | 高度$h$的树共有$2^h - 1$个结点 | 高度$h$的树结点数$n$满足:$2^{h-1} \leq n < 2^h$ | | **结构示例** | ``` 1 → 所有非叶结点都有2个子结点 / \ 2 3 / \ / \ 4 5 6 7``` | ``` 1 → 最后一层左对齐 / \ 2 3 / \ / 4 5 6``` | | **应用场景** | 理论模型 | 堆结构实现、内存管理 | #### 二、BFS Path(广度优先路径) 1. **定义**: 在广度优先遍历(Breadth-First Search)中形成的路径,按层级顺序访问结点[^2][^3] 2. **核心特性**: - 访问顺序:从根节点开始,逐层从左到右访问 - 路径长度:记录从根节点到目标结点的边数(即深度) - 数学表示:树的高度$h$时,第$k$层最多有$2^k$个结点 3. **算法实现**(队列结构): ```python def bfs(root): queue = collections.deque([root]) while queue: node = queue.popleft() process(node) # 处理当前结点 if node.left: queue.append(node.left) # 左子结点入队 if node.right: queue.append(node.right) # 右子结点入队 ``` 4. **应用场景**: - 最短路径搜索(树中任意两节点间唯一路径)[^4] - 层次遍历(如LeetCode 102题) - 二叉树序列化 #### 三、遍历方式对比 | **遍历方式** | 访问顺序 | 伪代码 | 应用场景 | |-------------|----------------------|-------------------------------|--------------------------| | **前序遍历**<br>(Pre-order) | 根结点 → 左子树 → 右子树 | ```visit(root)```<br>```preorder(root.left)```<br>```preorder(root.right)``` | 复制树结构<br>前缀表达式生成 | | **中序遍历**<br>(In-order) | 左子树 → 根结点 → 右子树 | ```inorder(root.left)```<br>```visit(root)```<br>```inorder(root.right)``` | 二叉搜索树排序输出<br>表达式解析 | **遍历示例**(同一棵树): ``` A / \ B C / \ D E ``` - **前序遍历**:A → B → D → E → C (根结点优先) - **中序遍历**:D → B → E → A → C (根结点在中间) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值