衆所周知,計算機是從0開始計數,而不是咱們平時經常使用的從1開始計數,但你有想過爲何嗎?html
其實不是計算機從0開始計數而是多數編程語言中的數組都使用0做爲起始下標,又是爲何呢?python
通過大量的搜索查證,我終於找到了答案。git
故事還要從一位真正的大佬艾茲格·迪科斯徹(Dijkstra)講起,github
這裏貼出我翻譯後的大佬語錄:爲了表示天然數1,2,3,4...14...的子序列,通常有四種序列的表示方法:算法
a) 2 ≤ i < 13編程
b) 1 < i ≤ 12數組
c) 2 ≤ i ≤ 12網絡
d) 1 < i < 13編程語言
以上的幾種表達方式裏,有哪種比其餘的好嗎?ui
是的,a和b有較爲明顯的優勢:他們上下界數值之間的差值就是這個序列的長度。在任何一種表示中,兩個子序列相鄰,最好是其中一個的上界等於另一個的下界,但這還不能抉擇出a和b方式哪一種更好,繼續分析;
假設序列裏要包含最小的天然數,若是使用b和d這種方式,那下界就必須是個非天然數,這就不太好看了,因此這裏更傾向於使用a和c的方式,即便用≤方式表示下界。這裏若是使用≤表示上界,那一個空的子序列表示方式也將會很醜陋,因此對於上界,大佬的結論是更喜歡使用a和d中的<方式,結合上一小段的分析,a方式最終獲勝,繼續分析;
當須要表示一個長度爲N的序列時,若是想經過下標來區分其中的元素,那又來了一個棘手的問題:初始元素的下標值應該用多少呢,若是從1開始,那範圍變成1 ≤ i < N+1,若是從0開始,那範圍會是0 ≤ i < N,顯而後一種方式更優雅更直觀,因此大佬最後的結論是本身更傾向於一個序列的表示最好從0開始。
大佬語錄總結
"在進行範圍表達的時候,使用左閉右開的方式更優雅,他思考過,在處理長度爲N的序列時,到底第一個元素的下標使用0更合適仍是使用1更合適?他的出發點很簡單,那就是哪一種方式更優雅。首先肯定使用左閉右開的方式,當下標從1開始時,下標範圍爲1<=i<n+1,當下標爲從0開始時,下標範圍爲0<=i<n,顯而後面這種方式更加優雅,因此他傾向於使用0做爲第一個元素的下標。"
難道就只有這一個緣由嗎?其實下標從0開始主要的意義是表示偏移,下面舉例:
數組爲何起始下標是0?其實數組是一種線性結構,它有一段連續的內存空間,存儲一組具備相同類型的數據。
如圖,拿一個長度爲10的int類型數組舉例,系統就會爲該數據分配一段連續的內存空間,空間大小爲40個字節,其中內存塊首地址base_address = 100。
數組是能夠隨機訪問的,當訪問第i個元素時,須要定位第i個元素的地址,定位公式以下:
第i個元素地址=base_address + i * data_type_size
其中data_type_size表示數組中元素類型的大小,int類型大小是4字節,因此公式裏data_type_size等於4。在這裏,下標能夠理解爲偏移,數組的首地址就是base_address,其中a[0]就是偏移爲0的位置,a[i]就是偏移了i個data_type_size大小的位置,因此計算a[i]地址的公式爲:
a[i]地址=base_address + i * data_type_size
這裏若是數組下標從1開始,那麼a[i]地址的公式爲:
a[i]地址=base_address + (i - 1) * data_type_size
兩個公式顯而易見,下標從0開始的更加簡單,後者從1開始,每次訪問數組元素都須要額外作一次減法操做,效率更低。
咱們知道在Python中數組也是將0做爲起始下標,對此Python之父Guido van Rossum也給出過正面回答,下面貼出他的翻譯後的語錄:
大佬語錄
關於這個問題以前就有人在Twitter上詢問過我,我給出過回答。這個問題我思考過好久:ABC語言是Python的祖先之一,使用的索引就是從1開始的,而另外一門對Python有重要影響的C語言,它的索引就是從0開始。以前的幾門編程語言(Algol,Fortran, Pascal)有使用1做爲起始索引的,有使用某個變量做爲索引。而推進我使用0做爲起始索引的緣由之一就是切片語法。
讓咱們先來看看切片的用例,可能關於切片最多見的用法就是「取前n個元素」和「取從i開始的後n個元素」,若是在使用這兩種用法時不須要帶有+1或者-1的補償操做,那代碼會很優雅。
使用基於0的索引方式,那上面兩種切片用法就會很是漂亮:a[:n]和a[i:i+n],前者是a[0:n]的縮寫。
使用基於1的索引方式,若是你想用a[:n]表示取前n個元素的意思,要麼使用閉合區間切片語法,要麼使用起始索引加切片長度做爲參數的方法。半開區間切片方法若是和基於1的索引方式結合起來那代碼將會變得不優雅。而若是使用閉合區間切片語法的話,爲了從第i位索引開始取n個元素,那就須要把表達式寫成a[i, i+n-1]。這樣看來也許使用切片起始位+長度的方式在基於1的索引方法中更合適?這樣你能夠寫成a[i:n],而且ABC語言就是這麼作的,你能夠寫成a@i|n這種特別的語法。
可是,index:length這種方式在其它狀況下也適用嗎?我有點記不清了,但我認爲我確實是被半開區間這種優雅的語法迷住啦。特別是當兩個切片操做相鄰時,第一個切片的終點索引是第二個切片的起始索引時,這種語法簡直太漂亮啦。例如你想要將一個字符串使用i和j分紅三部分,這三部分會是a[:i],a[i:j]和a[j:],真是太漂亮啦。
這就是爲何Python使用0做爲起始索引的緣由。
看到這裏你知道爲何不少編程語言都是從0開始計數了嗎?
文中若是有翻譯的不妥之處還請你們指正。
參考資料
https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD831.html
https://blog.csdn.net/csdnsevenn/article/details/107421466
https://docle.github.io/2018/08/26/Why-Numbering-Should-Start-At-Zero/
https://www.reddit.com/r/Python/comments/1p2za1/guido_van_rossum_why_python_uses_0based_indexing/
版權申明:內容來源網絡,版權歸原創者全部。