1. 程式人生 > >淺談深度優先和廣度優先(scrapy-redis)

淺談深度優先和廣度優先(scrapy-redis)

首先先談談深度優先和廣度優先的定義

深度優先搜尋演算法英語:Depth-First-Search,DFS)是一種用於遍歷或搜尋演算法。沿著樹的深度遍歷樹的節點,儘可能深的搜尋樹的分支。當節點v的所在邊都己被探尋過,搜尋將回溯到發現節點v的那條邊的起始節點。這一過程一直進行到已發現從源節點可達的所有節點為止。如果還存在未被發現的節點,則選擇其中一個作為源節點並重復以上過程,整個程序反覆進行直到所有節點都被訪問為止。屬於盲目搜尋。

 

深度優先搜尋
節點搜尋的順序 節點進行深度優先搜尋的順序
概況
類別: 搜尋演算法
資料結構:
時間複雜度: {\displaystyle O(b^{m})}O(b^m)
空間複雜度: {\displaystyle O(bm)}O(bm)
最佳解:
完全性:
其他: b - 分支系數
m - 圖的最大深度

 

廣度優先搜尋演算法英語:Breadth-First-Search,縮寫為BFS),又譯作寬度優先搜尋,或橫向優先搜尋,是一種圖形搜尋演算法。簡單的說,BFS是從根節點開始,沿著樹的寬度遍歷樹的節點。如果所有節點均被訪問,則演算法中止。廣度優先搜尋的實現一般採用open-closed表。

廣度優先搜尋
節點搜尋的順序 節點進行廣度優先搜尋的順序
概況
類別: 搜尋演算法
資料結構:
時間複雜度: {\displaystyle O(|V|+|E|)=O(b^{d})}O(|V|+|E|) = O(b^d)
空間複雜度: {\displaystyle O(|V|+|E|)=O(b^{d})}O(|V|+|E|) = O(b^d)
最佳解:
完全性:

 

 

通俗的講:

深度優先:一個一個節點往下找,不找兄弟節點,每一個深度一個節點,先進去的後出來

廣度優先:橫向取值,一個節點有關聯其他的節點,一同被取出來,一個深度多個節點,先進去的先出來

在settings裡面的配置:

from   scrapy_redis.queue import PriorityQueue,FifoQueue,LifoQueue
先進先出:廣度優先
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.FifoQueue'
後進先出:深度優先
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.LifoQueue'
優先順序佇列:
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.PriorityQueue'
優先順序佇列裡面也有深度優先和廣度優先:

requets.priority=1   廣度優先
requets.priority=1   深度優先

 

實現原理:

from scrapy_redis import queue

prio=1

depth = response.meta['depth'] + 1

requets.priority-=depth*self.prio

每一次迴圈,depth加1
同一個深度可以找到很多url(兄弟節點)

如果是1的話,廣度優先

廣度優先:
depth 優先順序
1 -1
1 -1
1 -1
2 -2

從深度為1的開始往下找,優先順序也越大
重點:深度越小,優先順序越小

def push(self, request):
"""Push a request"""
data = self._encode_request(request)
score = -request.priority##取反,注意

......

優先順序佇列:
放進佇列裡面:
反一下
1 1
1 1
1 1
2 2
......

print('這裡優先順序是',score)
print(request.meta.get('depth'))
# We don't use zadd method as the order of arguments change depending on
# whether the class is Redis or StrictRedis, and the option of using
# kwargs only accepts strings, not bytes.
self.server.execute_command('ZADD', self.key, score, data)
#按照分值來看


def pop(self, timeout=0):
"""
Pop a request
timeout not support in this queue class
"""
# use atomic range/remove using multi/exec
##開啟事物
pipe = self.server.pipeline()
pipe.multi()
##取第一個值出來,拿出一個刪除一個
pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)
results, count = pipe.execute()
if results:
return self._decode_request(results[0])

最終pop是按照這個優先順序來取值的,優先順序越小的越先被取出來,優先順序從小多大取值
總結:就是深度越小,優先順序越小,越先被取出來>>廣度優先(先進先出,橫向取值)

 

深度優先:
先進後出:一個一個節點的往下面執行

深度越大,優先順序越小,越先被pop出來

深度優先類似,就不多說了

....................