1. 程式人生 > >資料結構與算法系列3

資料結構與算法系列3

# 資料結構與算法系列3 # 寫在前面 前面兩章講了連結串列和動態陣列,我們這章來從記憶體的角度的來講講二者的區別 # 什麼是記憶體 ## 寫在前面: 由於本章是從記憶體的角度來講述陣列與連結串列,所以我們先來講講記憶體 ## 記憶體概述 記憶體是[計算機](https://baike.baidu.com/item/%E8%AE%A1%E7%AE%97%E6%9C%BA/140338)的重要部件之一。它是[外存](https://baike.baidu.com/item/%E5%A4%96%E5%AD%98/2445612)與[CPU](https://baike.baidu.com/item/CPU/120556)進行溝通的橋樑,計算機中所有程式的執行都在記憶體中進行。記憶體效能的強弱影響計算機整體發揮的水平。記憶體(Memory)也稱[記憶體儲器](https://baike.baidu.com/item/%E5%86%85%E5%AD%98%E5%82%A8%E5%99%A8/834392)和[主儲存器](https://baike.baidu.com/item/%E4%B8%BB%E5%AD%98%E5%82%A8%E5%99%A8/10635399),它用於暫時存放CPU中的運算資料,與[硬碟](https://baike.baidu.com/item/%E7%A1%AC%E7%9B%98/159825)等[外部儲存器](https://baike.baidu.com/item/%E5%A4%96%E9%83%A8%E5%AD%98%E5%82%A8%E5%99%A8/4843180)交換的資料。只要計算機開始執行,[作業系統](https://baike.baidu.com/item/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/192)就會把需要運算的資料從記憶體調到CPU中進行運算。當運算完成,CPU將結果傳送出來。記憶體的執行也決定計算機整體執行快慢的程度。記憶體條由[記憶體晶片](https://baike.baidu.com/item/%E5%86%85%E5%AD%98%E8%8A%AF%E7%89%87/3736671)、[電路板](https://baike.baidu.com/item/%E7%94%B5%E8%B7%AF%E6%9D%BF/10106124)、[金手指](https://baike.baidu.com/item/%E9%87%91%E6%89%8B%E6%8C%87/9950829)等部分組成。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/202102102147383.png) ## 記憶體工作原理 比如我們去考駕照,考駕照的地方有一個寄存櫃,你需要將你的東西寄存到寄存櫃裡 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214742447.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BqaDg4,size_16,color_FFFFFF,t_70) 假設每個櫃子只可以放一樣東西,你有兩樣東西需要寄存,因此需要兩個寄存櫃 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214749542.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BqaDg4,size_16,color_FFFFFF,t_70) 然後你就可以將你的兩樣東西寄存到箱子裡 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214753791.png) 然後你就可以放心的去考駕照了,等考好了再到對應的箱子裡取出自己的物品即可,這大致就是計算機記憶體的工作原理,計算機像是很多抽屜的集合,每個抽屜都有地址,就像下面一樣劃分成一個個區塊,一個個地址 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214757808.png) 需要將資料儲存到記憶體時,你請求計算機提供儲存空間,計算機給你一個儲存地址。需要儲存多項資料。有兩種基本方式---陣列和連結串列。他們並非都適用與所有場景。 # 陣列在記憶體中的分佈 陣列再記憶體中是連續分佈的,什麼是連續分佈呢,就拿上面的寄存櫃來說,比如寄存櫃有100個櫃子,你有四個東西要寄存,一個櫃子只能放一個東西,所以你要四個櫃子,連續分佈就是隻這四個櫃子要一個櫃子挨著一個櫃子連在一起,需要連號,比如1234,5678等等 **數字代表寄存的物品標號** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214804407.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BqaDg4,size_16,color_FFFFFF,t_70) ## 這種方式的優缺點是什麼呢? ### 我們再來舉一個例子 比如我們去組團看電影,看電影的時候一共有十個人,為了保證10個人能坐在一起,必須提前訂好10個連續的位置。這樣的好處就是能保證10個人可以在一起。但是這樣的缺點是,如果來的人不夠10個,那麼剩下的位置就浪費了。如果臨時有多來了個人,那麼10個就不夠用了,這時可能需要將第11個位置上的人挪走,或者是他們11個人重新去找一個11連坐的位置,效率都很低。如果沒有找到符合要求的作為,那麼就沒法坐了。 ### 缺點 人來在計算機中就是插入資料,人走在計算機中就是刪除資料。而陣列方式存放資料,插入資料和刪除資料效率低,插入資料時,這個位置後面的資料在記憶體中都要向後移。刪除資料時,這個資料後面的資料都要往前移動。 比如原來去了5個人,然後後來又去了一個人要坐在第三個位置上,那麼第三個到第五個都要往後移動一個位子,將第三個位置留給新來的人。 當這個人走了的時候,因為他們要連在一起的,所以他後面幾個人要往前移動一個位置,把這個空位補上。 #### 預留座位 對於這種位置不夠的缺點我們可以通過"預留座位的方式"來解決,即即使你們只有十個人去看電影,為了防止有人突然拖家帶口,導致位置不夠的情況,為了以防萬一你就事先買了十五張電影票。一旦有人來了就有位置做了。在計算機中我們為了防止陣列溢位,也可以使用這種方式,即申請一個比預期大的陣列,來防止陣列不夠大,儲存不了資料的情況。但這種"預留座位"的方式也會導致記憶體空間的浪費 ### 優點 隨機讀取效率很高。因為陣列是連續的,知道每一個數據的記憶體地址,可以直接找到給地址的資料。 並且不利於擴充套件,陣列定義的空間不夠時要重新定義陣列。(剛剛講的十個座位,多來了一個人,你就只能重新申請空間定義一個大於11的陣列) # 連結串列在記憶體中的分佈 陣列再記憶體中是非連續分佈的,什麼是非連續分佈呢,就拿上面的寄存櫃來說,比如寄存櫃有100個櫃子,你有四個東西要寄存,一個櫃子只能放一個東西,所以你要四個櫃子,非連續分佈就是隨便在寄存櫃中找四個櫃子就可以了,不需要連號,比如1589,2489等等都可以 **數字代表寄存的物品標號** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210210214811260.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BqaDg4,size_16,color_FFFFFF,t_70) ## 優缺點 在記憶體中可以存在任何地方,不要求連續。 在電影院幾個人可以隨便坐。比如十個人去看電影,這十個人可以在電影院隨便找十個位置坐下。不需要十個人坐在一起,這十個人每個人都記住下一個人的位置號,這樣到時候找人也就不會找不到了 在計算機中也一樣的道理,每一個數據都儲存了下一個資料的記憶體地址,通過這個地址找到下一個資料。 第一個人知道第二個人的座位號,第二個人知道第三個人的座位號…… ### 優點 增加資料和刪除資料很容易。 再來個人可以隨便坐,比如來了個人要做到第三個位置,那他只需要把自己的位置告訴第二個人,然後問第二個人拿到原來第三個人的位置就行了。其他人都不用動。 不指定大小,擴充套件方便。連結串列大小不用定義,資料隨意增刪。 ### 缺點 查詢資料時效率低,因為不具有隨機訪問性,所以訪問某個位置的資料都要從第一個資料開始訪問,然後根據第一個資料儲存的下一個資料的地址找到第二個資料,以此類推。 要找到第三個人,必須從第一個人開始問起。 # 小總結 ## 陣列的優點 - 隨機訪問性強 - 查詢速度快 ## 陣列的缺點 - 插入和刪除效率低 - 可能浪費記憶體 - 記憶體空間要求高,必須有足夠的連續記憶體空間。 - 陣列大小固定,不能動態拓展 ## 連結串列的優點 - 插入刪除速度快 - 記憶體利用率高,不會浪費記憶體 - 大小沒有固定,拓展很靈活。 ## 連結串列的缺點 - 不能隨機查詢,必須從第一個開始遍歷,查詢效率低 ## | - | 陣列 | 連結串列 | | --- | --- | --- | | 讀取 | O(1) | O(n) | | 插入 | O(n) | O(1) | | 刪除 | O(n) | O(1) | # 應用場景 ## 陣列應用場景: **資料比較少;經常做的運算是按序號訪問資料元素;陣列更容易實現,任何高階語言都支援;構建的線性表較穩定**。 ## 連結串列應用場景: **對線性表的長度或者規模難以估計;頻繁做插入刪除操作;構建動態性比較強的線性