数组 (Array)
- 访问元素:O(1)
- 数组:O(1) 无论数组中有多少元素,只要知道索引,就可以直接访问元素。
- 链表:O(n) 链表需要从头开始逐个遍历节点,直到找到目标节点,因此访问的时间与链表的长度成正比。
- 搜索:O(n)
- 无序数组:O(n) 在无序数组中搜索需要逐个比较每个元素,直到找到目标元素或者遍历完整个数组。
- 有序数组:O(log n) 使用二分查找可以将搜索范围每次减半,因此时间复杂度是对数级别的。
- 二叉搜索树(BST):O(log n) ~ O(n) 在平衡的情况下,二叉搜索树的搜索时间复杂度是O(log n),但在最坏情况下可能退化为链表,时间复杂度变为O(n)。
- 插入或删除:
- 数组:
- 在末尾插入或删除:O(1)
- 在开头插入或删除:O(n)
- 在中间插入或删除:O(n)
- 链表:
- 在任意位置插入或删除:O(1) 只需修改相邻节点的指针即可完成插入或删除操作。
- 数组:
- 排序:
- 选择排序:O(n^2)
- 插入排序:O(n^2)
- 冒泡排序:O(n^2)
- 堆排序:O(n log n)
- 归并排序:O(n log n)
- 快速排序:O(n log n)
链表 (Linked List)
- 访问元素:O(n)
- 搜索:O(n)
- 插入:
- 头部插入:O(1)
- 尾部插入:O(n) (需要遍历至链表尾部)
- 中间插入:O(n) (需要遍历至插入位置)
- 删除:
- 头部删除:O(1)
- 尾部删除:O(n) (需要遍历至倒数第二个节点)
- 中间删除:O(n) (需要遍历至待删除节点)
- 定义:链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
- 基本操作:
- 插入:在链表的任意位置插入元素。时间复杂度为O(1)到O(n),取决于插入位置。
- 删除:删除链表中的指定元素或节点。时间复杂度为O(1)到O(n),取决于删除位置。
- 访问:根据索引或位置访问链表中的元素。时间复杂度为O(n)。
- 适用场景:适用于需要频繁插入和删除操作,但不需要频繁随机访问的情况。
栈 (Stack)
- 入栈:O(1)
- 出栈:O(1)
- 查看栈顶元素:O(1)
- 定义:栈是一种后进先出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。
- 基本操作:
- 入栈:将元素压入栈顶。时间复杂度为O(1)。
- 出栈:从栈顶弹出元素。时间复杂度为O(1)。
- 查看栈顶元素:获取栈顶元素但不弹出。时间复杂度为O(1)。
- 适用场景:适用于需要临时保存数据并且后进先出的场景,如函数调用、表达式求值等。
队列 (Queue)
- 入队:O(1)
- 出队:O(1)
- 查看队首/队尾元素:O(1)
- 定义:队列是一种先进先出(FIFO)的数据结构,只允许在队列尾部插入元素,在队列头部删除元素。
- 基本操作:
- 入队:将元素插入队列尾部。时间复杂度为O(1)。
- 出队:从队列头部删除元素。时间复杂度为O(1)。
- 查看队首元素:获取队首元素但不删除。时间复杂度为O(1)。
- 适用场景:适用于需要按照先进先出顺序处理元素的场景,如任务调度、消息传递等。
哈希表 (Hash Table)
- 插入:平均情况O(1),最坏情况O(n)
- 删除:平均情况O(1),最坏情况O(n)
- 查找:平均情况O(1),最坏情况O(n)
- 定义:哈希表是一种根据关键字直接访问内存位置的数据结构,通过哈希函数将关键字映射到表中的位置。
- 基本操作:
- 插入:根据关键字插入元素。平均情况下时间复杂度为O(1),最坏情况下为O(n)。
- 删除:根据关键字删除元素。平均情况下时间复杂度为O(1),最坏情况下为O(n)。
- 查找:根据关键字查找元素。平均情况下时间复杂度为O(1),最坏情况下为O(n)。
- 适用场景:适用于需要快速查找、插入和删除元素的场景,如字典、缓存等。
树 (Tree)
- 搜索:O(log n) (对于平衡二叉搜索树)
- 插入:O(log n) (对于平衡二叉搜索树)
- 删除:O(log n) (对于平衡二叉搜索树)
- 遍历:O(n) (中序、前序、后序遍历)
- 定义:树是一种非线性数据结构,由节点和边组成,每个节点最多有一个父节点和多个子节点。
- 基本操作:
- 插入:根据规则插入节点。时间复杂度取决于树的平衡性和插入位置。
- 删除:根据规则删除节点。时间复杂度取决于树的平衡性和删除位置。
- 遍历:按照某种顺序访问树中的所有节点。时间复杂度为O(n),n为树中节点的数量。
- 适用场景:适用于需要组织层次关系的数据,如文件系统、组织结构等。
堆 (Heap)
- 插入:O(log n)
- 删除:O(log n)
- 获取最小/最大值:O(1)
- 定义:堆是一种特殊的树形数据结构,满足堆属性,如最大堆或最小堆,用于高效地查找和删除最大或最小元素。
- 基本操作:
- 插入:将新元素插入堆中,并保持堆的性质。时间复杂度为O(log n),n为堆中元素的数量。
- 删除:删除堆中的最大或最小元素,并保持堆的性质。时间复杂度为O(log n),n为堆中元素的数量。
- 获取最大或最小元素:获取堆中的最大或最小元素,但不删除。时间复杂度为O(1)。
- 适用场景:适用于需要快速获取最大或最小元素的场景,如优先队列、排序算法等。
图 (Graph)
- 深度优先搜索 (DFS):O(V + E)
- 广度优先搜索 (BFS):O(V + E)
- 最短路径 (Dijkstra算法):O((V + E) * log V)
- 定义:图是由顶点和边组成的非线性数据结构,用于表示多对多的关系。
- 基本操作:
- 插入顶点:添加新的顶点到图中。时间复杂度为O(1)。
- 插入边:在两个顶点之间添加一条边。时间复杂度为O(1)。
- 遍历:按照某种方式访问图中的所有顶点和边。时间复杂度取决于遍历算法的实现。
- 适用场景:适用于表示网络、社交关系等具有复杂关联的场景,如社交网络、路由器
自制表
时间复杂度耗费的时间从上往下为从小到大的顺序:
名称 | 时间复杂度 | 例子 | 例子说明 |
---|---|---|---|
常数阶 | O(1) | 1 | 常数时间复杂度,不受输入规模影响 |
对数阶 | O(log(m)n) | log(n) | 对数时间复杂度,通常用于二分查找 |
线性阶 | O(n) | n | 线性时间复杂度,随输入规模线性增长 |
线性对数阶 | O(n*log(m)n) | n*log(n) | 线性对数时间复杂度,常见于快速排序 |
平方阶 | O(n^2) | n^2 | 平方时间复杂度,通常用于简单的嵌套循环 |
立方阶 | O(n^3) | n^3 | 立方时间复杂度,通常用于三重嵌套循环 |
指数阶 | O(2^n) | 2^n | 指数时间复杂度,常见于穷举法 |
阶乘阶 | O(n!) | n! | 阶乘时间复杂度,通常用于穷举法 |
幂阶 | O(n^n) | n^n | 幂时间复杂度,常见于集合的幂集生成 |
常见时间复杂度表达式及其含义
- O(1) - 常数时间复杂度 算法的运行时间不随输入数据的增加而增长,通常由返回语句或极少量的运算产生。
- O(logn) - 对数时间复杂度
算法的运行时间随着输入数据的增长呈对数增长,通常出现在通过问题规模的递归分解实现的高效算法中,如二分查找、分治算法等。 - O(n) - 线性时间复杂度 算法的运行时间正比于输入数据的规模,通常存在于只循环一次的简单算法中,如顺序查找、链表的基本操作等。
- O(nlogn) - 对数线性时间复杂度 算法的运行时间是n与logn的乘积,通常存在于分治算法中,如快速排序、归并排序、堆排序等。
- O(n^2) - 平方时间复杂度 算法的运行时间与输入数据的平方成正比,常见于嵌套循环算法,如冒泡排序、插入排序等简单排序算法。
- O(n^3) - 立方时间复杂度 算法的运行时间与输入数据的立方成正比,罕见于实际应用,但有时会作为最坏情况出现。
- O(2^n) - 指数时间复杂度 算法的运行时间随着输入数据的增长呈指数增长,通常存在于求解复杂问题的暴力穷举算法中,如旅行商问题、背包问题等。
- O(n!) - 阶乘时间复杂度 算法的运行时间与输入数据的阶乘成正比,是最坏的情况,通常很少出现。
除了以上常见的时间复杂度表达式外,还有些特殊的表达式:
- O(sqrt(n)) - 平方根时间复杂度
- O(log(logn)) - 对数对数时间复杂度
- O(C^n) - 指数时间复杂度,其中C为常量