【算法】超詳細(xì)的遺傳算法(Genetic Algorithm)解析

00 目錄

  • 遺傳算法定義
  • 生物學(xué)術(shù)語
  • 問題導(dǎo)入
  • 大體實現(xiàn)
  • 具體細(xì)節(jié)
  • 代碼實現(xiàn)

01 什么是遺傳算法?

1.1 遺傳算法的科學(xué)定義

遺傳算法(Genetic Algorithm, GA)是模擬達(dá)爾文生物進化論的自然選擇和遺傳學(xué)機理的生物進化過程的計算模型,是一種通過模擬自然進化過程搜索最優(yōu)解的方法。

其主要特點是直接對結(jié)構(gòu)對象進行操作,不存在求導(dǎo)和函數(shù)連續(xù)性的限定;具有內(nèi)在的隱并行性和更好的全局尋優(yōu)能力;采用概率化的尋優(yōu)方法,不需要確定的規(guī)則就能自動獲取和指導(dǎo)優(yōu)化的搜索空間,自適應(yīng)地調(diào)整搜索方向。

遺傳算法以一種群體中的所有個體為對象,并利用隨機化技術(shù)指導(dǎo)對一個被編碼的參數(shù)空間進行高效搜索。其中,選擇、交叉和變異構(gòu)成了遺傳算法的遺傳操作;參數(shù)編碼、初始群體的設(shè)定、適應(yīng)度函數(shù)的設(shè)計、遺傳操作設(shè)計、控制參數(shù)設(shè)定五個要素組成了遺傳算法的核心內(nèi)容。

1.2 遺傳算法的執(zhí)行過程(參照百度百科)

遺傳算法是從代表問題可能潛在的解集的一個種群(population)開始的,而一個種群則由經(jīng)過基因(gene)編碼的一定數(shù)目的個體(individual)組成。每個個體實際上是染色體(chromosome)帶有特征的實體。

染色體作為遺傳物質(zhì)的主要載體,即多個基因的集合,其內(nèi)部表現(xiàn)(即基因型)是某種基因組合,它決定了個體的形狀的外部表現(xiàn),如黑頭發(fā)的特征是由染色體中控制這一特征的某種基因組合決定的。因此,在一開始需要實現(xiàn)從表現(xiàn)型到基因型的映射即編碼工作。由于仿照基因編碼的工作很復(fù)雜,我們往往進行簡化,如二進制編碼。

初代種群產(chǎn)生之后,按照適者生存和優(yōu)勝劣汰的原理,逐代(generation)演化產(chǎn)生出越來越好的近似解,在每一代,根據(jù)問題域中個體的適應(yīng)度(fitness)大小選擇(selection)個體,并借助于自然遺傳學(xué)的遺傳算子(genetic operators)進行組合交叉(crossover)和變異(mutation),產(chǎn)生出代表新的解集的種群。

這個過程將導(dǎo)致種群像自然進化一樣的后生代種群比前代更加適應(yīng)于環(huán)境,末代種群中的最優(yōu)個體經(jīng)過解碼(decoding),可以作為問題近似最優(yōu)解。

1.3 遺傳算法過程圖解

image

02 相關(guān)生物學(xué)術(shù)語

為了大家更好了解遺傳算法,在此之前先簡單介紹一下相關(guān)生物學(xué)術(shù)語,大家了解一下即可。

  • 基因型(genotype):性狀染色體的內(nèi)部表現(xiàn);

  • 表現(xiàn)型(phenotype):染色體決定的性狀的外部表現(xiàn),或者說,根據(jù)基因型形成的個體的外部表現(xiàn);

  • 進化(evolution):種群逐漸適應(yīng)生存環(huán)境,品質(zhì)不斷得到改良。生物的進化是以種群的形式進行的。

  • 適應(yīng)度(fitness):度量某個物種對于生存環(huán)境的適應(yīng)程度。

  • 選擇(selection):以一定的概率從種群中選擇若干個個體。一般,選擇過程是一種基于適應(yīng)度的優(yōu)勝劣汰的過程。

  • 復(fù)制(reproduction):細(xì)胞分裂時,遺傳物質(zhì)DNA通過復(fù)制而轉(zhuǎn)移到新產(chǎn)生的細(xì)胞中,新細(xì)胞就繼承了舊細(xì)胞的基因。

  • 交叉(crossover):兩個染色體的某一相同位置處DNA被切斷,前后兩串分別交叉組合形成兩個新的染色體。也稱基因重組或雜交;

  • 變異(mutation):復(fù)制時可能(很小的概率)產(chǎn)生某些復(fù)制差錯,變異產(chǎn)生新的染色體,表現(xiàn)出新的性狀。

  • 編碼(coding):DNA中遺傳信息在一個長鏈上按一定的模式排列。遺傳編碼可看作從表現(xiàn)型到基因型的映射。

  • 解碼(decoding):基因型到表現(xiàn)型的映射。

  • 個體(individual):指染色體帶有特征的實體;

  • 種群(population):個體的集合,該集合內(nèi)個體數(shù)稱為種群

03 問題引出與解決

3.1 一元函數(shù)最大值問題

如下的函數(shù)圖像:

image

現(xiàn)在我們要在既定的區(qū)間內(nèi)找出函數(shù)的最大值。

學(xué)過高中數(shù)學(xué)的孩紙都知道,上面的函數(shù)存在著很多的極大值和極小值。而最大值則是指定區(qū)間的極大值中的最大的那一個。從圖像上具體表現(xiàn)為,極大值像是一座座山峰,極小值則是像一座座山谷。因此,我們也可以把遺傳算法的過程看作是一個在多元函數(shù)里面求最優(yōu)解的過程。

這些山峰對應(yīng)著局部最優(yōu)解,其中有一個山峰是海拔最高的,這個山峰則對應(yīng)的是全局最優(yōu)解。那么,遺傳算法要做的就是盡量爬到最高峰,而不是困在較低的小山峰上。(如果問題求解是最小值,那么要做的就是盡量走到最低谷,道理是一樣的)。

image

3.2 "袋鼠蹦跳"

既然我們把函數(shù)曲線理解成一個一個山峰和山谷組成的山脈。那么我們可以設(shè)想所得到的每一個解就是一只袋鼠,我們希望它們不斷的向著更高處跳去,直到跳到最高的山峰。所以求最大值的過程就轉(zhuǎn)化成一個“袋鼠跳”的過程。

下面介紹介紹“袋鼠跳”的幾種方式。

  • 爬山算法:一只袋鼠朝著比現(xiàn)在高的地方跳去。它找到了不遠(yuǎn)處的最高的山峰。但是這座山不一定是最高峰。這就是爬山算法,它不能保證局部最優(yōu)值就是全局最優(yōu)值。

  • 模擬退火:袋鼠喝醉了。它隨機地跳了很長時間。這期間,它可能走向高處,也可能踏入平地。但是,它漸漸清醒了并朝最高峰跳去。這就是模擬退火算法。

  • 遺傳算法:有很多袋鼠,它們降落到喜瑪拉雅山脈的任意地方。這些袋鼠并不知道它們的任務(wù)是尋找珠穆朗瑪峰。但每過幾年,就在一些海拔高度較低的地方射殺一些袋鼠。于是,不斷有袋鼠死于海拔較低的地方,而越是在海拔高的袋鼠越是能活得更久,也越有機會生兒育女。就這樣經(jīng)過許多年,這些袋鼠們竟然都不自覺地聚攏到了一個個的山峰上,可是在所有的袋鼠中,只有聚攏到珠穆朗瑪峰的袋鼠被帶回了美麗的澳洲。

04 大體實現(xiàn)過程

遺傳算法中每一條染色體,對應(yīng)著遺傳算法的一個解決方案,一般我們用適應(yīng)性函數(shù)(fitness function)來衡量這個解決方案的優(yōu)劣。所以從一個基因組到其解的適應(yīng)度形成一個映射。遺傳算法的實現(xiàn)過程實際上就像自然界的進化過程那樣。

下面我們用袋鼠跳中的步驟一一對應(yīng)解釋,以方便大家理解:

  1. 首先尋找一種對問題潛在解進行“數(shù)字化”編碼的方案。(建立表現(xiàn)型和基因型的映射關(guān)系)

  2. 隨機初始化一個種群(那么第一批袋鼠就被隨意地分散在山脈上),種群里面的個體就是這些數(shù)字化的編碼。

  3. 接下來,通過適當(dāng)?shù)慕獯a過程之后(得到袋鼠的位置坐標(biāo))。

  4. 用適應(yīng)性函數(shù)對每一個基因個體作一次適應(yīng)度評估(袋鼠爬得越高當(dāng)然就越好,所以適應(yīng)度相應(yīng)越高)。

  5. 用選擇函數(shù)按照某種規(guī)定擇優(yōu)選擇(每隔一段時間,射殺一些所在海拔較低的袋鼠,以保證袋鼠總體數(shù)目持平。)。

  6. 讓個體基因變異(讓袋鼠隨機地跳一跳)。

  7. 然后產(chǎn)生子代(希望存活下來的袋鼠是多產(chǎn)的,并在那里生兒育女)。

遺傳算法并不保證你能獲得問題的最優(yōu)解,但是使用遺傳算法的最大優(yōu)點在于你不必去了解和操心如何去“找”最優(yōu)解。(你不必去指導(dǎo)袋鼠向那邊跳,跳多遠(yuǎn)。)而只要簡單的“否定”一些表現(xiàn)不好的個體就行了。(把那些總是愛走下坡路的袋鼠射殺,這就是遺傳算法的精粹!)

由此我們可以得出遺傳算法的一般步驟:

  1. 隨機產(chǎn)生種群。
  2. 根據(jù)策略判斷個體的適應(yīng)度,是否符合優(yōu)化準(zhǔn)則,若符合,輸出最佳個體及其最優(yōu)解,結(jié)束。否則,進行下一步。
  3. 依據(jù)適應(yīng)度選擇父母,適應(yīng)度高的個體被選中的概率高,適應(yīng)度低的個體被淘汰。
  4. 用父母的染色體按照一定的方法進行交叉,生成子代。
  5. 對子代染色體進行變異。

由交叉和變異產(chǎn)生新一代種群,返回步驟2,直到最優(yōu)解產(chǎn)生。

具體圖解可以回到1.3查看。

05 開始我們的進化(具體實現(xiàn)細(xì)節(jié))

5.1 先從編碼說起

編碼是應(yīng)用遺傳算法時要解決的首要問題,也是設(shè)計遺傳算法時的一個關(guān)鍵步驟。編碼方法影響到交叉算子、變異算子等遺傳算子的運算方法,大很大程度上決定了遺傳進化的效率。

迄今為止人們已經(jīng)提出了許多種不同的編碼方法。總的來說,這些編碼方法可以分為三大類:二進制編碼法、浮點編碼法、符號編碼法。下面分別進行介紹:

5.1.1 二進制編碼法

就像人類的基因有AGCT 4種堿基序列一樣。不過在這里我們只用了0和1兩種堿基,然后將他們串成一條鏈形成染色體。一個位能表示出2種狀態(tài)的信息量,因此足夠長的二進制染色體便能表示所有的特征。這便是二進制編碼。如下:
1110001010111

它由二進制符號0和1所組成的二值符號集。它有以下一些優(yōu)點:

  1. 編碼、解碼操作簡單易行
  2. 交叉、變異等遺傳操作便于實現(xiàn)
  3. 合最小字符集編碼原則
  4. 利用模式定理對算法進行理論分析。

二進制編碼的缺點是:對于一些連續(xù)函數(shù)的優(yōu)化問題,由于其隨機性使得其局部搜索能力較差,如對于一些高精度的問題(如上題),當(dāng)解迫近于最優(yōu)解后,由于其變異后表現(xiàn)型變化很大,不連續(xù),所以會遠(yuǎn)離最優(yōu)解,達(dá)不到穩(wěn)定。

5.1.2 浮點編碼法

二進制編碼雖然簡單直觀,但明顯地。但是存在著連續(xù)函數(shù)離散化時的映射誤差。個體長度較短時,可能達(dá)不到精度要求,而個體編碼長度較長時,雖然能提高精度,但增加了解碼的難度,使遺傳算法的搜索空間急劇擴大。

所謂浮點法,是指個體的每個基因值用某一范圍內(nèi)的一個浮點數(shù)來表示。在浮點數(shù)編碼方法中,必須保證基因值在給定的區(qū)間限制范圍內(nèi),遺傳算法中所使用的交叉、變異等遺傳算子也必須保證其運算結(jié)果所產(chǎn)生的新個體的基因值也在這個區(qū)間限制范圍內(nèi)。如下所示:

1.2-3.2-5.3-7.2-1.4-9.7

浮點數(shù)編碼方法有下面幾個優(yōu)點:

  1. 適用于在遺傳算法中表示范圍較大的數(shù)
  2. 適用于精度要求較高的遺傳算法
  3. 便于較大空間的遺傳搜索
  4. 改善了遺傳算法的計算復(fù)雜性,提高了運算交率
  5. 便于遺傳算法與經(jīng)典優(yōu)化方法的混合使用
  6. 便于設(shè)計針對問題的專門知識的知識型遺傳算子
  7. 便于處理復(fù)雜的決策變量約束條件

5.1.3 符號編碼法

符號編碼法是指個體染色體編碼串中的基因值取自一個無數(shù)值含義、而只有代碼含義的符號集如{A,B,C…}。
符號編碼的主要優(yōu)點是:

  1. 符合有意義積術(shù)塊編碼原則
  2. 便于在遺傳算法中利用所求解問題的專門知識
  3. 便于遺傳算法與相關(guān)近似算法之間的混合使用。

5.2 為我們的袋鼠染色體編碼

在上面介紹了一系列編碼方式以后,那么,如何利用上面的編碼來為我們的袋鼠染色體編碼呢?首先我們要明確一點:編碼無非就是建立從基因型到表現(xiàn)型的映射關(guān)系。這里的表現(xiàn)型可以理解為個體特征(比如身高、體重、毛色等等)。那么,在此問題下,我們關(guān)心的個體特征就是:袋鼠的位置坐標(biāo)(因為我們要把海拔低的袋鼠給殺掉)。無論袋鼠長什么樣,愛吃什么。我們關(guān)心的始終是袋鼠在哪里,并且只要知道了袋鼠的位置坐標(biāo)(位置坐標(biāo)就是相應(yīng)的染色體編碼,可以通過解碼得出),我們就可以:

  1. 在喜馬拉雅山脈的地圖上找到相應(yīng)的位置坐標(biāo),算出海拔高度。(相當(dāng)于通過自變量求得適應(yīng)函數(shù)的值)然后判讀該不該射殺該袋鼠。
  2. 可以知道染色體交叉和變異后袋鼠新的位置坐標(biāo)。

回到3.1中提的求一元函數(shù)最大值的問題。在上面我們把極大值比喻為山峰,那么,袋鼠的位置坐標(biāo)可以比喻為區(qū)間[-1, 2]的某一個x坐標(biāo)(有了x坐標(biāo),再通過函數(shù)表達(dá)式可以算出函數(shù)值 <==> 得到了袋鼠染色體編碼,解碼得到位置坐標(biāo),在喜馬拉雅山脈地圖查詢位置坐標(biāo)算出海拔高度)。這個x坐標(biāo)是一個實數(shù),現(xiàn)在,說白了就是怎么對這個x坐標(biāo)進行編碼。下面我們以二進制編碼為例講解,不過這種情況下以二進制編碼比較復(fù)雜就是了。(如果以浮點數(shù)編碼,其實就很簡潔了,就一浮點數(shù)而已。)

我們說過,一定長度的二進制編碼序列,只能表示一定精度的浮點數(shù)。在這里假如我們要求解精確到六位小數(shù),由于區(qū)間長度為2 - (-1) = 3 ,為了保證精度要求,至少把區(qū)間[-1,2]分為3 × 10^6等份。又因為

2^21 = 2097152 < 3*10^6 < 2^22 = 4194304

所以編碼的二進制串至少需要22位。

把一個二進制串(b0,b1,....bn)轉(zhuǎn)化為區(qū)間里面對應(yīng)的實數(shù)值可以通過下面兩個步驟:

  1. 將一個二進制串代表的二進制數(shù)轉(zhuǎn)化為10進制數(shù):

    image
  1. 對應(yīng)區(qū)間內(nèi)的實數(shù):

    image

例如一個二進制串(1000101110110101000111)2通過上面換算以后,表示實數(shù)值0.637197。

好了,上面的編碼方式只是舉個例子讓大家更好理解而已,編碼的方式千奇百怪,層出不窮,每個問題可能采用的編碼方式都不一樣。在這一點上大家要注意。

5.3 評價個體的適應(yīng)度--適應(yīng)度函數(shù)(fitness function)

前面說了,適應(yīng)度函數(shù)主要是通過個體特征從而判斷個體的適應(yīng)度。在本例的袋鼠跳中,我們只關(guān)心袋鼠的海拔高度,以此來判斷是否該射殺該袋鼠。這樣一來,該函數(shù)就非常簡單了。只要輸入袋鼠的位置坐標(biāo),在通過相應(yīng)查找運算,返回袋鼠當(dāng)前位置的海拔高度就行。

適應(yīng)度函數(shù)也稱評價函數(shù),是根據(jù)目標(biāo)函數(shù)確定的用于區(qū)分群體中個體好壞的標(biāo)準(zhǔn)。適應(yīng)度函數(shù)總是非負(fù)的,而目標(biāo)函數(shù)可能有正有負(fù),故需要在目標(biāo)函數(shù)與適應(yīng)度函數(shù)之間進行變換。

評價個體適應(yīng)度的一般過程為:

  1. 對個體編碼串進行解碼處理后,可得到個體的表現(xiàn)型。

  2. 由個體的表現(xiàn)型可計算出對應(yīng)個體的目標(biāo)函數(shù)值。

  3. 根據(jù)最優(yōu)化問題的類型,由目標(biāo)函數(shù)值按一定的轉(zhuǎn)換規(guī)則求出個體的適應(yīng)度。

5.4 射殺一些袋鼠--選擇函數(shù)(selection)

遺傳算法中的選擇操作就是用來確定如何從父代群體中按某種方法選取那些個體,以便遺傳到下一代群體。選擇操作用來確定重組或交叉?zhèn)€體,以及被選個體將產(chǎn)生多少個子代個體。前面說了,我們希望海拔高的袋鼠存活下來,并盡可能繁衍更多的后代。但我們都知道,在自然界中,適應(yīng)度高的袋鼠越能繁衍后代,但這也是從概率上說的而已。畢竟有些適應(yīng)度低的袋鼠也可能逃過我們的眼睛。

那么,怎么建立這種概率關(guān)系呢?

下面介紹幾種常用的選擇算子:

  1. 輪盤賭選擇(Roulette Wheel Selection):是一種回放式隨機采樣方法。每個個體進入下一代的概率等于它的適應(yīng)度值與整個種群中個體適應(yīng)度值和的比例。選擇誤差較大。

  2. 隨機競爭選擇(Stochastic Tournament):每次按輪盤賭選擇一對個體,然后讓這兩個個體進行競爭,適應(yīng)度高的被選中,如此反復(fù),直到選滿為止。

  3. 最佳保留選擇:首先按輪盤賭選擇方法執(zhí)行遺傳算法的選擇操作,然后將當(dāng)前群體中適應(yīng)度最高的個體結(jié)構(gòu)完整地復(fù)制到下一代群體中。

  4. 無回放隨機選擇(也叫期望值選擇Excepted Value Selection):根據(jù)每個個體在下一代群體中的生存期望來進行隨機選擇運算。方法如下:

    (1) 計算群體中每個個體在下一代群體中的生存期望數(shù)目N。

    (2) 若某一個體被選中參與交叉運算,則它在下一代中的生存期望數(shù)目減去0.5,若某一個體未 被選中參與交叉運算,則它在下一代中的生存期望數(shù)目減去1.0。

    (3) 隨著選擇過程的進行,若某一個體的生存期望數(shù)目小于0時,則該個體就不再有機會被選中。

  5. 確定式選擇:按照一種確定的方式來進行選擇操作。具體操作過程如下:

    (1) 計算群體中各個個體在下一代群體中的期望生存數(shù)目N。

    (2) 用N的整數(shù)部分確定各個對應(yīng)個體在下一代群體中的生存數(shù)目。

    (3) 用N的小數(shù)部分對個體進行降序排列,順序取前M個個體加入到下一代群體中。至此可完全確定出下一代群體中M個個體。

  6. 無回放余數(shù)隨機選擇:可確保適應(yīng)度比平均適應(yīng)度大的一些個體能夠被遺傳到下一代群體中,因而選擇誤差比較小。

  7. 均勻排序:對群體中的所有個體按期適應(yīng)度大小進行排序,基于這個排序來分配各個個體被選中的概率。

  8. 最佳保存策略:當(dāng)前群體中適應(yīng)度最高的個體不參與交叉運算和變異運算,而是用它來代替掉本代群體中經(jīng)過交叉、變異等操作后所產(chǎn)生的適應(yīng)度最低的個體。

  9. 隨機聯(lián)賽選擇:每次選取幾個個體中適應(yīng)度最高的一個個體遺傳到下一代群體中。

  10. 排擠選擇:新生成的子代將代替或排擠相似的舊父代個體,提高群體的多樣性。

下面以輪盤賭選擇為例給大家講解一下:

假如有5條染色體,他們的適應(yīng)度分別為5、8、3、7、2。

那么總的適應(yīng)度為:F = 5 + 8 + 3 + 7 + 2 = 25。

那么各個個體的被選中的概率為:

α1 = ( 5 / 25 ) * 100% = 20%

α2 = ( 8 / 25 ) * 100% = 32%

α3 = ( 3 / 25 ) * 100% = 12%

α4 = ( 7 / 25 ) * 100% = 28%

α5 = ( 2 / 25 ) * 100% = 8%

所以轉(zhuǎn)盤如下:

image

當(dāng)指針在這個轉(zhuǎn)盤上轉(zhuǎn)動,停止下來時指向的個體就是天選之人啦。可以看出,適應(yīng)性越高的個體被選中的概率就越大。

5.5 遺傳--染色體交叉(crossover)

遺傳算法的交叉操作,是指對兩個相互配對的染色體按某種方式相互交換其部分基因,從而形成兩個新的個體。

適用于二進制編碼個體或浮點數(shù)編碼個體的交叉算子:

  1. 單點交叉(One-point Crossover):指在個體編碼串中只隨機設(shè)置一個交叉點,然后再該點相互交換兩個配對個體的部分染色體。

  2. 兩點交叉與多點交叉:

    (1) 兩點交叉(Two-point Crossover):在個體編碼串中隨機設(shè)置了兩個交叉點,然后再進行部分基因交換。

    (2) 多點交叉(Multi-point Crossover)

  3. 均勻交叉(也稱一致交叉,Uniform Crossover):兩個配對個體的每個基因座上的基因都以相同的交叉概率進行交換,從而形成兩個新個體。

  4. 算術(shù)交叉(Arithmetic Crossover):由兩個個體的線性組合而產(chǎn)生出兩個新的個體。該操作對象一般是由浮點數(shù)編碼表示的個體。

咳咳,根據(jù)國際慣例。還是抓一個最簡單的二進制單點交叉為例來給大家講解講解。

二進制編碼的染色體交叉過程非常類似高中生物中所講的同源染色體的聯(lián)會過程――隨機把其中幾個位于同一位置的編碼進行交換,產(chǎn)生新的個體。

image

對應(yīng)的二進制交叉:

image

5.6 變異--基因突變(Mutation)

遺傳算法中的變異運算,是指將個體染色體編碼串中的某些基因座上的基因值用該基因座上的其它等位基因來替換,從而形成新的個體。

例如下面這串二進制編碼:

101101001011001

經(jīng)過基因突變后,可能變成以下這串新的編碼:

001101011011001

以下變異算子適用于二進制編碼和浮點數(shù)編碼的個體:

  1. 基本位變異(Simple Mutation):對個體編碼串中以變異概率、隨機指定的某一位或某幾位僅因座上的值做變異運算。

  2. 均勻變異(Uniform Mutation):分別用符合某一范圍內(nèi)均勻分布的隨機數(shù),以某一較小的概率來替換個體編碼串中各個基因座上的原有基因值。(特別適用于在算法的初級運行階段)

  3. 邊界變異(Boundary Mutation):隨機的取基因座上的兩個對應(yīng)邊界基因值之一去替代原有基因值。特別適用于最優(yōu)點位于或接近于可行解的邊界時的一類問題。

  4. 非均勻變異:對原有的基因值做一隨機擾動,以擾動后的結(jié)果作為變異后的新基因值。對每個基因座都以相同的概率進行變異運算之后,相當(dāng)于整個解向量在解空間中作了一次輕微的變動。

  5. 高斯近似變異:進行變異操作時用符號均值為P的平均值,方差為P**2的正態(tài)分布的一個隨機數(shù)來替換原有的基因值。

06 代碼實現(xiàn)環(huán)節(jié)

好了,上面我們介紹了一大截具體原理。現(xiàn)在就是把各個具體的零部件組裝起來,動手寫我們的代碼了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內(nèi)容