web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的

這篇文章主要講解了“web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的”吧!

我們提供的服務(wù)有:成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、涼州ssl等。為上千企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的涼州網(wǎng)站制作公司

數(shù)組的隨機(jī)訪問

盡管大家都知道了什么是數(shù)組,但是還是用官方的術(shù)語描述一下:數(shù)組(Array)是一種線性表數(shù)據(jù)結(jié)構(gòu)。它用一組連續(xù)的內(nèi)存空間,來存儲(chǔ)一組具有相同類型的數(shù)據(jù)。

我們可以抓住里面的幾個(gè)重點(diǎn)詞匯,來充分理解數(shù)組這種結(jié)構(gòu)。 

1、線性表,就是數(shù)據(jù)的排列從前到后順序排列,就像一條線,像隊(duì)列、棧列表、數(shù)組等都是線性表結(jié)構(gòu)。 

web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的

當(dāng)然有線性表結(jié)構(gòu)就有非線性表結(jié)構(gòu)
web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的

2、連續(xù)內(nèi)存空間和相同的數(shù)據(jù)類型。為啥數(shù)據(jù)訪問一個(gè)數(shù)據(jù)效率非常高?那是因?yàn)閿?shù)組的定義將數(shù)組這種結(jié)構(gòu)定好了規(guī)矩,線性連續(xù)給了我們快速隨機(jī)訪問的機(jī)會(huì)。但是同時(shí)也帶來了不好的地方,如果我們向其中插入或者刪除一條數(shù)據(jù)是比較費(fèi)勁的。 

來看看數(shù)組是怎么實(shí)現(xiàn)隨機(jī)訪問的? 

假設(shè)有這么一個(gè)數(shù)組:
java int[] a = new int[10]; 
操作系統(tǒng)給分配了一塊連續(xù)的內(nèi)存空間,假設(shè)為1000~1039,那么內(nèi)存的首地址就是base_add = 1000
web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的

如果你去走訪親戚,你需要知道的是什么?親戚家的地址吧(具體到門牌號(hào)),內(nèi)存也一樣,我們想讀取內(nèi)存里面的數(shù)據(jù),操作系統(tǒng)也是通過內(nèi)存的地址來訪問的,那么問題來了,內(nèi)存的地址是怎么知道呢? 

這就涉及到操作系統(tǒng)的尋址,比如我想獲取a[2]的值,那么操作系統(tǒng)先會(huì)根據(jù)下面的公式計(jì)算對(duì)應(yīng)內(nèi)存的地址:

 a[2]的地址 = base_add + 2 * data_unit_size 

dataunitsize表示該數(shù)據(jù)類型每個(gè)元素的大小,當(dāng)前是int類型為4個(gè)字節(jié),所以算出來a[2]的地址就是1008 

那是不是可以說數(shù)組的查找的時(shí)間復(fù)雜度就是O(1)?當(dāng)然不是了,正常情況下我們查找數(shù)可不是通過下標(biāo)來查找的,我們是通過值來查找的,即便是二分查找時(shí)間復(fù)雜度也是O(logn)。 

刪除和插入怎么就低效了

1、插入操作
假設(shè)我們要在長(zhǎng)度為n的數(shù)組的第k個(gè)位置插入一個(gè)數(shù)據(jù),我們就要講第k~n的數(shù)往后挪,同理如果在最后插入就不需要挪位置,如果在第一個(gè)位置插入就要挪n個(gè)數(shù),所以平均時(shí)間復(fù)雜度就是:(1+2+3+...+n)/n=O(n)

當(dāng)然,如果不要求插入后順序還保持原來一樣,有個(gè)討巧的插入方法就是講第K個(gè)元素放到最后,將待插入的數(shù)放到第K個(gè)位置。 

舉個(gè)例子,假設(shè)數(shù)組 a[10]中存儲(chǔ)了如下 5 個(gè)元素:a,b,c,d,e。 

我們現(xiàn)在需要將元素 x 插入到第 3 個(gè)位置。我們只需要將 c 放入到 a[5],將 a[2]賦值為 x 即可。最后,數(shù)組中的元素如下:a,b,x,d,e,c。
web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的

2、刪除操作

其實(shí)和插入操作是相似的,當(dāng)我們對(duì)長(zhǎng)度為n的數(shù)組的第K個(gè)數(shù)組進(jìn)行刪除時(shí),需要對(duì)后面的數(shù)據(jù)進(jìn)行向前搬移操作,同理,時(shí)間復(fù)雜度和插入一樣也是O(n),這里就不詳細(xì)介紹了。

當(dāng)然,在不考慮維持連續(xù)性的特殊情況下,為了提高刪除的效率,沒必要每次刪除立即進(jìn)行搬移操作,不然如果連續(xù)刪除數(shù)據(jù),就要連續(xù)進(jìn)行多次的搬移。比較討巧的辦法是將待刪除的元素進(jìn)行標(biāo)記,實(shí)際未做刪除,等等內(nèi)存不足的時(shí)候,將這些標(biāo)記的數(shù)據(jù)統(tǒng)一進(jìn)行刪除操作。這樣就會(huì)大大減少刪除操作帶來的大量數(shù)據(jù)搬移操作。 

災(zāi)難!數(shù)組越界啦

對(duì)于Java來說發(fā)生數(shù)據(jù)越界的時(shí)候會(huì)拋出異常,但是對(duì)于有些語言比如C語言發(fā)生數(shù)組越界的時(shí)候并不會(huì)給你異常提示,比如下面這段代碼: 

int i = 0; int arr[3] = {0};for(;i<=3;i++) {  arr[i] = 0;  System.out.println("test");  }

顯然定義的是長(zhǎng)度為3的數(shù)組,但是循環(huán)條件是<=,所以會(huì)訪問到數(shù)組外面的內(nèi)存,而a[3]的地址剛好是存儲(chǔ)i的內(nèi)存,所以當(dāng)循環(huán)到a[3]時(shí)又賦值為0,相當(dāng)于i=0;所以這個(gè)循環(huán)永遠(yuǎn)結(jié)束不了,“hello world”會(huì)一直打印。 

所以,對(duì)于C語言來說,如果沒控制好下標(biāo),發(fā)生數(shù)組越界會(huì)出現(xiàn)莫名其妙的邏輯問題,還很難調(diào)試。這也是很多病毒利用數(shù)組越界來非法訪問內(nèi)存來攻擊系統(tǒng)。 

各種容器滿天飛,還需要數(shù)組?

對(duì)于Java開發(fā)者來說,ArrayList再熟悉不過了,它為我們封裝好了各種API來操作,比使用數(shù)組方便的多,而且是支持動(dòng)態(tài)擴(kuò)容的,因?yàn)閿?shù)組是要提前訂好大小的,當(dāng)大小不滿足的時(shí)候,需要重新定義大的數(shù)組進(jìn)行復(fù)制操作,這顯然很不方便,而容器類是內(nèi)部有動(dòng)態(tài)的分配的機(jī)制,當(dāng)大小不夠的時(shí)候自動(dòng)的擴(kuò)容,當(dāng)然這也是非常耗性能的。如果能確定數(shù)據(jù)的大小,提前指定容器的大小更好。 

那是不是意味著數(shù)組沒有存在的必要,那也不是的,比如在下面的情況: 

  • ArrayList是不能存儲(chǔ)基本數(shù)據(jù)類型的,需要使用他們對(duì)應(yīng)的裝箱類,而拆箱和裝箱顯然都是非常耗性能的,如果特別關(guān)注性能,又需要使用基本數(shù)據(jù)類型,使用數(shù)組比使用ArrayList性能更好

  • 定義多維數(shù)組時(shí),使用數(shù)組更加的直觀

  • 如果數(shù)據(jù)大小事先知道,而對(duì)數(shù)據(jù)的操作比較簡(jiǎn)單。用不到ArrayList的大多API,這時(shí)候可以優(yōu)先使用數(shù)組

小結(jié):對(duì)于上層業(yè)務(wù)開發(fā)者,由于業(yè)務(wù)變化大,操作數(shù)據(jù)變化頻繁,使用容器更加方便,犧牲一點(diǎn)性能對(duì)系統(tǒng)的整體功能影響不大。但是如果是做比較偏底層的開發(fā)就需要關(guān)注性能了,性能一丁點(diǎn)的提升,影響也是很廣泛的,所以選擇數(shù)組比較合適。

回到主題

為什么數(shù)組從0開始呢?
從數(shù)組存儲(chǔ)的內(nèi)存模型來看,下標(biāo)比較確切的定義是“偏移”,如果用a來表示數(shù)組的首地址,那么a[0]就表示偏移為0的位置。a[x]就表示偏移x個(gè)類型大?。╥nt 4個(gè)字節(jié))的的位置。java a[x]_address = base_address + x * data_type_size;

但是如果從1開始計(jì)數(shù)呢,那么尋址公式就變成:
java a[x]_address = base_address + (x-1) * data_type_size;  
顯然要多運(yùn)算減一的操作,對(duì)于數(shù)組數(shù)據(jù)結(jié)構(gòu)的定義是偏基礎(chǔ)庫的,對(duì)于性能要求當(dāng)然是要追求極致的,多一步和少一步運(yùn)算都是非常重要的參考點(diǎn),所以為了更好的性能選擇從0開始而不是從1開始。 

當(dāng)然也有歷史因素,因?yàn)樽钤绲腃語言設(shè)計(jì)者使用從0開始的,所以后面的語言都延續(xù)了這一做法,這樣能減少程序員學(xué)習(xí)語言的成本。當(dāng)然也有一些不是從0開始的語言,這里就不舉例了,感興趣的同學(xué)可以自行去搜索一下。 

感謝各位的閱讀,以上就是“web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

網(wǎng)站標(biāo)題:web開發(fā)中為什么很多語言的數(shù)組下標(biāo)是從0開始的
文章起源:http://bm7419.com/article16/jdsedg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、網(wǎng)站設(shè)計(jì)搜索引擎優(yōu)化、商城網(wǎng)站、響應(yīng)式網(wǎng)站、標(biāo)簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)