很久之前在做題的時候,隱隱發現「搜尋」這種策略的影子,原打算做乙個總結來著,但後來因為沒有乙個較為系統的學習,所以就擱置了。這段時間在看《挑戰程式設計》這本書的時候,才發現這確實是一種解題策略,叫做「最基礎的窮竭搜尋」。
搜尋本質上是一種從所有的狀態空間裡尋找可行解(或者最優解)的過程,根據搜尋的策略不同,常見的搜尋方式有以下幾種:
以上是一些基本的搜尋方式,還有一些更高階的搜尋方式。如
小弟才疏學淺,目前只看了關於基礎篇的搜尋,高階篇的搜尋被一題《square destroyer》 卡住了許久(且面試的時候大都考不到高階的搜尋),這兒只總結關於基礎部分的搜尋方式。
深度遍歷相對來說使用的比較多,因為其可以利用遞迴這個利器,使得**看起來相當簡潔(前提條件是你能寫好遞迴的式子)。
這裡還需要注意一點,上面的示意圖比較簡單,
廣度遍歷其實也很簡單,就是優先從當前狀態往四周擴充套件,就像一條條章魚的觸手一樣。當四周的狀態都訪問完畢(需要加入到佇列裡)之後,在從佇列取出下乙個狀態,繼續以上步驟。如下圖所示。
如上圖所示,從狀態0開始,紅色為從狀態0第一次訪問的狀態,藍色為從狀態1(需要從佇列裡取出來)開始擴充套件的狀態。(上圖只畫了一部分)
廣度遍歷和深度遍歷一樣,也可以訪問到所有的狀態空間,但是相對來說用的比深度遍歷要少一些,因為其使用一般需要自己構造「佇列」這個資料結構來儲存待訪問的狀態(深度優先遍歷使用棧這個資料結構,編譯器已經幫我們實現好了),相對來說麻煩一些。 當然,有些問題只適合使用深度遍歷的方式。
但是廣度遍歷有乙個特點,其訪問的順序是從裡往外的,或者說從源節點往四周擴充套件的,所以其狀態是按照距離初始狀態由近到遠的順序遍歷的。按照這個特點,我們可以求最短路徑(當然,這個條件需要所有的路段距離都是一樣的)
還有一種最直接最簡單的方式,就是直接列舉所有的狀態空間( 當然,這需要狀態空間或者題目比較特殊時才可以)。 我們可以利用位運算,列舉從n個元素中取出k個元素組合、排列或者其他一些方式,如按照二項式選取(進行可行解的搜尋。
比如說,, 我們可以按照是否選取每個元素,劃分出2^5 = 32中狀態空間。
如上圖所示,每個元素都有被選取或者不被選取的可能。
好了,文章的最後,來總結一波。
(1)、上文所說的所有的狀態空間,有的並不是向上面介紹的那樣簡單,就是乙個單獨的數或者結點。 狀態空間中的狀態可能包括實際好多個結點,甚至是有一定順序規則的結點。
(2)、正因為上面的那個特點,所以實際的問題中深度優先遍歷或者廣度優先遍歷這些演算法並不僅僅用於樹或者圖這種顯而易見的問題中,還有可能用於陣列這樣表面上看是一維的資料結構上(資料是一維的,問題可能是二維的或者多維的)
(3)、leecode中深度優先遍歷有一些是陣列這樣一維的題,也有可能是矩陣深度遍歷這樣二維的題。本質上其實是一樣的。只不過前者可能只有兩個方向(一般從前到後),後者是上下左右四個方向。
C 實戰(一)二分搜尋
1.編寫乙個程式,使其實現二分搜尋 二分搜尋 以vector為例 include include using namespace std intmain p.sort p.begin p.end const int a,const int b 排序 auto beg p.begin cout 請輸入...
CABAC基礎一 二值化
在hevc中主要包括截斷萊斯編碼 truncated rice 指數哥倫布編碼 exp golomb 和定長編碼。tr二值化需要輸入三個引數 synval表示將要進行tr二值化的值,criceparam表示萊斯引數,cmax表示門限值。tr二值化的結果由兩部分組成 字首prefixval是一元碼,字...
計數排序 小講
計數排序是乙個類似於桶排序的排序演算法,其優勢是對已知數量範圍的陣列進行排序。它建立乙個長度為這個資料範圍的陣列c,c中每個元素記錄要排序陣列中對應記錄的出現個數。這個演算法於1954年由 harold h.seward 提出。它的優勢在於在對一定範圍內的整數排序時,它的複雜度為 n k 其中k是整...