数据结构与算法——学习整理记录

=注:此文由本人结合网上资源整理总结而来,仅代表个人的学习与理解,如有错漏,欢迎指正!=

1. 数据结构


1.1 数据结构是什么?


数据结构,直白地理解,就是研究数据的逻辑关系与存储方式的一门学科。

可以简单的分为:数据的逻辑结构(逻辑关系)和数据的存储结构(物理结构)。

它是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作。

1.1.1 数据的逻辑结构


数据的逻辑结构,简单地理解,就是指的数据之间的逻辑关系

数据之间的逻辑关系可简单的分为三类:

  • 一对一
  • 一对多
  • 多对多

1.1.1 数据的存储结构


数据的存储结构,也就是物理结构,指的是数据在物理存储空间上的存放方式,可以选择集中存放,还是分散存放

假设要存储大小为 10M 的数据,则集中存放就如图1(a)所示,分散存放就如图1(b)所示。

图1(a)集中存放

图1(a) 数据的集中存放

图1(b) 数据的分散存放

图1(b) 数据的分散存放

1.2 为什么要用数据结构?


使用数据结构的目的,即方便对数据的利用和操作。

1.3 数据结构有哪些?


根据数据的逻辑结构和存储结构,可以把数据结构分为三大类:

  • 第一类:线性表,用于存储具有“一对一”逻辑关系的数据。包括顺序表、链表、栈和队列;
  • 第二类:树结构,用于存储具有“一对多”逻辑关系的数据。包括普通树,二叉树,线索二叉树等;
  • 第三类:图结构,用于存储具有“多对多”逻辑关系的数据;

1.4 如何使用数据结构?


可以通过分析数据之间的逻辑关系来决定使用哪种存储结构,但具体使用顺序存储还是链式存储,还要通过数据的物理结构来决定。

如果选择集中存储,就使用顺序存储结构;反之,就使用链式存储。至于如何选择,主要取决于存储设备的状态以及数据的用途。

数据的用途不同,选择的存储结构也不同。将数据进行集中存储有利于后期对数据进行遍历操作,而分散存储更有利于后期增加或删除数据。因此,如果后期需要对数据进行大量的检索(遍历),就选择集中存储;反之,若后期需要对数据做进一步更新(增加或删除),则选择分散存储。

2. 算法


2.1 算法是什么:


算法,从表面意思来理解,即解决问题的方法。

算法是为求解一个问题需要遵循的、被清楚指定的简单指令的集合。

在计算机中,算法是指解决方案的准确而完整的描述。

2.1.1 算法与程序


算法是解决某个问题的想法、思路;而程序是在心中有算法的前提下编写出来的可以运行的代码。

某种程度上,算法相当于是程序的雏形。

当解决问题时,首先心中要有解决问题的算法,围绕算法编写出程序代码。

2.2 算法设计的要求


准确性、健壮性、运行效率(复杂度)

对于一个问题,想出解决的算法,不一定就能解决这个问题。为了避免这种情况的发生,要充分全面地思考问题,尽可能地考虑到所有地可能情况,慎重选择算法(需要在实践中不断地积累经验)。

2.2.1 算法的运行效率(复杂度)


算法的运行效率(复杂度)体现在两方面:

  • 算法的运行时间。(称为“时间复杂度”)
  • 运行算法所需的内存空间大小。(称为“空间复杂度”)

拿时间换空间,用空间换时间


算法的时间复杂度和空间复杂度是可以相互转化的。

比如:谷歌浏览器相比于其他的浏览器,运行速度要快。是因为它占用了更多的内存空间,以空间换取了时间。

2.3 一个好算法的标准


在符合算法本身的要求(准确性和健壮性)的基础上,使用算法编写的程序运行的时间短,运行过程中占用的内存空间少,就可以称这个算法是“好算法”。

2.4 算法时间复杂度计算


计算一个算法的时间复杂度,不可能把所有的算法都编写出实际的程序出来让计算机跑,这样会做很多无用功,效率太低。实际采用的方法是估算算法的时间复杂度。

程序(C语言)一般由三种结构构成:顺序结构、分支结构和循环结构。顺序结构和分支结构中的每段代码只运行一次;循环结构中的代码的运行时间要看循环的次数。

由于是估算算法的时间复杂度,相比而言,循环结构对算法的执行时间影响更大。所以,算法的时间复杂度,主要看算法中使用到的循环结构中代码循环的次数(称为“频度”)。次数越少,算法的时间复杂度越低。

2.4.1 时间复杂度的表示


算法的时间复杂度的表示方式为:

O(频度)

这种表示方式称为大“O”记法
——注意,是大写的字母O,不是数字0。

例如:

a) ++x; s=0;

b) for (int i=1; i<=n; i++) { ++x; s+=x; }

c) for (int i=1; i<=n; i++) { for (int j=1; i<=n; j++) { ++x; s+=x; } }

上边这个例子中,a 代码的运行了 1 次,b 代码的运行了 n 次,c 代码运行了 n*n 次。

所以使用算法的时间复杂度表示为:

a 的时间复杂度为O(1),b 的时间复杂度为O(n),c 的时间复杂度为为O(n2)。

如果把a、b、c三个例子组成一段程序,那么算法的时间复杂度为O(n2+n+1)。但这么表示是不对的,还需要对n2+n+1进行简化。

简化的过程总结为3步:

  • 去掉运行时间中的所有加法常数。(例如 n2+n+1,直接变为 n2+n)
  • 只保留最高项。(例如 n2+n 变成 n2
  • 如果最高项存在但是系数不是1,去掉系数。(例如 n2 系数为 1)

所以,最终a、b和c合并而成的代码的时间复杂度为O(n2)。

2.5 常用的时间复杂度的排序


列举了几种常见的算法时间复杂度的比较(又小到大):

O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)

3. 数据结构与算法关系

可以从分析问题的角度去理清数据结构和算法之间的关系。

通常,每个问题的解决都经过以下两个步骤:

  • 第一步:分析问题,从问题中提取出有价值的数据,将其存储;
  • 第二步:对存储的数据进行处理,最终得出问题的答案;

数据结构负责解决第一个问题,即数据的存储问题。针对数据不同的逻辑结构和物理结构,可以选出最优的数据存储结构来存储数据。而算法负责为剩下的第二个问题提供解决方案。

总而言之,数据结构用于解决数据存储问题,而算法用于处理和分析数据,它们是完全不同的两类学科。

参考


posted @ 2018-11-28 06:12  elinuxboy  阅读(1175)  评论(1编辑  收藏  举报