# 几种基本的数据结构
> 图引自『我的第一本算法书』第一章
## 1.链表
### 概念图
如下图,`Blue`、`Yellow`、`Red`三个字符串存储于链表中,每个数据都有一个『指针』,它指向下一个数据的内存地址(`Red`是最后一个数据,其指针不指向任何位置)。
![概念图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/lianbiao_gainian.png)
### 在内存中存储
由上述内容可知,在链表中,数据无需存储在连续空间内,一般都是分散存储的。
![内存中存储图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/lianbiao_neicun.png)
### 访问方式 - 顺序访问
因为数据是分散存储的,所以想要访问一个数据,只能从第一个数据开始,顺着指针往下找。比如,想查找`Red`,查找顺序如下:
`Blue` -> `Yellow` -> `Red`(Done)
查找数据的耗时和链表长度`n`有关,时间复杂度为:
O(n)
### 添加数据
如果想添加数据,只需改变添加位置前后的指针指向即可,比如『在`Blue`和`Yellow`直接添加`Green`』:
![添加数据](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/lianbiao_tianjia.png)
添加数据的耗时和链表长度`n`无关,如果已经到达需要添加数据的位置,则时间复杂度为:
O(1)
### 删除数据
删除数据也一样,我们只需要改变指针的指向即可,比如『删除`Yellow`』:
![删除数据](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/lianbiao_shanchu.png)
此时,`Yellow`本身还存在,不过没关系,它已经无法被访问,今后需要用到其所在存储空间时,直接覆盖掉即可。
和『添加数据』一样,删除数据的时间复杂度为:
O(1)
### 特点
由上述内容我们可以看出,链表有以下特点:
* 数据呈线性排列,分散存储
* 访问比较耗时 O(n)
* 数据的添加和删除都比较方便 O(1)
## 2.数组
### 概念图
数组也是线性排列的,它的结构和最开始讲的『按姓名首字母排序的电话薄』类似。
![概念图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_gainian.png)
### 在内存中存储
数组的数据按顺序存放在连续空间内:
![内存中存储图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_neicun.png)
### 访问方式 - 随机访问
因为数据存放在连续空间内,所以我们可以用数组下标计算出每个数据的内存位置,借此直接访问目标数据,这叫做『随机访问』:
![数组访问-随机访问](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_fangwen.png)
我们可以通过数组下标查找目标数据,查找数据的耗时和数组长度`n`无关,时间复杂度恒为:
O(n)
### 添加数据
如果想添加数据,需要经过以下步骤:
① 在数组末位增加存储空间
② 从新数据要存放的位置,把后面已有数据一个个后移
③ 插入新数据
例如,我们尝试将`Green`添加到第二个位置上:
![添加数据](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_tianjia.png)
添加数据的耗时和链表长度`n`有关,如果在数组头部添加数据,则时间复杂度为:
O(n)
### 删除数据
删除数据是将『添加数据』反过来操作一遍,需要经过以下步骤:
① 删除目标数据
② 把目标数据后面已有数据一个个往前移
③ 删除末尾多余空间
![删除数据](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_shanchu_1.png)
![删除数据](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/shuzu_shanchu_2.png)
和『添加数据』一样,删除数据的时间复杂度为:
O(n)
### 特点
由上述内容我们可以看出,数组有以下特点:
* 数据呈线性排列,连续存储
* 访问快速 O(1)
* 数据的添加和删除比较复杂 O(n)
### 和链表对比
通过对比,我们可以根据哪种操作频繁来决定使用哪种数据结构。
|访问|添加|删除
---|---|---|
链表|慢|快|快
数组|快|慢|慢
## 3.栈
### 概念图
栈也是线性排列的。栈就像一摞书,新书都会被堆在最上面,取书时也只能从最上面开始取。
![概念图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/zhan_gainian.png)
### 添加数据 - 入栈(`push`)
往栈中添加数据的操作叫做**入栈(`push`)**
添加`Green`:
![入栈1](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/zhan_ruzhan_1.png)
添加`Red`:
![入栈2](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/zhan_ruzhan_2.png)
### 取出数据 - 出栈(`pop`)
从栈中取出数据的操作叫做**出栈**(`pop`)
例,我们要取出`Green`:
① 先取出`Red`:
![出栈1](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/zhan_chuzhan_1.png)
② 这时`Green`在顶部,才能通过出栈操作取出:
![出栈2](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/zhan_chuzhan_2.png)
# 代码库地址
[https://github.com/liuzhen153/play-algorithm-python](https://github.com/liuzhen153/play-algorithm-python)
### 特点
由上述内容我们可以看出,栈有以下特点:
* 『后进先出』,Last In First Out (LIFO)
* 添加和删除数据只能在一端进行
* 只能访问到顶端的数据
* 要想访问中间的数据,必须通过出栈操作将目标数据移到栈顶
* 很适合『只需要访问最新数据』的情况
## 4.队列
### 概念图
队列也是线性排列的。队列就像排队取款的人,只能从前面往后处理,新来的人只能排在队尾。
![概念图](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/duilie_gainian.png)
### 添加数据 - 入列
往队列中添加数据的操作叫做**入列**
添加`Green`:
![入列1](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/duilie_rulie_1.png)
添加`Red`:
![入列2](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/duilie_rulie_2.png)
### 取出(删除)数据 - 出列
从队列中取出(删除)数据的操作叫做**出列**
例,我们要取出`Green`:
① 先取出(删除)`Blue`:
![出列1](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/duilie_chulie_1.png)
② 这时`Green`在头部,才能通过出列操作取出(删除):
![出列2](https://raw.githubusercontent.com/liuzhen153/play-algorithm-python/master/images/duilie_chulie_2.png)
### 特点
由上述内容我们可以看出,队列有以下特点:
* 『先进先出』,First In First Out (FIFO)
* 添加和删除数据是在两端进行的(添加-尾端,删除-头部)
* 只能访问到头部的数据
* 要想访问中间的数据,必须通过出列操作将目标数据移到头部
* 很适合『先来的数据先处理』的情况