理论 | 何谓数据结构?

113 阅读8分钟

引言

为什么要学习 算法, 它到底能给我带来什么呢?

  1. 对于求职者而, 算法 能力能成为你拿到优质 offer 的敲门砖, 不管是大厂还是国外面试都要求有一定 算法 能力
  2. 算法 是解决某类问题的思路, 通过它可以很好培养我们的逻辑思维能力
  3. 也许在平常工作中你用不到你所学的 算法, 但是当遇到一些复杂问题, 它可以帮助你在复杂的情况中更好地分析问题、解决问题、从而寻找出最优的解决问题的思路
  4. 让我们自己研究 算法 很难, 但是目前很多 算法 都是几代人努力, 研究出来的, 我们可以直接研究学习, 站在巨人的肩膀上成就自我, 何乐而不为呢
  5. 算法 是一种解决问题的思路和方法, 也许有机会应用到生活和事业的其他方面呢
  6. 长期来看, 大脑思考能力是个人最重要的核心竞争力, 而算法是为数不多的能够有效训练大脑思考能力的途径之一

所以相信我, 学习 算法 应该是一件很酷的事情, 下面请开始进入正题...

一、举个栗子

这里我们拿 电话簿 举例, 虽然现在我们大部分人都把电话号码直接存在手机里, 但我们这里以考虑使用纸质来作为电话簿的情况! 那么想象下, 我们会如果管理这个电话簿呢?

1.1 按顺序添加

一种比较常见的方式就是, 按照顺序(没有固定规则), 一条一条将联系人和对应电话号码记录在 电话簿

  • 每次有新增的联系人直接在 电话簿 最后新增一行即可
  • 如果需要修改电话号码, 则需要从上往下找到对应的联系人, 修改其电话号码即可
  • 如果需要找到对应联系人的电话号码, 也是一样需要从上往下, 逐条查询
联系人电话号码
张三13952***
李四13952***
王哥13952***
林哥13952***
大哥13952***
........

1.2 分类别类

当联系人比较多的情况下, 上面这种方式在查找的效率上就很慢了, 如果运气比较差的情况下, 可能得翻遍整个 电话簿 才行。为了方便查找, 常见的一种做法就是对 电话簿 进行分类然后再按分类进行排序, 分类规则可以是多种多样的, 可以按照和联系人的关系、也可以按照联系人的身份或职业, 当然最常见的则是根据联系人 姓氏 首字母来进行归类, 并按字母顺序进行排序。

  • 每次有新增的联系人, 按照其 姓氏 首字母, 找到对应的分组, 然后在分组最后新增一行即可
  • 如果需要修改电话号码, 按照其 姓氏 首字母, 找到对应的分组, 然后在分组内找到对应的联系人, 修改其电话号码即可
  • 如果需要找到对应联系人的电话号码, 也是一样, 需要按照其 姓氏 首字母, 找到对应的分组, 然后在分组内找到对应的联系人
联系人(L)电话号码
林三13952***
李四13952***
........
联系人(W)电话号码
王五13952***
王六13952***
........
联系人(M)电话号码
马五13952***
孟六13952***
........

....

1.3 优缺点

  1. 无脑按顺序进行排列的话, 在添加数据时是非常简单的, 只需要把数据加在最后就可以了, 但是在查询时较为麻烦
  2. 按分类进行分组后排序(比如按姓氏拼音首字母顺序)来排列的话, 虽然在查询上较为简单, 但是添加数据时又会比较麻烦
  3. 虽说这两种方法各有各的优缺点, 但具体选择哪种还是要取决于这个电话簿的用法。如果电话簿做好之后就不再添加新号码, 那么选择后者更为合适; 相反如果需要经常添加新号码, 但不怎么需要再查询, 就应该选择前者

二、什么是数据结构

结合上面例子我们来简单说明下, 什么是数据结? 联系人和对应电话号码如何存储在电话簿中? 数据之间的顺序、关系其实就是所谓的数据结构! 不同的数据存储介质不同, 一个是纸质一个是计算机内存!

简单来说所谓数据结构指的是, 存储数据之间的 顺序和关系

我们都知道, 数据是存储在内存之中的, 数据所占用的内存可以是连续的, 也可以是分散的!

image

而每条数据间的 顺序和关系, 则被称之为数据结构!

三、分类

如上所述, 数据存储于内存中, 数据之间的 顺序和关系 被称为数据结构, 那么常见的数据结构又有哪些呢?

如下图, 常见的数据结构有: 数组、链表、栈、队列、哈希表、堆、树、图

image

3.1 线性与非线性(逻辑关系)

根据数据之间的逻辑关系, 我们可以将所有常见的数据结构分为两大类: 线性与非线性

  • 所谓线性即数据从开始到结束是连续的没有其他额外的分叉! 反之即为非线性
  • 特别的是哈希表, 其由 keyvalue 构成, 它可以包含其他结构的数据, 所以它可能是线性的也有可能是非线性的

image

3.2 连续与分散(物理关系)

根据数据在内存(物理)中的顺序, 我们又可以将所有常见的数据结构分为两大类: 连续与分散

image

物理结构反映了数据在计算机内存中的存储方式, 因为内存是所有程序的共享资源, 在实际情况中我们可能无法同时分配到一块完整的连续大块的内存空间(数据量比较大情况下), 所以我们可能就需要将数据打散存储在不同位置上。

因此在数据结构与算法的设计中, 内存资源是一个重要的考虑因素, 它将决定采用何种的数据结构, 合适的数据结构可以很好提高内存的利用率。当然不同的数据存储方式, 物理结构从底层决定了数据的访问、更新、增删等操作方法, 两种物理结构在时间效率和空间效率方面呈现出互补的特点。

3.3 补充: 数组和链表是一切的基础

严格来说数据结构的存储方式只有 数组和链表 两种, 它们代表的是两种不同的也是最基础的数据存储结构:

  • 数组: 由于是紧凑连续存储, 可以随机访问(通过 index 进行访问), 通过索引快速找到对应元素, 而且相对节约存储空间。但正因为连续存储, 内存空间必须一次性分配够, 所以说数组如果要扩容, 需要重新分配一块更大的空间, 再把数据全部复制过去, 时间复杂度 O(N); 而且你如果想在数组中间进行插入和删除, 每次必须搬移后面的所有数据以保持连续, 时间复杂度 O(N)

  • 链表: 因为存储的内存不连续, 而是靠指针指向下一个元素的位置, 所以不存在数组的扩容问题; 如果知道某一元素的前驱和后驱, 操作指针即可删除该元素或者插入新元素, 时间复杂度 O(1)。但是正因为存储空间不连续, 你无法根据一个索引算出对应元素的地址, 所以不能随机访问(通过 index 进行访问); 而且由于每个元素必须存储指向前后元素位置的指针, 会消耗相对更多的储存空间。

所有数据结构其实都是基于 数组链表 或二者的组合实现的。例如, 栈和队列既可以使用数组实现, 也可以使用链表实现; 而哈希表的实现可能同时包含数组和链表; 甚至你也可以发明自己的数据结构, 但是底层存储无非 数组或者链表

链表在初始化后, 仍可以在程序运行过程中对其长度进行调整, 因此也称 动态数据结构。数组在初始化后长度不可变, 因此也称 静态数据结构。值得注意的是, 数组可通过重新分配内存实现长度变化, 从而具备一定的 动态性

四、参考

大家好, 我是墨渊君, 如果您喜欢我的文章可以: