
眾所周知,計算機是從0開始計數,而不是我們平時常用的從1開始計數,但你有想過為什么嗎?
其實不是計算機從0開始計數而是多數編程語言中的陣列都使用0作為起始下標,又是為什么呢?
經過大量的搜索查證,我終于找到了答案,
故事還要從一位真正的大佬艾茲格·迪科斯徹(Dijkstra)講起,
- 提出“goto有害論”;
- 提出信號量和PV原語;
- 解決了“哲學家聚餐”問題;
- Dijkstra最短路徑演算法和銀行家演算法的創造者;
- THE作業系統的設計者和開發者;
- 第一個Algol 60編譯器的設計者和實作者;
- 與D. E. Knuth并稱為我們這個時代最偉大的計算機科學家的人,
這里貼出我翻譯后的大佬語錄:為了表示自然數1,2,3,4...14...的子序列,一般有四種序列的表示方法:
a) 2 ≤ i < 13
b) 1 < i ≤ 12
c) 2 ≤ i ≤ 12
d) 1 < i < 13
以上的幾種表達方式里,有哪一種比其他的好嗎?
是的,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/
著作權申明:內容來源網路,著作權歸原創者所有,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/236414.html
標籤:其他
上一篇:都說代碼注釋是程式員必備技能,但是你這注釋也太奇葩了吧!
下一篇:MySQL學習——操作自定義函式
