欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-26 11:35:17
...

一.个人理解


(以下只是个人理解,觉的有问题就忽略他)搜索本质就是对图的遍历,也就是考虑全部的情况后找出需要的结果。这和动态规划思想基本一样,不一样的在于优化的方向不同。搜索优化在于剪枝,也就是把不需要的情况减去从而优化(还有对结果预测如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);