数据结构和算法这是一门不太容易学好的课程,因为这门课程比较搞脑子,所以建议每循序渐进,并准备好鸡汤等营养品。
虽然这门课程不太好学,但如果你想让自己的编程能力有质的飞跃,不再停留于调用现成的东西而是追求更完美的实现,那么这是你的必修课!
如果你的目的是为了考计算机、软件方面的研究生,那么这门必考课现在就值得你开始准备。因为很多时候,考研玩的不是智商,其实就是一个人投入的时间而已。
什么是数据结构?
数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及它们之间的关系和操作等相关问题的学科。
简单来说,数据结构事实上就是这样子:
程序设计 = 数据结构 + 算法
再简单的来说数据结构就是关系,没错,就是数据元素相互之间存在的一种或多种特定关系的集合。
逻辑结构和物理结构
逻辑结构
传统上,我们把数据结构分为逻辑结构和物理结构。
- 逻辑结构:是指数据对象中数据元素之间的相互关系,也是我们今后最需要关注和讨论的问题。
- 物理结构:是指数据的逻辑结构在计算机中的存储形式。
接下来给大家介绍下四大逻辑结构吧:
(1)集合结构
集合结构中的数据元素除了同属于一个集合外,它们之间没有其他不三不四的关系。
(2)线性结构
线性结构中的数据元素之间是一对一的关系。
(3)树形结构
树形结构中的数据元素之间存在一种一对多的层次关系。
(4)图形结构
图形结构的数据元素是多对多的关系。
下面给出上述4中逻辑结构的图例:
物理结构
说完逻辑结构,我们再来说说数据的物理结构。
根据物理结构的定义,我们实际上研究的的就是如何把数据元素存储到计算机的存储器中。
存储器主要是针对内存而言的,像硬盘、软盘、光盘等外部存储器的数据组织通常用文件结构来描述。
数据元素的存储结构形式有两种:顺序存储和链式存储。
顺序存储结构
顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。
例如我们编程语言的数组结构就是这样滴。
链式存储结构
从顺序存储结构我们想到了日常生活中我们的排队,有木有?但现实生活中,我们发觉也并不完全如此。
例如有人排着排着她内急,她要被迫离开队伍去上洗手间,还有人不遵守基本基本道德规范他插队,这些情况会大破存储存储结构的基本原则。
面对这样时常要变化的结构,顺序存储是不科学的,那么就该让链式存储结构露面了。
现在如银行、医院等地方,都设置了排队系统。也就是每个人去了,先领一个号,等着叫号,叫到你的时候就可以去存一百块给我或看病。
而在等待的时候,你爱在哪在哪,可以坐着、站着或者四处看看美眉,只要你及时回来就行。
这些情况下,你关注的是前一个号有没有被叫到,叫到了,下一个就该轮到你了。
链式存储结构就是这样的原理,相比起顺序存储结构就灵活多了。
链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。
很显然,这样说的话链式存储结构的数据元素存储关系并不能反映其逻辑关系,因此需要用一个指针存放数据元素的地址,这样子通过地址就可以找到相关联数据元素的位置。
谈谈算法
我们这门课程叫“数据结构和算法”,这不是两门课程呢?为什么整在一起讲解呢?不是徒增我们的思想负担吗?
解释一下数据结构和算法的关系。
打个比方,其实数据结构和算法的关系就比好基友是一辈子的关系。
事实上,数据结构和算法也有类似的关系。只谈数据结构,我们可以在很短的时间内就把几种重要的数据结构介绍完。
不过听完后,你可能没啥感觉,不知道这些数据结构有啥用处。
但如果我们把相应的算法结合起来讲一讲,演示一下,你就会发现,甚至开始感慨:原来计算机界的前辈们,的确是一些很牛很牛的人,他们的工作使很多看似很难解决的问题变得如此美妙和神奇。
算法初体验
小学学过珠算的应该很有印象,每天加法运算敲得手指都快断了就算那1+2+…+99+100。
这会儿,就以一个从1加到100的小故事作为开端吧!
很久很久很久以前……(高斯先生的故事)
有人可能会不屑于顾,我们刚开始学习《零基础入门学习C语言》的时候,早就教过我们用C来写1加到100的代码咯。那时候你还说咱计算机的速度是何其快啊!
int i, sum = 0, n = 100;
for(i=1; i <= n; i++)
{
sum = sum + i;
}
printf(“%d”, sum);
对比下,用高斯先生的算法,我们可以这么写:
int i, sum = 0, n = 100;
sum = (1+n)*n/2;
printf(“%d”, sum);
可能以计算机的神速,两个算法都可以秒杀解决掉!但是,如果我们把条件换成1加到1千万,或者1加到1千亿,差距就可想而知了,甚至人脑都可以比电脑计算得快了。
那么什么是算法呢?
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
从刚才的例子中我们看到,对于给定的问题,是可以有多种算法来解决的。
这就像追女孩子,总不可能每个人追女孩子的方式都一样吧?
就像没有药可以包治百病一样,一个问题可以由多个算法解决,一个算法也不可能具有通解所有问题的能力。
算法的特性
考虑到大部分学习《数据结构和算法》的都是学生,都要对付各种考试和考核。
所以该教程也是针对性的要把经常考试的概念提一提说一说谈一谈侃一侃。
嗯,算法具有五个基本特征:输入、输出、有穷性、确定性和可行性。
(1)输入
算法具有零个或多个输入。
尽管对于绝大多数算法来说,输入参数都是必要的。但是有些时候,像打印“I love csdn.net”,就不需要啥参数啦。
void print()
{
printf(“I love csdn.net\n”);
}
(2)输出
算法至少有一个或多个输出。
算法是一定要输出的,不需要它输出,那你要这个算法来干啥?输出的形式可以是打印形式输出,也可以是返回一个值或多个值等。
(3)有穷性
指算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成。一个永远都不会结束的算法,我们还要他来干啥?
(4)确定性
算法的每一个步骤都具有确定的含义,不会出现二义性。
算法在一定条件下,只有一条执行路径,相同的输入只能有唯一的输出结果。
算法的每个步骤都应该被精确定义而无歧义。
(5)可行性
算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限次数完成。
算法设计的要求
刚才我们谈到了,算法并不是唯一的。也就是说同一个问题,可以有多种解决问题的算法。
这可能让那些常年只做有标准答案题目的童鞋失望了,他们多么希望存在标准答案,因为只有一个正确的,把它背下来万事大吉!
但是咱的算法是变幻无穷的,还记得我们刚才讲过的高斯童鞋吗?世界上要多几个这样的童鞋,那又会有多几种牛掰的算法哈。
尽管算法不唯一,但我们要学习掌握一些好的算法,对我们解决问题很有帮助!
(1)正确性
算法的正确性是指算法至少应该具有输入、输出和加工处理无歧义性、能正确反映问题的需求、能够得到问题的正确答案。
大体分为以下四个层次:
- 算法程序没有语法错误。
- 算法程序对于合法输入能够产生满足要求的输出。
- 算法程序对于非法输入能够产生满足规格的说明。
- 算法程序对于故意刁难的测试输入都有满足要求的输出结果。
(2)可读性
算法设计另一目的是为了便于阅读、理解和交流。
我么写代码的目的,一方面是为了让计算机执行,但还有一个重要的目的是为了便于他人阅读和自己日后阅读修改。
(3)健壮性
当输入数据不合法时,算法也能做出相关处理,而不是产生异常、崩溃或莫名其妙的结果。
(4)时间效率高和存储量低
生活中,每个男人都希望找一个贤惠的老婆,她们温柔又体贴,美丽又大方,还会做着一手的好菜。
好算法就犹如好老婆,应该具备时间效率高和存储量低的特点。所以在设计算法的时候我们应该尽量思考这两方面的问题!