目 录
1 数据结构的基本概念
1.1 数据元素与数据项
什么是数据元素?什么是数据项?
数据元素、数据项数据元素是数据的基本单位,通常作为一个整体进行考虑和处理个数据元素可由若干数据项组成,数据项是构成数据元素的不可分割的最小单位。
1.2 数据对象
数据对象是具有相同性质的数据元素的集合,是数据的一个子集。
例如在图书管理系统中,数据库里图书馆的书籍名是一个集合,isbn号也是一个集合
1.3 数据结构
什么是数据结构?
在计算机中:程序=数据结构+算法
在数据对象中,数据元素可以组成不同的数据结构,例如有逻辑结构(线性关系,非线性关系),树状结构以及图等。
线性关系:各个元素之间是一种一对一的关系,比如图书馆中的书架的书,除了首尾两本书之外,其余的任意一本书的编号假设是N,都有且仅有一个直接前驱节点N-1,有且仅有一个直接后继节点N+1。这种关系就是典型的线性逻辑。
非线性关系:与上述线性关系的表述不同,如果各个元素之间不是严格一对一的关系,则被称为非线性关系,比如家族中的各个成员、不同城市间的交通道路等,对于它们中间的某个元素,都可能有不止一个元素与之关联。这种关系是典型的非线性逻辑。
不同的数据结构有不同的存储方式,最常见的存储方式有顺序存储以及链式存储,不同的存储方式对最终数据处理效率有很大影响。逻辑结构与存储形式无必然联系。
1.4 算法
算法分析是指算法在正确的情况下,对其优劣的分析。一个好的算法通常是指:
- 算法对应的程序所耗时间少
- 算法对应的程序所耗存储空间少
- 算法结构性好、易读、易移植和调试
数据结构与算法的本质任务,是提高程序的时间空间效率,简单讲就是让程序的执行速度越快越好,所需内存空间越少越好。虽然在很多情况下,程序的时空特性是相互制约的,就像鱼和熊掌不可兼得,但我们可以根据程序实际解决问题的侧重点,去平衡时间和空间的对性能的消耗。
1.5 时间复杂度
时间复杂度一般指的是代码的语句执行总次数,称为语句频度。在程序中,时间复杂度因为计算机的参数不同,因此时间复杂度不考虑绝对时间。
例子1:
void counting(int n)
{
for(int i=0; i<n; i++)
{
printf("本行语句将会出现n次\n");
for(int j=0; j<n; j++)
{
printf("本行语句将会出现n*n次\n");
}
}
}
在上述代码中,程序执行的语句频度理论是:T(n)=n^2+n
但一般情况下,我们只关心多项式的最高次幂,于是上述代码的时间复杂度我们表示为:
T(n)=O(n^2)
例子2:
for(int i = 1; i <= n; i++)
{
int j = 1;
while (j<=n)
{
j = j * 2;
}
}
外层循环的时间复杂度是 𝑂(𝑛)。
内层循环的时间复杂度则取决于n的值。由于内层循环中的j每次迭代都乘以2,所以它将达到或超过n的值的迭代次数是 log2𝑛。
当我们说由于内层循环中的 j 每次迭代都乘以2,所以它将达到或超过 𝑛 的值的迭代次数是 log2𝑛,这里的意思是,我们想要找到 𝑗 乘以2多少次后会等于或超过 𝑛。
所以语句频度是:T(n)=n* log2n
这意味着,该程序算法所需要的时间,与传进来的参数n的平方成正比。
不同算法的时间复杂度相差很大,如下图所示,随着所处理的问题规模的增大,不同时间复杂度的程序所需要的时间有天壤之别。
1.6 空间复杂度
空间复杂度是一段程序运行时所需的内存字节量。
下面举个例子来表示空间复杂度:
我们定义了一个array,它的空间复杂度为 S(n) = n;
而定义二维数组array,它的空间复杂度为S(n) = n²
1.7 时空复杂度
俗话说鱼和熊掌不可兼得,一段程序的性能指标,既要运行快速,又要节省内存,而通常这两者又是相互制约的,很难兼得。因此在实际解决问题时,会根据需要侧重一方,牺牲另一方。
则想要让算法的效率更快,时间更快,需要牺牲空间。