算法-无向图(深度优先搜索和广度优先搜索)

图中最常用到的两种搜索深度优先搜索和广度优先搜索,深度优先搜索是一种在开发爬虫早期使用较多的方法它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链接的Html文件) ,广度搜索属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

深度优先搜索

图中我们经常会遇到一个问题就是图的连通性,比如说从一个顶点到另外一个顶点,判断顶点和其他顶点之间的连通性,以下图为例:

搜索API定义:

@interface DepthFirstSearch : NSObject
//记录顶点是否被标记
@property  (strong,nonatomic)  NSMutableArray  *marked;

@property (assign,nonatomic)  NSInteger count;
//找到与七点vertex所有连通的节点
-(instancetype)initWithGraphAndVertex:(Graph *)graph  vertex:(NSInteger)vertex;

-(void)depthSearch:(Graph *)graph  vertex:(NSInteger)vertex;

//节点是否被标记
-(Boolean)isMarked:(NSInteger)vertex;

@end

实现:

@implementation DepthFirstSearch

#pragma mark  getter and setter
-(NSMutableArray *)marked{
    if (!_marked) {
        _marked=[[NSMutableArray alloc]initWithCapacity:1];
    }
    return _marked;
}

-(instancetype)initWithGraphAndVertex:(Graph *)graph vertex:(NSInteger)vertex{
    self=[super init];
    if (self) {
        for (NSInteger i=0; i<graph.vertexs;i++) {
            [self.marked addObject:[NSNull null]];
        }
        [self depthSearch:graph vertex:vertex];
    }
    return self;
}
//http://www.cnblogs.com/xiaofeixiang/
-(void)depthSearch:(Graph *)graph vertex:(NSInteger)vertex{
    self.marked[vertex]=[NSNumber numberWithBool:true];
    self.count++;
    for (NSInteger i=0; i<[graph.adjDataSource[vertex] count]; i++) {
        NSInteger temp=[[graph.adjDataSource[vertex] objectAtIndex:i] integerValue];
        if (![self isMarked:temp]) {
            [self depthSearch:graph vertex:temp];
        }
    }
}

-(Boolean)isMarked:(NSInteger)vertex{
    return self.marked[vertex]==[NSNull null]?false:[self.marked[vertex] boolValue];
}

@end

代码测试:

        Graph  *graph=[[Graph alloc]initWithVertex:6];
        [graph addEdges:0 endVertex:5];
        [graph addEdges:2 endVertex:4];
        [graph addEdges:2 endVertex:3];
        [graph addEdges:1 endVertex:2];
        [graph addEdges:0 endVertex:1];
        [graph addEdges:3 endVertex:4];
        [graph addEdges:5 endVertex:3];
        [graph addEdges:0 endVertex:2];
        DepthFirstSearch  *search=[[DepthFirstSearch alloc]initWithGraphAndVertex:graph vertex:0];
        for (NSInteger i=0; i<graph.vertexs; i++) {
            NSLog(@"节点%ld--值为:%@",i,search.marked[i]);
        }
        NSLog(@"技术交流群:%@",@"228407086");
        NSLog(@"原文地址:http://www.cnblogs.com/xiaofeixiang");

测试效果:

1表示连通,节点0和其他节点直接都可以直接连通,我们通过递归的方式成功的判断亮点之间的连通性,顶点直接的连通性是通过边链接的,深度搜索将在此方法上改动然后给出单点之间的路径,注意是路径不是最短路径,我们会发现代码变动很小。

//深度优先
@interface DepthFirstPath : NSObject

//记录顶点是否被标记
@property  (strong,nonatomic)  NSMutableArray  *marked;
//起点
@property (assign,nonatomic)  NSInteger  beginVertex;
//从起点到一个顶点的已知路径上的最后一个顶点
@property  (strong,nonatomic)  NSMutableArray *edgeTo;

@property (assign,nonatomic)  NSInteger count;
//找到与七点vertex所有连通的节点
-(instancetype)initWithGraphAndVertex:(Graph *)graph  vertex:(NSInteger)vertex;

-(void)depthSearch:(Graph *)graph  vertex:(NSInteger)vertex;

-(NSMutableArray *)pathTo:(NSInteger)vertex;

//节点是否被标记
-(Boolean)hasPathTo:(NSInteger)vertex;

@end

实现代码:

@implementation DepthFirstPath

#pragma mark  getter and setter
-(NSMutableArray *)marked{
    if (!_marked) {
        _marked=[[NSMutableArray alloc]initWithCapacity:1];
    }
    return _marked;
}

-(NSMutableArray *)edgeTo{
    if (!_edgeTo) {
        _edgeTo=[[NSMutableArray alloc]initWithCapacity:1];
    }
    return _edgeTo;
}

-(instancetype)initWithGraphAndVertex:(Graph *)graph vertex:(NSInteger)vertex{
    self=[super init];
    if (self) {
        for (NSInteger i=0; i<graph.vertexs;i++) {
            [self.marked addObject:[NSNull null]];
            [self.edgeTo addObject:[NSNull null]];
        }
        self.beginVertex=vertex;
        [self depthSearch:graph vertex:vertex];
    }
    return self;
}
//http://www.cnblogs.com/xiaofeixiang
-(void)depthSearch:(Graph *)graph vertex:(NSInteger)vertex{
    self.marked[vertex]=[NSNumber numberWithBool:true];
    self.count++;
    for (NSInteger i=0; i<[graph.adjDataSource[vertex] count]; i++) {
        NSInteger temp=[[graph.adjDataSource[vertex] objectAtIndex:i] integerValue];
        if (![self hasPathTo:temp]) {
            self.edgeTo[temp]=[NSNumber numberWithInteger:vertex];
            [self depthSearch:graph vertex:temp];
        }
    }
}

-(Boolean)hasPathTo:(NSInteger)vertex{
    return self.marked[vertex]==[NSNull null]?false:[self.marked[vertex] boolValue];
}

-(NSMutableArray *)pathTo:(NSInteger)vertex{
    if (![self hasPathTo:vertex]) {
        return NULL;
    }
    NSMutableArray  *path=[[NSMutableArray alloc]initWithCapacity:1];
    for (NSInteger i=vertex; i!=self.beginVertex; i=[self.edgeTo[i] integerValue]) {
        [path insertObject:[NSNumber numberWithInteger:i] atIndex:0];
    }
    [path insertObject:[NSNumber numberWithInteger:self.beginVertex] atIndex:0];
    return path;
}

@end

代码中我们多了一个edgeTo数组记录当前索引顶点的最后一个顶点,当edgeTo[1]=2表示顶点1和顶点2之间是直接相连,最后输出路径的时候利用栈的特性,先进后出,输出正确路径,测试代码如下:

        NSInteger  beginVertex=0;
        DepthFirstPath *path=[[DepthFirstPath alloc]initWithGraphAndVertex:graph vertex:beginVertex];
        for (NSInteger i=0; i<[path.edgeTo count]; i++) {
            NSLog(@"节点%ld--值为:%@",i,path.edgeTo[i]);
        }
        for (NSInteger i=0; i<graph.vertexs;i++) {
            NSMutableArray *data=[path pathTo:i];
             NSLog(@"%ld到%ld路径为:%@",beginVertex,i,[data componentsJoinedByString:@"--"]);
        }
        NSLog(@"技术交流群:%@",@"228407086");
        NSLog(@"原文地址:http://www.cnblogs.com/xiaofeixiang");

测试效果:

广度优先搜索

如果我们仔细观察会发现一个现象,图片中我们很明显看到顶点0可以直接到5,我们确发现广度搜索的路径给出的是0-2-3-5,如果想要获取最短路径,界限来一起看一下广度优先搜索,代码与上面的代码也是改动了一部分,比较好懂,代码如下:

@interface BreadthFirstPath : NSObject

//记录顶点是否被标记
@property  (strong,nonatomic)  NSMutableArray  *marked;
//起点
@property (assign,nonatomic)  NSInteger  beginVertex;
//从起点到一个顶点的已知路径上的最后一个顶点
@property  (strong,nonatomic)  NSMutableArray *edgeTo;

//找到与七点vertex所有连通的节点
-(instancetype)initWithGraphAndVertex:(Graph *)graph  vertex:(NSInteger)vertex;

-(void)breadthSearch:(Graph *)graph  vertex:(NSInteger)vertex;

-(NSMutableArray *)pathTo:(NSInteger)vertex;

//节点是否被标记
-(Boolean)hasPathTo:(NSInteger)vertex;

@end

实现代码:

@implementation BreadthFirstPath

#pragma mark  getter and setter
-(NSMutableArray *)marked{
    if (!_marked) {
        _marked=[[NSMutableArray alloc]initWithCapacity:1];
    }
    return _marked;
}

-(NSMutableArray *)edgeTo{
    if (!_edgeTo) {
        _edgeTo=[[NSMutableArray alloc]initWithCapacity:1];
    }
    return _edgeTo;
}

-(instancetype)initWithGraphAndVertex:(Graph *)graph vertex:(NSInteger)vertex{
    self=[super init];
    if (self) {
        for (NSInteger i=0; i<graph.vertexs;i++) {
            [self.marked addObject:[NSNull null]];
            [self.edgeTo addObject:[NSNull null]];
        }
        self.beginVertex=vertex;
        [self breadthSearch:graph vertex:vertex];
    }
    return self;
}
//http://www.cnblogs.com/xiaofeixiang
-(void)breadthSearch:(Graph *)graph vertex:(NSInteger)vertex{
    NSMutableArray *queue=[[NSMutableArray alloc]initWithCapacity:1];
    self.marked[vertex]=[NSNumber numberWithBool:true];
    [queue addObject:[NSNumber numberWithInteger:vertex]];

    while ([queue count]>0) {
        NSInteger header=[[queue objectAtIndex:0] integerValue];
        [queue removeObjectAtIndex:0];
        for (NSInteger i=0; i<[graph.adjDataSource[header] count]; i++) {

            NSInteger temp=[[graph.adjDataSource[header] objectAtIndex:i] integerValue];

            if (![self isMarked:temp]) {
                self.marked[temp]=[NSNumber numberWithBool:true];
                self.edgeTo[temp]=[NSNumber numberWithInteger:header];
                [queue addObject:[NSNumber numberWithInteger:temp]];
            }
        }
    }

}

-(Boolean)isMarked:(NSInteger)vertex{
    return self.marked[vertex]==[NSNull null]?false:[self.marked[vertex] boolValue];
}

-(Boolean)hasPathTo:(NSInteger)vertex{
    return self.marked[vertex]==[NSNull null]?false:[self.marked[vertex] boolValue];
}

-(NSMutableArray *)pathTo:(NSInteger)vertex{
    if (![self hasPathTo:vertex]) {
        return NULL;
    }
    NSMutableArray  *path=[[NSMutableArray alloc]initWithCapacity:1];
    for (NSInteger i=vertex; i!=self.beginVertex; i=[self.edgeTo[i] integerValue]) {
        [path insertObject:[NSNumber numberWithInteger:i] atIndex:0];
    }
    [path insertObject:[NSNumber numberWithInteger:self.beginVertex] atIndex:0];
    return path;
}
@end

测试代码:

        NSInteger  beginVertex=0;
        BreadthFirstPath  *breadthPath=[[BreadthFirstPath alloc]initWithGraphAndVertex:graph vertex:beginVertex];

        for (NSInteger i=0; i<[breadthPath.edgeTo count]; i++) {
            NSLog(@"节点%ld--值为:%@",i,breadthPath.edgeTo[i]);
        }
        for (NSInteger i=0; i<graph.vertexs;i++) {
            NSMutableArray *data=[breadthPath pathTo:i];
            NSLog(@"%ld到%ld路径为:%@",beginVertex,i,[data componentsJoinedByString:@"--"]);
        }
        NSLog(@"技术交流群:%@",@"228407086");
        NSLog(@"原文地址:http://www.cnblogs.com/xiaofeixiang");

测试效果:

时间: 2024-10-20 02:06:51

算法-无向图(深度优先搜索和广度优先搜索)的相关文章

十大基础实用算法之深度优先搜索和广度优先搜索

深度优先搜索算法(Depth-First-Search),是搜索算法的一种.它沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点.这一过程一直进行到已发现从源节点可达的所有节点为止.如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止.DFS属于盲目搜索. 深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相

算法_图的深度优先搜索和广度优先搜索

一.图的基本数据结构 图是由一组顶点和一组能够将两个顶点相互连接的边所构成的,一般使用0~V-1这样的数字形式来表示一张含有V个顶点的图.用v-w来指代一张图的边,由于是无向图,因此v-w和w-v是同一种边的两种表示方法.无向图是指边没有方向的图结构在无向图中,边仅仅表示的是两个顶点之间的连接.图的数据结构的可视化如下图所示(其中边上的箭头没有任何意义): 当两个顶点通过一条边相互连接,则称这两个顶点是相邻的.某个顶点的度数即为依附它的边的总数.当两个顶点之间存在一条连接双方的路径的时候,称为这

图算法系列-深度优先搜索与广度优先搜索

2.深度优先搜索 为了访问一个顶点,我们将它标记为已经访问过,然后递归的访问所有与子邻接的并且尚未标记的顶点,这就是深度优先搜索(DFS),DFS常用于解决路径问题. 比如下面的连通图,我们从顶点0开始对图进行探索 下面这个图显示了DFS处理时的递归调用树. DFS可以解决的问题:1)环检测:一个图中有环吗?该图是森林吗?2)简单路径:给定两个顶点,是否存在一条连接他们的路径3)简单连通性:无论何时使用DFS,都可以在线性时间内确定一个图是否连通4)顶点搜索:在给定顶点所在的同一个连通分量中有多

图的遍历之 深度优先搜索和广度优先搜索

本章会先对图的深度优先搜索和广度优先搜索进行介绍,然后再给出C/C++/Java的实现. 目录 1. 深度优先搜索的图文介绍 1.1 深度优先搜索介绍 1.2 深度优先搜索图解 2. 广度优先搜索的图文介绍 2.1 广度优先搜索介绍 2.2 广度优先搜索图解 3. 搜索算法的源码 深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似. 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然

图的深度优先搜索与广度优先搜索

无向图的深度优先搜索与广度优先搜索 #include "stdafx.h" #include<vector> #include<iostream> using namespace std; #define N 9 typedef struct{ int vexnum, arcnum; char vexs[N]; int matirx[N][N]; }graph; graph g; int a[N] = { 0 }; // 初始化图数据 // 0---1---2-

深度优先搜索与广度优先搜索

有两种常用的方法可用来搜索图:即深度优先搜索和广度优先搜索.它们最终都会到达所有连通的顶点.深度优先搜索通过栈来实现,而广度优先搜索通过队列来实现. 深度优先搜索: 为了实现深度优先搜索,首先选择一个起始顶点并需要遵守三个规则:(1) 如果可能,访问一个邻接的未访问顶点,标记它,并把它放入栈中.(2) 当不能执行规则1时,如果栈不空,就从栈中弹出一个顶点.(3) 如果不能执行规则1和规则2,就完成了整个搜索过程. 广度优先搜索:在深度优先搜索中,算法表现得好像要尽快地远离起始点似的.相反,在广度

深度优先搜索和广度优先搜索的深入讨论

一.深度优先搜索和广度优先搜索的深入讨论 (一)深度优先搜索的特点是: (1)从上面几个实例看出,可以用深度优先搜索的方法处理的题目是各种各样的.有的搜索深度是已知和固定的,如例题2-4,2-5,2-6:有的是未知的,如例题2-7.例题2-8:有的搜索深度是有限制的,但达到目标的深度是不定的. 但也看到,无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法(二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求. (2)深

深度优先搜索和广度优先搜索的比较与分(转)

深度优先搜索和广度优先搜索的深入讨论   (一)深度优先搜索的特点是: (1)无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法(二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求. (2)深度优先搜索法有递归以及非递归两种设计方法.一般的,当搜索深度较小.问题递归方式比较明显时,用递归方法设计好,它可以使得程序结构更简捷易懂.当搜索深度较大时,当数据量较大时,由于系统堆栈容量的限制,递归容易产生溢出,用非递归方法设

“生动”讲解——深度优先搜索与广度优先搜索

深度优先搜索(Depth First Search,DFS) 主要思想:不撞南墙不回头 深度优先遍历的主要思想就是:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点:当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问. 沿着某条路径遍历直到末端,然后回溯,再沿着另一条进行同样的遍历,直到所有的顶点都被访问过为止. 图解: 分析: 通过上面的图例可以非常直观的了解深度优先搜索的工作方式.下面来分析一下如何用代码来实现它. 大家都知道,深度