Guide
本章对各种data structure进行对比:
1) 找出它们的共性、内在关联
2) 找出它们的个性
这样做的目的是为选择data structure提供参考意见。
"So how to choose data structure ? It is an art and worth learning"
从最基础的array 和 linked list开始说起
array 和 linked list不仅仅是两种data structure,它们所代表的是两种典型的存储方式,存储方式的不同决定了它们的典型差异,在下面的文章中,对此进行了非常好的解读:
1、geeksforgeeks Linked List vs Array
2、studytonight Difference between Array and Linked List
linked list只能够 sequential access,但是array能够random access。
在 wanweibaike Linked list 中,有着非常好的总结。
Trade off
下面这段话摘取自维基百科Hash function:
In data storage and retrieval applications, use of a hash function is a trade off between search time and data storage space. If search time were unbounded, a very compact unordered linear list would be the best medium; if storage space were unbounded, a randomly accessible structure indexable by the key value would be very large, very sparse, but very fast. A hash function takes a finite amount of time to map a potentially large key space to a feasible amount of storage space searchable in a bounded amount of time regardless of the number of keys.
在选择data structure的时候,我们总是在如下方面进行tradeoff:
Time complexity
各种operation的time complexity,programmer需要根据
Space complexity
相比于其他的,是否需要花费更多的空间,典型的例子就是linked list的next pointer
Concurrency
对于concurrent programming,这是非常重要的一个角度,参见 Concurrent-data-structure
章节。
Sorted or unsorted
是否有序?
Cache performance
1、在 wikipedia Hash table 中对此进行了说明
Classification
Linear and non-linear
本节讨论对ADT的分类:
1) sequence
2) non-linear,比如map-dict
底层的data structure,则分为非常多的类别。
存储方式
参见下面的"存储方式"章节。
存储方式
存储方式包括:
1、Array-based (顺序存储)
2、linked-list-based(链式存储)
3、mixed
如下是一些较好的素材。
labuladong 数据结构和算法学习指南
数据结构的存储方式只有两种:数组(顺序存储)和链表(链式存储)。
NOTE:
1、后续将它们称为array-based、linked-list-based
2、其实还有混合两者的,比如hash table
这句话怎么理解,不是还有散列表、栈、队列、堆、树、图等等各种数据结构吗?
我们分析问题,一定要有递归的思想,自顶向下,从抽象到具体。你上来就列出这么多,那些都属于「上层建筑」,而数组和链表才是「结构基础」。因为那些多样化的数据结构,究其源头,都是在链表或者数组上的特殊操作,API 不同而已。
比如说**「队列」、「栈」**这两种数据结构既可以使用链表也可以使用数组实现。用数组实现,就要处理扩容缩容的问题;用链表实现,没有这个问题,但需要更多的内存空间存储节点指针。
**「图」**的两种表示方法,邻接表就是链表,邻接矩阵就是二维数组。邻接矩阵判断连通性迅速,并可以进行矩阵运算解决一些问题,但是如果图比较稀疏的话很耗费空间。邻接表比较节省空间,但是很多操作的效率上肯定比不过邻接矩阵。
...
对比
综上,数据结构种类很多,甚至你也可以发明自己的数据结构,但是底层存储无非数组或者链表,二者的优缺点如下:
**数组**由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间。但正因为连续存储,内存空间必须一次性分配够,所以说数组如果要扩容,需要重新分配一块更大的空间,再把数据全部复制过去,时间复杂度 O(N);而且你如果想在数组中间进行插入和删除,每次必须搬移后面的所有数据以保持连续,时间复杂度 O(N)。
**链表**因为元素不连续,而是靠指针指向下一个元素的位置,所以不存在数组的扩容问题;如果知道某一元素的前驱和后驱,操作指针即可删除该元素或者插入新元素,时间复杂度 O(1)。但是正因为存储空间不连续,你无法根据一个索引算出对应元素的地址,所以不能随机访问;而且由于每个元素必须存储指向前后元素位置的指针,会消耗相对更多的储存空间。
NOTE:
1、还可以从cache的角度对两者的访问性能进行对比,这就是C++中的value semantic和reference semantic