搜索总结)(深搜和广搜)

一.个人理解


(以下只是个人理解,觉的有问题就忽略他)搜索本质就是对图的遍历,也就是考虑全部的情况后找出需要的结果。这和动态规划思想基本一样,不一样的在于优化的方向不同。搜索优化在于剪枝,也就是把不需要的情况减去从而优化(还有对结果预测如A*算法,现在还不大会以后会了在总结吧)。而动态规划则是利用空间记录重复过程的值,从而减少重复遍历而达到优化(有点像递推,从小往大推,保存小的推大时候不用再求小的)。所以动态规划本质也就是优雅的暴力(以空间换时间)。(暴力出奇迹0.0)

二. 基础知识


一.遍历

首先搜索虽然是对图的搜索,但是大部分图节点都是只遍历一次,这样的话图遍历也就可以看做树遍历。而树的遍历分层次遍历,先序遍历,中序遍历,后序遍历4种。而层次遍历一般借助队列完成。先中后则借助递归完成(输出节点顺序不同,遍历过程一样)。这也就是广度优先搜索和深度优先搜索了。

二.图的存储

图的存储分有两种:基于二维数组邻接矩阵和链表邻接表。在c++ STL提供头插法的邻接表vector,而值得一提是自己身模拟尾插邻接表的效率会大于STL提供的vector。不理解的看下图:(有几张自己画丑了点将就看吧)
邻接矩阵:这里写图片描述这里写图片描述

头插法邻接表:这里写图片描述这里写图片描述

尾插法邻接表:这里写图片描述这里写图片描述

三.广度优先搜索


广度优先搜索的搜索顺序就是每个父亲节点的子节点遍历完才遍历新的节点。以上图为例,起点为v0,那么他的遍历顺序就是:v0->v1->v3->v2->v4;先遍历v0子节点v1,v3。遍历完后遍历v1的子节点v2,v4.然后发现全部节点遍历完了(如果遍历v0子节点时先遍历v3那么v0结束后先遍历v3的子节点。这和存储的结构顺序有关)。
对于算法的实现,不难看出哪个节点先出现先遍历哪个节点,能实现先进先出的结构当然是队列了。所以广度优先借用队列实现。STL提供queue(队列),当然你也可以直接模拟。
代码:

void BFS(Graph G){   ///G图,G.num节点数
    for (int v=0;v<G.num;v++) ///先将其所有顶点都设为未访问状态
        visited[v]=false;
    queue<int> Q;
    for(int v=0;v<G.num;v++) {
        if(visited[v]==false){  ///若该点没有访问
            Q.push(v);    ///将其加入到队列中
            visited[v]=true;
            while (!Q.empty()){  ///只要队列不空,遍历就没有结束
                int t =Q.front();  ///取出对头元素
                Q.pop(); 
                printf(" %d ",t+1);  ///打印节点
                for(int j=0;j<G.num;j++) ///将其未访问过的邻接点加进入队列
                    if(G.arcs[t][j]==1&&visited[j]== false) {
                        Q.push(j);
                        visited[j]=true; ///在这里要设置true为了防止重复加入!
                    }///if
            }//while
        }///if 
    }///for
}///BFS

四.深度优先搜索


深度优先搜索的搜索顺序就是每次选父节点中的一个子节点进行搜索不断下移,直到子树为空后回溯。以上图为例,起点为v0,那么他的遍历顺序就是:v0->v1->v2->v3->v4;先遍历v0子节点v1。然后遍历v1的子节点v2.接着遍历v2子节点v3,发现v3子节点都遍历过了(也就相当子节点为空)所以返回v2节点,再遍历v2子节点v4。最后一层层返回(节点都遍历了)。(有灭九族的味道,从爷爷开始杀,杀了大伯,杀大伯儿子,杀完大伯杀二伯一家,最后一个不留)。
其思想就是递归,递归至最深层,开始一层返回。而递归控制好三点就基本没问题:1.递归出口,也就是结束条件。2.递归的条件,类似递推公式找到共通部分。3.传的参数,递归不断进行参数在不断改变。
代码:

void DFS(Graph G,int v)
{
    visited[v]= true; ///从V开始访问,flag它
    printf("%d",v);    ///打印出节点。
    for(int j=0;j<G.num;j++) 
        if(G.arcs[v][j]==1&&visited[j]== false) ///这里可以获得V未访问过的邻接点
            DFS(G,j); ///递归调用,如果所有节点都被访问过,就回溯,而不再调用这里的DFS
}
for (int v = 0; v < G.num; v++)
      visited[v] = false; ///刚开始都没有被访问过
 for (int v = 0; v < G.num; ++v)
      if (visited[v] == false) ///从没有访问过的第一个元素来遍历图
          DFS(G, v);
<think>好的,我现在要解决用户关于深度优先搜索(DFS)广度优先搜索(BFS)时间复杂度的问题。首先,我需要回忆这两种算法的基本概念应用场景,然后分析它们的时间复杂度。 用户可能已经知道DFSBFS是图遍历的两种基本方法,但想更入理解它们的时间复杂度差异。我需要明确时间复杂度的计算方式,以及在不同情况下两者的表现。 首先,考虑DFS的时间复杂度。DFS通常使用栈或递归实现,访问节点时会尽可能地探索分支。时间复杂度主要取决于访问每个节点边的次数。假设图有V个顶点E条边,那么时间复杂度通常是O(V + E),因为每个节点边都会被访问一次。但如果是邻接矩阵,可能需要O(V²),因为检查每个节点的邻居需要遍历整个行。 接下来是BFS,它使用队列实现,按层次遍历节点。同样,时间复杂度通常也是O(V + E),因为在最坏情况下需要访问所有节点边。邻接矩阵的情况DFS类似,会是O(V²)。需要比较两者的异同,尤其是在不同数据结构下的表现。 然后要思考用户可能的疑问,比如为什么两者的时间复杂度相同,但实际应用中可能有不同的性能。需要解释虽然大O表示法相同,但常数因子或访问顺序可能影响实际运行时间,比如BFS在找到最短路径时更快,而DFS可能更节省内存。 还需要考虑特殊情况,比如当图是树结构时,边的数量E大约是V-1,所以时间复杂度可以简化为O(V)。或者当使用不同的数据结构(如邻接表或邻接矩阵)时的影响。 另外,用户可能想知道空间复杂度的区别。虽然问题主要是时间,但简要提及空间有助于全面回答。DFS的空间复杂度在最坏情况下是O(V)(比如线性链结构),而BFS也是O(V)(当需要存储所有节点在队列中)。 最后,要确保回答结构清晰,分点说明DFSBFS的时间复杂度,并解释它们的异同,可能的应用场景对选择的影响。需要避免过于技术化的术语,保持易懂,同时准确传达关键点。</think>深度优先搜索(DFS)与广度优先搜索(BFS)的时间复杂度分析如下: --- ### **时间复杂度共性** 对**图或树**的遍历,两者的**最坏情况时间复杂度均为**: $$ O(V + E) $$ - **$V$**:顶点数量(节点总数) - **$E$**:边数量(连接关系总数) --- ### **差异对比** | 特性 | DFS(深度优先搜索) | BFS(广度优先搜索) | |--------------------|--------------------------------|--------------------------------| | **访问顺序** | 纵向入(先访问最节点) | 横向扩展(逐层遍历) | | **空间复杂度** | $O(h)$($h$为树的最大度) | $O(w)$($w$为树的最大宽度) | | **数据结构** | 栈或递归调用栈 | 队列 | | **适用场景** | 拓扑排序、路径存在性检测 | 最短路径(无权图)、层级分析 | --- ### **详细说明** 1. **DFS时间复杂度推导**: - 每个节点被访问一次($O(V)$) - 每条边被遍历两次(无向图)或一次(有向图)($O(E)$) - 总时间复杂度为 $O(V + E)$ 2. **BFS时间复杂度推导**: - 每个节点入队出队各一次($O(V)$) - 每条边被检查一次($O(E)$) - 总时间复杂度同样为 $O(V + E)$ --- ### **特殊情形对比** - **邻接矩阵存储的图**: - 时间复杂度退化为 $O(V^2)$(需遍历所有顶点检查邻接关系) - **完全二叉树**: - 时间复杂度均为 $O(V)$($E = V-1$) --- ### **关键结论** - **时间复杂度等价性**:二者在遍历所有节点边时的渐进时间复杂度相同 - **实际性能差异**: - BFS适合**最短路径搜索**(首次访问即最短层数) - DFS适合**路径存在性验证**或**回溯类问题** - **空间差异更显著**:DFS空间复杂度由递归度决定,BFS由队列宽度决定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值