学习资料来源【算法通关手册】:https://algo.itcharge.cn/
【datawhale组队学习】https://github.com/datawhalechina/team-learning
大多是对这次组队学习的学习资料的学习笔记,非原创~
1数据结构与算法
- 数据结构(Data Structure) 是数据的计算机表示和相应的一组操作。
- 我们追求的是:选择更加合适的「数据结构」,使用花费时间更少、占用空间更小的「算法」。
- 在编程中从时间复杂度、空间复杂度方面考虑解决方案
1.1数据结构
- 数据的组织结构,用来组织、存储数据。
- 数据结构研究的是数据的逻辑结构、物理结构以及它们之间的相互关系,并对这种结构定义相应的运算,设计出相应的算法,并确保经过这些运算以后所得到的新结构仍保持原来的结构类型。
- 数据结构的作用,就是为了提高计算机硬件的利用率。
- 数据结构可以分为【逻辑结构】和【物理结构】
1.1.1数据的逻辑结构
- 集合结构
- 线性结构【一对一】
- 数组、链表->栈、队列、哈希表
- 左侧和右侧分别只有一个数据与其相邻(除了首位)
- 树形结构【一对多】
- 二叉树:根, 左子树, 右子树
- 多叉树、字典树
- 图形结构【多对多】
- 任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的
- 无向图、有向图、连通图
1.1.2数据的物理结构
物理结构(Physical Structure):数据的逻辑结构在计算机中的存储方式。
常用的物理结构有:顺序存储结构、链式存储结构。
- 顺序存储结构(Sequential Storage Structure)
- 地址连续(存储单元),逻辑相邻
- 数据元素之间的逻辑关系通过数据元素的存储地址来直接反映
- 简单,占用少;但需要占用连续,事先进行存储分配、操作的时间效率较低
- 链式存储结构 (Linked Storage Structure):将数据元素存放在任意的存储单元里,存储单元可以连续,也可以不连续。
- 链结点:将每个数据元素占用的若干单元的组合
- 每个链结点存放:
- 一个数据元素的数据信息
- 指针:这个数据元素在逻辑关系的直接后继元素所在链结点的地址。换句话说,数据元素之间的逻辑关系是通过指针来间接反映的。
- 存储空间不必事先分配,可以临时申请,不会造成空间的浪费。操作的时间效率远比顺序存储结构高;指针也需要占用存储空间,空间开销大。
1.2算法
一系列指令的集合,解决问题的方法。
1.2.1算法的基本特性
- 输入
- 输出
- 有穷性
- 确定性
- 可行性
1.2.2算法追求的目标
-
所需运行时间更少(时间复杂度更低);
-
占用内存空间更小(空间复杂度更低)。
-
正确性:正确性是指算法能够满足具体问题的需求,程序运行正常,无语法错误,能够通过典型的软件测试,达到预期的需求。
-
可读性:可读性指的是算法遵循标识符命名规则,简洁易懂,注释语句恰当,方便自己和他人阅读,便于后期修改和调试。
-
健壮性:健壮性指的是算法对非法数据以及操作有较好的反应和处理。
1.3总结
1.3.1数据结构总结
「逻辑结构」指的是数据之间的 关系,「物理结构」指的是这种关系 在计算机中的表现形式。
- 栈(线性表):数据元素之间的关系是一对一的,除头和尾结点之外的每个结点都有唯一的前驱和唯一的后继,这体现的是逻辑结构。对栈中结点:
- 顺序栈:一段连续的存储空间,栈中每个结点和它的前驱结点、后继结点在物理上都是相邻的。
- 链式栈:每个结点和它的前驱结点、后继结点在物理上不一定相邻,每个结点是靠前驱结点的指针域来进行访问的。
1.4算法复杂度
算法复杂度(Algorithm complexity):在问题的输入规模为 n 的条件下,程序的时间使用情况和空间使用情况。
- 「问题规模 n」 指的是:算法问题输入的数据量大小:
- 排序算法中:n 表示需要排序的元素数量。
- 查找算法中:n 表示查找范围内的元素总数:比如数组大小、二维矩阵大小、字符串长度、二叉树节点数、图的节点数、图的边界点等。
- 二进制计算相关算法中:n 表示二进制的展开宽度。
1.4.1时间复杂度
时间复杂度(Time Complexity):在问题的输入规模为 n 的条件下,算法运行所需要花费的时间,可以记作为 T(n)。
- 基本操作次数作为时间复杂度的度量标准
- 基本操作 :算法执行中的每一条语句。每一次基本操作都可在常数时间内完成。
- 比如两个整数相加的操作,如果两个数的规模不大,运行时间不依赖于整数的位数,则相加操作就可以看做是基本操作。
- f ( n ) : f(n): f(n):语句执行次数
- T ( n ) = O ( f ( n ) ) T(n)=O(f(n)) T(n)=O(f(n)),称为渐近时间复杂度,简称时间复杂度
1.4.2渐近符号
-
Θ
\Theta
Θ
- 渐近紧确界,上下界都是常数倍
-
O
O
O
- 渐近上界
-
Ω
\Omega
Ω
- 渐近下界
1.4.3时间复杂度计算
通常使用渐近上界 O O O,求解时间复杂度的步骤:
- 找出算法中的基本操作(基本语句):算法中执行次数最多的语句就是基本语句,通常是最内层循环的循环体部分。
- 计算基本语句执行次数的数量级:只需要计算基本语句执行次数的数量级,即保证函数中的最高次幂正确即可。像最高次幂的系数和低次幂可以忽略。
- 用大 O 表示法表示时间复杂度:将上一步中计算的数量级放入 O 渐进上界符号中。
求解原则:
- 加法原则:总的时间复杂度等于量级最大的基本语句的时间复杂度。
- 乘法原则:循环嵌套代码的复杂度等于嵌套内外基本语句的时间复杂度乘积。
举例:
- 常数 O ( 1 ) O(1) O(1),要算法中不存在循环语句、递归语句,其时间复杂度都是 O ( 1 ) O(1) O(1)
- 线性 O ( n ) O(n) O(n),随着问题规模n的增大,对应计算次数呈线性增长
- 平方 O ( n 2 ) O(n^2) O(n2)
- 阶乘
O
(
n
!
)
O(n!)
O(n!) 多见【全排列算法】:
def algorithm(n):
if n <= 0:
return 1
return n * algorithm(n - 1) - 对数 O ( l o g 2 n ) O(log_2n) O(log2n) 多见【二分查找】【分治】这种一分为二的算法中。
- 线性对数 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) 【快速排序】、【归并排序】、【堆排序】;例如:外城logn,内层n
- 排序: O ( 1 ) < O ( l o g 2 n ) < O ( n ) < O ( n l o g 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(log_2n)<O(n)<O(nlog_2n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
1.4.4最佳、最坏、平均时间复杂度
最佳时间复杂度:每个输入规模下用时最短的输入对应的时间复杂度。
最坏时间复杂度:每个输入规模下用时最长的输入对应的时间复杂度。
平均时间复杂度:每个输入规模下所有可能输入对应用时平均值的复杂度(随机输入下期望用时的复杂度)。
1.5空间复杂度
空间复杂度(Space Complexity):在问题的输入规模为 n 的条件下,算法所占用的空间大小,可以记作为 S(n)。一般将 算法的辅助空间作为衡量空间复杂度的标准。主要包括:
- 「局部变量(算法范围内定义的变量)所占用的存储空间」
- 「系统为实现递归(如果算法是递归的话)所使用的堆栈空间」