绪论
之前在大二上过数据结构课,不过早已经把知识还给了老师,最近出于各种需求,决定重新拾起来,在博客上记录学习过程,本人文笔粗糙,也不指望有人看了。
我用的是各大高校广泛使用的严蔚敏版的数据结构(晦涩难懂。。。),第一章绪论部分没太多重要部分,我着重记录几个知识点
数据结构基本概念和术语
- 数据(data):所有能被计算机识别、存储和处理的符号的集合(不多解释)。
- 数据元素(data element):数据的基本单位,一个数据元素由多个数据项组成,数据项是不可分割的最小单位啦。
比如,一个学生是一个数据元素的话,学生的学号,姓名,性别等信息都是一个个数据项。 - 数据对象(data object):是性质相同的数据元素的一个集合,也是数据的一个子集啦。
- 数据结构(data structure):互相之间存在一种或多种关系的数据元素的集合。互相之间存在一种或多种关系称为结构,通常有4种基本结构。
- 数据结构的三要素:数据的逻辑结构,数据的物理结构(存储结构),数据的运算。
数据的逻辑结构:是从逻辑关系上来描述数据,它与数据的存储无关,是独立于计算机的。它有两类划分方式,一类划分方式可以分为线性结构和非线性结构。
另一类可以划分为如下4种基本数据结构
1 集合
数据元素之间除了同属一个集合,没啥关系。
2 线性结构
数据元素之间存在一对一的关系。
3 树形结构
数据元素之间存在一对多的关系。
4 图状结构(网状结构)
数据元素之间存在多对多的关系。
数据的物理结构:根据数据元素之间的关系在计算机有两种不同表示方法,顺序映像和非顺序映像,由此可分为顺序存储结构和链式存储结构。
数据的运算:检索、排序、插入、删除、修改等 - 数据类型(data type):是一个值的集合和定义在该值上的一组操作的总称。
- 抽象数据类型(abstract date dype,简称ADT):一个数学模型以及定义在该模型上的操作,和数据类型实质是一个概念。
- 多形数据类型(polymorphic data type):其值的成分不确定的数据类型。
算法和算法分析
- 算法(algorithm):对特定问题求解步骤的一种描述,是指令的有限序列,每一条指令包括1或多个操作。算法具备以下5个特性。
1.1有穷性:一个算法在执行有限步骤,每一步执行有限时间后完成。
1.2确定性:算法的每一条指令都有明确定义。
1.3可行性:算法的所有操作都可执行。
1.4输入:一个算法有0或多个输入。
1.5输出:一个算法有1或多个输出。 - 算法设计的要求:正确性,可读性,健壮性,效率与低存储量需求。
时间复杂度与空间复杂度
时间复杂度
时间复杂度:T(n)=O(f(n)) ,执行次数T(n) 是关于问题规模n的函数。
f(n)的增长率:即随问题规模n增大,算法执行时间的增长率。
我们通常用大写O()来体现算法时间复杂度的记法,称为大O阶方法,有3个步骤来推导。
1 用**常数1**取代运行时间中的所有**加法常数**。
2 在修改后的运行次数函数中,只**保留最高阶项**。
3 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
推导时间复杂度的大O阶方法
-
常数阶
1 int sum = 0, n = 100; /*执行一次*/ 2 3 sum = (1 + n) * n / 2; /*执行一次*/ 4 5 printf("%d",sum); /*执行一次*/
这个算法的运行次数函数是f (n) =3。 根据我们推导大O阶的方法,第一步就是把常数项3 改为1。在保留最高阶项时发现,它根本没有最高阶项,所以这个算法的时间复杂度为O(1)。
-
线性阶
1 int i; 2 3 for(i = 0; i < n; i++){ 4 5 /*时间复杂度为O(1)的程序步骤序列*/ 6 7 }
它的循环的时间复杂度为O(n), 因为循环体中的代码须要执行n次。
-
对数阶
1 int count = 1; 2 3 while (count < n){ 4 5 count = count * 2; 6 7 /*时间复杂度为O(1)的程序步骤序列*/ 8 9 }
由2^x=n 得到x=logn。 所以这个循环的时间复杂度为O(logn)。
-
平方阶
1 int i, j; 2 3 for(i = 0; i < n; i++){ 4 5 for(j = 0; j < n; j++){ 6 7 /*时间复杂度为O(1)的程序步骤序列*/ 8 9 } 10 11 }
这段代码的时间复杂度为O(n^2)。如果外循环的循环次数改为了m,时间复杂度就变为O(mXn)。
1 int i, j; 2 3 for(i = 0; i < n; i++){ 4 5 for(j = i; j < n; j++){ /*注意j = i而不是0*/ 6 7 /*时间复杂度为O(1)的程序步骤序列*/ 8 9 } 10 11 }
当i=0时,内循环执行了n次,当i = 1时,执行了n-1次,到当i=n-1时,执行了1次。所以总执行次数为:
n+(n-1)+(n-2)+…+1=n(n+1)/2=n^2/2+n/2
根据大O阶方法,第一条,没有加法常数不予考虑;第二条,只保留最高阶项,因此保留时(n^2)/2; 第三条,去除这个项相乘的常数,也就是去除1/2,最终这段代码的时间复杂度为O(n^2)。 -
立方阶
int i, j; for(i = 1; i < n; i++) for(j = 1; j < n; j++) for(j = 1; j < n; j++){ /*时间复杂度为O(1)的程序步骤序列*/ }
按照上述大O阶推导方法,时间复杂度为O(n^3)。
时间复杂度大小排序
常用的时间复杂度所耗费的时间从小到大依次是:
时间复杂度的最坏情况、最好情况与平均情况
比如我们在一个a[n]数组查找一个数字,最好情况是第一次就查到了,最坏的一种情况是最后一次查到,那么算法的时间复杂度就是O(n)。
最坏情况运行时间是一种保证,那就是运行时间将不会再坏了。通常, 一般讨论的时间复杂度均是最坏时间复杂度。
空间复杂度
S(n)= O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。
存储空间分为三部分,1是指令、常数、变量所占据的空间,2是输入数据占用的空间,3是一些对数据进行操作的工作单元和存储计算所需信息的辅助空间。
其中算法的空间复杂度指的是辅助空间,一维数组a[n]空间复杂度O(n),二维数组a[n][m]空间复杂度O(n*m)。