数据 : 对计算机来说,能被计算机程序识别和处理的符号的集合。(比如二进制0和1)
数据元素:数据的基本单位,通常作为一个整体进行考虑和处理。(比如一个学生的信息是一个数据元素)
数据项 :构成数据元素 的最小单位。(学生的学号,姓名,班级构成一个学生信息)
要根据实际的业务需求来确定什么是数据元素、什么是数据项。
数据结构 :相互之间存在一种或多种特定关系的数据元素的集合。
比如汉字有左右、上下结构,把它们根据各自的结构拆开后,每个部分与每个部分间都存在 关系 。
再比如一张班级学生表,按学号从小到大排列,这种排列方式就代表了前后的数据结构(“前后”就代表了一种关系),而且班级的每个学生是一个数据元素,构成了一个班级这个集合。
数据对象 :具有相同性质的数据元素的集合,是数据的一个子集。
班级的每个学生是一个数据元素,每个学生都有相同的性质(具有学号、姓名、电话号码等信息),所有学生构成了一个集合。
区别 :数据结构强调 关系 ,数据对象强调 相同性质 。
数据结构的三要素
逻辑结构
存储结构(也叫物理结构),在计算机中将数据的逻辑结构中表示出来,也叫数据的存储方式
注意 :
如果是顺序存储,想要插入元素在某个特殊位置,则这个位置的每个元素都要往后移动一位;若是链式存储,只需要找到这个位置的前一个指针与后一个指针修改指向即可。(可以看出链式存储更方便)
2. 数据的存储结构会影响对数据运算的速度
例如想找到某个特定索引的元素,如果是顺序存储,直接下标访问即可(时间复杂度O(1));但如果是链式存储,需要从头节点开始查找(时间复杂度O(n))。
数据的运算
运算的 定义 是针对 逻辑结构 的,指出运算的功能;
线性表是一种线性结构,其逻辑结构是数据元素之间存在一对一的关系。线性表的常见运算包括:
- 插入:在指定位置插入一个元素。
- 删除:删除指定位置的元素。
- 查找:查找某个特定值的元素。
- 遍历:依次访问线性表中的每个元素。
这些运算的定义是基于线性表的逻辑结构的,即数据元素之间的一对一关系。无论线性表采用何种存储结构,这些运算的定义都是一样的。
运算的 实现 是针对 存储结构 的,指出运算的具体操作步骤。
假设我们使用数组来实现线性表,数组的每个元素存储线性表的一个数据元素。
- 插入:
- 定义:在指定位置插入一个元素。
- 实现:假设要在位置
i
插入一个元素x
,具体步骤如下:
- 从位置
i
开始,将所有元素向后移动一个位置,为新元素腾出空间。- 将新元素
x
放在位置i
。- 更新线性表的长度。
假设我们使用链表来实现线性表,链表的每个节点存储线性表的一个数据元素和指向下一个节点的指针。
- 插入:
- 定义:在指定位置插入一个元素。
- 实现:假设要在位置
i
插入一个元素x
,具体步骤如下:
- 创建一个新节点,存储新元素
x
。- 遍历链表,找到位置
i-1
的节点。- 将新节点插入到位置
i-1
的节点之后。
数据类型、抽象数据类型
数据类型是一个值的集合和定义在此集合上的一组操作的总称。
1)原子类型。其值不可再分的数据类型。
2)结构类型。其值可以再分解为若干成分(分量)的数据类型。
抽象数据类型(Abstract Data Type
,ADT)是抽象数据组织及与之相关的操作。
ADT 用数学化的语言定义数据的逻辑结构、定义运算。与具体的实现无关。
定义一个ADT,就是定义了数据的逻辑结构、数据的运算。也就是定义了一个数据结构。
比如后续学习的栈、队列、树等。
什么是算法?
算法(Algorithm
):对特定问题求解步骤的一种描述。
算法的特性
有穷性:一个算法总在执行有穷步之后结束,且每一步都可在有穷时间内完成
注:算法必须是有穷的,因为算法是有限步骤解决某个特定的问题。而程序可以是无穷的,如微信是程序,不是算法
确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得出相同的输出。
可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。
“好”算法的特质
1)正确性。算法应能够正确地解决求解问题。
2)可读性。算法应具有良好的可读性,以帮助人们理解。
3)健壮性。输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。
4)高效率与低存储量需求。高效率指的是花的时间少,时间复杂度低。低存储量指的是不费内存,空间复杂度低。
衡量一个算法的时间开销,不能用事后统计的方式,比如计算刚开始的时间与结束的时间差,这是因为存在与算法本身无关的外界因素,比如机器性能,编程语言的执行效率等。
因此,我们只能采用事前预估,即预估时间开销与 问题规模n 的关系。
常用技巧
加法规则:O(f(n)) + O(g(n)) = O(max(f(n),g(n)))
O(1) < O(log2n) < O(n) < O(nlog2n) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
乘法规则:O(f(n)) × O(g(n)) = O(f(n) × g(n))
三种复杂度
最坏时间复杂度:考虑输入数据“最坏”的情况
平均时间复杂度:考虑所有输入数据都等概率出现的情况
最好时间复杂度:考虑输入数据“最好”的情况
跟时间复杂度一样,空间复杂度只需关注存储空间大小与问题规模相关的变量即可。
加法规则与乘法规则也是和时间复杂度的方法一样
特别的,当该算法存在递归时,因根据实际情况来分析递归调用的深度,此时的深度就是空间复杂度的大小