首頁 > 收藏

資料結構線性表入門

作者:由 技術範王有志 發表于 收藏日期:2023-02-03

線索樹是什麼儲存結構

資料結構線性表入門

大家好,我是王有志。關注

王有志

,回覆

DSA

獲取資料結構和演算法學習資源。

從今天開始就進入到資料結構的部分了,整體分為3個部分:線性表,樹和圖,從認識每種資料結構到它們的高階應用。今天我們先從最簡單的線性表和陣列開始。

什麼是線性表?

線性表是我們工作中最常用的資料結構之一,同時它也是我們接觸到的最簡單的資料結構。

根據操作節點的自由度,我們可以將線性表分為兩大類:

非受限線性表

受限線性表

非受限線性表:陣列,連結串列

受限線性表:棧,佇列

除此之外,字串也是一種特殊的線性表。

在頻繁的使用過程中,你有沒有思考過什麼是線性表?

我們一起來看下百度百科中

線性表

的定義:

線性表(linear list),是資料結構的一種,一個線性表是n個具有相同特性的資料元素的有限序列。

線性表的概念還是很容易理解的,接著來看點頭疼的:

線性表中的個數n定義為線性表的長度,n=0時稱為空表。在非空表中每個資料元素都有一個確定的位置,如用ai表示資料元素,則i稱為資料元素ai線上性表中的位序。

線性表的相鄰元素之間存在著序偶關係。如用(a1,…,ai-1,ai,ai+1,…,an)表示一個順序表,則表中ai-1領先於ai,ai領先於ai+1,稱ai-1是ai的直接前驅元素,ai+1是ai的直接後繼元素。當i=1,2,…,n-1時,ai有且僅有一個直接後繼,當i=2,3,…,n時,ai有且僅有一個直接前驅。

這些看起來是不是就有些頭疼了?我們舉個簡單的例子,糖葫蘆都吃過吧?如果我說糖葫蘆就是一個線性表呢?

資料結構線性表入門

我們來看看糖葫蘆是不是符合線性表的定義:

相同特性的資料元素

:都是山楂;

有限

:總共5個山楂;

序列

:給山楂編上號就是完整的序列。

很多小夥伴可能忘記了序列的特點,

序列存在順序關係(可以是混亂的順序,但是要固定)和排成一列(不會有分支,前後一對一的關係)

透過這串糖葫蘆,也給出位序,前驅節點和後繼節點的解釋:

位序

:山楂在籤子上確定位置的編號,就是透過這個編號可以找到指定的山楂;

前驅節點

:以2號山楂為例,排在2號前面的都是前驅節點;

直接前驅節點

:還是2號山楂,排在2號山楂,並且緊挨2號山楂的1號山楂就是直接前驅節點;

後繼節點

:和前驅節點反過來;

直接後繼節點

:和直接前驅節點反過來。

再通俗點解釋,可以用“一根線”穿起來的相同物件(元素),並保持固定順序的就是線性表。

這樣理解起來是不是比定義中的數學符號簡單多了?

陣列

知道了什麼是線性表之後,我們來看線性表中最簡單的資料結構:

陣列

還記得我們在

演算法的概念和資料的儲存結構

提到的順序儲存結構嗎?陣列正是使用了順序儲存結構。

另外我們提到過每塊記憶體都有自己的編號。這種順序儲存結構加上記憶體編號,使得陣列具有了強大的

隨機存取

能力。

陣列的優點

陣列最大的優點就是隨機存取的能力,換句話說就是

在資料中查詢指定下標的元素速度非常

快。

因為計算機可以透過一步簡單的計算得到儲存該元素的記憶體地址:

起始地址+下標X型別大小

這是不是陣列下標從零開始的原因之一呢?

陣列的缺點

計算機的世界中沒有能解決一切問題的“銀彈”,隨機存取的能力不僅僅給了陣列快速查詢元素的資本,也使得陣列在插入和刪除元素後必須要“整理”記憶體,順序儲存結構。

陣列在插入元素後,為了保持隨機存取的特性,必須要向後移動元素。

資料結構線性表入門

陣列在刪除元素後,為了保持隨機存取的特性,必須要向前移動元素。

資料結構線性表入門

當然,也並不是全部的插入刪除都要移動元素。最好的情況下,在陣列的尾部插入和刪除元素,不需要移動任何元素,此時的時間複雜度是

。如果是最壞的情況,需要在陣列的頭部插入和刪除元素,則要移動整個陣列,此時的時間複雜度是

除了陣列的插入和刪除外,還有一種情況我們不得不考慮,如果我們在插入元素時,緊鄰陣列的記憶體已經被分配了怎麼辦?

陣列的擴容

我們先來看一段程式碼:

資料結構線性表入門

這3種建立陣列的程式碼,哪個會有編譯時異常?哪個會有執行時異常?

答案是,都能透過編譯,但是第三種在執行時會丟擲異常。

強制要求建立陣列時進行初始化或者指定陣列大小,是為了能夠給陣列分配合適的記憶體。但是這麼做就帶來另一個問題,

建立陣列時,大小已經固定

,如果想新增更多的元素該怎麼辦?

相信你一定非常熟悉

ArrayList

了吧?

ArrayList正是Java中提供的可動態擴容的陣列,它的底層是Object[],擴容的方式也非常的“粗暴”,當陣列大小不足時,重新申請記憶體(1。5倍),將原陣列元素複製到新的陣列上,並修改引用。

結語

陣列的內容就到此結束了,僅僅從資料結構的角度來看陣列,還是非常簡單的。

可能很多小夥伴會說,工作中都是使用ArrayList了,陣列要退出舞臺了。

我的想法是,大部分場景選擇ArrayList是沒有任何問題的,在追求極致效能,且沒有插入刪除的場景時,陣列或許會是一個不錯的選擇。

練習

嘗試實現一個動態陣列

1。兩數之和:https://leetcode-cn。com/problems/two-sum

53。最大子陣列和:https://leetcode-cn。com/problems/maximum-subarray

88。合併兩個有序陣列:https://leetcode-cn。com/problems/merge-sorted-array

本篇內容的程式碼倉庫:https://gitee。com/wyz-A2/DSA

好了,今天就到這裡了,Bye~~

參考連結

線性表定義

https://baike。baidu。com/item/%E7%BA%BF%E6%80%A7%E8%A1%A8/3228081

序列定義

https://baike。baidu。com/item/%E5%BA%8F%E5%88%97/1302588

陣列定義

https://baike。baidu。com/item/%E6%95%B0%E7%BB%84/3794097

隨機存取

https://baike。baidu。com/item/%E9%9A%8F%E6%9C%BA%E5%AD%98%E5%8F%96

ArrayList原始碼

https://hg。openjdk。java。net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/ArrayList。java