• 算法-有向图及可达性


    图是由顶点和边连接而成,如果边是没有方向的是就是之前文章中说的无向图,关于无向图可以参考本人之前的文章,如果边是有方向的,则称之为有向图。从顶点A→B,我们可以理解为A到B可达,有向图和无向图一样通过邻接表保存每一条边,由于边是有方向的,因此在添加边的过程中只需要添加一条边即可。关于可达性一个节点数组的可达性,采用的方法是之前的深度优先搜索一样的代码,通过递归将标记位Bool标记位判断数组中每个顶点的可达性。为了测试,选择下面一张有向图:

    有向图基础

    通过图片我们可以发现图中有13个节点,22条边,顶点0指出的节点有1,5,指入的节点有2,6,我们先实现所有顶点指出的节点,之后可以通过反转判断所有节点的指入节点:

    @interface Digraph : NSObject
    
    //顶点的总数
    @property  (assign,nonatomic) NSInteger  vertexs;
    //边的数总数
    @property (assign,nonatomic) NSInteger  edges;
    //连接点的边
    @property (strong,nonatomic)  NSMutableArray  *adjDataSource;
    
    -(instancetype)initWithVertex:(NSInteger)vertexs;
    //添加一条有向边 startVertex→endVertex
    -(void)addEdges:(NSInteger)startVertex  endVertex:(NSInteger)endVertex;
    
    
    -(Digraph *)reverse;//该图的反向图
    
    @end

    实现代码:

    @implementation Digraph
    
    -(instancetype)initWithVertex:(NSInteger)vertexs{
        self=[super init];
        if (self) {
            self.vertexs=vertexs;
            for (NSInteger i=0; i<vertexs; i++) {
                NSMutableArray  *neighbourVertex=[[NSMutableArray alloc]initWithCapacity:1];
                [self.adjDataSource addObject:neighbourVertex];//创建邻接表,将所有链表初始化为空
            }
        }
        return self;
    }
    //http://www.cnblogs.com/xiaofeixiang
    -(void)addEdges:(NSInteger)startVertex endVertex:(NSInteger)endVertex{
        //将endVertex添加到startVertex的链表中
        [self.adjDataSource[startVertex] insertObject:[NSNumber numberWithInteger:endVertex] atIndex:0];
        self.edges=self.edges+1;
    }
    
    -(Digraph *)reverse{    
        Digraph  *digraph=[[Digraph alloc]initWithVertex:self.vertexs];
        for (NSInteger i=0; i<self.vertexs; i++) {
            NSMutableArray  *tempArr=self.adjDataSource[i];
            for (NSInteger j=0; j<[tempArr count]; j++) {
                [digraph addEdges:[tempArr[j] integerValue] endVertex:i];
            }
        }
        return digraph;
    }
    
    #pragma mark getter and setter
    -(NSMutableArray *)adjDataSource{
        if (!_adjDataSource) {
            _adjDataSource=[[NSMutableArray alloc]initWithCapacity:1];
        }
        return _adjDataSource;
    }
    
    @end
    

    测试代码:

            Digraph  *graph=[[Digraph alloc]initWithVertex:13];
            [graph addEdges:4 endVertex:2];
            [graph addEdges:2 endVertex:3];
            [graph addEdges:3 endVertex:2];
            [graph addEdges:6 endVertex:0];
            [graph addEdges:0 endVertex:1];
            [graph addEdges:2 endVertex:0];
            [graph addEdges:11 endVertex:12];
            [graph addEdges:12 endVertex:9];
            [graph addEdges:9 endVertex:10];
            [graph addEdges:9 endVertex:11];
            [graph addEdges:8 endVertex:9];
            [graph addEdges:10 endVertex:12];
            [graph addEdges:11 endVertex:4];
            [graph addEdges:4 endVertex:3];
            [graph addEdges:3 endVertex:5];
            [graph addEdges:7 endVertex:8];
            [graph addEdges:8 endVertex:7];
            [graph addEdges:5 endVertex:4];
            [graph addEdges:0 endVertex:5];
            [graph addEdges:6 endVertex:4];
            [graph addEdges:6 endVertex:9];
            [graph addEdges:7 endVertex:6];
            for (NSInteger i=0; i<[graph.adjDataSource count]; i++) {
                NSLog(@"节点%ld指出→的节点:%@",i,[graph.adjDataSource[i] componentsJoinedByString:@"--"]);
            }
            NSLog(@"技术交流群:%@",@"228407086");
            NSLog(@"原文地址:http://www.cnblogs.com/xiaofeixiang");
    

    测试效果:

    现在可以判断出顶点的指出节点,实现文件中有一个reverse方法将图反转,求出顶点的转入节点:

            Digraph  *digraph=[graph reverse];
            for (NSInteger i=0; i<[digraph.adjDataSource count]; i++) {
                NSLog(@"指入%ld⬅️的节点:%@",i,[digraph.adjDataSource[i] componentsJoinedByString:@"--"]);
            }
            NSLog(@"技术交流群:%@",@"228407086");
            NSLog(@"原文地址:http://www.cnblogs.com/xiaofeixiang");
    

    测试效果:

    可达性

    可达性的判断和之前的深度优先搜索基本没变化,先来看一下需要实现的方法:

    @interface DirectedDFS : NSObject
    
    //标记数组
    @property  (strong,nonatomic)  NSMutableArray  *marked;
    
    //找到arr中顶点可达的所有顶点
    -(instancetype)initDirectedDFSWithVertex:(Digraph *)graph  vertexArr:(NSArray *)arr;
    //在graph中找到从vertex可达的所有顶点
    -(void)directedDFS:(Digraph *)graph  vertex:(NSInteger)vertex;
    
    //vertex是否可达
    -(Boolean)isMarked:(NSInteger)vertex;
    
    @end

    实现代码:

    @implementation DirectedDFS
    
    #pragma mark  getter and setter
    -(NSMutableArray *)marked{
        if (!_marked) {
            _marked=[[NSMutableArray alloc]initWithCapacity:1];
        }
        return _marked;
    }
    
    
    -(instancetype)initDirectedDFSWithVertex:(Digraph *)graph vertexArr:(NSArray *)arr{
        self=[super init];
        if (self) {
            for (NSInteger i=0; i<graph.vertexs;i++) {
                [self.marked addObject:[NSNull null]];
            }
            //遍历有向图中的顶点
            for (NSInteger j=0; j<[arr count]; j++) {
                if (![self isMarked:[arr[j] integerValue]]) {
                    [self directedDFS:graph vertex:[arr[j] integerValue]];
                }
            }
        }
        return self;
    }
    //博客园-FlyElephant:http://www.cnblogs.com/xiaofeixiang/
    -(void)directedDFS:(Digraph *)graph vertex:(NSInteger)vertex{
        self.marked[vertex]=[NSNumber numberWithBool:true];
        for (NSInteger i=0; i<[graph.adjDataSource[vertex] count]; i++) {
            NSInteger temp=[[graph.adjDataSource[vertex] objectAtIndex:i] integerValue];
            if (![self isMarked:temp]) {
                [self directedDFS:graph vertex:temp];
            }
        }
    }
    
    -(Boolean)isMarked:(NSInteger)vertex{
        return self.marked[vertex]==[NSNull null]?false:[self.marked[vertex] boolValue];
    }
    
    @end
    

    测试代码:

            NSArray  *sources=[NSArray arrayWithObjects:@"2", nil];
            DirectedDFS  *directedDFS=[[DirectedDFS alloc]initDirectedDFSWithVertex:graph vertexArr:sources];
            NSMutableArray  *reachableArr=[[NSMutableArray alloc]initWithCapacity:1];
            for (NSInteger i=0; i<graph.vertexs; i++) {
                
                if (directedDFS.marked[i]&&directedDFS.marked[i]!=[NSNull null]) {
                    [reachableArr addObject:[NSNumber numberWithInteger:i]];
                }
            }
            NSLog(@"可达的节点:%@",[reachableArr componentsJoinedByString:@"--"]);
            NSLog(@"技术交流群:%@",@"228407086");
            NSLog(@"博客园-FlyElephant:http://www.cnblogs.com/xiaofeixiang");
    

    测试效果:

     

  • 相关阅读:
    2012 人民搜索 实习生招聘 笔试题(转)
    招行两地一卡——PayPal美元兑换人民币的最佳解决方案
    PHP上传图片类
    PHP获取随机数
    Linux下解压RAR软件下载和解压.zip和.rar文件
    Zend Framework学习(1)简介
    编程指导
    Zend Framework数据库操作总结
    Zend Framework学习(4)之前端控制器
    参数是否为FALSE的区别
  • 原文地址:https://www.cnblogs.com/xiaofeixiang/p/4703980.html
Copyright © 2020-2023  润新知