数据结构到底是个什么玩意儿?——数据结构总结篇

注意啊这篇文章不是软文广告啥的,一般如果起这种标题的话,估计最后就是让你报个xx班了(23333)。不过我这是篇总结性质的文章了。转载著明出处,谢谢。

目录

数据结构到底是什么?

那么为什么我们要学习数据结构呢?栈啊队啊树啊图啊都是什么呢?

程序=数据结构+算法

数据结构的分类

总结


今天就不讲具体的技术或者算法了,今天来对数据结构到底是什么这一问题进行一下讨论。其实这个问题由我来回答的话可能会有点讽刺,毕竟数据结构是我本科期间分数最低的一门课。不过作为曾经数据结构没学好的人,我也更能理解为什么有时候我们感觉数据结构那么难,为什么数据结构就是学不好。这篇文章基本上没有涉及技术层面的问题,因此完全当个乐子看也是可以的。我是希望能给那些上数据结构没上明白,或者即将上数据结构的朋友们一些启示。至于玩的很溜的大佬也可以看看,指点指点我这篇博客的问题。

对于数据结构的理解往往可能是学完课之后的几个学期才能加深一些。至于为什么学的时候学不好呢,可能有这些问题。一是语言本身语法有些没弄明白,入门数据结构大部份学校可能都是用C语言,指针这些语法可能会挡住一些人的理解;然后可能是教材,上面的代码自己跑的时候都跑不通,例如上到图发现连建图都不会,自信心受挫;还有学习方法,可能老师讲了啥,我们就往上硬怼,不知道为什么要写这个数据结构也不知道有什么用。可能学了这一部分,学会了这些算法,到时候oj就对着这些算法刷题,但是当时可能并不知道为什么是这样,学这个有什么用。这些问题可能并不难,但是主要是没有想过。

那么首先先讨论一个问题:

数据结构到底是什么?

我觉得这里如果我们还把书上的概念拿出来“数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。”,可能就真是劝退了。这种冗长的概念估计没人会去看的。

这里从OJ开始谈起吧。大家最开始接触到OJ刷OJ的时候,估计都是从这一题开始的,这也是很多很多OJ的第一题:

题目描述
输入两个整数 a,b,输出它们的和。

输入格式
两个整数以空格分开。

输出格式
一个整数。

输入输出样例
输入 
20 30
输出 
50

看到这里我们马上就动手敲代码了,很快啊,就把代码写出来了:

#include <stdio.h>

int main() {
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d", a+b);
    return 0;
}

有的OJ,甚至提交上去这一段还会WA掉。不过这并不是重点,重点在于,看到输入,我们习惯性的就把int a, b;这一句敲出来了,基本上是本能的。我们不会去思考为什么要这样写。

有的人会说,不这样写我怎么去把输入数据读进来呢?其实这里就已经把第一个概念引进来了,那就是数据。小到a+b问题,大到大数据,几乎所有的程序都是与数据息息相关,所有的程序都在处理数据,你在OJ上刷的题其实就是给一连串输入数据让你通过一个算法得到输出(即使a+b问题也可以这么说);网上的大数据分析平台其实就是根据海量数据通过算法来分析得到个体性或者普遍性结论。当然你可以说hello world不是处理数据,我也可以说hello world根本不是一个有用的程序。这个议题没什么太大意义,只需要明白,我们写的所有程序,无一例外都在与数据打交道。

接下来我们把题面改一下,改成三数之和,大家会很自然的改用int a,b,c;改成四数之和,大家会很自然的用int a,b,c,d;....

改成二十六数之和,大家会很自然的改用int a,b,c,d....z;.....当然不会了!谁会一个个地敲26个小写字母啊!大家会很自然的使用 int  a[26];也就是数组。在不知不觉间,其实我们存放数据的方式也改变了,而我们也可以说存放数据的结构改变了。这里就是第二个概念,结构。看似就是把数据元素放在一个数组内,其实我们已经把数据按照我们需要的有序的方式存储管理起来了,可以很快地取出来。

实际上说了这么多,就是为了引出数据和结构两个词。单独认这两个词的意思都不难,那么放在一起,其实意思也不难。数据结构就是存放、组织数据的结构。正如刷OJ的时候a+b,我们就用int a,b存储;数据比较多的时候,我们会用数组存储;处理大数据的时候,我们用的是HDFS存储。看似都是本能的东西,其实都包含着前人经验与智慧。

那么再回到刚才的问题,数据结构到底是什么?其实就是我们在写程序处理数据的时候,先想个办法把数据存起来而已,不然就没法应用这些数据了。

那么为什么我们要学习数据结构呢?栈啊队啊树啊图啊都是什么呢?

其实可以看出来,解决26数之和,我们用a,b,c,d...z或者a[26]是都能解决的。但是我们本能性的倾向于a[26]的存储方式。然而解决a+b问题,其实我们也没有人会想到用a[2]来存数据。这是为什么呢?很简单,方便。写a+b就用a,b存写起来多方便,写26数之和,a[26]写起来多方便。处理数据时,当然要按照最方便最好用的方式来存储数据。

这就是为什么我们需要学数据结构。在我们写各种各样的程序,处理各种各样的数据时,也要掌握数据的规律,以最方便为基础而来存储数据。不然的话就是找自己的不痛快了。例如在写底层的操作系统的时候,如果把所有数据都存在一个数组里面,那后续管理起来将会是一场灾难的。

所以数据结构是灵活的,根据需要可以灵活选择和管理。这也是我感觉自己不足的地方,在前几篇博客也写过,太僵化了。但是注意在学习的前期,结构化的思维也是必要的。这时候把每一种数据结构都自己写一遍,造轮子,能够帮助自己灵活的理解与运用。当然熟练之后,再开始用STL或者java python封装好的数据结构,比自己造轮子肯定是好不少的。不够结构化是我大一的主要问题,所以写出来的代码现在看到仍然觉得是trash。

正是为了让数据处理起来更方便,我们才需要学习数据结构,我们可以举出很多例子:

为了有序的管理数据,我们才需要有序表,包括顺序表(数组)。但是我们发现往前面添加元素的时候需要往后挪动很多元素,所以我们才需要链表。后来为了让链表有更多的操作,我们有了双向链表、循环链表、双向循环链表、静态链表......

在程序设计时递归是很常见的,但是程序怎么知道递归到哪一层了呢?于是设计出了这样一种结构,能够把最近的程序递归状态放进去。返回的时候,从那个结构里面取出来,一定是最近的程序递归状态。这就是栈了。我们可以想成一筒薯片,每次只能拿最上面那一片。如果我们想把最下面那一片拿出来,那就必须把一整筒倒出来。

为了在访问元素时,能把先放进去的先访问,与栈正好相反,于是有了队列。队列在BFS中是不可或缺的(正如DFS与栈密不可分)。我们可以想象在银行排队办手续,那肯定得排队叫号了,这就是队列。但是有时候,我们会发现VIP可能比我们后来,却先去办手续了,这是因为队列是优先队列(然而优先队列并不是用队列实现的)。

计算机的文件系统我们每天都打交道,这种文件夹存放的方式使用的十分习惯了。我们无法想象如果没有文件夹,文件是顺序存储的,你只能从第一个文件一个个往后找,这样的话基本没有人会去找文件的。实际上计算机的文件系统构成的是一棵树,一个磁盘里面可能有很多很多文件夹,文件夹里面又有很多的文件与文件夹.....这就是树的应用。但是为什么我们学的树都是二叉树呢?因为树可以转换为二叉树(长子-兄弟法)。实际上族谱的记录可能也是一棵树....

图的应用就更普遍了,例如我曾经举过坐地铁的例子。实际上地铁站就构成了一张图,如果我们知道两站间需要多久才能到,我们就能根据这张图规划出该怎么坐地铁,这很cool。

说了这么多,其实我想说,掌握数据的意义与规律,规划合适的数据结构,才能更快更方便的写出程序。例如,我们如果把文件系统按照顺序存储,那是不堪设想的。如果我们把北京地铁图按照数组存储:[海淀黄庄、西直门、国家图书馆、....]这样我们想写程序规划路径,估计没个几天写不出来。

程序=数据结构+算法

这句话我相信大家都听过,那么我还是举个题目的例子来解释一下吧。

题目描述
输入两个整数 a,b,输出它们较大的数。

输入格式
两个整数以空格分开。

输出格式
一个整数。

输入输出样例
输入 
20 30
输出 
30

那么我们又可以马上开始写程序,很快就能写出来printf("%d", (a>b?a:b));这样的代码。

接着题目要我们输出三个数里面最大的数,开始棘手起来了,但是我们还是会用a,b,c存储。

if((a>b) && (a>c))
    max = a;
else if((b>a) && (b>c))
    max = b;
else
    max = c;

可以看到代码量多了不少。接着题目要我们输出四个数里面最大的数....正常人已经不会再用abcd存储了,因为实在是太麻烦了。而是会开始改用数组

for(int i = 1; i <= 4; i++)
    if(a[i] > max)
        max = a[i];

哪怕再让我们更多数找最大数,我们只需要改掉4就行。可以看到,非常方便。这一些肯定都不用别人来教,而是比较本能的能写出来。因为我们知道,在这种小数据量的时候怎么写最方便。

所以数据结构的选择与数据的规模,规律都是息息相关的。这可以帮助我们选择合适的数据结构。一旦数据结构选择合适,我们就能很快的写出代码。如果数据结构选择的不合适,例如我们用a,b,c,d来存,可能存的时候非常简单,但是求最大值的时候,代码量就很多了。其实,数据结构的选择是任意的,但是好的数据结构能帮助我们规划算法,而坏的数据结构则会让算法设计更加复杂甚至无法实现。同样好的算法可以加快速度,坏的算法则会减慢速度甚至运行错误。

所以程序=数据结构+算法是很好理解的。数据结构和算法在程序设计中就是相辅相成的。

数据结构的分类

最后我们把大学本科常用的数据结构分个类,作为对数据结构部分的总结。有的地方会把数据结构分为线性的和非线性的,有的又分成顺序的和链式的。当然都是可以的,但我感觉我的这个应该是最合理的。数据结构应该分为逻辑上的和物理实现上的。

逻辑上指的是我们如何规划数据结构,这里分为线性的和非线性的。线性的包括顺序表、链表、栈、队;非线性的包括树、图。

物理上指的是我们在程序中到底是如何存储这一数据结构的,这里才分为顺序的和链式的。顺序的就是用数组存储数据结构的,链式的则是用链来存储数据结构的。

需要注意逻辑上和物理上的并不是一一对应的关系,而是一对多多对一的关系。例如我们给出某一数据结构在实际中的物理储存实现,很多人会第一时间反应,这是条链表。其实并不一定。

它可能表示一个栈,可能表示一棵只有一边的二叉树,甚至可能表示一个有向图。

再比如我给一个数组,你也不知道它是栈还是队列还是顺序表,甚至可能是堆。

所以说,数据结构分为物理的和逻辑的更为准确。而至于怎么记和理解呢,我觉得还是以逻辑上的为主。每种逻辑上的数据结构都有自己最适合的物理上的实现。例如栈,其实很少用链式来实现。但双端队列用链式比数组方便不少。再例如同样是树,二叉搜索树大多采用链式存储,而二叉堆则完全可以用顺序的数组来存储。

总结

说了那么多,其实还是很想把数据结构到底是什么这一议题讲清楚的,尽管可能也没有讲清楚。作为以前数据结构没学好的人,我是走过一些弯路的。例如对着一个图生怼,半天怼不出啥结果。例如看教材上神秘的代码,却没法敲出来实现。再例如看着网上的教程又是*又是&的,.c编译都编译不了。

所以我的建议是,先理解什么是数据结构,再去学习,比对着一个算法对着一个数据结构生怼要好不少。然后选择一本适合的教材,最好能有从无到有的实现(不建议平时作业对着抄,但是可以对着自己实现一下),可以提升自己的自信心。最后推荐一下浙江大学陈越的数据结构课程(教材也可以网上买一本),对于要求C语言写数据结构的萌新来说的话,应该还是比较友好的。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值