迴圈是程式的基本語法之一,每個程式語言都會有迴圈。大致上分成兩種
今天這篇不講語法,講一些比較深入要去探討的問題:
現在很多工程師可能透過很多管道入行,有自學的,有拜師的,有上課的,有boot camp的,當然也有本科生繼續留在這個行業裡打拼。然而,知道Big O的應該就沒那麼多了。
什麼是Big-O?可以把它想像成一個衡量程式複雜度的指標,之所以叫Big的原因是因為他是指標的上指標:所以也有Small O以及其他各種的Notation。而這個指標會應用在兩個維度上:空間(記憶體)及時間(執行時間)
Big-O的介紹很多,我在這裡就不再贅述了。
為什麼要有這個指標?在過去那個CPU和RAM都很貴的年代,工程師追求的是用最便宜的方法執行程式,所有的工程師無不想方設法去找出有效率的方式來執行程式。
cc https://cs.techruto.com/2017/05/big-oh-notation-theory-and-calculation.html
為什麼要在這裡提Big-O?因為一個迴圈,就是一個級數的差別,其實也不難想像,因為迴圈的設計就是在原地做同樣的事情N遍,而如果有兩層迴圈,那就要在原地做N*M遍,以此類推。
就因為迴圈是那麼的容易,但又那麼的昂貴,在使用迴圈時要更加注意:是否真的有必要使用迴圈?有沒有更好的方法可以取代?例如用HashSet取代Array,用Binary Search取代原本的逐一搜尋,把重要的值存在變數裡….等等。
cc http://blog.benoitvallon.com/data-structures-in-javascript/data-structures-in-javascript/
熟悉愈多種語言提供的資料結構對工程師愈有利,如果一個工程師只會用Array或者List,其實是相當不足的:這己經是一個什麼都東西準備好隨時可以用的時代,應該透過更多管道讓自己強壯起來。
在寫迴圈時,最常碰到的錯誤,就叫Off-By-One。什麼是Off-By-One?就是迴圈在計數時,多算了一個,而造成程式在執行時發生錯誤,例如:
var array = new int[10];
for(int i = 0 ; I <= array.Length ; i++){
Show(array[i]);
}
這段程式會嘗試印出整個陣列,但因為計數器的範圍設定錯誤,會跑到i[10],然後拋出index out of range exception。
看似很蠢的錯誤,但卻經常發生。
這個其實很難避免,就算是手指有著肌肉記憶也常會多打出錯誤的條件。比較好的做法是:利用比較新的的語法,例如foreach或者LINQ來處理迴圈,避免OBOE。
foreach(var element in array){
Show(element);
}
有沒有trade off?當然有,效能會有所影響,但以語法來看,我會建議如果沒有一定需要去計數的話,還是使用foreach比較好。
前面講到工程師應該要了解資料結構,除了知道有那些外,還要注意使用上是否有隱藏了一些效能上的問題。
在前面我們說到了Big-O,他有一個很簡單的計算方法,就是看眼前的迴圈有幾個。而SDK可能把這方面的資訊包裝了起來,例如:
HashSet<string> hashSet = new HashSet<string>();
hashSet.Contains("HelloWorld");
好像沒有迴圈對吧,但如果查看Contains的實作方法:
public bool Contains(T item)
{
if (this.m_buckets != null)
{
int hashCode = this.InternalGetHashCode(item);
for (int index = this.m_buckets[hashCode % this.m_buckets.Length] - 1; index >= 0; index = this.m_slots[index].next)
{
if (this.m_slots[index].hashCode == hashCode && this.m_comparer.Equals(this.m_slots[index].value, item))
return true;
}
}
return false;
}
它還是一個迴圈,雖然效能上還是有調整過(例如它是使用bucket,所以搜尋的範圍比較小),但這個隱藏成本經常被忽略。
除此之外,有些像LINQ的工具也有很多方便又神奇的功能可以使用,然而使用它可能要付出更大的成本:無論是時間或空間。不是不能使用,而是使用時一定要先了解使用方法,避免眼前看起來很漂亮,但實際卻折損了效能。
以前我聽說數學系的把高等微積分當成小說在看,我覺得程式設計師應該把資料結構與演算法當小說看,總會看出一些有趣的東西。
如果不想看那麼難的東西,可以看看這本書:雖然是為面試準備的,但其實裡面很多有趣的技術可以學習。