---
# System prepended metadata

title: 淺談資料結構
tags: [DataStructure]

---

###### tags: `DataStructure`
# 淺談資料結構
資料結構就是電腦儲存資料的架構，包含儲存的位址及模式
好的結構可以提升演算效率，即降低運算時間、減少記憶體佔用空間
本篇會簡單的介紹幾個常見的結構

---
資料結構大致分成三種型態
- 基本資料型態
    - 最基本的資料單位，例如:整數、浮點、布林等
- 結構化資料型態
    - 基本型態的集合體，例如:陣列、串列、字典
- 抽象資料型態
    - 著重於資料的狀態、操作、封裝，是一種擁有特定模式的抽象概念，例如:堆疊、佇列

基本型態是資料的基礎單位，而結構化型態就是一組基本資料的集合
有些程式語言可以自定義struct，這也屬於結構化型態
這兩種型態比較基本，所以就不細說，接下來僅介紹抽象資料型態

## 抽象資料型態(Abstract Data Type, ADT)
抽象資料型態，是一種組織過的資料型態
提供 『物件 (objects)』 與 『作用於這些物件的 操作 (operations)』 規範，
<font color=red>而非實際表示法與具體實現的方式</font>，規範需說明每個操作要做什麼，而非如何做

操作規範基本上需包含以下四種：
- 函式名稱
- 參數型態
- 結果型態
- 函式功能的描述 (不必說明內部表示法或實作細節)

在物件導向程式中，ADT 可以用介面 (interface) 來表示
介面的中心思想是<font color=green>封裝隔離</font>，也就是外部類別只需呼叫介面提供的方法，不需知道內部如何實作
善用介面可使系統具高維護性、彈性，不論是擴充或重構，呼叫時內部僅會受到最小幅度的影響
有在串接第三方函式庫的人看到這裡就可以明白，其實 API 就是一種 ADT
> https://notfalse.net/5/adt

### 堆疊(Stack)
顧名思義他是一層層疊起來的結構，最先放入的會在最下方，而後放入的會在上方
因此要取得資料時，會先拿到最新的資料，這種原理叫做後進先出(Last In First Out)
而放入的動作稱為推入(Push)，拿取資料的動作稱為彈出(Pop)
嚴格來說，推疊使用上並不方便，因為只能單向操作，但從隨時能取得最新的資料這點來看
其實是相當便利，另外，在搜尋法中被稱為深度優先搜尋法，能隨時在搜尋選項中選擇最新資料
所以可利用堆疊的方式來管理內部的選項資訊

### 佇列(Queue)
它跟堆疊很像，差別僅在於它會優先取得最早的資料，這種原理叫做先進先出(First In First Out)
先進去的資料會先取得，這種依序的方式相當自然，也因此廣受應用，後來也出現了雙向佇列
另外，在搜尋法中被稱為廣度優先搜尋法，能優先在搜尋選項中選擇最早資料
所以可利用佇列的方式來管理內部的選項資訊

### 雜湊表(Hash Table)
在談雜湊表之前，先來談談與它相關的結構—列表與陣列
- 列表
列表內儲存的數據都搭配著一個指標，指標會對應到下一個數據存放的位址
所以不需要依序存在記憶體中，大多是分散於不同領域，然而分散儲存的方式
造成存取數據時，只能從頭跟著指標存取數據，此方式稱為順序存取(Sequential Access)
好處是追加與刪除數據時，只要把該數據位址的前後指標做修改即可
- 陣列
數據會依序存在記憶體的連續領域中，因為是連續領域，所以可用索引計算記憶體位址
直接存取每個數據，此方式稱為隨機存取(Random Access)
然而連續儲存的方式，造成追加、刪除數據時，需要高於列表的代價
追加數據要先確定陣列有空間可以新增數據，再者，為了挪出新數據需要的空間
需要將原數據依序向後移動(若追加在最後則不用移動)，再將新數據放入空間
刪除也同理，將預刪除資料移出後，把後方數據向前移動，這樣的操作相當耗時
- 優缺點
    - 列表：存取慢、追加快、刪除快
    - 陣列：存取快、追加慢、刪除慢
> 可以考慮哪種操作比較頻繁來決定用何種資料結構

再來談談雜湊表，它其實正是列表與陣列的合體，是一種Key-Value的形式
首先準備好一個陣列(ex:大小5)，存放數據時，先用雜湊函數計算此數據的Key值
假設算出的雜湊值為4928，將其除以陣列大小取餘數可得3，則該數據將存放在索引值3
若存放的索引值已經有數據，我們稱之為碰撞，此時新數據也存於相同索引值
而原數據增加一個指標，指向新數據的位址(如同列表的結構)
查找數據一樣先算出雜湊值，除以陣列大小取餘數，找到對應的的索引值即可
若索引值不是該數據，則依指標進行線性搜尋，找出Key值相同的資料

整體看下來，我們可以把雜湊表的結構想成行列樣式，行是陣列，列是列表
雜湊表利用雜湊函數，可以快速讀取陣列中的數據，當發生碰撞，可利用列表
但如果一開始陣列規模過小，將造成碰撞次數增加，容易產生線性搜尋
反之，陣列規模過大，會產生許多未儲存的空間，造成記憶體浪費
因此設定適當的陣列規模相當重要
```
補充:發生碰撞時，利用列表的方式稱為鏈結法，此外還有很多方式
最廣為使用的是開放定址法，求出第二候補的陣列位置，並儲存
若第二位置也有數據，則求出第三位置，這樣的方式可以解決陣列空間浪費的問題
而求出候補位置的方式也有很多種，例如使用多個雜湊函數或線性探測法。
雜湊函數有一項規則是無法從雜湊值回推出原始值，此條件適用於安全性相關用途
例如使用者密碼，並非使用雜湊表的必要條件。
雜湊表能彈性儲存、快速讀取數據，常用於程式語言的關聯陣列
```

### 堆積(Heap)
堆積是樹狀結構之一，屬於特殊的完全二元樹，用於實踐優先佇列
優先佇列是一種可以自由追加數據、讀取數據以極值(最小、最大)開始選取的資料結構
極值存於最上方，取數據只要從最上端拿取，然後最右下方的數據會往最上方補，再進行排序
追加數據則以最左下方開始追加，然後再進行排序。由於不易理解，請參考以下連結
> https://ithelp.ithome.com.tw/articles/10206479

### 二元搜尋樹(Binary Search Tree)
樹狀結構之一，所有節點都會大於其左邊的節點、小於其右邊的節點
因此最小值在最左方，最大值在最右方
追加數據從最上方開始，將其與所在節點比較，小於節點往左，大於節點往右
直到移動的位置沒有節點為止
> https://ithelp.ithome.com.tw/articles/10205875

> http://alrightchiu.github.io/SecondRound/mu-lu-yan-suan-fa-yu-zi-liao-jie-gou.html









