天天看點

走下神壇吧,算法!

走下神壇吧,算法!

作者 | 周林

引言

在網際網路、大資料、人工智能火爆的今天,“算法”這個詞幾乎婦孺皆知,業已成為“高薪”“牛X”的代名詞。

應不少朋友的邀請,特連載本系列,旨在用最通俗的方式——“”講人話、無廢話、看得懂、用得上“”——将位于神龛之上的算法送進尋常百姓家。

本篇作為系列的第一篇,采用“What、Why、How”文章結構,來給大家普及一下算法的基本概念(也糾正一些朋友的錯誤概念)。

What is Algorithm?(算法是個什麼鬼 )

為了不落入俗套,本文不會重複wiki上“算法”的官方定義,而采用啟發式結構來闡述算法的本質,試想平時在遇到問題的時候,我們是如何解決的。

樸素而廣泛的過程方法論如下:

       1. 重新定義問題,結構化描述

       2. 根據重定義,歸類問題

       3. 根據問題類别,做經驗比對

       4. 根據比對結果,分支處理:若比對,采用經驗方法;若比對不上,設計開發新方法

       5. 疊代更新經驗庫,增強面向未來問題的能力

       與算法相關的就是上面的第3步~第5步。

簡單來說,算法本質是:解決某類問題的方法。如果方法已經在經驗庫裡了,直接拿來主義,也就是“既有算法”;如果不在,那麼設計開發的新方法,新方法就是“新算法”。

當然還有一種情況:雖然經驗庫裡有針對該類問題的方法了,但是設計開發了一個更有效的新方法,那麼也稱為“新算法”。下面來對幾個關鍵點進行闡述!!!

什麼是“更有效的算法”?

“更有效”的背後邏輯其實比較的就是“代價”,或者稱為“開銷”。經濟上衡量就是成本,它分為兩個次元:時間成本和資源成本。

資源成本在計算機上的展現就是硬碟、記憶體、CPU等一系列硬體資源開銷。對這些硬體資源開銷進一步抽象,就是空間成本。

算法其實從學科分類上講,屬于計算數學,計算數學屬于應用數學。用學科術語來描述時間成本與空間成本,就是計算複雜度,很自然地,它也有兩個次元:時間複雜度和空間複雜度。描述複雜度的數學符号是O()。後面我們會詳細介紹O()的表達。

綜上所述,所謂的“更有效”的算法,指的就是時間複雜度或者空間複雜度更優的算法。

 為什麼要“重新定義問題,結構化描述”?

把人腦也看做一台機器的話,很顯然這台機器的運作方式和效率與計算機有所不同(盡管現在的機器學習在盡可能地模拟人腦的機理,但是兩者至少在現階段還有本質不同)。

人腦在連續信号和非結構化場景下的處理能力是卓越的,但是計算機隻能處理離散信号,并且必須最終轉化成結構化資料才能進行處理(盡管現在的機器學習可以通過自我學習來将資料結構化)。

用一張圖來描述這個過程就是:

走下神壇吧,算法!

Why to use Algorithm?(算法有什麼鬼用)

從上面對解決現實問題的過程方法論的描述中,其實已經可以看出算法的價值就在于:經驗的重用。

套用一句IT行話就是“不要重複制造輪子”。好了,既然現在你已經對算法有了大緻的感性認識,那麼接下來根據人類的學習習慣,就需要來看看抽象的算法概念,在現實裡到底“長什麼模樣”。

很多人認為“算法=程式或者程式”,這其實是一個狹義的了解。如前面所說的,算法的本質是解決某類問題的方法,而程式或者代碼隻是方法的一種表達形式而已。你也可以用自然語言或者僞代碼來進行表達算法。

算法的“模樣”(應對電燈不工作的算法——代碼方式):

public STATUS_CODE lamp_issue_handler(){
  STATUS_CODE ret_val = UNKNOWN_ISSUE;
 if (!isPowerOn(this)) {
   ret_val = powerOn(this) ? NOT_POWER_ON_ISSUE : POWER_ISSE;
  }
  else if(!isBulbCrash(this)) {
   ret_val = replaceBulb(this) ? BULB_CRASH_ISSUE : REPLACE_ISSUE;
  }
  else {
    ret_val = fixBulb(this) ? BULB_FIXABLE_ISSUE : FIX_FAILURE_ISSUE;
  }
  return ret_val;
}      

  算法的“模樣”(應對電燈不工作的算法——自然語言方式):

首先檢查電源是否接好了:沒有接好,接上。

如果接上了仍然不工作,看看燈泡是否燒壞了:如果是,換個新燈泡

如果燈泡沒有燒壞,修理燈泡

算法的“模樣”(應對電燈不工作的算法——流程圖方式):

走下神壇吧,算法!

How to use Algorithm?(如何使用算法)

算法的本質就是方法,既然是方法,就是一系列的操作;既然是操作,就必然有作用對象。在軟體程式設計中,這樣的作用對象就是“資料結構”。

怎麼來了解資料結構呢?

前面我們講到了,解決問題的第一步就是要将問題結構化描述。結構化描述的本質就是利用一系列便于操作的“基礎元素”來表達。

那麼怎樣的“基礎元素”是便于操作的呢?

首先我們要清楚,操作的主體是誰。從上一段的闡述來看,這個主體貌似是算法,但是我們注意,算法不是憑空去運作的,是要在計算機上運作的。

是以歸根結底,操作的主體是計算機。是以,這裡所謂的“便于操作”指的是便于計算機運作。

計算機運作有兩個次元:硬體次元和軟體次元。

1.從硬體次元看:

學過計算機組成原理就知道,程式是在計算機的CPU高速緩存和記憶體中運作的。對應的存儲結構,通常都是線性的。

為了充分提升線性結構的性能優勢,硬體廠商(如CPU廠商)在設計硬體時,就抽象了針對一些結構(如堆棧)的操作(如壓棧、出棧),是以很自然地,這樣的結構就應該作為資料結構。

2.從軟體次元看:

我們編寫的應用程式一般不會直接運作在硬體之上,而是運作在作業系統、運作時或者虛拟機(如JVM)之上。

是以作業系統、運作時或者虛拟機已經抽象的結構(如數組、隊列、樹、圖等),也應該作為資料結構。

上面贅述了這麼多,其實就是要表達一個觀點:算法是要配合資料結構的,抛開資料結構談算法就是無源之水、無根之樹。

看到這裡,我想你一定徹底明白,為什麼圖靈獎得主尼古拉斯·沃斯會提出那個著名的等式了:程式 = 算法 +資料結構。

總結

看到這裡,相信你已經對算法這個概念已經不再陌生,它對于你而言也不再高高在上。

無論在大學學習,還是在工作中,大家都幾乎被一種說法反複洗腦:算法非常重要,它是計算機的靈魂。

在這裡,我想糾正一下這個錯誤的觀點。首先,廣義的算法不僅僅隻是軟體算法;再次,計算機系統不僅僅隻是由軟體構成,還有硬體。

硬體涉及到材料科學、制造技術等一系列技術,這些是不能簡單被算法替代的。是以,脫離上下文、一味強調算法的重要性是耍流氓。

那麼:你對算法了解有多少呢?

歡迎關注

走下神壇吧,算法!

繼續閱讀