• Sql中实现查找最短路径


     That was a problem, and today on getting the message when I have found the problem, interesting, noted.

    In table RelationGraph, there are three fields (ID,Node,RelatedNode), in which the Node RelatedNode two fields describe the connection between the two nodes now require to identify nodes "p" to node "j", the shortest path (that is, after the nodes at least once).

    Figure 1.

      

    In order to better describe the relationship between fields in tables RelationGraph Node RelatedNode, I made a point of using a graphic to describe here, as in Figure 2.

    Figure 2.

    In Figure 2, can clearly see how individual nodes directly connected, you can clearly see that node "p" to node "j" several possible paths.

    As can be seen from above the 2nd possible path, after the nodes at least once.

    In order to solve the problem of starting, I made reference to the two methods,

    1th method is,

    Refer to the single source shortest path algorithms:Dijkstra ( dijiesitela ) algorithm, the main feature is an extension to the starting point at the Center to the outer layer, until the extension up to the end.

    Figure 3.

    The 2nd method is that

    Improvement of 1th, who used to source a little more, and here's to node "p" and the node "j" for expansion to the outer layer of the Centre, until the two round cut, as shown in Figure 4. 

    Figure 4.

    Next, I describe on SQL Server, how to do this. And of course I said before the 2nd approach adopted here, with "p" and "j" as the starting point as Center the outer layer extension.

    There is a table create&Insert data RelactionGraph script:

    use TestDB    

    go

    if object_id('RelactionGraph') Is not null drop table RelactionGraph

    create table RelactionGraph(ID int identity,Item nvarchar(50),RelactionItemnvarchar(20),constraint PK_RelactionGraph primary key(ID))

    go

    create nonclustered index IX_RelactionGraph_Item on RelactionGraph(Item)include(RelactionItem)

    create nonclustered index IX_RelactionGraph_RelactionItem on RelactionGraph(RelactionItem)include(Item)

    go

    insert into RelactionGraph (Item, RelactionItem ) values

        ('a','b'),('a','c'),('a','d'),('a','e'),

        ('b','f'),('b','g'),('b','h'),

        ('c','i'),('c','j'),

        ('f','k'),('f','l'),

        ('k','o'),('k','p'),

        ('o','i'),('o','l')

    go

    Write a stored procedure up_GetPath

    use TestDB

    go

    --Procedure:

    if object_id('up_GetPath') Is not null

        Drop proc up_GetPath

    go

    create proc up_GetPath

    (

        @Node nvarchar(50),

        @RelatedNode nvarchar(50)

    )

    As

    set nocount on

    declare

        @level smallint =1, -the depth of the current search

        @MaxLevel Smallint=100, -the maximum search depth

        @Node_WhileFlag Bit=1, -Search-@Node as the center when, as the possibility of cyclic search tags

        @RelatedNode_WhileFlag Bit=-Search-@RelatedNode as the center when, as the possibility of cyclic search tags

    --If you find two Node there is a direct relationship between the direct return

    if Exists(select 1 from RelationGraph where (Node=@Node And RelatedNode=@RelatedNode) or(Node=@RelatedNode And RelatedNode=@Node) ) or @Node=@RelatedNode

    begin

        select convert(nvarchar(2000),@Node + ' --> '+ @RelatedNode) AsRelationGraphPath,convert(smallint,0) As StopCount

        return

    end

    --

    if object_id('tempdb.. #1') Is not null Drop Table #1 -#1-temporary tables, storage was @Node as the center of the nodes in the scale-out data

    if object_id('tempdb.. #2') Is not null Drop Table #2 -#2-temporary tables, storage was @RelatedNode as the center of the nodes in the scale-out data

    create table #1(

        Node Nvarchar(50),-the source

        RelatedNode Nvarchar(50), – relative target

        Level smallint -The depth

        )

        

    create table #2(Node nvarchar(50),RelatedNode nvarchar(50),Level smallint)

    insert into #1 ( Node, RelatedNode, Level )

        select Node, RelatedNode, @level from RelationGraph a where aNode =@Node Union -is to: to @Node as the source query

        select RelatedNode, Node, @level from RelationGraph a where aRelatedNode = @Node -the reverse: to query @Node as the destination

    set @Node_WhileFlag=sign(@@rowcount)

        

    insert into #2 ( Node, RelatedNode, Level )

        select Node, RelatedNode, @level from RelationGraph a where aNode =@RelatedNode Union-is to: to @RelatedNode as the source query

        select RelatedNode, Node, @level from RelationGraph a where aRelatedNode =@RelatedNode -the reverse: to query @RelatedNode as the destination

    set @RelatedNode_WhileFlag=sign(@@rowcount)

    --If @Node is not found in the table RelationGraph or @RelatedNode data, skip While, later

    if not exists(select 1 from #1) or not exists(select 1 from #2)

    begin

        goto While_Out

    end

    while not exists(select 1 from #1 a inner join #2 b on bRelatedNode=aRelatedNode) – to judge if the tangent point occurs

         and (@Node_WhileFlag@RelatedNode_WhileFlag) >– can determine whether a search

         And @Level<@MaxLevel – control depth

    begin

        if @Node_WhileFlag >0

        begin    

            insert into #1 ( Node, RelatedNode, Level )

                --Forward

                select a.Node,a.RelatedNode,@level+1

                    From RelationGraph a

                    where exists(select 1 from #1 where RelatedNode=aNode And Level=@level)And

                        Not exists(select 1 from #1 where Node=aNode)

                union

                --Reverse

                select a.RelatedNode,a.Node,@level+1

                    From RelationGraph a

                    where exists(select 1 from #1 where RelatedNode=aRelatedNode AndLevel=@level) And

                        Not exists(select 1 from #1 where Node=aRelatedNode)

            

            set @Node_WhileFlag=sign(@@rowcount)

        end

          

        

        if @RelatedNode_WhileFlag >0

        begin        

            insert into #2 ( Node, RelatedNode, Level )

                --Forward

                select a.Node,a.RelatedNode,@level+1

                    From RelationGraph a

                    where exists(select 1 from #2 where RelatedNode=aNode And Level=@level)And

                        Not exists(select 1 from #2 where Node=aNode)

                union

                --Reverse

                select a.RelatedNode,a.Node,@level+1

                    From RelationGraph a

                    where exists(select 1 from #2 where RelatedNode=aRelatedNode AndLevel=@level) And

                        Not exists(select 1 from #2 where Node=aRelatedNode)

            set @RelatedNode_WhileFlag=sign(@@rowcount)

        end

        

        select @level+=1

    end

    While_Out:

    --Here is to construct returns the result path

    if object_id('tempdb.. #Path1') Is not null Drop Table #Path1

    if object_id('tempdb.. #Path2') Is not null Drop Table #Path2

    ;with cte_path1 As

    (

    select a.Node,a.RelatedNode,Level,convert(nvarchar(2000),a.Node+' -> '+a.RelatedNode) AsRelationGraphPath,Convert(smallint,1) As PathLevel From #1 a where exists(select 1 from #2where RelatedNode=a.RelatedNode)

    union all

    select b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),b.Node+' -> '+a.RelationGraphPath) As RelationGraphPath ,Convert(smallint,a.PathLevel+1) As PathLevel

        from cte_path1 a

            inner join #1 b on bRelatedNode=aNode

                and bLevel=aLevel-1

    )

    select * Into #Path1 from cte_path1

    ;with cte_path2 As

    (

    select a.Node,a.RelatedNode,Level,convert(nvarchar(2000),a.Node) AsRelationGraphPath,Convert(smallint,1) As PathLevel From #2 a where exists(select 1 from #1where RelatedNode=a.RelatedNode)

    union all

    select b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),a.RelationGraphPath+' -> '+b.Node) As RelationGraphPath ,Convert(smallint,a.PathLevel+1)

        from cte_path2 a

            inner join #2 b on bRelatedNode=aNode

                and bLevel=aLevel-1

    )

    select * Into #Path2 from cte_path2

    ;with cte_result As

    (

    select a.RelationGraphPath+' -> '+b.RelationGraphPath AsRelationGraphPath,a.PathLevel+b.PathLevel -As StopCount,rank() over(order bya.PathLevel+b.PathLevel) As Result_row

        From #Path1 a

            inner join #Path2 b on bRelatedNode=aRelatedNode

                and bLevel=1

        where aLevel=1

    )    

    select distinct RelationGraphPath,StopCount From cte_result where Result_row=1

    go

    The above stored procedure, can be divided into two, 1th part was realizing how to search, 2nd part for how to construct returns the results. Which 1th Department points of code according to front of method 2, through @Node and @RelatedNode two a node to outer search, every time search returns of node are save to temporary table #1 and #2, again judgment temporary table #1 and #2 has no appeared pointcut, if appeared on description has found shortest of path (after more node number at least), or on continues to cycle search, until cycle to maximum of search depth (@MaxLevel smallint=100) or found pointcut. If I haven't search up to 100 levels to cut, will give up the search. Maximum search depth @MaxLevel used here in order to control due to the large amount of data can cause poor performance, because here is inversely proportional to data volume and search performance. Also spoke of a forward and reverse search code is mainly relative Node RelatedNode, two complementary to the reference object, to search out.

    Here is the execution of the stored procedure:

    use TestDB

    go

    exec dboup_GetPath

            @Node = 'p',

    @RelatedNode = 'j'

    go

    You can come if you want to give different values of @Node and @RelatedNode.

    The previous example can be extended to urban public transport routes, provided two site, search through this site at least two sites bus routes; the search can be extended to community relationships, such as a person with another person to know, so they have to go through many people. Apart from people associated with directly directly to the person's friends, relatives, or can be found by people associated with people associated with the person, such as several writers by publishing this, then it means that few people are able to find them in the list of authors of a book co-published books Association, this path provides references to search for two people know.This problem may be very large and complex, but can be extended.

    Here just looking for two node of the path, the path with the least number of, in a real application, may run into more complex situation than here. In other environments or scenarios may carry length, time, nodes, some information, such as the scope. In any case, usually refer to some principle, algorithm implementations.

    转自:http://www.cnblogs.com/wghao/archive/2013/04/23/3036965.html

  • 相关阅读:
    数据结结构学习 赫夫曼树
    C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
    Linux/Unix time时间戳的处理转换函数
    gcc中include文件的搜索路径
    数据结结构学习 2叉树
    C++ 虚函数表解析
    数据结结构学习 线性表
    C#实现MD5加密
    学习的艺术
    C# 3.0实现类本身的方法扩展
  • 原文地址:https://www.cnblogs.com/comsokey/p/InTheSQLServerImplementationOfShortestPathsearching.html
Copyright © 2020-2023  润新知