程序是什么?
程序 = 数据结构 + 算法;
把编写程序想象成搭积木的过程,那么数据结构就是一块块形状各异的积木块,而算法则是你要搭配它们的策略,只有你真正了解了每个积木块的特点和用途,然后运用不用的算法,就可以搭建出漂亮的房子、车子…
最基本的数据结构是什么?
很多人可能对这个问题一头雾水,数组?栈和队列?他们都很基本啊,但显然我想要的答案不是这些,最基本的数据结构其实是变量
,在面向对象的语言中,这个变量的范畴会更加宽泛,例如在Java中,变量包括基本类型变量(基本类型的实例)和对象(类的实例)。接下来我会解释为什么我这么说。
两类数据结构
在分类之前,我们想探讨一下关于数组和链表的问题,这两种数据结构相信大家再熟悉不过,请回答以下问题:
- 数组的基本定义是什么?数组的特点是什么?
- 链表的基本定义是什么?链表的特点是什么?
无论是数组还是链表,他们都是变量(实例)的集合,这是他们最基本的定义;但数组的特点是变量在内存中连续存储,所以访问快,插入、删除慢;而链表的特点是在内存中分布存储,每个变量(对象)都包含指向下一个变量(对象)的指针,所以访问慢,插入、删除快。我们的分类方法正基于此。
我认为所有常用的数据结构可以分为以下两类:基于内存连续存储
的数据结构 和 基于引用的内存不连续存储
的数据结构。
内存连续存储的数据结构
- 数组
- 栈 = 数组 + 栈顶指针(变量) + 入栈函数 + 出栈函数
- 队列 = 数组 + 队头指针(变量) + 队尾指针(变量) + 入队函数 + 出队函数
内存不连续存储的数据结构
- 链表:特殊的树
- 树:特殊的图
- 图:这类数据结构其实只有一类,就是图,因为链表和树都是一种特殊的图
注意:上述所分类的基于数组的栈和队列是基于其功能定义最朴素的实现,当然栈和队列完全可以通过链表来实现,例如在Java里,底层基于链表的 LinkedList 既可以用于实现队列又可以用于实现栈,所以具体的实现选择应取决于应用场景,上面的划分只是给大家提供一个理解的思路。
内存连续存储 + 内存不连续存储
内存连续存储(数组)访问快,内存不连续存储(链表)插入、删除快;如果想两者兼顾怎么办,还有一种复合的数据结构,折中地解决了这个问题:哈希表
。
- 哈希表 = 数组 + 图
注意,我上面写的是图,我们知道最简单的哈希表基本结构为一个数组,称为bucket,然后每个桶位上存储的是一个链表的头结点,但这个头结点不仅可以指向链表,也可以指向一个树,例如在Jdk1.8之后,HashMap的实现就是基于数组 + 链表 or 红黑树
的,甚至可以指向一个图,只要能够满足业务需求,但很少这么用。