# 2.5 数据结构（Data Structures）

数据结构是用于表示算法所处理的数据在内存中存储的格式，当数据是结构化的，会更便于读取。

不同的数据结构有不同的特性，适用于不同的场景,正确选择数据结构会让工作更为简单。

大多数编程语言自带了预先做好的数据结构，比如 C++ 中的「标准模板库」（Standard Template Library）和 Java 中的「Java 类库」（Java Class Library）。

## 2.5.1 数组（Array）

### 数组

数组又名列表（list）或是向量（Vector），其连续存储在内存中，可存储多个值。

数组中不同值使用下标（index）区分，下标从 0 开始，使用方括号 \[ ] 表示所访问数组的数值。e.g 数组 j 的第一个元素为 j\[0]，第三个元素为 j\[2]。

本质上是通过计算第一个元素地址的**偏移量**，来得到数组中其他元素的地址。注意区分数组中第 5 个数字和数组中下标为 5 的数，前者下标为 4，后者实际为第六个数。

数组用途广泛，几乎所有的编程语言都自带了很多函数来处理数据，比如数组排序函数。

### 字符串

字符串（string）是由字母、数字、标点等组成的数组，以二进制值 \0 （null）结尾。处理字符串的常见函数有 strcat，其接受两个数组，将第二个放在第一个结尾处。

### 矩阵

数组仅能操作一维数据，二维及以上数据需要使用**矩阵（Matrix）**。以二维矩阵为例，取值需要 2 个下标，如 j\[2]\[1] :

![矩阵](https://275040345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FycDQGvckh16RY095vh62%2Fuploads%2FDwMt5x8BsuLJXMfIUG1m%2F0.png?alt=media)

## 2.5.2 结构体（struct）

结构体是指将几个逻辑上有关系的变量打包在一起的结构，比如将银行卡和余额打包在一个称为一个结构体放入数组中。

但数组创建时则大小固定，无法动态增加，同时其按序排列，在中间插入某值需移动后续诸多值，着实不便。因而可以使用结构体建立新的数据结构消除相关限制。

## 2.5.3 链表

通常采用名为 node 的结构体构建，节点（node）是变量（variable）和指针（pointer）构成的结构体，指针是指向一个内存地址的特殊变量。

![node](https://275040345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FycDQGvckh16RY095vh62%2Fuploads%2Fsox12CGOJdfAO5DXDWHH%2F1.png?alt=media)

### 单链表（linked list）

多个节点可以组成链表（linked list），通过链表中的每个节点指向下一个节点来实现灵活性。下图所示为「循环链表」（circular linked），若最后一个指针为 0(null)，则为非循环列表。

链表的大小可以动态增减，插入也比数组更加容易，只需改变指针即可（如下图）。在链表中，重新排序、两端缩减、分割以及倒序等操作也很容易进行。

![链表插入](https://275040345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FycDQGvckh16RY095vh62%2Fuploads%2FIdgrobVA72fyJO9RMIOm%2F2.png?alt=media)

### 队列（queue）

一种可以使用链表构建的复杂数据结构，采用「先进先出」（First-In First-Out, FIFO）的原则。

处理完一个数据则可以其「出队」（dequeue），将数据加入队列则称为「入队」（enqueue）。入队需要遍历整个链表直至结尾，然后将原先结尾节点的指针指向要加入的节点。

### 栈（stacks）

栈是一种「后进先出」（Last-In First-Out, LIFO）的数据结构，类似于放羽毛球进筒里。栈中数据的出入称为「进栈」（push）和「出栈」（pop）。

## 2.5.4 树（tree）

在 node 的基础上再新增一个指针可以构造出树：

![树的结构体](https://275040345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FycDQGvckh16RY095vh62%2Fuploads%2FAKwfoNWH3QJF6wnjuKqa%2F3.png?alt=media)

抽象来看，可以将最高的节点称为「根节点」（root），节点下的所有节点称为「子节点」（children），任何子节点的直属上层节点称为「父节点」（parent node），没有任何子节点的节点（i.e. 树结束的地方）叫做「叶节点」（leaf）。

![树](https://275040345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FycDQGvckh16RY095vh62%2Fuploads%2FgqK2UB1hFy1CfAMy9wMc%2F4.png?alt=media)

上图这种每个节点最多只有两个节点的树称为「二叉树」（binary tree），这是一种特殊的树。树的节点个数是任意的，甚至我们可以在 node 中使用链表来存储所有的子节点。

树的特性是从根到叶是单向进行，而非循环。若数据随意连接，则构成 2.4.4 节中提过的图（graph），图的指向任意，可以使用多个指针的 node 来表示。
