算法-無向圖(深度優先搜索和廣度優先搜索)

圖中最經常使用到的兩種搜索深度優先搜索和廣度優先搜索,深度優先搜索是一種在開發爬蟲早期使用較多的方法它的目的是要達到被搜索結構的葉結點(即那些不包含任何超連接的Html文件) ,廣度搜索屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的全部節點,以找尋結果。換句話說,它並不考慮結果的可能位置,完全地搜索整張圖,直到找到結果爲止。數組

深度優先搜索

圖中咱們常常會遇到一個問題就是圖的連通性,好比說從一個頂點到另一個頂點,判斷頂點和其餘頂點之間的連通性,如下圖爲例:測試

搜索API定義:atom

@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

實現:spa

@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

代碼測試:component

        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");

測試效果:blog

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");

測試效果:ci

 

廣度優先搜索

若是咱們仔細觀察會發現一個現象,圖片中咱們很明顯看到頂點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");

測試效果:

相關文章
相關標籤/搜索