1. 數(shù)組:為什么很多編程語言中數(shù)組都是從0開始姚建?

1. 數(shù)組:為什么很多編程語言中數(shù)組都是從0開始矫俺?

在大部分編程語言中,數(shù)組都是從0開始編號的,但你是否下意識想過厘托,為什么數(shù)組要從0開始編號友雳,而不是1開始呢? 從1開始不是更符合人類的思維習慣嗎铅匹?下面以這個問題來學習數(shù)組押赊。

數(shù)組的基本概念與特性

什么是數(shù)組?

什么是數(shù)組包斑?估計你心中已經(jīng)有了答案流礁。不過,這里還是總結(jié)一下舰始。數(shù)組(Array)是一種線性表數(shù)據(jù)結(jié)構(gòu)崇棠。它用一組連續(xù)的內(nèi)存空間,來存儲一組具有相同類型的數(shù)據(jù)丸卷。
這里定義里有幾個關(guān)鍵詞枕稀,理解了這幾個關(guān)鍵詞,就能徹底掌握數(shù)組的概念了谜嫉。

線性表(Linear List)萎坷。顧名思義,線性表就是數(shù)據(jù)排成像一條線一樣的結(jié)構(gòu)沐兰。每個線性表上的數(shù)據(jù)最多只有前和后兩個方向哆档。除了數(shù)組,鏈表住闯、隊列瓜浸、棧等也是線性表結(jié)構(gòu)。

而與它相對立的概念是非線性表,比如二叉樹比原、堆插佛、圖等。之所以叫非線性量窘,是因為在非線性表中雇寇,數(shù)據(jù)之間并不是簡單的前后關(guān)系。

總結(jié)下數(shù)組的特性

  • 第一是線性表(Linear List)蚌铜。
  • 第二是連續(xù)的內(nèi)存空間和相同類型的數(shù)據(jù)锨侯。

正是因為這兩個限制,它才有一個堪稱“殺手锏”的特性 “隨機訪問” 冬殃。但有利就有弊囚痴,這兩個限制也讓數(shù)組的很多操作變得非常低效,比如要想在數(shù)組中刪除审葬、插入一條數(shù)據(jù)深滚,為來保證連續(xù)性骂束,就需要左大量的數(shù)據(jù)搬移工作。

如何實現(xiàn)隨機訪問成箫?

數(shù)組到底是如何實現(xiàn)根據(jù)下標隨機訪問數(shù)組元素的展箱?
例如:長度為 10 的 int 類型的數(shù)組 int[] a = new int[10]

  1. 計算機給數(shù)組 a[10] ,分配了一塊連續(xù)內(nèi)存空間 1000 ~ 1039 蹬昌;
  2. 內(nèi)存塊的首地址為 base_address = 1000 混驰;
  3. 計算機會給每個內(nèi)存單元分配一個地址,計算機通過地址來訪問內(nèi)存中的數(shù)據(jù)皂贩。

當計算機需要隨機訪問數(shù)組中的某個元素時栖榨,它會通過下面的尋址公式,計算出該元素存儲的內(nèi)存地址:
a[i]_address = base_address + i * data_type_size

arr[i] 首地址 = 數(shù)組內(nèi)存塊首地址 + 數(shù)據(jù)類型大小 * i明刷,其中 i 為偏移量婴栽,其中 data_type_size 表示數(shù)組中每個元素的大小。

上面這個例子里面:
base_address :內(nèi)存塊的首地址辈末。
data_type_size : 表示數(shù)組中每個元素的大小愚争,比如目前數(shù)組中存儲的是 int 類型數(shù)據(jù),所以 data_type_size 就為 4 個字節(jié)挤聘。

數(shù)組時間復雜度

數(shù)組(Array)是一種線性表數(shù)據(jù)結(jié)構(gòu)轰枝。它用一組連續(xù)的內(nèi)存空間,來存儲一組具有相同類型的數(shù)據(jù)组去。
注意點:

  1. 數(shù)組是一種線性表鞍陨;
  2. 連續(xù)的內(nèi)存空間和相同類型的數(shù)據(jù)。
    由于第二個性質(zhì)从隆,數(shù)組支持 “隨機訪問”诚撵,根據(jù)下標隨機訪問時間復雜度為 O(1)键闺,但是在數(shù)組中刪除寿烟、插入數(shù)據(jù)時需要做數(shù)據(jù)搬移工作艾杏。

低效的“插入”和“刪除”操作

1. 插入操作

假如數(shù)組的長度為 n盅藻,我們需要將一個數(shù)據(jù)插入到數(shù)據(jù)的第 k 個位置购桑,則需要將 [k , n] 位元素都順序地往后挪動一位。

  • 最好的情況:時間復雜度為O(1)氏淑,此時在數(shù)組末尾插入元素。
  • 最壞的情況:時間復雜度為O(n)假残,此時在數(shù)組開頭插入元素炉擅。
  • 平均的情況:時間復雜度為O(n),因為在每個位置插入元素的概率相同阳惹,故(1+2+3+......+n)/ n = O(n)谍失。

2. 刪除操作

和插入操作一樣,為了保證內(nèi)存的連續(xù)性莹汤,刪除操作也需要搬移數(shù)據(jù)。

  • 最好的情況:時間復雜度為O(1)抹竹,此時刪除數(shù)組末尾的元素。
  • 最壞的情況:時間復雜度為O(n)窃判,此時刪除數(shù)組開頭的元素喇闸。
  • 平均的情況:時間復雜度為O(n),因為刪除每個位置的元素的概率相同燃乍,故(1+2+3+......+n)/ n = O(n)跨蟹。

更高級用法

在某些特殊場景下窗轩,在不追求數(shù)組中數(shù)組的連續(xù)時座咆,我們將多次刪除操作集中在一起執(zhí)行,會提高刪除的效率介陶?
例如:假設(shè)有一個數(shù)組 a , 長度為 10,存儲了 8 個元素哺呜,分別為 a,b,c,d,e,f,g,h 。現(xiàn)在我們依次刪除 a,b,c 三個元素:

a = [a,b,c,d,e,f,g,h];

為了避免 d,e,f,g,h 這個幾個數(shù)據(jù)會被搬移 3 次国撵,我們先記錄已經(jīng)刪除的數(shù)據(jù)(每次刪除操作并不是真正的搬移數(shù)據(jù)玻墅,只是記錄數(shù)據(jù)已經(jīng)被刪除)。當 a 數(shù)組沒有空間存儲數(shù)據(jù)時澳厢,這才觸發(fā)依次真正的刪除操作囚似,這樣就減少了刪除操作導致的數(shù)據(jù)搬移。

上述這個操作其實就是 JVM標記清除垃圾回收算法 的核心思想线得。

3. 警惕數(shù)組訪問越界

在 C 語言中,只要不是訪問受限的內(nèi)存搬素,所有的內(nèi)存空間都是可以自由訪問的。如果疏忽會造成嚴重的后果熬尺。當然谓罗,Java語言會自動檢測。

4. 總結(jié)
**
數(shù)組是最基礎(chǔ)檩咱、最簡單的數(shù)據(jù)結(jié)構(gòu)。數(shù)組用一塊連續(xù)的內(nèi)存空間刻蚯,來存儲相同類型的一組數(shù)據(jù),最大特點就是隨機訪問元素躬充,并且時間復雜度為 O(1)讨便。但是插入、刪除操作也因此比較低效霸褒,時間復雜度為O(n)。

數(shù)組和鏈表的區(qū)別

  • 數(shù)組支持隨機訪問废菱,根據(jù)下標隨機訪問的時間復雜度為O(1),注意數(shù)組查找衰倦,即便是排好序的數(shù)組梳凛,使用二分查找時間復雜度為O(logn)梳杏。
  • 鏈表適合插入淹接、刪除叛溢、時間復雜度為O(1)

最后總結(jié)一下:為什么大多數(shù)編程語言中,數(shù)組要從 0 開始編號楷掉,而不是從 1 開始呢厢蒜?

  • 第一:歷史原因, c 語言設(shè)計者用 0 開始計數(shù)數(shù)組下標斑鸦,之后 Java草雕、JavaScript等高級語言都效仿 C 語言,因此繼續(xù)沿用從 0 開始計數(shù)的習慣墩虹。部分語言數(shù)組不是從 0 開始計數(shù)的,比如 Matlab旬昭,還有部分語言支持負數(shù)下標菌湃,如 Python问拘。
  • 第二:從數(shù)組存儲的內(nèi)存模型上來看惧所,“下標”最確切的定義應該是 “偏移(offset)”。前面也講到或油,如果用 a 來表示數(shù)組的首地址驰唬,a[0] 就是偏移為 0 的位置,也就是首地址叫编,a[k] 就表示偏移 k 個 type_size 的位置,所以計算 a[k] 的內(nèi)存地址只需要用這個公式:

a[k]_address = base_address + k * type_size
但是卷谈,如果數(shù)組從1 開始計數(shù)霞篡,那我們計算數(shù)組元素 a[k] 的內(nèi)存地址就會變?yōu)椋?br> a[k]_address = base_address + (k-1)* type_size

對比兩個公式端逼,不難發(fā)現(xiàn),從 1 開始編號顶滩,每次隨機訪問數(shù)組元素都多來一次減法運算寸爆,對于 CPU 來說,就多來一次減法指令赁豆。

數(shù)組作為非常基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)着憨,通過下標隨機訪問數(shù)組元素又是其非澄竦眨基礎(chǔ)的編程操作,效率的優(yōu)化就要盡可能做到極致心铃,所以為來減少一次減法操作,數(shù)組選擇來從 0 開始編號去扣,而不是 1 開始。

以上謝謝大家唆铐,求贊求贊求贊奔滑!

?? 大佬們隨手關(guān)注下我的wx公眾號【一角錢小助手】和 掘金專欄【一角錢】 更多題解干貨等你來~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市王浴,隨后出現(xiàn)的幾起案子梅猿,更是在濱河造成了極大的恐慌,老刑警劉巖袱蚓,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異体斩,居然都是意外死亡,警方通過查閱死者的電腦和手機硕勿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門源武,熙熙樓的掌柜王于貴愁眉苦臉地迎上來想幻,“玉大人,你說我怎么就攤上這事脏毯。” “怎么了食店?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵吉嫩,是天一觀的道長。 經(jīng)常有香客問我自娩,道長,這世上最難降的妖魔是什么忙迁? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任姊扔,我火速辦了婚禮,結(jié)果婚禮上恰梢,老公的妹妹穿的比我還像新娘。我一直安慰自己共虑,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布妈拌。 她就那樣靜靜地躺著,像睡著了一般猜惋。 火紅的嫁衣襯著肌膚如雪培愁。 梳的紋絲不亂的頭發(fā)上著摔,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天谍咆,我揣著相機與錄音私股,去河邊找鬼。 笑死倡鲸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的峭状。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼劝赔,長吁一口氣:“原來是場噩夢啊……” “哼羔巢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起竿秆,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤幽钢,失蹤者是張志新(化名)和其女友劉穎歉备,沒想到半個月后匪燕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡龟再,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年尼变,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哀澈。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖割按,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情现柠,我是刑警寧澤束凑,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布栅盲,位于F島的核電站,受9級特大地震影響谈秫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拟烫,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一硕淑、第九天 我趴在偏房一處隱蔽的房頂上張望课竣。 院中可真熱鬧置媳,春花似錦、人聲如沸迂曲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽传黄。三九已至,卻和暖如春膘掰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工苍日, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留窗声,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓拦耐,卻偏偏與公主長得像见剩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子苍苞,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348