经常使用数据结构操做与算法复杂度总结

博客:blog.shinelee.me | 博客园 | CSDN算法

时间复杂度

如何评估一个算法的计算时间?数据结构

一个算法的实际运行时间很难评估,当时的输入、CPU主频、内存、数据传输速度、是否有其余程序在抢占资源等等,这些因素都会影响算法的实际运行时间。为了公平地对比不一样算法的效率,须要脱离开这些物理条件,抽象出一个数学描述。在全部这些因素中,问题的规模每每是决定算法时间的最主要因素。所以,定义算法的时间复杂度\(T(n)\),用来描述算法的执行时间随着输入规模的增加将如何变化,增加速度是怎样的数据结构和算法

在输入规模较小时,运行时间原本就少,不一样算法的差别不大。因此,时间复杂度一般关注的是输入规模\(n\)较大时运行时间的变化趋势,称之为渐进复杂度,采用大O记号,表示渐进上界,对于任意的\(n >> 2\),如有常数\(c\)和函数\(f(n)\)知足
\[ T(n) \leq c \cdot f(n) \]
则记做
\[ T(n) = O(f(n)) \]
能够简单地认为,\(O(f(n))\)表示运行时间与\(f(n)\)成正比,好比\(O(n^2)\)表示运行时间与输入规模的平方成正比,这样讲虽然并不严谨,但通常状况下无伤大雅函数

\(n\)很大时,常数\(c\)变得可有可无,不一样算法间的比较主要关注\(f(n)\)部分的大小。好比,在\(n >> 100\)时,\(n^2\)要比\(100n\)大得多,所以重点关注\(n^2\)\(n\)增加速度的差别便可。优化

不一样时间复杂度的增加速度对好比下,图片来自Big-O Cheat Sheet Posterui

Big-O Complexity

除了大\(O\)记号,还有大\(\Omega\)记号和\(\Theta\)记号,分别表示下界和确界,
\[ \Omega(f(n)) : \ c\cdot f(n) \leq T(n) \\\Theta(f(n)) : \ c_1 \cdot f(n) \leq T(n) \leq c_2 \cdot f(n) \]
他们的关系以下图所示,图片截自邓俊辉-数据结构C++描述第三版spa

渐进复杂度不一样记号关系

经常使用数据结构操做与算法的复杂度

下面汇总摘录了经常使用数据结构操做和排序算法的复杂度,来源见引用。其中包含最坏时间复杂度、平均时间复杂度以及空间复杂度等,对于排序算法还含有最好时间复杂度。.net

Common Data Structure Operations

Graph and Heap Operations

array sorting algorithms

附带上连接:server

Array Stack Queue Singly-Linked List Doubly-Linked List Skip List Hash Table Binary Search Tree Cartesian Tree B-Tree Red-Black Tree Splay Tree AVL Tree KD Tree

Quicksort Mergesort Timsort Heapsort Bubble Sort Insertion Sort Selection Sort Tree Sort Shell Sort Bucket Sort Radix Sort Counting Sort Cubesort

以及Data Structures in geeksforgeeks

输入规模较小时的状况

渐进复杂度分析的是输入规模较大时的状况,输入规模较小时呢?

在输入规模较小时,就不能轻易地忽略掉常数\(c\)的做用,以下图所示,图片来自Growth Rates Review复杂度增加快的在输入规模较小时可能会小于复杂度增加慢的

complexity growth rates

因此在选择算法时,不能无脑上看起来更快的高级数据结构和算法,还得具体问题具体分析,由于高级数据结构和算法在实现时每每附带额外的计算开销,若是其带来的增益没法抵消掉隐含的代价,可能就会得不偿失。

这同时也给了咱们在代码优化方向上的启示,

  • 一是从\(f(n)\)上进行优化,好比使用更高级的算法和数据结构;
  • 还有是对常数\(c\)进行优化,好比移除循环体中没必要要的索引计算、重复计算等。

以上

引用

相关文章
相关标签/搜索