算法与数据结构学习笔记

认识时间复杂度

什么是常数操作?

一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。

​ 我们常见的常数操作,如加减乘除和位(^)运算等,比如我们在写代码时,常常会写 int a = arr[i],因为这个操作和arr的数据量没什么关系,只是把i位置的元素取出,是一个固定的事件。

​ 如果有一个链表,我们想要拿到它 i 位置的值,int b = list。get(i),虽然链表在逻辑概念是一个从左到右的线性结构,但在计算机底层实际结构中,我们不知道它下面的next指向哪里,所以要找到 i的位置,就必须通过遍历才能得到,即此操作不是常数操作。

时间复杂度

时间复杂度就是算法流程中,来估计常数操作数量的一个指标。常用 O(读作bigO) 来表示。

​ 具体来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少常数操作,进而总结出常数操作数量的表达式。

如何确定算法流程的时间复杂度?

​ 当确定了算法表达式,只保留高阶项,去除低阶项,高阶项的系数也去掉,剩下的部分如果为f(N),那么时间复杂度为O(N)。例如一个选择排序,我们计算出它的常数操作数量的表达式为:a * n² + b * n +c,时间复杂度我们计算为O(N²),评价一个算法流程的好坏,先看时间复杂度的指标,当时间复杂度相同时,可以比较实际运行时间,也就是“常数项时间”。

额外空间复杂度:算法运行所耗费的储存空间。

排序算法

排序算法 时间复杂度 空间复杂度 稳定性 基于比较
选择排序 O(N²) O(1) ×
冒泡排序 O(N²) O(1)
插入排序 O(N²) O(1)
归并排序 O(N*logN) O(N)
快排 O(N*logN) O(logN) ×
堆排 O(N*logN) O(1) ×
计数排序 O(N)
基数排序 O(N)
  1. 稳定性:数组中值相同的元素,使用排序算法排序后,这些相同的元素相对次序位置不发生改变(桶排序思想),该排序算法就具备稳定性。
  2. 一般情况下选择一种排序算法的话,选择快速排序 (虽然快排和堆排时间复杂度是一样,但是快排的常数时间是最快的),只有储存空间有限制的时候才选择堆排序。
  3. 基于比较的排序,没有一种算法可以将时间复杂度做到O(N*logN)以下*
  4. 基于比较的排序,在时间复杂度为O(N*logN)情况下,空间复杂度在O(N)以下,没有一种算法可以做到稳定
常见的坑(非常难,不要求掌握,会破坏):
  • 归并排序额外空间复杂度可以通过 “归并排序内部缓存法” 降为O(1),但会丢失其稳定性。
  • 原地归并排序可以将额外空间复杂度变为O(1),但是时间复杂度会变成O(N^2)。
  • 快速排序可以通过论文"01 stable sort"将稳定性变为稳定,但是于此同时,其额外空间复杂度会变成O(N)
posted @ 2022-05-04 23:29  是廖一啊  阅读(94)  评论(0编辑  收藏  举报