成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SQL Server實現最短路徑的搜索算法

數據庫 SQL Server 數據庫運維 算法
在表RelationGraph中,有三個字段(ID,Node,RelatedNode),其中Node和RelatedNode兩個字段描述兩個節點的連接關系;現在要求,找出從節點"p"至節點"j",最短路徑(即經過的節點最少)。

這是去年的問題了,今天在整理郵件的時候才發現這個問題,感覺頂有意思的,特記錄下來。

圖1.

解析

為了能夠更好的描述表RelationGraph中字段Node和 RelatedNode的關系,我在這里特意使用一個圖形來描述,如圖2.

圖2.

在圖2,可清晰的看出各個節點直接如何相連,也可以清楚的看出節點"p"至節點"j"的的幾種可能路徑。

從上面可以看出第2種可能路徑,經過的節點最少。

為了解決開始的問題,我參考了兩種方法,

第1方法是,

參考單源最短路徑算法:Dijkstra(迪杰斯特拉)算法,主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。

圖3.

第2方法是,

針對第1種方法的改進,就是采用多源點方法,這里就是以節點"p"和節點"j"為中心向外層擴展,直到兩圓外切點,如圖4. :

圖4.

實現

在接下來,我就描述在SQL Server中,如何實現。當然我這里采用的前面說的第2種方法,以"P"和"J"為始點像中心外層層擴展。

這里提供有表RelactionGraph的create& Insert數據的腳本:

  1. use TestDB     
  2. go 
  3. if object_id('RelactionGraph') Is not null drop table RelactionGraph 
  4. create table RelactionGraph(ID int identity,Item nvarchar(50),RelactionItemnvarchar(20),constraint PK_RelactionGraph primary key(ID)) 
  5. go 
  6. create nonclustered index IX_RelactionGraph_Item on RelactionGraph(Item)include(RelactionItem) 
  7. create nonclustered index IX_RelactionGraph_RelactionItem on RelactionGraph(RelactionItem)include(Item) 
  8. go 
  9. insert into RelactionGraph (Item, RelactionItem ) values 
  10.     ('a','b'),('a','c'),('a','d'),('a','e'), 
  11.     ('b','f'),('b','g'),('b','h'), 
  12.     ('c','i'),('c','j'), 
  13.     ('f','k'),('f','l'), 
  14.     ('k','o'),('k','p'), 
  15.     ('o','i'),('o','l'
  16. go 

編寫一個存儲過程up_GetPath

  1. use TestDB 
  2. go 
  3. exec dbo.up_GetPath 
  4.         @Node = 'p'
  5. @RelatedNode = 'j' 
  6. go 

上面的存儲過程,主要分為兩大部分,第1部分是實現如何搜索,第2部分實現如何構造返回結果。其中第1部分的代碼根據前面的方法2,通過@Node 和 @RelatedNode 兩個節點向外層搜索,每次搜索返回的節點都保存至臨時表#1和#2,再判斷臨時表#1和#2有沒有出現切點,如果出現就說明已找到最短的路徑(經過多節點數最少),否則就繼續循環搜索,直到循環至***的搜索深度(@MaxLevel smallint=100)或找到切點。要是到100層都沒搜索到切點,將放棄搜索。這里使用***可搜索深度@MaxLevel,目的是控制由于數據量大可能會導致性能差,因為在這里數據量與搜索性能成反比。代碼中還說到一個正向和反向搜索,主要是相對Node 和 RelatedNode來說,它們兩者互為參照對象,進行向外搜索使用。

下面是存儲過程的執行:

 

你可以根據需要來,賦予@Node 和 @RelatedNode不同的值。

  1. use TestDB 
  2. go 
  3. --Procedure: 
  4. if object_id('up_GetPath') Is not null 
  5.     Drop proc up_GetPath 
  6. go 
  7. create proc up_GetPath 
  8.     @Node nvarchar(50), 
  9.     @RelatedNode nvarchar(50) 
  10. As 
  11. set nocount on 
  12. declare 
  13.     @level smallint =1, --當前搜索的深度 
  14.     @MaxLevel smallint=100, --***可搜索深度 
  15.     @Node_WhileFlag bit=1, --以@Node作為中心進行搜索時候,作為能否循環搜索的標記 
  16.     @RelatedNode_WhileFlag bit=1 --以@RelatedNode作為中心進行搜索時候,作為能否循環搜索的標記 
  17. --如果直接找到兩個Node存在直接關系就直接返回 
  18. if Exists(select 1 from RelationGraph where (Node=@Node And RelatedNode=@RelatedNode) 
  19. or(Node=@RelatedNode And RelatedNode=@Node) ) or @Node=@RelatedNode 
  20. begin 
  21.     select convert(nvarchar(2000),@Node + ' --> '+ @RelatedNode) AsRelationGraphPath,convert(smallint,0) As StopCount 
  22.     return 
  23. end 
  24. -- 
  25. if object_id('tempdb..#1') Is not null Drop Table #1 --臨時表#1,存儲的是以@Node作為中心向外擴展的各節點數據 
  26. if object_id('tempdb..#2') Is not null Drop Table #2 --臨時表#2,存儲的是以@RelatedNode作為中心向外擴展的各節點數據 
  27. create table #1( 
  28.     Node nvarchar(50),--相對源點 
  29.     RelatedNode nvarchar(50), --相對目標 
  30.     Level smallint --深度 
  31.     ) 
  32. create table #2(Node nvarchar(50),RelatedNode nvarchar(50),Level smallint) 
  33. insert into #1 ( Node, RelatedNode, Level ) 
  34.     select Node, RelatedNode, @level from RelationGraph a where a.Node =@Node union --正向:以@Node作為源查詢 
  35.     select RelatedNode, Node, @level from RelationGraph a where a.RelatedNode = @Node --反向:以@Node作為目標進行查詢 
  36. set @Node_WhileFlag=sign(@@rowcount) 
  37. insert into #2 ( Node, RelatedNode, Level ) 
  38.     select Node, RelatedNode, @level from RelationGraph a where a.Node =@RelatedNode union --正向:以@RelatedNode作為源查詢 
  39.     select RelatedNode, Node, @level from RelationGraph a where a.RelatedNode = @RelatedNode--反向:以@RelatedNode作為目標進行查詢 
  40. set @RelatedNode_WhileFlag=sign(@@rowcount) 
  41. --如果在表RelationGraph中找不到@Node 或 @RelatedNode 數據,就直接跳過后面的While過程 
  42. if not exists(select 1 from #1) or not exists(select 1 from #2) 
  43. begin 
  44.     goto While_Out 
  45. end 
  46. while not exists(select 1 from #1 a inner join #2 b on b.RelatedNode=a.RelatedNode) --判斷是否出現切點 
  47.      and (@Node_WhileFlag|@RelatedNode_WhileFlag)>0 --判斷是否能搜索 
  48.      And @level<@MaxLevel --控制深度 
  49. begin 
  50.     if @Node_WhileFlag >0 
  51.     begin     
  52.         insert into #1 ( Node, RelatedNode, Level ) 
  53.             --正向 
  54.             select a.Node,a.RelatedNode,@level+1 
  55.                 From RelationGraph a 
  56.                 where exists(select 1 from #1 where RelatedNode=a.Node And Level=@level) And 
  57.                     Not exists(select 1 from #1 where Node=a.Node)             
  58.             union 
  59.             --反向 
  60.             select a.RelatedNode,a.Node,@level+1 
  61.                 From RelationGraph a 
  62.                 where exists(select 1 from #1 where RelatedNode=a.RelatedNode AndLevel=@level) And 
  63.                     Not exists(select 1 from #1 where Node=a.RelatedNode) 
  64.         set @Node_WhileFlag=sign(@@rowcount) 
  65.    end 
  66.     if @RelatedNode_WhileFlag >0 
  67.     begin         
  68.         insert into #2 ( Node, RelatedNode, Level ) 
  69.            --正向 
  70.             select a.Node,a.RelatedNode,@level+1 
  71.                 From RelationGraph a 
  72.                 where exists(select 1 from #2 where RelatedNode=a.Node And Level=@level) And 
  73.                     Not exists(select 1 from #2 where Node=a.Node) 
  74.             union 
  75.             --反向 
  76.             select a.RelatedNode,a.Node,@level+1 
  77.                 From RelationGraph a 
  78.                 where exists(select 1 from #2 where RelatedNode=a.RelatedNode AndLevel=@level) And 
  79.                     Not exists(select 1 from #2 where Node=a.RelatedNode) 
  80.         set @RelatedNode_WhileFlag=sign(@@rowcount) 
  81.   end 
  82.     select @level+=1 
  83. end 
  84. While_Out: 
  85. --下面是構造返回的結果路徑 
  86. if object_id('tempdb..#Path1') Is not null Drop Table #Path1 
  87. if object_id('tempdb..#Path2') Is not null Drop Table #Path2 
  88. ;with cte_path1 As 
  89. select a.Node,a.RelatedNode,Level,convert(nvarchar(2000),a.Node+' -> '+a.RelatedNode) AsRelationGraphPath,Convert(smallint,1) As PathLevel 
  90. From #1 a where exists(select 1 from #2where RelatedNode=a.RelatedNode) 
  91. union all 
  92. select b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),b.Node+' -> '+a.RelationGraphPath) As RelationGraphPath ,Convert(smallint,a.PathLevel+1) 
  93. As PathLevel 
  94.     from cte_path1 a 
  95.         inner join #1 b on b.RelatedNode=a.Node 
  96.             and b.Level=a.Level-1 
  97. select * Into #Path1 from cte_path1 
  98. ;with cte_path2 As 
  99. select a.Node,a.RelatedNode,Level,convert(nvarchar(2000),a.Node) AsRelationGraphPath,Convert(smallint,1) As PathLevel 
  100. From #2 a where exists(select 1 from #1where RelatedNode=a.RelatedNode) 
  101. union all 
  102. select b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),a.RelationGraphPath+' -> '+b.Node) As RelationGraphPath ,Convert(smallint,a.PathLevel+1) 
  103.     from cte_path2 a 
  104.         inner join #2 b on b.RelatedNode=a.Node 
  105.             and b.Level=a.Level-1 
  106. select * Into #Path2 from cte_path2 
  107. ;with cte_result As 
  108. select a.RelationGraphPath+' -> '+b.RelationGraphPath AsRelationGraphPath,a.PathLevel+b.PathLevel -1 
  109. As StopCount,rank() over(order bya.PathLevel+b.PathLevel) As Result_row 
  110.     From #Path1 a 
  111.         inner join #Path2 b on b.RelatedNode=a.RelatedNode 
  112.             and b.Level=1 
  113.     where a.Level=1 
  114. )     
  115. select distinct RelationGraphPath,StopCount From cte_result where Result_row=1 
  116. go 

擴展

前面的例子,可擴展至城市的公交路線,提供兩個站點,搜索經過這兩個站點最少站點公交路線;可以擴展至社區的人際關系的搜索,如一個人與另一個人想認識,那么他們直接要經過多少個人才可以。除了人與人直接有直接的朋友、親戚關聯,還可以通過人與物有關聯找到人與人關聯,如幾個作家通過出版一個本,那么就說明這幾個人可以通過某一本書的作者列表中找到他們存在共同出版書籍的關聯,這為搜索兩個人認識路徑提供參考。這問題可能會非常大復雜,但可以這樣的擴展。

小結

這里只是找兩個節點的所有路徑中,節點數最少的路徑,在實際的應用中,可能會碰到比這里更復雜的情況。在其他的環境或場景可能會帶有長度,時間,多節點,多作用域等一些信息。無論如何,一般都要參考一些原理,算法來實現。

原文鏈接:http://www.cnblogs.com/wghao/archive/2013/04/23/3036965.html

【編輯推薦】

 

責任編輯:彭凡 來源: 博客園
相關推薦

2011-05-17 13:58:37

最短路徑

2024-05-24 08:00:00

2021-05-10 08:07:40

圖算法路徑頂點

2011-12-19 12:39:37

Java

2021-03-10 09:50:15

算法Dijkstra短路問題

2023-05-30 07:58:01

谷歌搜索算法

2018-10-12 15:15:45

電商搜索算法

2025-02-26 05:00:00

DFS算法遞歸

2012-02-29 13:32:28

Java

2021-08-26 17:36:42

Floyd算法數據結構

2015-07-16 14:25:56

SDN網絡感知服務

2015-12-07 17:07:36

SDN網絡流量

2011-06-01 09:27:00

OSPF路由路由器

2019-03-29 09:40:38

數據結構算法前端

2012-08-24 09:16:53

App Store

2019-10-29 15:22:24

Google算法搜索

2014-03-26 09:04:42

算法Floyd最短算法

2024-04-02 11:37:59

AGI網絡模型GAN

2021-09-04 23:40:53

算法程序員前端

2022-09-24 09:03:55

前端單元測試冒泡排序
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久草中文网 | 午夜免费观看体验区 | 91国产在线视频在线 | 性一交一乱一伦视频免费观看 | 粉色午夜视频 | 日韩在线三级 | 国产精品日韩欧美一区二区 | 国产亚洲高清视频 | 91在线网站 | 欧美一区二区三区视频在线 | 欧美日韩一区二区在线观看 | 一区二区三区欧美 | 午夜一区| 国产精品一区二区视频 | 欧美一区二区成人 | 欧美精品一区二区三区在线 | 久久精品这里 | 国产精品激情小视频 | 黄色av大片 | 国产视频日韩 | 亚洲精品一二三区 | 亚洲热在线视频 | 国产精品久久久久无码av | 久久久久电影 | www.欧美.com | av在线播放一区二区 | 五月婷婷中文 | 欧美一级淫片免费视频黄 | 国产精品视频 | 日日日操| 狠狠艹 | 在线观看视频亚洲 | 国产成人综合av | 一区二区三区回区在观看免费视频 | 色偷偷噜噜噜亚洲男人 | 玖玖国产精品视频 | 久久久久久综合 | 国产精品久久久久久久久久久久久 | 国产视频h | 网络毛片 | 免费观看www7722午夜电影 |