在很多数据结构相关的书籍,尤其是中文书籍中,常常把数据结构与算法“混合”起来讲,导致很多人初学时对于“数据结构”这个词的意思把握不准,从而降低了学习兴趣和学习信心。然而实际上,数据结构就是其字面意思:数据的结构。而“结构”这个词的标准意思又是“组成整体的各部分的搭配和安排”。所以,数据结构的意思就是“数据存储的结构”,而我们学习数据结构其实就是为了研究“应该以什么样的(抽象的)结构存储数据”。更广泛地说,数据结构不仅关心“数据如何存储”,还关心“存储哪些数据”。
那么,数据存储的不同结构(抽象的,因为数据的实际存储是物理的、底层的)会有什么区别,或者说我们为什么要学习数据结构呢?原因当然就是数据结构与我们的程序性能息息相关喽!为了举例说明这一点,我们先简要说明一下“链表”这种数据结构(后期会有相应文章讲解“链表”)。所谓“链表”,可以视作是“扩展的数组”,它与数组的不同之处在于其“元素”个数是不确定的(数组在创建时就需要指定大小,也就指定了元素个数),且“元素”间的位置也不再是相邻的。“链表”初始化后其内是没有“元素”空间的,当你需要添加元素时“链表”就在内存中随意找一个“元素”大小的空间加进“链表”中,然后写入数据到该空间。这样一来,“链表”就可以随着我们的需要动态地增大或减小其大小。至于为什么“元素不相邻却还能找到相关的其它元素”的原因,我们将在“链表”相应章节讲解,目前我们只需要知道其抽象概念及效果就好了。
现在,我们来假设一个程序(你也可以称为软件,可能会更高大上一点),其接收用户的输入,当输入完全结束后,进行相应操作,然后输出结果。但是,已知用户的输入数量是不确定的,有时候只需要1、2MB内存来存储,而有时候高达几百MB,并且用户的内存就只有1GB可用,那么程序设计时,如果使用数组来暂存用户的输入,这个数组该是多大呢?如果数组设置成2MB大小,那么程序将无法应对用户大量输入的情况,而如果将数组设置为比如500MB,那么有可能大部分情况下准备的空间都是浪费的!如果只运行你这一个程序,浪费也就罢了,然而现在同时运行多个程序已经是常见的现象,若一个程序占用了过多的空间那么其它程序怎么办呢?这个时候,显然“链表”才是该程序用于存储用户输入的更佳的数据结构。在特定的情况下,有的数据结构更合适而有的更不合适,我们要明白数据结构存在哪些选择,而哪个选择是更好的,才能写出更适合更优秀的程序。这就是为什么要学习数据结构的原因。
讲到这儿,数据结构的含义应该已经清楚了,接下来要说一说什么是算法。算法粗略地说就是“解决问题的方法或步骤”,而在编程中,我们解决问题往往就是处理数据。比如最常听说的排序算法,就是将数据处理成排好顺序的状态。很多时候算法的优劣决定了程序的性能,当数据个数为数万个时,使用插入排序算法可能需要耗费几十秒的时间,而快速排序算法则只需要零点几秒,这显然是有巨大差别的,且数据越多这两者差别越大。因此,算法对于编程是极其重要的。
那么,为什么数据结构与算法往往是一起讲解的呢?这个问题想要通俗地解释有点困难,但是我们可以将原因归纳为两点:
1.特殊的数据结构需要特殊的算法进行处理。
有时候我们的程序会使用到特殊的数据结构来存储数据,比如上面提到的情形,我们就需要一个能动态变化大小的线性表——链表——来替代普通的数组去存储数据。而数据的存储结构发生变化后,我们存、取数据的方式也会发生变化,使用数组时我们想要第X个数据只需要用下标(X-1)就可以直接取出,但是如果使用链表,我们则不得不从第一个元素一路数过去,数到第X个就是第X个数据。此时因为我们使用了特殊的数据结构,所以相应的处理数据的方法也得变化,也就是说介绍某个特殊的数据结构,就必然要介绍“操作”该数据结构的算法,不然这个数据结构可怎么用?
2.特殊的算法需要特殊的数据结构来支持。
其实大部分情况下算法与数据结构一起讲解的原因都是第一点,即有了某种数据结构,再引出“配套”的算法。但是为了实现某种算法而必须使用特殊的数据结构的情况也是有的,比如用于快速查找的散列算法就需要链表提供支持,此处限于篇幅不予细讲。
总而言之,由于“算法需要有合适的数据结构支持,数据结构离开算法就没有什么意义”,数据结构与算法往往是一起提出的。日后本系列文章讲解时也会尽量做到:提出某种情形——提出合适的数据结构——给出该数据结构对应的算法,或者:提出某种情形——提出合适的算法——选择合适的数据结构。
网友评论