常见的排序算法的时间复杂度
排序算法的时间复杂度通常取决于输入数据的规模(通常表示为n)。以下是一些常见排序算法及其平均、最好和最坏情况下的时间复杂度:
1、冒泡排序(Bubble Sort)
-
平均时间复杂度:O(n^2)
-
最好情况时间复杂度:O(n)
-
最坏情况时间复杂度:O(n^2)
冒泡排序通过重复地遍历待排序序列,比较相邻元素的大小并交换它们的位置,直到没有元素需要交换为止。
在最坏情况下,即序列完全逆序时,冒泡排序需要进行n-1轮比较,每轮比较都需要遍历整个序列。因此,时间复杂度为O(n^2)。
在最好情况下,即序列已经有序时,冒泡排序只需要进行一轮比较,时间复杂度为O(n)。
平均情况下,冒泡排序的时间复杂度也是O(n^2)。
2、选择排序(Selection Sort)
-
平均时间复杂度:O(n^2)
-
最好情况时间复杂度:O(n^2)
-
最坏情况时间复杂度:O(n^2)
选择排序在每一轮迭代中选择剩余元素中的最小(或最大)元素,并将其放到序列的起始位置。
选择排序的时间复杂度与输入序列的顺序无关,因为每轮迭代都需要遍历剩余元素以找到最小(或最大)元素。因此,无论最好、最坏还是平均情况,选择排序的时间复杂度都是O(n^2)。
3、插入排序(Insertion Sort)
- 平均时间复杂度:O(n^2)
- 最好情况时间复杂度:O(n)
- 最坏情况时间复杂度:O(n^2)
插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
在最坏情况下,即序列完全逆序时,每次插入都需要将已排序的元素逐个向后移动,时间复杂度为O(n^2)。
在最好情况下,即序列已经有序时,插入排序只需要遍历一次序列即可完成,时间复杂度为O(n)。
平均情况下,插入排序的时间复杂度也是O(n^2),但通常比冒泡排序和选择排序稍快一些。
4、希尔排序(Shell Sort)
- 平均时间复杂度:O(n log n) 到 O(n^2),取决于增量序列的选择
- 最好情况时间复杂度:O(n log n)
- 最坏情况时间复杂度:O(n^2)
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
该算法由希尔(Donald Shell)于1959年提出,基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
具体算法步骤为:
- 选择一个增量序列t1,t2,...,tk,其中ti>tj,tk=1。
- 按增量序列个数k,对序列进行k趟排序。
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。
希尔排序的时间复杂度与增量序列的选择有关,但通常情况下,希尔排序的时间复杂度较直接插入排序、冒泡排序、选择排序等方法有较大改进。在实际应用中,希尔排序是一种性能较好的排序算法。
5、归并排序(Merge Sort)
- 平均时间复杂度:O(n log n)
- 最好情况时间复杂度:O(n log n)
- 最坏情况时间复杂度:O(n log n)
归并排序采用分治策略,将序列递归地分成两半,直到子序列长度为1(认为已有序),然后将有序子序列合并成一个有序序列。
归并排序的时间复杂度与输入序列的顺序无关,总是为O(n log n)。这是因为它将问题划分为两个大致相等的子问题,并将它们递归地解决,然后将结果合并。
6、快速排序(Quick Sort)
- 平均时间复杂度:O(n log n)
- 最好情况时间复杂度:O(n log n)
- 最坏情况时间复杂度:O(n^2)(当输入数据已经排序或逆序时)
快速排序是一种高效的排序算法,它采用分治策略。通过选择一个基准元素,将序列划分为左右两部分,左边部分小于基准,右边部分大于基准,然后递归地对左右两部分进行排序。
在最好情况下,即每次划分都能将序列均匀分为两部分时,快速排序的时间复杂度为O(n log n)。
在最坏情况下,即输入序列已经有序或逆序时,快速排序退化为O(n^2)。
平均情况下,快速排序的时间复杂度为O(n log n),但由于划分的不均匀性,实际性能可能有所波动。
7、堆排序(Heap Sort)
- 平均时间复杂度:O(n log n)
- 最好情况时间复杂度:O(n log n)
- 最坏情况时间复杂度:O(n log n)
堆排序利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
堆排序包括两个主要阶段:建堆和堆调整排序。建堆的时间复杂度为O(n),堆调整排序的时间复杂度为O(nlogn),因此总的时间复杂度为O(nlogn)。
8、计数排序(Counting Sort)
- 时间复杂度:O(n + k),其中k是整数的范围
计数排序(Counting Sort)是一种线性时间复杂度的排序算法,它的基本思想是将输入的数据值转化为键存储在额外开辟的数组空间中。计数排序不是基于比较的排序算法,其优势在于在对一定范围内的整数排序时,复杂度为O(n+k),其中n为输入元素个数,k为待排序列中最大的数。这使得计数排序快于任何比较排序算法。
计数排序要求输入的数据必须是有确定范围的整数。排序过程大致如下:
- 找出待排序数组中的最大和最小元素。
- 统计数组中每个值为i的元素出现的次数,存入数组count的第i项。
- 对所有的计数进行累加(从count中的第一个元素开始,每一项和前一项相加),为了直接求得元素的位置。
- 反向填充目标数组:将每个元素i放在新数组的第count[i]项,每放一个元素就将count[i]减去1。
需要注意的是,计数排序的空间复杂度为O(k),其中k为待排序列中最大的数。这意味着如果数据的范围很大,计数排序可能需要消耗大量的内存。因此,计数排序更适合于数据范围较小的情况,如排序0到100之间的数字。对于数据范围很大的数组或者非整数数据,计数排序可能不是最佳选择。
9、桶排序(Bucket Sort)
- 时间复杂度:取决于数据分布和桶的数量,通常在O(n + n^2/k)到O(n^2)之间,其中k是桶的数量
桶排序(Bucket Sort)是一种分配式排序算法,它的工作原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来以得到有序序列。
桶排序的假设是:待排序的一组数均匀独立地分布在一个范围中,并将这一范围划分成几个子范围(即桶)。然后基于某种映射函数,将待排序列的关键字映射到第i个桶中(即桶数组B的下标i),那么该关键字就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着,对每个桶中的元素进行排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次将各个桶中的元素取出,得到的就是有序序列。
桶排序的时间复杂度依赖于数据的分布和桶的数量。当数据均匀分布时,桶排序使用线性时间(Θ(n))。然而,如果数据分布不均匀,或者桶的数量选择不当,桶排序的性能可能会下降。此外,桶排序并不是比较排序,因此它不受O(n log n)下限的影响。
需要注意的是,桶排序在实际应用中可能受到一些限制。例如,如果数据的范围非常大,或者数据的分布极不均匀,那么可能需要大量的桶,这可能导致空间复杂度的增加。此外,桶排序还需要额外的空间来存储桶和桶中的元素,因此可能不适合内存有限的环境。
10、基数排序(Radix Sort)
- 时间复杂度:O(d(n + k)),其中d是数字的位数,k是整数的范围
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
基数排序的时间复杂度是线性的,为O(dn),其中d为数字的位数,n为待排序序列的长度。这是因为基数排序需要对每一位进行计数或分配,然后将它们收集起来。
需要注意的是,这些时间复杂度是理论上的,实际性能可能受到多种因素的影响,包括输入数据的特性、计算机系统的特性以及算法的具体实现方式。此外,对于某些特定的应用场景,可能还需要考虑空间复杂度等其他因素。
先赞后看,养成习惯!!!^ _ ^ ❤️ ❤️ ❤️
码字不易,大家的支持就是我的坚持下去的动力。点赞后不要忘了关注我哦!