資料結構專題——那些難以理解的資料結構基本概念
不知有沒有人和博主一樣,在上大學的時候最頭疼的一門課就是資料結構與演算法了,其中枯燥的概念、冗長的虛擬碼都讓博主昏昏欲睡。
尤其是嚴大媽在《資料結構》中開篇講述的資料結構、資料型別與抽象資料型別的概念,讓博主完美地將這三個概念混淆了很久(這裡沒有黑嚴大媽的意思……但是資料結構確實給當時沒有認真聽課的博主留下了深刻的印象)。
博主希望在這個系列的博文中將自己眼中的資料結構與各位同學進行分享,希望大牛們能不吝賜教或是對初學者能有一點幫助。
在本篇博文中我主要談談我對以下三個概念的理解,歡迎大家與我一起討論。
- 資料結構
- 資料型別
- 抽象資料型別
首先來看資料結構的概念:
資料結構: 是相互之間存在一種或多種特定關係的資料元素的集合。這種結構可以是邏輯結構或者是物理結構
邏輯結構是指資料之間的邏輯關係,比如
- 當所有資料都屬於一個集合,而彼此之間沒有別的關係時,這就是邏輯上的集合關係,如下圖;
- 當資料之間有下圖所展示的一一對應的關係時,就屬於線性結構
- 當資料之間有下圖所展示的一對多的關係時,就屬於樹形結構
- 當資料之間有下圖所展示的多對多的關係時,就屬於圖形結構
物理結構是指資料如何計算機中儲存的形式
若資料被存放在連續的儲存單元中,則屬於順序儲存結構,這種資料結構中資料間的邏輯關係和物理關係是一致的。這種資料結構很簡單,最常見的例子就是陣列。當我們向計算機申請建立一個裝有10個整型元素的陣列時,計算機會在記憶體中找一塊連續的空間,按照一個整型元素所需的記憶體大小乘以10,為這個陣列開闢所需的記憶體空間,其中第一個元素放在第一個位置,第二個元素放在第二個位置,依次擺放,如下圖所示。
若資料被存放在任意的儲存單元中,則屬於鏈式儲存結構,這種資料結構中的資料存放位置可以是連續的,也可以是不連續的。資料間的儲存關係並不能反應它的邏輯關係,因此需要指標來存放元素的位置,這樣通過地址就可以找到相關聯元素的位置了,如下圖所示。
根據上述的概念來看,我們平常所說的樹(Tree)、線性表(List)、圖(Graph)都屬於資料結構,因為它們的元素滿足邏輯結構中元素的特定邏輯關係。
同樣,以Java語言為例,ArrayList(基於陣列實現的線性表)、LinkedList(連結串列)也屬於資料結構,因為他們的元素在計算機中是以順序與鏈式的物理結構來儲存的。
邏輯結構是面向邏輯關係的結構,而物理結構是面向計算機儲存的結構。對於我們程式設計師來說我們更傾向於關注物理結構,因此我們更習慣叫ArrayList這種線性表的實現為資料結構。
接下來我們來看資料型別的概念:
資料型別:是指一組性質相同的值的集合及在此集合上的一些操作的總稱。
同樣以Java語言為例,每一個變數在被宣告的時候我們都需要指明它的資料型別。因為記憶體需要知道你這個資料應該被分配多大的空間。
同樣的一個變數 i=12, 如果它被宣告為byte型別就會被分配8 bits的空間,而被宣告為int型別就會被分配32 bits的空間。
通常來說,資料型別分為原子型別和結構型別。
原子型別就是不可再分的基本型別:整型、浮點型等等
結構型別就是由若干個原子型別組成符合型別。
以Java為例,原子型別就是8個基本資料型別,而結構型別就是引用型別。對於C語言、或是C++而言,原子型別就是基本型別,結構型別就是struct。
但是不同的硬體系統在將這些資料型別轉換為底層語言時肯定會有不同。這點對於C語言來說尤為明顯,比如int型別沒有固定的取值範圍,而是依賴於硬體系統來決定。
因此這些我們人為為資料劃定的“型別”就有硬體的侷限性了。
這也是抽象資料型別出現的原因。
抽象資料型別:是指一個數據模型及定義在該模型上的一組操作
抽象資料型別可以解決上述 int 型別在不同硬體上有不同取值的問題。
比如說,我們可以抽象出一個數據型別叫做整型。那麼在任何硬體系統中需要用到的整數型別以及整數的操作都可以在這個抽象型別中宣告。至於在某種程式語言中將它實現為32位的 int 型別還是16位的 int 型別抽象型別都不需要關心。
以Java語言為例,線性表List是一個抽象資料型別;但ArrayList與LinkedList就不是抽象資料型別,因為這兩種具體的資料結構已經是線性表的具體實現了,並不具有抽象性。
三者的關係總結
- 資料結構與資料型別的關係
資料結構是由一個個的資料元素組成的,而這些資料在宣告的時候都會屬於某一種資料型別。
- 資料結構與抽象資料型別的關係
邏輯資料結構一般也可以看作抽象資料型別;但物理資料結構不是抽象資料型別,而是抽象資料型別的具體實現。
- 資料型別與抽象資料型別的關係
資料型別是人為規定的平臺相關的型別;而抽象資料型別是將數學模型和模型的相關操作抽象出來
注:本文圖片來源於程傑老師的《大話資料結構》